diff --git a/accessible/public/nsIAccessible.idl b/accessible/public/nsIAccessible.idl index 8af90ba6266a..bef69df27772 100644 --- a/accessible/public/nsIAccessible.idl +++ b/accessible/public/nsIAccessible.idl @@ -56,7 +56,7 @@ interface nsIAccessibleRelation; * Mozilla creates the implementations of nsIAccessible on demand. * See http://www.mozilla.org/projects/ui/accessibility for more information. */ -[scriptable, uuid(c7ac764a-b4c5-4479-9fb7-06e3c9f3db34)] +[scriptable, uuid(3126544c-826c-4694-a2ed-67bfe56a1f37)] interface nsIAccessible : nsISupports { /** @@ -221,26 +221,6 @@ interface nsIAccessible : nsISupports */ nsIAccessible getChildAt(in long aChildIndex); - /** - * Accessible node geometrically to the right of this one - */ - nsIAccessible getAccessibleToRight(); - - /** - * Accessible node geometrically to the left of this one - */ - nsIAccessible getAccessibleToLeft(); - - /** - * Accessible node geometrically above this one - */ - nsIAccessible getAccessibleAbove(); - - /** - * Accessible node geometrically below this one - */ - nsIAccessible getAccessibleBelow(); - /** * Return accessible relation by the given relation type (see. * constants defined in nsIAccessibleRelation). diff --git a/accessible/src/base/nsAccessible.cpp b/accessible/src/base/nsAccessible.cpp index 414c70d11cc1..8e0ecfad01bc 100644 --- a/accessible/src/base/nsAccessible.cpp +++ b/accessible/src/base/nsAccessible.cpp @@ -1974,30 +1974,6 @@ NS_IMETHODIMP nsAccessible::GetHelp(nsAString& _retval) return NS_ERROR_NOT_IMPLEMENTED; } -/* nsIAccessible getAccessibleToRight(); */ -NS_IMETHODIMP nsAccessible::GetAccessibleToRight(nsIAccessible **_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -/* nsIAccessible getAccessibleToLeft(); */ -NS_IMETHODIMP nsAccessible::GetAccessibleToLeft(nsIAccessible **_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -/* nsIAccessible getAccessibleAbove(); */ -NS_IMETHODIMP nsAccessible::GetAccessibleAbove(nsIAccessible **_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -/* nsIAccessible getAccessibleBelow(); */ -NS_IMETHODIMP nsAccessible::GetAccessibleBelow(nsIAccessible **_retval) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - nsIContent* nsAccessible::GetAtomicRegion() const { diff --git a/accessible/src/msaa/nsAccessibleWrap.cpp b/accessible/src/msaa/nsAccessibleWrap.cpp index b6eac300fc1c..c506b3839e0b 100644 --- a/accessible/src/msaa/nsAccessibleWrap.cpp +++ b/accessible/src/msaa/nsAccessibleWrap.cpp @@ -810,42 +810,35 @@ __try { if (!pvarEndUpAt) return E_INVALIDARG; - nsAccessible *xpAccessibleStart = GetXPAccessibleFor(varStart); - if (!xpAccessibleStart || IsDefunct()) + nsAccessible* accessible = GetXPAccessibleFor(varStart); + if (!accessible || accessible->IsDefunct()) return E_FAIL; VariantInit(pvarEndUpAt); - nsCOMPtr xpAccessibleResult; + nsAccessible* navAccessible = nsnull; PRUint32 xpRelation = 0; switch(navDir) { - case NAVDIR_DOWN: - xpAccessibleStart->GetAccessibleBelow(getter_AddRefs(xpAccessibleResult)); - break; case NAVDIR_FIRSTCHILD: - if (!nsAccUtils::MustPrune(xpAccessibleStart)) - xpAccessibleStart->GetFirstChild(getter_AddRefs(xpAccessibleResult)); + if (!nsAccUtils::MustPrune(accessible)) + navAccessible = accessible->FirstChild(); break; case NAVDIR_LASTCHILD: - if (!nsAccUtils::MustPrune(xpAccessibleStart)) - xpAccessibleStart->GetLastChild(getter_AddRefs(xpAccessibleResult)); - break; - case NAVDIR_LEFT: - xpAccessibleStart->GetAccessibleToLeft(getter_AddRefs(xpAccessibleResult)); + if (!nsAccUtils::MustPrune(accessible)) + navAccessible = accessible->LastChild(); break; case NAVDIR_NEXT: - xpAccessibleStart->GetNextSibling(getter_AddRefs(xpAccessibleResult)); + navAccessible = accessible->NextSibling(); break; case NAVDIR_PREVIOUS: - xpAccessibleStart->GetPreviousSibling(getter_AddRefs(xpAccessibleResult)); + navAccessible = accessible->PrevSibling(); break; + case NAVDIR_DOWN: + case NAVDIR_LEFT: case NAVDIR_RIGHT: - xpAccessibleStart->GetAccessibleToRight(getter_AddRefs(xpAccessibleResult)); - break; case NAVDIR_UP: - xpAccessibleStart->GetAccessibleAbove(getter_AddRefs(xpAccessibleResult)); - break; + return E_NOTIMPL; // MSAA relationship extensions to accNavigate case NAVRELATION_CONTROLLED_BY: @@ -896,17 +889,20 @@ __try { case NAVRELATION_DESCRIPTION_FOR: xpRelation = nsIAccessibleRelation::RELATION_DESCRIPTION_FOR; break; + + default: + return E_INVALIDARG; } pvarEndUpAt->vt = VT_EMPTY; if (xpRelation) { Relation rel = RelationByType(xpRelation); - xpAccessibleResult = rel.Next(); + navAccessible = rel.Next(); } - if (xpAccessibleResult) { - pvarEndUpAt->pdispVal = NativeAccessible(xpAccessibleResult); + if (navAccessible) { + pvarEndUpAt->pdispVal = NativeAccessible(navAccessible); pvarEndUpAt->vt = VT_DISPATCH; return S_OK; } diff --git a/aclocal.m4 b/aclocal.m4 index efaca9b457d3..2e6734a9440a 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -16,6 +16,7 @@ builtin(include, build/autoconf/mozheader.m4)dnl builtin(include, build/autoconf/acwinpaths.m4)dnl builtin(include, build/autoconf/lto.m4)dnl builtin(include, build/autoconf/gcc-pr49911.m4)dnl +builtin(include, build/autoconf/frameptr.m4)dnl MOZ_PROG_CHECKMSYS() diff --git a/browser/components/sessionstore/src/nsSessionStore.js b/browser/components/sessionstore/src/nsSessionStore.js index 6a67311bf011..5c15e6e0ccee 100644 --- a/browser/components/sessionstore/src/nsSessionStore.js +++ b/browser/components/sessionstore/src/nsSessionStore.js @@ -486,6 +486,11 @@ SessionStoreService.prototype = { this._forEachBrowserWindow(function(aWindow) { this._collectWindowData(aWindow); }); + // we must cache this because _getMostRecentBrowserWindow will always + // return null by the time quit-application occurs + var activeWindow = this._getMostRecentBrowserWindow(); + if (activeWindow) + this.activeWindowSSiCache = activeWindow.__SSi || ""; this._dirtyWindows = []; break; case "quit-application-granted": @@ -1512,6 +1517,13 @@ SessionStoreService.prototype = { let lastWindow = this._getMostRecentBrowserWindow(); let canUseLastWindow = lastWindow && !lastWindow.__SS_lastSessionWindowID; + let lastSessionFocusedWindow = null; + this.windowToFocus = lastWindow; + + // move the last focused window to the start of the array so that we + // minimize window movement (see bug 669272) + lastSessionState.windows.unshift( + lastSessionState.windows.splice(lastSessionState.selectedWindow - 1, 1)[0]); // Restore into windows or open new ones as needed. for (let i = 0; i < lastSessionState.windows.length; i++) { @@ -1549,9 +1561,18 @@ SessionStoreService.prototype = { // weirdness but we will still merge other extData. // Bug 588217 should make this go away by merging the group data. this.restoreWindow(windowToUse, { windows: [winState] }, canOverwriteTabs, true); + if (i == 0) + lastSessionFocusedWindow = windowToUse; + + // if we overwrote the tabs for our last focused window, we should + // give focus to the window that had it in the previous session + if (canOverwriteTabs && windowToUse == lastWindow) + this.windowToFocus = lastSessionFocusedWindow; } else { - this._openWindowWithState({ windows: [winState] }); + let win = this._openWindowWithState({ windows: [winState] }); + if (i == 0) + lastSessionFocusedWindow = win; } } @@ -2544,8 +2565,12 @@ SessionStoreService.prototype = { this._closedWindows = root._closedWindows; var winData; - if (!aState.selectedWindow) { - aState.selectedWindow = 0; + if (!root.selectedWindow) { + root.selectedWindow = 0; + } else { + // put the selected window at the beginning of the array to ensure that + // it gets restored first + root.windows.unshift(root.windows.splice(root.selectedWindow - 1, 1)[0]); } // open new windows for all further window entries of a multi-window session // (unless they don't contain any tab data) @@ -2553,9 +2578,6 @@ SessionStoreService.prototype = { winData = root.windows[w]; if (winData && winData.tabs && winData.tabs[0]) { var window = this._openWindowWithState({ windows: [winData] }); - if (w == aState.selectedWindow - 1) { - this.windowToFocus = window; - } } } winData = root.windows[0]; diff --git a/browser/devtools/styleinspector/StyleInspector.jsm b/browser/devtools/styleinspector/StyleInspector.jsm index 19798ab15afb..9ca4b6c4fefa 100644 --- a/browser/devtools/styleinspector/StyleInspector.jsm +++ b/browser/devtools/styleinspector/StyleInspector.jsm @@ -55,7 +55,13 @@ var StyleInspector = { return Services.prefs.getBoolPref("devtools.styleinspector.enabled"); }, - createPanel: function SI_createPanel() + /** + * Factory method to create the actual style panel + * @param {Boolean} aPreserveOnHide Prevents destroy from being called + * onpopuphide. USE WITH CAUTION: When this value is set to true then you are + * responsible to manually call destroy from outside the style inspector. + */ + createPanel: function SI_createPanel(aPreserveOnHide) { let win = Services.wm.getMostRecentWindow("navigator:browser"); let popupSet = win.document.getElementById("mainPopupSet"); @@ -98,7 +104,10 @@ var StyleInspector = { hbox.appendChild(resizer); popupSet.appendChild(panel); - panel.addEventListener("popupshown", function SI_popup_shown() { + /** + * Initialize the popup when it is first shown + */ + function SI_popupShown() { if (!this.cssHtmlTree) { this.cssLogic = new CssLogic(); this.cssHtmlTree = new CssHtmlTree(iframe, this.cssLogic, this); @@ -107,12 +116,23 @@ var StyleInspector = { this.cssLogic.highlight(this.selectedNode); this.cssHtmlTree.highlight(this.selectedNode); Services.obs.notifyObservers(null, "StyleInspector-opened", null); - }, false); + } + + /** + * Hide the popup and conditionally destroy it + */ + function SI_popupHidden() { + if (panel.preserveOnHide) { + Services.obs.notifyObservers(null, "StyleInspector-closed", null); + } else { + panel.destroy(); + } + } + + panel.addEventListener("popupshown", SI_popupShown); + panel.addEventListener("popuphidden", SI_popupHidden); + panel.preserveOnHide = !!aPreserveOnHide; - panel.addEventListener("popuphidden", function SI_popup_hidden() { - Services.obs.notifyObservers(null, "StyleInspector-closed", null); - }, false); - /** * Check if the style inspector is open */ @@ -138,6 +158,19 @@ var StyleInspector = { } }; + /** + * Destroy the style panel, remove listeners etc. + */ + panel.destroy = function SI_destroy() + { + this.cssLogic = null; + this.cssHtmlTree = null; + this.removeEventListener("popupshown", SI_popupShown); + this.removeEventListener("popuphidden", SI_popupHidden); + this.parentNode.removeChild(this); + Services.obs.notifyObservers(null, "StyleInspector-closed", null); + }; + /** * Is the Style Inspector initialized? * @returns {Boolean} true or false diff --git a/browser/devtools/webconsole/HUDService.jsm b/browser/devtools/webconsole/HUDService.jsm index d0b852b28492..e71468955e87 100644 --- a/browser/devtools/webconsole/HUDService.jsm +++ b/browser/devtools/webconsole/HUDService.jsm @@ -1786,7 +1786,6 @@ HUD_SERVICE.prototype = panels = popupset.querySelectorAll("panel[hudToolId=" + aHUDId + "]"); for (let i = 0; i < panels.length; i++) { panels[i].hidePopup(); - popupset.removeChild(panels[i]); } let id = ConsoleUtils.supString(aHUDId); diff --git a/browser/themes/pinstripe/browser/browser.css b/browser/themes/pinstripe/browser/browser.css index 6ff7ddf1d48a..554499062b11 100644 --- a/browser/themes/pinstripe/browser/browser.css +++ b/browser/themes/pinstripe/browser/browser.css @@ -811,9 +811,22 @@ toolbar[mode="icons"] #zoom-in-button { background-clip: padding-box; } -#urlbar:-moz-window-inactive, -.searchbar-textbox:-moz-window-inactive { - border-color: @toolbarbuttonInactiveBorderColor@; +@media (-moz-mac-lion-theme) { + #urlbar, + .searchbar-textbox { + background-image: -moz-linear-gradient(hsl(0,0%,97%), hsl(0,0%,100%)); + border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.25) hsla(0,0%,0%,.15); + box-shadow: 0 1px 0 hsla(0,0%,100%,.2), + inset 0 0 1px hsla(0,0%,0%,.05), + inset 0 1px 2px hsla(0,0%,0%,.1); + } +} + +@media not all and (-moz-mac-lion-theme) { + #urlbar:-moz-window-inactive, + .searchbar-textbox:-moz-window-inactive { + border-color: @toolbarbuttonInactiveBorderColor@; + } } #urlbar[focused="true"], diff --git a/build/autoconf/frameptr.m4 b/build/autoconf/frameptr.m4 new file mode 100644 index 000000000000..77a6d71aedc8 --- /dev/null +++ b/build/autoconf/frameptr.m4 @@ -0,0 +1,25 @@ +dnl Set MOZ_FRAMEPTR_FLAGS to the flags that should be used for enabling or +dnl disabling frame pointers in this architecture based on the configure +dnl options + +AC_DEFUN([MOZ_SET_FRAMEPTR_FLAGS], [ + if test "$GNU_CC"; then + MOZ_ENABLE_FRAME_PTR="-fno-omit-frame-pointer" + MOZ_DISABLE_FRAME_PTR="-fomit-frame-pointer" + else + case "$target" in + *-mingw*) + MOZ_ENABLE_FRAME_PTR="-Oy-" + MOZ_DISABLE_FRAME_PTR="-Oy" + ;; + esac + fi + + # if we are debugging or profiling, we want a frame pointer. + if test -z "$MOZ_OPTIMIZE" -o \ + -n "$MOZ_PROFILING" -o -n "$MOZ_DEBUG"; then + MOZ_FRAMEPTR_FLAGS="$MOZ_ENABLE_FRAME_PTR" + else + MOZ_FRAMEPTR_FLAGS="$MOZ_DISABLE_FRAME_PTR" + fi +]) diff --git a/caps/src/nsScriptSecurityManager.cpp b/caps/src/nsScriptSecurityManager.cpp index 4c0e084801e6..461545a8b206 100644 --- a/caps/src/nsScriptSecurityManager.cpp +++ b/caps/src/nsScriptSecurityManager.cpp @@ -2423,7 +2423,7 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj // avoid wasting time checking properties of their classes etc in // the loop. - if (jsClass == &js_FunctionClass) { + if (jsClass == &js::FunctionClass) { aObj = aObj->getParent(); if (!aObj) @@ -2431,7 +2431,7 @@ nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj jsClass = aObj->getClass(); - if (jsClass == &js_CallClass) { + if (jsClass == &js::CallClass) { aObj = aObj->getParent(); if (!aObj) diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index ea68d9fcc3f0..52ccb44c59b5 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -303,6 +303,7 @@ ACDEFINES = @MOZ_DEFINES@ WARNINGS_AS_ERRORS = @WARNINGS_AS_ERRORS@ MOZ_OPTIMIZE = @MOZ_OPTIMIZE@ +MOZ_FRAMEPTR_FLAGS = @MOZ_FRAMEPTR_FLAGS@ MOZ_OPTIMIZE_FLAGS = @MOZ_OPTIMIZE_FLAGS@ MOZ_PGO_OPTIMIZE_FLAGS = @MOZ_PGO_OPTIMIZE_FLAGS@ MOZ_OPTIMIZE_LDFLAGS = @MOZ_OPTIMIZE_LDFLAGS@ diff --git a/config/config.mk b/config/config.mk index 54c03ed8e989..bfb2c1596945 100644 --- a/config/config.mk +++ b/config/config.mk @@ -463,6 +463,9 @@ endif # MOZ_OPTIMIZE == 1 endif # MOZ_OPTIMIZE endif # CROSS_COMPILE +CFLAGS += $(MOZ_FRAMEPTR_FLAGS) +CXXFLAGS += $(MOZ_FRAMEPTR_FLAGS) + # Check for FAIL_ON_WARNINGS & FAIL_ON_WARNINGS_DEBUG (Shorthand for Makefiles # to request that we use the 'warnings as errors' compile flags) diff --git a/configure.in b/configure.in index cc0305262a09..261d86765953 100644 --- a/configure.in +++ b/configure.in @@ -2071,12 +2071,7 @@ case "$target" in *-darwin*) MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' - # If we're building with --enable-profiling, we need a frame pointer. - if test -z "$MOZ_PROFILING"; then - MOZ_OPTIMIZE_FLAGS="-O3 -fomit-frame-pointer" - else - MOZ_OPTIMIZE_FLAGS="-O3 -fno-omit-frame-pointer" - fi + MOZ_OPTIMIZE_FLAGS="-O3" _PEDANTIC= CFLAGS="$CFLAGS -fno-common" CXXFLAGS="$CXXFLAGS -fno-common" @@ -2188,12 +2183,7 @@ ia64*-hpux*) TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"' MOZ_GFX_OPTIMIZE_MOBILE=1 - # If we're building with --enable-profiling, we need a frame pointer. - if test -z "$MOZ_PROFILING"; then - MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fomit-frame-pointer" - else - MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fno-omit-frame-pointer" - fi + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions" ;; *-*linux*) @@ -2211,14 +2201,8 @@ ia64*-hpux*) # -Os is broken on gcc 4.1.x 4.2.x, 4.5.x we need to tweak it to get good results. MOZ_OPTIMIZE_SIZE_TWEAK="-finline-limit=50" esac - # If we're building with --enable-profiling, we need a frame pointer. - if test -z "$MOZ_PROFILING"; then - MOZ_FRAMEPTR_FLAGS="-fomit-frame-pointer" - else - MOZ_FRAMEPTR_FLAGS="-fno-omit-frame-pointer" - fi - MOZ_PGO_OPTIMIZE_FLAGS="-O3 $MOZ_FRAMEPTR_FLAGS" - MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks $MOZ_OPTIMIZE_SIZE_TWEAK $MOZ_FRAMEPTR_FLAGS" + MOZ_PGO_OPTIMIZE_FLAGS="-O3" + MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks $MOZ_OPTIMIZE_SIZE_TWEAK" MOZ_DEBUG_FLAGS="-g" fi @@ -2315,12 +2299,7 @@ ia64*-hpux*) MOZ_DEBUG_FLAGS='-Zi' MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV' WARNINGS_AS_ERRORS='-WX' - # If we're building with --enable-profiling, we need -Oy-, which forces a frame pointer. - if test -z "$MOZ_PROFILING"; then - MOZ_OPTIMIZE_FLAGS='-O1' - else - MOZ_OPTIMIZE_FLAGS='-O1 -Oy-' - fi + MOZ_OPTIMIZE_FLAGS='-O1' MOZ_FIX_LINK_PATHS= DYNAMIC_XPCOM_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib $(LIBXUL_DIST)/lib/mozalloc.lib' XPCOM_FROZEN_LDOPTS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/mozalloc.lib' @@ -6897,6 +6876,8 @@ else MOZ_OPTIMIZE= fi ], MOZ_OPTIMIZE=1) +MOZ_SET_FRAMEPTR_FLAGS + if test "$COMPILE_ENVIRONMENT"; then if test -n "$MOZ_OPTIMIZE"; then AC_MSG_CHECKING([for valid optimization flags]) @@ -6915,6 +6896,7 @@ fi fi # COMPILE_ENVIRONMENT AC_SUBST(MOZ_OPTIMIZE) +AC_SUBST(MOZ_FRAMEPTR_FLAGS) AC_SUBST(MOZ_OPTIMIZE_FLAGS) AC_SUBST(MOZ_OPTIMIZE_LDFLAGS) AC_SUBST(MOZ_OPTIMIZE_SIZE_TWEAK) diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index 0503e6b64a0e..5769b13e3d62 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1700,6 +1700,26 @@ public: */ static PRBool IsFocusedContent(const nsIContent *aContent); + /** + * Returns PR_TRUE if the DOM full-screen API is enabled. + */ + static PRBool IsFullScreenApiEnabled(); + + /** + * Returns PR_TRUE if requests for full-screen are allowed in the current + * context. Requests are only allowed if the user initiated them (like with + * a mouse-click or key press), unless this check has been disabled by + * setting the pref "full-screen-api.allow-trusted-requests-only" to false. + */ + static PRBool IsRequestFullScreenAllowed(); + + /** + * Returns PR_TRUE if key input is restricted in DOM full-screen mode + * to non-alpha-numeric key codes only. This mirrors the + * "full-screen-api.key-input-restricted" pref. + */ + static PRBool IsFullScreenKeyInputRestricted(); + static void GetShiftText(nsAString& text); static void GetControlText(nsAString& text); static void GetMetaText(nsAString& text); @@ -1864,6 +1884,9 @@ private: static PRBool sIsHandlingKeyBoardEvent; static PRBool sAllowXULXBL_for_file; + static PRBool sIsFullScreenApiEnabled; + static PRBool sTrustedFullScreenOnly; + static PRBool sFullScreenKeyInputRestricted; static nsHtml5Parser* sHTMLFragmentParser; static nsIParser* sXMLFragmentParser; diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index aa8a104328b2..00a1309f2c89 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -125,10 +125,9 @@ class Element; } // namespace dom } // namespace mozilla - #define NS_IDOCUMENT_IID \ -{ 0x455e4d79, 0x756b, 0x4f73, \ - { 0x95, 0xea, 0x3f, 0xf6, 0x0c, 0x6a, 0x8c, 0xa6 } } +{ 0x170d5a75, 0xff0b, 0x4599, \ + { 0x9b, 0x68, 0x18, 0xb7, 0x42, 0xe0, 0xf9, 0xf7 } } // Flag for AddStyleSheet(). #define NS_STYLESHEET_FROM_CATALOG (1 << 0) @@ -742,6 +741,43 @@ public: virtual void AddToNameTable(Element* aElement, nsIAtom* aName) = 0; virtual void RemoveFromNameTable(Element* aElement, nsIAtom* aName) = 0; + /** + * Resets the current full-screen element to nsnull. + */ + virtual void ResetFullScreenElement() = 0; + + /** + * Returns the element which either is the full-screen element, or + * contains the full-screen element if a child of this document contains + * the fullscreen element. + */ + virtual Element* GetFullScreenElement() = 0; + + /** + * Requests that the document make aElement the full-screen element, + * and move into full-screen mode. + */ + virtual void RequestFullScreen(Element* aElement) = 0; + + /** + * Requests that the document, and all documents in its hierarchy exit + * from DOM full-screen mode. + */ + virtual void CancelFullScreen() = 0; + + /** + * Updates the full-screen status on this document, setting the full-screen + * mode to aIsFullScreen. This doesn't affect the window's full-screen mode, + * this updates the document's internal state which determines whether the + * document reports as being in full-screen mode. + */ + virtual void UpdateFullScreenStatus(PRBool aIsFullScreen) = 0; + + /** + * Returns PR_TRUE if this document is in full-screen mode. + */ + virtual PRBool IsFullScreenDoc() = 0; + //---------------------------------------------------------------------- // Document notification API's diff --git a/content/base/public/nsINode.h b/content/base/public/nsINode.h index 5813cb95bc50..bf7713e91662 100644 --- a/content/base/public/nsINode.h +++ b/content/base/public/nsINode.h @@ -282,8 +282,8 @@ private: // IID for the nsINode interface #define NS_INODE_IID \ -{ 0x5572c8a9, 0xbda9, 0x4b78, \ - { 0xb4, 0x1a, 0xdb, 0x1a, 0x83, 0xef, 0x53, 0x7e } } +{ 0xb59269fe, 0x7f60, 0x4672, \ + { 0x8e, 0x56, 0x01, 0x84, 0xb2, 0x58, 0x14, 0xb0 } } /** * An internal interface that abstracts some DOMNode-related parts that both @@ -1085,6 +1085,14 @@ public: return GetNextNodeImpl(aRoot, PR_TRUE); } + /** + * Returns true if 'this' is either document or element or + * document fragment and aOther is a descendant in the same + * anonymous tree. + */ + PRBool Contains(const nsINode* aOther) const; + nsresult Contains(nsIDOMNode* aOther, PRBool* aReturn); + private: nsIContent* GetNextNodeImpl(const nsINode* aRoot, diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 276b80e64f99..de2995a9f6d2 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -176,6 +176,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID); #include "nsIPluginHost.h" #include "nsICategoryManager.h" #include "nsIViewManager.h" +#include "nsEventStateManager.h" #ifdef IBMBIDI #include "nsIBidiKeyboard.h" @@ -261,6 +262,9 @@ nsString* nsContentUtils::sAltText = nsnull; nsString* nsContentUtils::sModifierSeparator = nsnull; PRBool nsContentUtils::sInitialized = PR_FALSE; +PRBool nsContentUtils::sIsFullScreenApiEnabled = PR_FALSE; +PRBool nsContentUtils::sTrustedFullScreenOnly = PR_TRUE; +PRBool nsContentUtils::sFullScreenKeyInputRestricted = PR_TRUE; nsHtml5Parser* nsContentUtils::sHTMLFragmentParser = nsnull; nsIParser* nsContentUtils::sXMLFragmentParser = nsnull; @@ -384,6 +388,15 @@ nsContentUtils::Init() Preferences::AddBoolVarCache(&sAllowXULXBL_for_file, "dom.allow_XUL_XBL_for_file"); + Preferences::AddBoolVarCache(&sIsFullScreenApiEnabled, + "full-screen-api.enabled"); + + Preferences::AddBoolVarCache(&sTrustedFullScreenOnly, + "full-screen-api.allow-trusted-requests-only"); + + Preferences::AddBoolVarCache(&sFullScreenKeyInputRestricted, + "full-screen-api.key-input-restricted"); + sInitialized = PR_TRUE; return NS_OK; @@ -5696,3 +5709,20 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern, return res == JS_FALSE || rval != JSVAL_NULL; } + +PRBool +nsContentUtils::IsFullScreenApiEnabled() +{ + return sIsFullScreenApiEnabled; +} + +PRBool nsContentUtils::IsRequestFullScreenAllowed() +{ + return !sTrustedFullScreenOnly || nsEventStateManager::IsHandlingUserInput(); +} + +PRBool +nsContentUtils::IsFullScreenKeyInputRestricted() +{ + return sFullScreenKeyInputRestricted; +} diff --git a/content/base/src/nsDOMAttribute.cpp b/content/base/src/nsDOMAttribute.cpp index 6a5d20c167c3..9b41ceaeee70 100644 --- a/content/base/src/nsDOMAttribute.cpp +++ b/content/base/src/nsDOMAttribute.cpp @@ -657,6 +657,12 @@ nsDOMAttribute::IsSameNode(nsIDOMNode *other, PRBool *aResult) return NS_OK; } +NS_IMETHODIMP +nsDOMAttribute::Contains(nsIDOMNode* aOther, PRBool* aReturn) +{ + return nsINode::Contains(aOther, aReturn); +} + NS_IMETHODIMP nsDOMAttribute::LookupPrefix(const nsAString & namespaceURI, nsAString & aResult) diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 7a0c6a012652..d3371abe2573 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -181,6 +181,7 @@ #include "nsGlobalWindow.h" #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h" #include "nsDOMNavigationTiming.h" +#include "nsEventStateManager.h" #ifdef MOZ_SMIL #include "nsSMILAnimationController.h" @@ -1544,6 +1545,7 @@ nsDOMImplementation::CreateHTMLDocument(const nsAString& aTitle, nsDocument::nsDocument(const char* aContentType) : nsIDocument() , mAnimatingImages(PR_TRUE) + , mIsFullScreen(PR_FALSE) { SetContentTypeInternal(nsDependentCString(aContentType)); @@ -1871,6 +1873,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument) nsIDOMNodeList) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOriginalDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCachedEncoder) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFullScreenElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStateObjectCached) // Traverse all our nsCOMArrays. @@ -1927,6 +1930,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mImageMaps) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOriginalDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedEncoder) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFullScreenElement) tmp->mParentDocument = nsnull; @@ -5874,6 +5878,12 @@ nsDocument::GetUserData(const nsAString & key, return nsINode::GetUserData(key, aResult); } +NS_IMETHODIMP +nsDocument::Contains(nsIDOMNode* aOther, PRBool* aReturn) +{ + return nsINode::Contains(aOther, aReturn); +} + NS_IMETHODIMP nsDocument::GetInputEncoding(nsAString& aInputEncoding) { @@ -8459,6 +8469,221 @@ nsIDocument::SizeOf() const return size; } +// Returns the root document in a document hierarchy. +static nsIDocument* +GetRootDocument(nsIDocument* aDoc) +{ + if (!aDoc) { + return nsnull; + } + nsCOMPtr shell = aDoc->GetShell(); + if (!shell) { + return nsnull; + } + nsPresContext* ctx = shell->GetPresContext(); + if (!ctx) { + return nsnull; + } + nsRootPresContext* rpc = ctx->GetRootPresContext(); + if (!rpc) { + return nsnull; + } + return rpc->Document(); +} + +class nsDispatchFullScreenChange : public nsRunnable +{ +public: + nsDispatchFullScreenChange(nsIDocument *aDoc) + : mDoc(aDoc) + { + mTarget = aDoc->GetFullScreenElement(); + if (!mTarget) { + mTarget = aDoc; + } + } + + NS_IMETHOD Run() + { + nsContentUtils::DispatchTrustedEvent(mDoc, + mTarget, + NS_LITERAL_STRING("mozfullscreenchange"), + PR_TRUE, + PR_FALSE); + return NS_OK; + } + + nsCOMPtr mDoc; + nsCOMPtr mTarget; +}; + +void +nsDocument::UpdateFullScreenStatus(PRBool aIsFullScreen) +{ + if (mIsFullScreen != aIsFullScreen) { + nsCOMPtr event(new nsDispatchFullScreenChange(this)); + NS_DispatchToCurrentThread(event); + } + mIsFullScreen = aIsFullScreen; + if (!mIsFullScreen) { + // Full-screen is being turned off. Reset the full-screen element, to + // save us from having to traverse the document hierarchy again in + // MozCancelFullScreen(). + ResetFullScreenElement(); + } +} + +static PRBool +UpdateFullScreenStatus(nsIDocument* aDocument, void* aData) +{ + aDocument->UpdateFullScreenStatus(*static_cast(aData)); + aDocument->EnumerateSubDocuments(UpdateFullScreenStatus, aData); + return PR_TRUE; +} + +static void +UpdateFullScreenStatusInDocTree(nsIDocument* aDoc, PRBool aIsFullScreen) +{ + nsIDocument* root = GetRootDocument(aDoc); + if (root) { + UpdateFullScreenStatus(root, static_cast(&aIsFullScreen)); + } +} + +void +nsDocument::ResetFullScreenElement() +{ + if (mFullScreenElement) { + nsEventStateManager::SetFullScreenState(mFullScreenElement, PR_FALSE); + } + mFullScreenElement = nsnull; +} + +static PRBool +ResetFullScreenElement(nsIDocument* aDocument, void* aData) +{ + aDocument->ResetFullScreenElement(); + aDocument->EnumerateSubDocuments(ResetFullScreenElement, aData); + return PR_TRUE; +} + +static void +ResetFullScreenElementInDocTree(nsIDocument* aDoc) +{ + nsIDocument* root = GetRootDocument(aDoc); + if (root) { + ResetFullScreenElement(root, nsnull); + } +} + +NS_IMETHODIMP +nsDocument::MozCancelFullScreen() +{ + if (!nsContentUtils::IsRequestFullScreenAllowed()) { + return NS_OK; + } + CancelFullScreen(); + return NS_OK; +} + +void +nsDocument::CancelFullScreen() +{ + if (!nsContentUtils::IsFullScreenApiEnabled() || + !IsFullScreenDoc() || + !GetWindow()) { + return; + } + + // Disable full-screen mode in all documents in this hierarchy. + UpdateFullScreenStatusInDocTree(this, PR_FALSE); + + // Move the window out of full-screen mode. + GetWindow()->SetFullScreen(PR_FALSE); + + return; +} + +PRBool +nsDocument::IsFullScreenDoc() +{ + return nsContentUtils::IsFullScreenApiEnabled() && mIsFullScreen; +} + +void +nsDocument::RequestFullScreen(Element* aElement) +{ + if (!aElement || !nsContentUtils::IsFullScreenApiEnabled() || !GetWindow()) { + return; + } + + // Reset the full-screen elements of every document in this document + // hierarchy. + ResetFullScreenElementInDocTree(this); + + if (aElement->IsInDoc()) { + // Propagate up the document hierarchy, setting the full-screen element as + // the element's container in ancestor documents. Note we don't propagate + // down the document hierarchy, the full-screen element (or its container) + // is not visible there. + mFullScreenElement = aElement; + // Set the full-screen state on the element, so the css-pseudo class + // applies to the element. + nsEventStateManager::SetFullScreenState(mFullScreenElement, PR_TRUE); + nsIDocument* child = this; + nsIDocument* parent; + while (parent = child->GetParentDocument()) { + nsIContent* content = parent->FindContentForSubDocument(child); + nsCOMPtr element(do_QueryInterface(content)); + // Containing frames also need the css-pseudo class applied. + nsEventStateManager::SetFullScreenState(element, PR_TRUE); + static_cast(parent)->mFullScreenElement = element; + child = parent; + } + } + + // Set all documents in hierarchy to full-screen mode. + UpdateFullScreenStatusInDocTree(this, PR_TRUE); + + // Make the window full-screen. Note we must make the state changes above + // before making the window full-screen, as then the document reports as + // being in full-screen mode when the Chrome "fullscreen" event fires, + // enabling browser.js to distinguish between browser and dom full-screen + // modes. + GetWindow()->SetFullScreen(PR_TRUE); +} + +NS_IMETHODIMP +nsDocument::GetMozFullScreenElement(nsIDOMHTMLElement **aFullScreenElement) +{ + NS_ENSURE_ARG_POINTER(aFullScreenElement); + if (!nsContentUtils::IsFullScreenApiEnabled() || !IsFullScreenDoc()) { + *aFullScreenElement = nsnull; + return NS_OK; + } + nsCOMPtr e(do_QueryInterface(GetFullScreenElement())); + NS_IF_ADDREF(*aFullScreenElement = e); + return NS_OK; +} + +Element* +nsDocument::GetFullScreenElement() +{ + if (!nsContentUtils::IsFullScreenApiEnabled() || + (mFullScreenElement && !mFullScreenElement->IsInDoc())) { + return nsnull; + } + return mFullScreenElement; +} + +NS_IMETHODIMP +nsDocument::GetMozFullScreen(PRBool *aFullScreen) +{ + NS_ENSURE_ARG_POINTER(aFullScreen); + *aFullScreen = nsContentUtils::IsFullScreenApiEnabled() && IsFullScreenDoc(); + return NS_OK; +} + PRInt64 nsDocument::SizeOf() const { diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 28e5310b919b..8f5d0d83e423 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -941,6 +941,13 @@ public: virtual Element* FindImageMap(const nsAString& aNormalizedMapName); + virtual void ResetFullScreenElement(); + virtual Element* GetFullScreenElement(); + virtual void RequestFullScreen(Element* aElement); + virtual void CancelFullScreen(); + virtual void UpdateFullScreenStatus(PRBool aIsFullScreen); + virtual PRBool IsFullScreenDoc(); + protected: friend class nsNodeUtils; @@ -1078,6 +1085,9 @@ protected: // Recorded time of change to 'loading' state. mozilla::TimeStamp mLoadingTimeStamp; + // The current full-screen element of this document. + nsCOMPtr mFullScreenElement; + // True if the document has been detached from its content viewer. PRPackedBool mIsGoingAway:1; // True if the document is being destroyed. @@ -1110,6 +1120,9 @@ protected: // Whether we currently require our images to animate PRPackedBool mAnimatingImages:1; + // Whether we are currently in full-screen mode, as per the DOM API. + PRPackedBool mIsFullScreen:1; + PRUint8 mXMLDeclarationBits; PRUint8 mDefaultElementType; diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 5a7406438888..e59738af3eeb 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -5530,3 +5530,44 @@ nsGenericElement::SizeOf() const #include "nsEventNameList.h" #undef TOUCH_EVENT #undef EVENT + +PRBool +nsINode::Contains(const nsINode* aOther) const +{ + if (!aOther || + aOther == this || + GetOwnerDoc() != aOther->GetOwnerDoc() || + IsInDoc() != aOther->IsInDoc() || + !(aOther->IsElement() || + aOther->IsNodeOfType(nsINode::eCONTENT)) || + !GetFirstChild()) { + return PR_FALSE; + } + + const nsIContent* other = static_cast(aOther); + if (this == GetOwnerDoc()) { + // document.contains(aOther) returns true if aOther is in the document, + // but is not in any anonymous subtree. + // IsInDoc() check is done already before this. + return !other->IsInAnonymousSubtree(); + } + + if (!IsElement() && !IsNodeOfType(nsINode::eDOCUMENT_FRAGMENT)) { + return PR_FALSE; + } + + const nsIContent* thisContent = static_cast(this); + if (thisContent->GetBindingParent() != other->GetBindingParent()) { + return PR_FALSE; + } + + return nsContentUtils::ContentIsDescendantOf(other, this); +} + +nsresult +nsINode::Contains(nsIDOMNode* aOther, PRBool* aReturn) +{ + nsCOMPtr node = do_QueryInterface(aOther); + *aReturn = Contains(node); + return NS_OK; +} diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h index e24ae0c02e3b..740aba8c8652 100644 --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -63,6 +63,7 @@ GK_ATOM(_empty, "") GK_ATOM(moz, "_moz") +GK_ATOM(mozallowfullscreen, "mozallowfullscreen") GK_ATOM(moztype, "_moz-type") GK_ATOM(mozdirty, "_moz_dirty") GK_ATOM(mozdonotsend, "moz-do-not-send") @@ -583,6 +584,7 @@ GK_ATOM(mouseout, "mouseout") GK_ATOM(mouseover, "mouseover") GK_ATOM(mousethrough, "mousethrough") GK_ATOM(mouseup, "mouseup") +GK_ATOM(mozfullscreenchange, "mozfullscreenchange") GK_ATOM(moz_opaque, "moz-opaque") GK_ATOM(moz_action_hint, "mozactionhint") GK_ATOM(x_moz_errormessage, "x-moz-errormessage") @@ -695,6 +697,7 @@ GK_ATOM(onMozMouseHittest, "onMozMouseHittest") GK_ATOM(onmouseup, "onmouseup") GK_ATOM(onMozAfterPaint, "onMozAfterPaint") GK_ATOM(onMozBeforePaint, "onMozBeforePaint") +GK_ATOM(onmozfullscreenchange, "onmozfullscreenchange") GK_ATOM(onMozMousePixelScroll, "onMozMousePixelScroll") GK_ATOM(onMozScrolledAreaChanged, "onMozScrolledAreaChanged") GK_ATOM(ononline, "ononline") diff --git a/content/base/test/chrome/Makefile.in b/content/base/test/chrome/Makefile.in index 36704bf87384..0f0f3590f705 100644 --- a/content/base/test/chrome/Makefile.in +++ b/content/base/test/chrome/Makefile.in @@ -69,6 +69,7 @@ _CHROME_FILES = \ test_bug357450.xul \ test_bug571390.xul \ test_bug574596.html \ + test_bug683852.xul \ $(NULL) libs:: $(_TEST_FILES) diff --git a/content/base/test/chrome/test_bug683852.xul b/content/base/test/chrome/test_bug683852.xul new file mode 100644 index 000000000000..b6cd99e241a2 --- /dev/null +++ b/content/base/test/chrome/test_bug683852.xul @@ -0,0 +1,67 @@ + + + + + + + diff --git a/content/base/test/test_bug482935.html b/content/base/test/test_bug482935.html index 525add2d723e..1bfa5f4b43a7 100644 --- a/content/base/test/test_bug482935.html +++ b/content/base/test/test_bug482935.html @@ -38,51 +38,6 @@ function testCancelInPhase4() { xhr2.addEventListener("load", function() { is(xhr2.responseText, "0", "Received fresh value for second request"); - testCancelBeforePhase4(); - }, false); - - xhr2.open("GET", url); - xhr2.setRequestHeader("X-Request", "1", false); - - try { xhr2.send(); } - catch(e) { - is(xhr2.status, "200", "Exception!"); - } - }, 0); - }, false); - - xhr.abort(); - } - }, false); - - xhr.open("GET", url, true); - xhr.setRequestHeader("X-Request", "0", false); - try { xhr.send(); } - catch(e) { - is("Nothing", "Exception", "Boom: " + e); - } -} - -// Tests that response is NOT cached if the request is cancelled -// before it has reached state 4 -function testCancelBeforePhase4() { - - clearCache(); - - // First request - should be loaded from server - var xhr = new XMLHttpRequest(); - xhr.addEventListener("readystatechange", function(e) { - if (xhr.readyState == 3) { - xhr.addEventListener("abort", function() { - setTimeout(function() { - // This request was cancelled, so the responseText should be empty string - is(xhr.responseText, "", "Expected empty response to cancelled request"); - - // Second request - should be found in cache - var xhr2 = new XMLHttpRequest(); - - xhr2.addEventListener("load", function() { - is(xhr2.responseText, "1", "Received cached value for second request"); SimpleTest.finish(); }, false); diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 30e668240a8b..b8e864546808 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -502,9 +502,7 @@ protected: PRBool ValidateAttribIndex(WebGLuint index, const char *info); PRBool ValidateStencilParamsForDrawCall(); - bool ValidateGLSLVariableName(const nsAString& name, const char *info); - bool ValidateGLSLCharacter(PRUnichar c); - bool ValidateGLSLString(const nsAString& string, const char *info); + bool ValidateGLSLIdentifier(const nsAString& name, const char *info); static PRUint32 GetTexelSize(WebGLenum format, WebGLenum type); diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index c8c7998dcd47..b6d027557cb6 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -62,7 +62,6 @@ #endif #include "WebGLTexelConversions.h" -#include "WebGLValidateStrings.h" using namespace mozilla; @@ -183,8 +182,8 @@ WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, cons if (!GetGLName("bindAttribLocation: program", pobj, &progname)) return NS_OK; - if (!ValidateGLSLVariableName(name, "bindAttribLocation")) - return NS_OK; + if (name.IsEmpty()) + return ErrorInvalidValue("BindAttribLocation: name can't be null or empty"); if (!ValidateAttribIndex(location, "bindAttribLocation")) return NS_OK; @@ -1857,7 +1856,7 @@ WebGLContext::GetAttribLocation(nsIWebGLProgram *pobj, if (!GetGLName("getAttribLocation: program", pobj, &progname)) return NS_OK; - if (!ValidateGLSLVariableName(name, "getAttribLocation")) + if (!ValidateGLSLIdentifier(name, "getAttribLocation")) return NS_OK; MakeContextCurrent(); @@ -2672,7 +2671,7 @@ WebGLContext::GetUniformLocation(nsIWebGLProgram *pobj, const nsAString& name, n if (!GetConcreteObjectAndGLName("getUniformLocation: program", pobj, &prog, &progname)) return NS_OK; - if (!ValidateGLSLVariableName(name, "getUniformLocation")) + if (!ValidateGLSLIdentifier(name, "getUniformLocation")) return NS_OK; MakeContextCurrent(); @@ -4138,10 +4137,7 @@ WebGLContext::ShaderSource(nsIWebGLShader *sobj, const nsAString& source) WebGLuint shadername; if (!GetConcreteObjectAndGLName("shaderSource: shader", sobj, &shader, &shadername)) return NS_OK; - - if (!ValidateGLSLString(source, "shaderSource")) - return NS_OK; - + const nsPromiseFlatString& flatSource = PromiseFlatString(source); if (!NS_IsAscii(flatSource.get())) diff --git a/content/canvas/src/WebGLContextValidate.cpp b/content/canvas/src/WebGLContextValidate.cpp index 1861179c4d48..bf2fe6a200fb 100644 --- a/content/canvas/src/WebGLContextValidate.cpp +++ b/content/canvas/src/WebGLContextValidate.cpp @@ -328,31 +328,14 @@ PRBool WebGLContext::ValidateDrawModeEnum(WebGLenum mode, const char *info) } } -bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info) +bool WebGLContext::ValidateGLSLIdentifier(const nsAString& name, const char *info) { - const PRUint32 maxSize = 255; + const PRUint32 maxSize = 4095; if (name.Length() > maxSize) { ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters", info, name.Length(), maxSize); return false; } - - if (!ValidateGLSLString(name, info)) { - return false; - } - - return true; -} - -bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info) -{ - for (PRUint32 i = 0; i < string.Length(); ++i) { - if (!ValidateGLSLCharacter(string.CharAt(i))) { - ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i)); - return false; - } - } - return true; } diff --git a/content/canvas/src/WebGLValidateStrings.h b/content/canvas/src/WebGLValidateStrings.h deleted file mode 100644 index ccf124f1db21..000000000000 --- a/content/canvas/src/WebGLValidateStrings.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2011 Apple Inc. All rights reserved. - * Copyright (C) 2011 Mozilla Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBGLVALIDATESTRINGS_H_ -#define WEBGLVALIDATESTRINGS_H_ - -#include "WebGLContext.h" - -namespace mozilla { - -// The following function was taken from the WebKit WebGL implementation, -// which can be found here: -// http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp#L123 -/****** BEGIN CODE TAKEN FROM WEBKIT ******/ -bool WebGLContext::ValidateGLSLCharacter(PRUnichar c) -{ - // Printing characters are valid except " $ ` @ \ ' DEL. - if (c >= 32 && c <= 126 && - c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'') - { - return true; - } - - // Horizontal tab, line feed, vertical tab, form feed, carriage return are also valid. - if (c >= 9 && c <= 13) { - return true; - } - - return false; -} -/****** END CODE TAKEN FROM WEBKIT ******/ - -} // end namespace mozilla - -#endif // WEBGLVALIDATESTRINGS_H_ diff --git a/content/canvas/test/webgl/failing_tests_linux.txt b/content/canvas/test/webgl/failing_tests_linux.txt index 7a34f85d6b19..cf805e61c3d1 100644 --- a/content/canvas/test/webgl/failing_tests_linux.txt +++ b/content/canvas/test/webgl/failing_tests_linux.txt @@ -12,6 +12,7 @@ conformance/gl-getshadersource.html conformance/gl-uniform-bool.html conformance/glsl-conformance.html conformance/glsl-long-variable-names.html +conformance/invalid-passed-params.html conformance/premultiplyalpha-test.html conformance/read-pixels-test.html conformance/uninitialized-test.html diff --git a/content/canvas/test/webgl/failing_tests_mac.txt b/content/canvas/test/webgl/failing_tests_mac.txt index 14bf23092a9e..26d590021322 100644 --- a/content/canvas/test/webgl/failing_tests_mac.txt +++ b/content/canvas/test/webgl/failing_tests_mac.txt @@ -6,6 +6,7 @@ conformance/gl-getshadersource.html conformance/gl-object-get-calls.html conformance/glsl-conformance.html conformance/glsl-long-variable-names.html +conformance/invalid-passed-params.html conformance/premultiplyalpha-test.html conformance/program-test.html conformance/read-pixels-test.html diff --git a/content/canvas/test/webgl/failing_tests_windows.txt b/content/canvas/test/webgl/failing_tests_windows.txt index 1ef04b4ad483..504c0df09c5d 100644 --- a/content/canvas/test/webgl/failing_tests_windows.txt +++ b/content/canvas/test/webgl/failing_tests_windows.txt @@ -4,6 +4,7 @@ conformance/framebuffer-object-attachment.html conformance/gl-getshadersource.html conformance/glsl-conformance.html conformance/glsl-long-variable-names.html +conformance/invalid-passed-params.html conformance/premultiplyalpha-test.html conformance/read-pixels-test.html conformance/more/conformance/quickCheckAPI.html diff --git a/content/events/public/nsEventNameList.h b/content/events/public/nsEventNameList.h index 3b98283d66ff..8c5c4fb971a7 100644 --- a/content/events/public/nsEventNameList.h +++ b/content/events/public/nsEventNameList.h @@ -243,6 +243,10 @@ EVENT(mouseup, NS_MOUSE_BUTTON_UP, EventNameType_All, NS_MOUSE_EVENT) +EVENT(mozfullscreenchange, + NS_FULLSCREENCHANGE, + EventNameType_HTML, + NS_EVENT_NULL) // Not supported yet; probably never because "wheel" is a better idea. // EVENT(mousewheel) EVENT(pause, diff --git a/content/events/public/nsEventStates.h b/content/events/public/nsEventStates.h index bcca98915797..97078ce864a8 100644 --- a/content/events/public/nsEventStates.h +++ b/content/events/public/nsEventStates.h @@ -261,6 +261,9 @@ private: #define NS_EVENT_STATE_MOZ_UI_INVALID NS_DEFINE_EVENT_STATE_MACRO(32) // UI friendly version of :valid pseudo-class. #define NS_EVENT_STATE_MOZ_UI_VALID NS_DEFINE_EVENT_STATE_MACRO(33) +// Content is the full screen element, or a frame containing the +// current full-screen element. +#define NS_EVENT_STATE_FULL_SCREEN NS_DEFINE_EVENT_STATE_MACRO(34) /** * NOTE: do not go over 63 without updating nsEventStates::InternalType! @@ -268,7 +271,8 @@ private: #define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS | \ NS_EVENT_STATE_HOVER | NS_EVENT_STATE_DRAGOVER | \ - NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING) + NS_EVENT_STATE_URLTARGET | NS_EVENT_STATE_FOCUSRING | \ + NS_EVENT_STATE_FULL_SCREEN) #define INTRINSIC_STATES (~ESM_MANAGED_STATES) diff --git a/content/events/src/nsDOMEvent.cpp b/content/events/src/nsDOMEvent.cpp index 059ee02eeaf1..8df917f6b581 100644 --- a/content/events/src/nsDOMEvent.cpp +++ b/content/events/src/nsDOMEvent.cpp @@ -92,6 +92,7 @@ static const char* const sEventNames[] = { "MozAfterPaint", "MozBeforePaint", "MozBeforeResize", + "mozfullscreenchange", "MozSwipeGesture", "MozMagnifyGestureStart", "MozMagnifyGestureUpdate", @@ -1366,6 +1367,8 @@ const char* nsDOMEvent::GetEventName(PRUint32 aEventType) return sEventNames[eDOMEvents_devicemotion]; case NS_DEVICE_ORIENTATION: return sEventNames[eDOMEvents_deviceorientation]; + case NS_FULLSCREENCHANGE: + return sEventNames[eDOMEvents_mozfullscreenchange]; default: break; } diff --git a/content/events/src/nsDOMEvent.h b/content/events/src/nsDOMEvent.h index c8a3f726ba1d..d5df9854db78 100644 --- a/content/events/src/nsDOMEvent.h +++ b/content/events/src/nsDOMEvent.h @@ -177,6 +177,7 @@ public: eDOMEvents_afterpaint, eDOMEvents_beforepaint, eDOMEvents_beforeresize, + eDOMEvents_mozfullscreenchange, eDOMEvents_MozSwipeGesture, eDOMEvents_MozMagnifyGestureStart, eDOMEvents_MozMagnifyGestureUpdate, diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index aeb3411ab8b9..ed5be0be8892 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -4384,6 +4384,14 @@ static nsIContent* FindCommonAncestor(nsIContent *aNode1, nsIContent *aNode2) return nsnull; } +/* static */ +void +nsEventStateManager::SetFullScreenState(Element* aElement, + PRBool aIsFullScreen) +{ + DoStateChange(aElement, NS_EVENT_STATE_FULL_SCREEN, aIsFullScreen); +} + /* static */ inline void nsEventStateManager::DoStateChange(Element* aElement, nsEventStates aState, diff --git a/content/events/src/nsEventStateManager.h b/content/events/src/nsEventStateManager.h index d67832b139dd..d0ad98475b62 100644 --- a/content/events/src/nsEventStateManager.h +++ b/content/events/src/nsEventStateManager.h @@ -203,6 +203,10 @@ public: // if aContent is non-null, marks the object as active. static void SetActiveManager(nsEventStateManager* aNewESM, nsIContent* aContent); + + // Sets the full-screen event state on aElement to aIsFullScreen. + static void SetFullScreenState(mozilla::dom::Element* aElement, PRBool aIsFullScreen); + protected: void UpdateCursor(nsPresContext* aPresContext, nsEvent* aEvent, nsIFrame* aTargetFrame, nsEventStatus* aStatus); /** diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 86721b1150ad..a1e3ca0fb935 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -3379,6 +3379,50 @@ nsGenericHTMLElement::Focus() return fm ? fm->SetFocus(elem, 0) : NS_OK; } +nsresult nsGenericHTMLElement::MozRequestFullScreen() +{ + // Only grant full-screen requests if this is called from inside a trusted + // event handler (i.e. inside an event handler for a user initiated event). + // This stops the full-screen from being abused similar to the popups of old, + // and it also makes it harder for bad guys' script to go full-screen and + // spoof the browser chrome/window and phish logins etc. + if (!nsContentUtils::IsFullScreenApiEnabled() || + !nsContentUtils::IsRequestFullScreenAllowed()) { + return NS_OK; + } + + // Ensure that all ancestor +

+ +
+
+
+ + diff --git a/dom/tests/mochitest/general/Makefile.in b/dom/tests/mochitest/general/Makefile.in index 2fbf42742eab..12f5e9ddf552 100644 --- a/dom/tests/mochitest/general/Makefile.in +++ b/dom/tests/mochitest/general/Makefile.in @@ -68,6 +68,7 @@ _TEST_FILES = \ test_framedhistoryframes.html \ test_windowedhistoryframes.html \ test_focusrings.xul \ + file_moving_xhr.html \ $(NULL) _CHROME_FILES = \ diff --git a/dom/tests/mochitest/general/file_moving_xhr.html b/dom/tests/mochitest/general/file_moving_xhr.html new file mode 100644 index 000000000000..d6a0e5d0a3ac --- /dev/null +++ b/dom/tests/mochitest/general/file_moving_xhr.html @@ -0,0 +1,26 @@ + + + + + + + diff --git a/editor/composer/src/nsEditorSpellCheck.cpp b/editor/composer/src/nsEditorSpellCheck.cpp index ad4bc1675ec0..ecaa421472ef 100644 --- a/editor/composer/src/nsEditorSpellCheck.cpp +++ b/editor/composer/src/nsEditorSpellCheck.cpp @@ -729,8 +729,9 @@ nsEditorSpellCheck::UpdateCurrentDictionary() } // otherwise, get language from preferences + nsAutoString preferedDict(Preferences::GetLocalizedString("spellchecker.dictionary")); if (dictName.IsEmpty()) { - dictName.Assign(Preferences::GetLocalizedString("spellchecker.dictionary")); + dictName.Assign(preferedDict); } if (dictName.IsEmpty()) @@ -755,27 +756,50 @@ nsEditorSpellCheck::UpdateCurrentDictionary() rv = SetCurrentDictionary(dictName); if (NS_FAILED(rv)) { // required dictionary was not available. Try to get a dictionary - // matching at least language part of dictName: If required dictionary is - // "aa-bb", we try "aa", then we try any available dictionary aa-XX + // matching at least language part of dictName: + nsAutoString langCode; PRInt32 dashIdx = dictName.FindChar('-'); if (dashIdx != -1) { langCode.Assign(Substring(dictName, 0, dashIdx)); - // try to use langCode - rv = SetCurrentDictionary(langCode); } else { langCode.Assign(dictName); } + + nsDefaultStringComparator comparator; + + // try dictionary.spellchecker preference if it starts with langCode (and + // if we haven't tried it already) + if (!preferedDict.IsEmpty() && !dictName.Equals(preferedDict) && + nsStyleUtil::DashMatchCompare(preferedDict, langCode, comparator)) { + rv = SetCurrentDictionary(preferedDict); + } + + // Otherwise, try langCode (if we haven't tried it already) + if (NS_FAILED(rv)) { + if (!dictName.Equals(langCode) && !preferedDict.Equals(langCode)) { + rv = SetCurrentDictionary(langCode); + } + } + + // Otherwise, try any available dictionary aa-XX if (NS_FAILED(rv)) { // loop over avaible dictionaries; if we find one with required // language, use it nsTArray dictList; rv = mSpellChecker->GetDictionaryList(&dictList); NS_ENSURE_SUCCESS(rv, rv); - nsDefaultStringComparator comparator; PRInt32 i, count = dictList.Length(); for (i = 0; i < count; i++) { nsAutoString dictStr(dictList.ElementAt(i)); + + if (dictStr.Equals(dictName) || + dictStr.Equals(preferedDict) || + dictStr.Equals(langCode)) { + // We have already tried it + continue; + } + if (nsStyleUtil::DashMatchCompare(dictStr, langCode, comparator) && NS_SUCCEEDED(SetCurrentDictionary(dictStr))) { break; diff --git a/editor/composer/test/test_bug434998.xul b/editor/composer/test/test_bug434998.xul index 2e9ccc929e56..3a5f50faa778 100644 --- a/editor/composer/test/test_bug434998.xul +++ b/editor/composer/test/test_bug434998.xul @@ -65,6 +65,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=434998 threw = true; } ok(!threw, "The execCommand API should work on "); + progress.removeProgressListener(progressListener, Components.interfaces.nsIWebProgress.NOTIFY_ALL); SimpleTest.finish(); } } diff --git a/editor/libeditor/html/nsHTMLEditRules.cpp b/editor/libeditor/html/nsHTMLEditRules.cpp index 689a7e586179..fa2b1189f58a 100644 --- a/editor/libeditor/html/nsHTMLEditRules.cpp +++ b/editor/libeditor/html/nsHTMLEditRules.cpp @@ -4047,11 +4047,26 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool * NS_ENSURE_SUCCESS(res, res); continue; } + // is it a block with a 'margin' property? + if (useCSS && IsBlockNode(curNode)) + { + nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, curNode); + nsAutoString value; + mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(curNode, marginProperty, value); + float f; + nsCOMPtr unit; + mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit)); + if (f > 0) + { + RelativeChangeIndentationOfElementNode(curNode, -1); + continue; + } + } // is it a list item? if (nsHTMLEditUtils::IsListItem(curNode)) { // if it is a list item, that means we are not outdenting whole list. - // So we need to finish up dealng with any curBlockQuote, and then + // So we need to finish up dealing with any curBlockQuote, and then // pop this list item. if (curBlockQuote) { @@ -4123,7 +4138,7 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool * float f; nsCOMPtr unit; mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit)); - if (f > 0) + if (f > 0 && !(nsHTMLEditUtils::IsList(curParent) && nsHTMLEditUtils::IsList(curNode))) { curBlockQuote = n; firstBQChild = curNode; diff --git a/editor/libeditor/html/tests/test_bug290026.html b/editor/libeditor/html/tests/test_bug290026.html index a8a9be3e9bd1..b3ed867ec544 100644 --- a/editor/libeditor/html/tests/test_bug290026.html +++ b/editor/libeditor/html/tests/test_bug290026.html @@ -40,7 +40,7 @@ addLoadEvent(function() { var twoindent = '

  • Item 1
  • Item 2

'; is(editor.innerHTML, twoindent, "a twice indented bulleted list"); document.execCommand("outdent", false, false); - todo_is(editor.innerHTML, oneindent, "outdenting a twice indented bulleted list"); + is(editor.innerHTML, oneindent, "outdenting a twice indented bulleted list"); // done SimpleTest.finish(); diff --git a/editor/libeditor/html/tests/test_bug291780.html b/editor/libeditor/html/tests/test_bug291780.html index b551b380196a..93f63af61ecf 100644 --- a/editor/libeditor/html/tests/test_bug291780.html +++ b/editor/libeditor/html/tests/test_bug291780.html @@ -38,7 +38,7 @@ addLoadEvent(function() { var expected = '
  • Item 1
    • Item 2
    • Item 3
  • Item 4
'; is(editor.innerHTML, expected, "indenting part of an already indented bulleted list"); document.execCommand("outdent", false, false); - todo_is(editor.innerHTML, original, "outdenting the partially indented part of an already indented bulleted list"); + is(editor.innerHTML, original, "outdenting the partially indented part of an already indented bulleted list"); // done SimpleTest.finish(); diff --git a/embedding/android/GeckoApp.java b/embedding/android/GeckoApp.java index 1655b60786e0..560e00e0d1b5 100644 --- a/embedding/android/GeckoApp.java +++ b/embedding/android/GeckoApp.java @@ -467,9 +467,15 @@ abstract public class GeckoApp componentsDir.mkdir(); componentsDir.setLastModified(applicationPackage.lastModified()); + surfaceView.mSplashStatusMsg = + getResources().getString(R.string.splash_firstrun); + surfaceView.drawSplashScreen(); + + GeckoAppShell.killAnyZombies(); + ZipFile zip = new ZipFile(applicationPackage); - byte[] buf = new byte[8192]; + byte[] buf = new byte[32768]; try { if (unpackFile(zip, buf, null, "removed-files")) removeFiles(); @@ -520,8 +526,6 @@ abstract public class GeckoApp } - boolean haveKilledZombies = false; - private boolean unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry, String name) throws IOException, FileNotFoundException @@ -533,22 +537,12 @@ abstract public class GeckoApp zip.getName()); File outFile = new File(sGREDir, name); - if (outFile.exists() && - outFile.lastModified() == fileEntry.getTime() && + if (outFile.lastModified() == fileEntry.getTime() && outFile.length() == fileEntry.getSize()) return false; - surfaceView.mSplashStatusMsg = - getResources().getString(R.string.splash_firstrun); - surfaceView.drawSplashScreen(); - - if (!haveKilledZombies) { - haveKilledZombies = true; - GeckoAppShell.killAnyZombies(); - } - File dir = outFile.getParentFile(); - if (!outFile.exists()) + if (!dir.exists()) dir.mkdirs(); InputStream fileStream; diff --git a/embedding/android/GeckoSurfaceView.java b/embedding/android/GeckoSurfaceView.java index b8a49477efc3..34a64ca59406 100644 --- a/embedding/android/GeckoSurfaceView.java +++ b/embedding/android/GeckoSurfaceView.java @@ -597,9 +597,9 @@ class GeckoSurfaceView switch (event.getAction()) { case KeyEvent.ACTION_DOWN: - return onKeyDown(keyCode, event); + return processKeyDown(keyCode, event, true); case KeyEvent.ACTION_UP: - return onKeyUp(keyCode, event); + return processKeyUp(keyCode, event, true); case KeyEvent.ACTION_MULTIPLE: return onKeyMultiple(keyCode, event.getRepeatCount(), event); } @@ -608,6 +608,10 @@ class GeckoSurfaceView @Override public boolean onKeyDown(int keyCode, KeyEvent event) { + return processKeyDown(keyCode, event, false); + } + + private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: if (event.getRepeatCount() == 0) { @@ -644,6 +648,11 @@ class GeckoSurfaceView default: break; } + + if (isPreIme && mIMEState != IME_STATE_DISABLED) + // Let active IME process pre-IME key events + return false; + // KeyListener returns true if it handled the event for us. if (mIMEState == IME_STATE_DISABLED || keyCode == KeyEvent.KEYCODE_ENTER || @@ -656,6 +665,10 @@ class GeckoSurfaceView @Override public boolean onKeyUp(int keyCode, KeyEvent event) { + return processKeyUp(keyCode, event, false); + } + + private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: if (!event.isTracking() || event.isCanceled()) @@ -664,6 +677,11 @@ class GeckoSurfaceView default: break; } + + if (isPreIme && mIMEState != IME_STATE_DISABLED) + // Let active IME process pre-IME key events + return false; + if (mIMEState == IME_STATE_DISABLED || keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_DEL || diff --git a/extensions/spellcheck/locales/en-US/hunspell/en-US.aff b/extensions/spellcheck/locales/en-US/hunspell/en-US.aff index 2ddd98543718..33deb299d496 100644 --- a/extensions/spellcheck/locales/en-US/hunspell/en-US.aff +++ b/extensions/spellcheck/locales/en-US/hunspell/en-US.aff @@ -110,13 +110,14 @@ SFX B e able [^aeiou]e SFX L Y 1 SFX L 0 ment . -REP 88 +REP 89 REP a ei REP ei a REP a ey REP ey a REP ai ie REP ie ai +REP alot a_lot REP are air REP are ear REP are eir diff --git a/gfx/thebes/gfxFT2Fonts.cpp b/gfx/thebes/gfxFT2Fonts.cpp index 773bbff2a680..f5e19f4322b5 100644 --- a/gfx/thebes/gfxFT2Fonts.cpp +++ b/gfx/thebes/gfxFT2Fonts.cpp @@ -697,10 +697,11 @@ gfxFT2Font::InitTextRun(gfxContext *aContext, } if (!ok) { - aTextRun->AdjustAdvancesForSyntheticBold(aRunStart, aRunLength); AddRange(aTextRun, aString, aRunStart, aRunLength); } + aTextRun->AdjustAdvancesForSyntheticBold(aContext, aRunStart, aRunLength); + return PR_TRUE; } @@ -809,9 +810,7 @@ gfxFT2Font::gfxFT2Font(cairo_scaled_font_t *aCairoFont, : gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle) { NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack."); - if (aNeedsBold) { - mSyntheticBoldOffset = 1.0; - } + mApplySyntheticBold = aNeedsBold; mCharGlyphCache.Init(64); } diff --git a/gfx/thebes/gfxFont.cpp b/gfx/thebes/gfxFont.cpp index d677da77405f..85b869f35f2e 100644 --- a/gfx/thebes/gfxFont.cpp +++ b/gfx/thebes/gfxFont.cpp @@ -581,12 +581,28 @@ StyleDistance(gfxFontEntry *aFontEntry, // and the given fontEntry, // considering italicness and font-stretch but not weight. - // TODO (refine CSS spec...): discuss priority of italic vs stretch; - // whether penalty for stretch mismatch should depend on actual difference in values; - // whether a sign mismatch in stretch should increase the effective distance - - return (aFontEntry->IsItalic() != anItalic ? 1 : 0) + - (aFontEntry->mStretch != aStretch ? 10 : 0); + PRInt32 distance = 0; + if (aStretch != aFontEntry->mStretch) { + // stretch values are in the range -4 .. +4 + // if aStretch is positive, we prefer more-positive values; + // if zero or negative, prefer more-negative + if (aStretch > 0) { + distance = (aFontEntry->mStretch - aStretch) * 2; + } else { + distance = (aStretch - aFontEntry->mStretch) * 2; + } + // if the computed "distance" here is negative, it means that + // aFontEntry lies in the "non-preferred" direction from aStretch, + // so we treat that as larger than any preferred-direction distance + // (max possible is 8) by adding an extra 10 to the absolute value + if (distance < 0) { + distance = -distance + 10; + } + } + if (aFontEntry->IsItalic() != anItalic) { + distance += 1; + } + return PRUint32(distance); } PRBool @@ -609,9 +625,11 @@ gfxFontFamily::FindWeightsForStyle(gfxFontEntry* aFontsForWeights[], aFontsForWeights[wt] = fe; ++foundWeights; } else { - PRUint32 prevDistance = StyleDistance(aFontsForWeights[wt], anItalic, aStretch); + PRUint32 prevDistance = + StyleDistance(aFontsForWeights[wt], anItalic, aStretch); if (prevDistance >= distance) { - // replacing a weight we already found, so don't increment foundWeights + // replacing a weight we already found, + // so don't increment foundWeights aFontsForWeights[wt] = fe; } } @@ -1035,10 +1053,10 @@ gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, PRBool aOtherIsOnLeft gfxFont::gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle, AntialiasOption anAAOption) : mFontEntry(aFontEntry), mIsValid(PR_TRUE), + mApplySyntheticBold(PR_FALSE), mStyle(*aFontStyle), mAdjustedSize(0.0), mFUnitsConvFactor(0.0f), - mSyntheticBoldOffset(0), mAntialiasOption(anAAOption), mPlatformShaper(nsnull), mHarfBuzzShaper(nsnull) @@ -1115,6 +1133,33 @@ struct GlyphBuffer { #undef GLYPH_BUFFER_SIZE }; +// Bug 674909. When synthetic bolding text by drawing twice, need to +// render using a pixel offset in device pixels, otherwise text +// doesn't appear bolded, it appears as if a bad text shadow exists +// when a non-identity transform exists. Use an offset factor so that +// the second draw occurs at a constant offset in device pixels. + +static double +CalcXScale(gfxContext *aContext) +{ + // determine magnitude of a 1px x offset in device space + gfxSize t = aContext->UserToDevice(gfxSize(1.0, 0.0)); + if (t.width == 1.0 && t.height == 0.0) { + // short-circuit the most common case to avoid sqrt() and division + return 1.0; + } + + double m = sqrt(t.width * t.width + t.height * t.height); + + NS_ASSERTION(m != 0.0, "degenerate transform while synthetic bolding"); + if (m == 0.0) { + return 0.0; // effectively disables offset + } + + // scale factor so that offsets are 1px in device pixels + return 1.0 / m; +} + void gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd, gfxContext *aContext, PRBool aDrawToPath, gfxPoint *aPt, @@ -1128,9 +1173,18 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd, const double devUnitsPerAppUnit = 1.0/double(appUnitsPerDevUnit); PRBool isRTL = aTextRun->IsRightToLeft(); double direction = aTextRun->GetDirection(); - // double-strike in direction of run - double synBoldDevUnitOffsetAppUnits = - direction * (double) mSyntheticBoldOffset * appUnitsPerDevUnit; + + // synthetic-bold strikes are each offset one device pixel in run direction + // (these values are only needed if IsSyntheticBold() is true) + double synBoldOnePixelOffset; + PRInt32 strikes; + if (IsSyntheticBold()) { + double xscale = CalcXScale(aContext); + synBoldOnePixelOffset = direction * xscale; + // use as many strikes as needed for the the increased advance + strikes = NS_lroundf(GetSyntheticBoldOffset() / xscale); + } + PRUint32 i; // Current position in appunits double x = aPt->x; @@ -1169,15 +1223,21 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd, glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit); glyph->y = ToDeviceUnits(y, devUnitsPerAppUnit); - // synthetic bolding by drawing with a one-pixel offset - if (mSyntheticBoldOffset) { - cairo_glyph_t *doubleglyph; - doubleglyph = glyphs.AppendGlyph(); - doubleglyph->index = glyph->index; - doubleglyph->x = - ToDeviceUnits(glyphX + synBoldDevUnitOffsetAppUnits, - devUnitsPerAppUnit); - doubleglyph->y = glyph->y; + // synthetic bolding by multi-striking with 1-pixel offsets + // at least once, more if there's room (large font sizes) + if (IsSyntheticBold()) { + double strikeOffset = synBoldOnePixelOffset; + PRInt32 strikeCount = strikes; + do { + cairo_glyph_t *doubleglyph; + doubleglyph = glyphs.AppendGlyph(); + doubleglyph->index = glyph->index; + doubleglyph->x = + ToDeviceUnits(glyphX + strikeOffset * appUnitsPerDevUnit, + devUnitsPerAppUnit); + doubleglyph->y = glyph->y; + strikeOffset += synBoldOnePixelOffset; + } while (--strikeCount > 0); } glyphs.Flush(cr, aDrawToPath, isRTL); @@ -1216,15 +1276,20 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd, glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit); glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit); - // synthetic bolding by drawing with a one-pixel offset - if (mSyntheticBoldOffset) { - cairo_glyph_t *doubleglyph; - doubleglyph = glyphs.AppendGlyph(); - doubleglyph->index = glyph->index; - doubleglyph->x = - ToDeviceUnits(glyphX + synBoldDevUnitOffsetAppUnits, - devUnitsPerAppUnit); - doubleglyph->y = glyph->y; + if (IsSyntheticBold()) { + double strikeOffset = synBoldOnePixelOffset; + PRInt32 strikeCount = strikes; + do { + cairo_glyph_t *doubleglyph; + doubleglyph = glyphs.AppendGlyph(); + doubleglyph->index = glyph->index; + doubleglyph->x = + ToDeviceUnits(glyphX + strikeOffset * + appUnitsPerDevUnit, + devUnitsPerAppUnit); + doubleglyph->y = glyph->y; + strikeOffset += synBoldOnePixelOffset; + } while (--strikeCount > 0); } glyphs.Flush(cr, aDrawToPath, isRTL); @@ -3492,7 +3557,9 @@ struct BufferAlphaColor { }; void -gfxTextRun::AdjustAdvancesForSyntheticBold(PRUint32 aStart, PRUint32 aLength) +gfxTextRun::AdjustAdvancesForSyntheticBold(gfxContext *aContext, + PRUint32 aStart, + PRUint32 aLength) { const PRUint32 appUnitsPerDevUnit = GetAppUnitsPerDevUnit(); PRBool isRTL = IsRightToLeft(); @@ -3501,7 +3568,9 @@ gfxTextRun::AdjustAdvancesForSyntheticBold(PRUint32 aStart, PRUint32 aLength) while (iter.NextRun()) { gfxFont *font = iter.GetGlyphRun()->mFont; if (font->IsSyntheticBold()) { - PRUint32 synAppUnitOffset = font->GetSyntheticBoldOffset() * appUnitsPerDevUnit; + PRUint32 synAppUnitOffset = + font->GetSyntheticBoldOffset() * + appUnitsPerDevUnit * CalcXScale(aContext); PRUint32 start = iter.GetStringStart(); PRUint32 end = iter.GetStringEnd(); PRUint32 i; diff --git a/gfx/thebes/gfxFont.h b/gfx/thebes/gfxFont.h index 3a8b1e19fdfb..4cd5574d17c5 100644 --- a/gfx/thebes/gfxFont.h +++ b/gfx/thebes/gfxFont.h @@ -1193,8 +1193,12 @@ public: // This is called by the default Draw() implementation above. virtual PRBool SetupCairoFont(gfxContext *aContext) = 0; - PRBool IsSyntheticBold() { return mSyntheticBoldOffset != 0; } - PRUint32 GetSyntheticBoldOffset() { return mSyntheticBoldOffset; } + PRBool IsSyntheticBold() { return mApplySyntheticBold; } + + // Amount by which synthetic bold "fattens" the glyphs: 1/16 of the em-size + gfxFloat GetSyntheticBoldOffset() { + return GetAdjustedSize() * (1.0 / 16.0); + } gfxFontEntry *GetFontEntry() { return mFontEntry.get(); } PRBool HasCharacter(PRUint32 ch) { @@ -1224,6 +1228,11 @@ protected: nsRefPtr mFontEntry; PRPackedBool mIsValid; + + // use synthetic bolding for environments where this is not supported + // by the platform + PRPackedBool mApplySyntheticBold; + nsExpirationState mExpirationState; gfxFontStyle mStyle; nsAutoTArray mGlyphExtentsArray; @@ -1232,9 +1241,6 @@ protected: float mFUnitsConvFactor; // conversion factor from font units to dev units - // synthetic bolding for environments where this is not supported by the platform - PRUint32 mSyntheticBoldOffset; // number of devunit pixels to offset double-strike, 0 ==> no bolding - // the AA setting requested for this font - may affect glyph bounds AntialiasOption mAntialiasOption; @@ -2043,7 +2049,9 @@ public: #endif // post-process glyph advances to deal with synthetic bolding - void AdjustAdvancesForSyntheticBold(PRUint32 aStart, PRUint32 aLength); + void AdjustAdvancesForSyntheticBold(gfxContext *aContext, + PRUint32 aStart, + PRUint32 aLength); protected: /** diff --git a/gfx/thebes/gfxFontconfigUtils.cpp b/gfx/thebes/gfxFontconfigUtils.cpp index 8c7353ba5c7c..78d5c2bc6481 100644 --- a/gfx/thebes/gfxFontconfigUtils.cpp +++ b/gfx/thebes/gfxFontconfigUtils.cpp @@ -177,6 +177,66 @@ gfxFontconfigUtils::FcWeightForBaseWeight(PRInt8 aBaseWeight) return aBaseWeight < 2 ? FC_WEIGHT_THIN : FC_WEIGHT_EXTRABLACK; } +/* static */ PRInt16 +gfxFontconfigUtils::GetThebesStretch(FcPattern *aPattern) +{ + int width; + if (FcPatternGetInteger(aPattern, FC_WIDTH, 0, &width) != FcResultMatch) { + return NS_FONT_STRETCH_NORMAL; + } + + if (width <= (FC_WIDTH_ULTRACONDENSED + FC_WIDTH_EXTRACONDENSED) / 2) { + return NS_FONT_STRETCH_ULTRA_CONDENSED; + } + if (width <= (FC_WIDTH_EXTRACONDENSED + FC_WIDTH_CONDENSED) / 2) { + return NS_FONT_STRETCH_EXTRA_CONDENSED; + } + if (width <= (FC_WIDTH_CONDENSED + FC_WIDTH_SEMICONDENSED) / 2) { + return NS_FONT_STRETCH_CONDENSED; + } + if (width <= (FC_WIDTH_SEMICONDENSED + FC_WIDTH_NORMAL) / 2) { + return NS_FONT_STRETCH_SEMI_CONDENSED; + } + if (width <= (FC_WIDTH_NORMAL + FC_WIDTH_SEMIEXPANDED) / 2) { + return NS_FONT_STRETCH_NORMAL; + } + if (width <= (FC_WIDTH_SEMIEXPANDED + FC_WIDTH_EXPANDED) / 2) { + return NS_FONT_STRETCH_SEMI_EXPANDED; + } + if (width <= (FC_WIDTH_EXPANDED + FC_WIDTH_EXTRAEXPANDED) / 2) { + return NS_FONT_STRETCH_EXPANDED; + } + if (width <= (FC_WIDTH_EXTRAEXPANDED + FC_WIDTH_ULTRAEXPANDED) / 2) { + return NS_FONT_STRETCH_EXTRA_EXPANDED; + } + return NS_FONT_STRETCH_ULTRA_EXPANDED; +} + +/* static */ int +gfxFontconfigUtils::FcWidthForThebesStretch(PRInt16 aStretch) +{ + switch (aStretch) { + default: // this will catch "normal" (0) as well as out-of-range values + return FC_WIDTH_NORMAL; + case NS_FONT_STRETCH_ULTRA_CONDENSED: + return FC_WIDTH_ULTRACONDENSED; + case NS_FONT_STRETCH_EXTRA_CONDENSED: + return FC_WIDTH_EXTRACONDENSED; + case NS_FONT_STRETCH_CONDENSED: + return FC_WIDTH_CONDENSED; + case NS_FONT_STRETCH_SEMI_CONDENSED: + return FC_WIDTH_SEMICONDENSED; + case NS_FONT_STRETCH_SEMI_EXPANDED: + return FC_WIDTH_SEMIEXPANDED; + case NS_FONT_STRETCH_EXPANDED: + return FC_WIDTH_EXPANDED; + case NS_FONT_STRETCH_EXTRA_EXPANDED: + return FC_WIDTH_EXTRAEXPANDED; + case NS_FONT_STRETCH_ULTRA_EXPANDED: + return FC_WIDTH_ULTRAEXPANDED; + } +} + // This makes a guess at an FC_WEIGHT corresponding to a base weight and // offset (without any knowledge of which weights are available). @@ -244,6 +304,7 @@ gfxFontconfigUtils::NewPattern(const nsTArray& aFamilies, FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aFontStyle.size); FcPatternAddInteger(pattern, FC_SLANT, GetFcSlant(aFontStyle)); FcPatternAddInteger(pattern, FC_WEIGHT, GuessFcWeight(aFontStyle)); + FcPatternAddInteger(pattern, FC_WIDTH, FcWidthForThebesStretch(aFontStyle.stretch)); if (aLang) { AddString(pattern, FC_LANG, aLang); diff --git a/gfx/thebes/gfxFontconfigUtils.h b/gfx/thebes/gfxFontconfigUtils.h index e072b4ee3d06..5f4d0f0451ea 100644 --- a/gfx/thebes/gfxFontconfigUtils.h +++ b/gfx/thebes/gfxFontconfigUtils.h @@ -149,12 +149,15 @@ public: static PRUint8 FcSlantToThebesStyle(int aFcSlant); static PRUint8 GetThebesStyle(FcPattern *aPattern); // slant static PRUint16 GetThebesWeight(FcPattern *aPattern); + static PRInt16 GetThebesStretch(FcPattern *aPattern); static int GetFcSlant(const gfxFontStyle& aFontStyle); // Returns a precise FC_WEIGHT from |aBaseWeight|, // which is a CSS absolute weight / 100. static int FcWeightForBaseWeight(PRInt8 aBaseWeight); + static int FcWidthForThebesStretch(PRInt16 aStretch); + static PRBool GetFullnameFromFamilyAndStyle(FcPattern *aFont, nsACString *aFullname); diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index 6ce4fd91f6e1..b84390654a24 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -213,17 +213,20 @@ FontTypeToOutPrecision(PRUint8 fontType) * */ -GDIFontEntry::GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType, - PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData) : - gfxFontEntry(aFaceName), - mWindowsFamily(0), mWindowsPitch(0), - mFontType(aFontType), - mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE), - mCharset(), mUnicodeRanges() +GDIFontEntry::GDIFontEntry(const nsAString& aFaceName, + gfxWindowsFontType aFontType, + PRBool aItalic, PRUint16 aWeight, PRInt16 aStretch, + gfxUserFontData *aUserFontData) + : gfxFontEntry(aFaceName), + mWindowsFamily(0), mWindowsPitch(0), + mFontType(aFontType), + mForceGDI(PR_FALSE), mUnknownCMAP(PR_FALSE), + mCharset(), mUnicodeRanges() { mUserFontData = aUserFontData; mItalic = aItalic; mWeight = aWeight; + mStretch = aStretch; if (IsType1()) mForceGDI = PR_TRUE; mIsUserFont = aUserFontData != nsnull; @@ -318,8 +321,8 @@ GDIFontEntry::GetFontTable(PRUint32 aTableTag, void GDIFontEntry::FillLogFont(LOGFONTW *aLogFont, PRBool aItalic, - PRUint16 aWeight, gfxFloat aSize, - PRBool aUseCleartype) + PRUint16 aWeight, gfxFloat aSize, + PRBool aUseCleartype) { memcpy(aLogFont, &mLogFont, sizeof(LOGFONTW)); @@ -414,7 +417,7 @@ GDIFontEntry::TestCharacterMap(PRUint32 aCh) void GDIFontEntry::InitLogFont(const nsAString& aName, - gfxWindowsFontType aFontType) + gfxWindowsFontType aFontType) { #define CLIP_TURNOFF_FONTASSOCIATION 0x40 @@ -444,14 +447,15 @@ GDIFontEntry::InitLogFont(const nsAString& aName, } GDIFontEntry* -GDIFontEntry::CreateFontEntry(const nsAString& aName, gfxWindowsFontType aFontType, - PRBool aItalic, PRUint16 aWeight, - gfxUserFontData* aUserFontData) +GDIFontEntry::CreateFontEntry(const nsAString& aName, + gfxWindowsFontType aFontType, PRBool aItalic, + PRUint16 aWeight, PRInt16 aStretch, + gfxUserFontData* aUserFontData) { // jtdfix - need to set charset, unicode ranges, pitch/family - GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aItalic, aWeight, - aUserFontData); + GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aItalic, + aWeight, aStretch, aUserFontData); return fe; } @@ -500,8 +504,10 @@ GDIFontFamily::FamilyAddStylesProc(const ENUMLOGFONTEXW *lpelfe, } } - fe = GDIFontEntry::CreateFontEntry(nsDependentString(lpelfe->elfFullName), feType, (logFont.lfItalic == 0xFF), - (PRUint16) (logFont.lfWeight), nsnull); + fe = GDIFontEntry::CreateFontEntry(nsDependentString(lpelfe->elfFullName), + feType, (logFont.lfItalic == 0xFF), + (PRUint16) (logFont.lfWeight), 0, + nsnull); if (!fe) return 1; @@ -747,7 +753,7 @@ gfxGDIFontList::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry, gfxFontEntry *fe = GDIFontEntry::CreateFontEntry(lookup->Name(), gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL), - w, nsnull); + w, aProxyEntry->mStretch, nsnull); if (!fe) return nsnull; @@ -966,7 +972,7 @@ gfxGDIFontList::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, GDIFontEntry *fe = GDIFontEntry::CreateFontEntry(uniqueName, gfxWindowsFontType(isCFF ? GFX_FONT_TYPE_PS_OPENTYPE : GFX_FONT_TYPE_TRUETYPE) /*type*/, PRUint32(aProxyEntry->mItalic ? FONT_STYLE_ITALIC : FONT_STYLE_NORMAL), - w, winUserFontData); + w, aProxyEntry->mStretch, winUserFontData); if (!fe) return fe; diff --git a/gfx/thebes/gfxGDIFontList.h b/gfx/thebes/gfxGDIFontList.h index 35603629b463..254bb0d7a42d 100644 --- a/gfx/thebes/gfxGDIFontList.h +++ b/gfx/thebes/gfxGDIFontList.h @@ -275,14 +275,15 @@ public: virtual PRBool TestCharacterMap(PRUint32 aCh); // create a font entry for a font with a given name - static GDIFontEntry* CreateFontEntry(const nsAString& aName, - gfxWindowsFontType aFontType, - PRBool aItalic, PRUint16 aWeight, - gfxUserFontData* aUserFontData); + static GDIFontEntry* CreateFontEntry(const nsAString& aName, + gfxWindowsFontType aFontType, + PRBool aItalic, + PRUint16 aWeight, PRInt16 aStretch, + gfxUserFontData* aUserFontData); // create a font entry for a font referenced by its fullname static GDIFontEntry* LoadLocalFont(const gfxProxyFontEntry &aProxyEntry, - const nsAString& aFullname); + const nsAString& aFullname); PRUint8 mWindowsFamily; PRUint8 mWindowsPitch; @@ -298,7 +299,8 @@ protected: friend class gfxWindowsFont; GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType, - PRBool aItalic, PRUint16 aWeight, gfxUserFontData *aUserFontData); + PRBool aItalic, PRUint16 aWeight, PRInt16 aStretch, + gfxUserFontData *aUserFontData); void InitLogFont(const nsAString& aName, gfxWindowsFontType aFontType); diff --git a/gfx/thebes/gfxMacFont.cpp b/gfx/thebes/gfxMacFont.cpp index 14a878bcd64d..e1e8d62e6b0a 100644 --- a/gfx/thebes/gfxMacFont.cpp +++ b/gfx/thebes/gfxMacFont.cpp @@ -57,9 +57,7 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyl mFontFace(nsnull), mScaledFont(nsnull) { - if (aNeedsBold) { - mSyntheticBoldOffset = 1; // devunit offset when double-striking text to fake boldness - } + mApplySyntheticBold = aNeedsBold; mCGFont = aFontEntry->GetFontRef(); if (!mCGFont) { @@ -167,7 +165,7 @@ gfxMacFont::InitTextRun(gfxContext *aContext, aRunStart, aRunLength, aRunScript, static_cast(GetFontEntry())->RequiresAATLayout()); - aTextRun->AdjustAdvancesForSyntheticBold(aRunStart, aRunLength); + aTextRun->AdjustAdvancesForSyntheticBold(aContext, aRunStart, aRunLength); return ok; } @@ -320,8 +318,10 @@ gfxMacFont::InitMetrics() mMetrics.aveCharWidth = mMetrics.maxAdvance; } } - mMetrics.aveCharWidth += mSyntheticBoldOffset; - mMetrics.maxAdvance += mSyntheticBoldOffset; + if (IsSyntheticBold()) { + mMetrics.aveCharWidth += GetSyntheticBoldOffset(); + mMetrics.maxAdvance += GetSyntheticBoldOffset(); + } mMetrics.spaceWidth = GetCharWidth(cmap, ' ', &glyphID, cgConvFactor); if (glyphID == 0) { diff --git a/gfx/thebes/gfxPangoFonts.cpp b/gfx/thebes/gfxPangoFonts.cpp index 6bf70f8544eb..c29ea7e25305 100644 --- a/gfx/thebes/gfxPangoFonts.cpp +++ b/gfx/thebes/gfxPangoFonts.cpp @@ -449,6 +449,14 @@ gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern) IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN); } + int fontWidth = -1; + FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth); + int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch); + if (cssWidth != fontWidth) { + FcPatternDel(aPattern, FC_WIDTH); + FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth); + } + // Ensure that there is a fullname property (if there is a family // property) so that fontconfig rules can identify the real name of the // font, because the family property will be replaced. @@ -1250,8 +1258,9 @@ private: // and style |aStyle| properties. static const nsTArray< nsCountedRef >* FindFontPatterns(gfxUserFontSet *mUserFontSet, - const nsACString &aFamily, PRUint8 aStyle, PRUint16 aWeight, - PRBool& aFoundFamily, PRBool& aWaitForUserFont) + const nsACString &aFamily, PRUint8 aStyle, + PRUint16 aWeight, PRInt16 aStretch, + PRBool& aFoundFamily, PRBool& aWaitForUserFont) { // Convert to UTF16 NS_ConvertUTF8toUTF16 utf16Family(aFamily); @@ -1264,6 +1273,7 @@ FindFontPatterns(gfxUserFontSet *mUserFontSet, gfxFontStyle style; style.style = aStyle; style.weight = aWeight; + style.stretch = aStretch; gfxUserFcFontEntry *fontEntry = static_cast (mUserFontSet->FindFontEntry(utf16Family, style, aFoundFamily, @@ -1431,10 +1441,13 @@ gfxFcFontSet::SortPreferredFonts(PRBool &aWaitForUserFont) gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant); PRUint16 thebesWeight = gfxFontconfigUtils::GetThebesWeight(mSortPattern); + PRInt16 thebesStretch = + gfxFontconfigUtils::GetThebesStretch(mSortPattern); PRBool foundFamily, waitForUserFont; familyFonts = FindFontPatterns(mUserFontSet, cssFamily, - thebesStyle, thebesWeight, + thebesStyle, + thebesWeight, thebesStretch, foundFamily, waitForUserFont); if (waitForUserFont) { aWaitForUserFont = PR_TRUE; diff --git a/intl/uconv/src/nsUTF8ConverterService.cpp b/intl/uconv/src/nsUTF8ConverterService.cpp index ab85dd6a8d7e..34d422864f0d 100644 --- a/intl/uconv/src/nsUTF8ConverterService.cpp +++ b/intl/uconv/src/nsUTF8ConverterService.cpp @@ -76,7 +76,7 @@ ToUTF8(const nsACString &aString, const char *aCharset, nsACString &aResult) rv = unicodeDecoder->Convert(inStr.get(), &srcLen, ustr, &dstLen); if (NS_SUCCEEDED(rv)){ - // Tru64 Cxx and IRIX MIPSpro 7.3 need an explicit get() + // Tru64 Cxx needs an explicit get() CopyUTF16toUTF8(Substring(ustr.get(), ustr + dstLen), aResult); } return rv; diff --git a/js/src/aclocal.m4 b/js/src/aclocal.m4 index 6b0a411d8ca5..144a8641298a 100644 --- a/js/src/aclocal.m4 +++ b/js/src/aclocal.m4 @@ -11,5 +11,6 @@ builtin(include, build/autoconf/mozprog.m4)dnl builtin(include, build/autoconf/acwinpaths.m4)dnl builtin(include, build/autoconf/lto.m4)dnl builtin(include, build/autoconf/gcc-pr49911.m4)dnl +builtin(include, build/autoconf/frameptr.m4)dnl MOZ_PROG_CHECKMSYS() diff --git a/js/src/assembler/assembler/AssemblerBuffer.h b/js/src/assembler/assembler/AssemblerBuffer.h index d8fcf9f560b1..26127138dc69 100644 --- a/js/src/assembler/assembler/AssemblerBuffer.h +++ b/js/src/assembler/assembler/AssemblerBuffer.h @@ -192,7 +192,11 @@ namespace JSC { void grow(int extraCapacity = 0) { - int newCapacity = m_capacity + m_capacity / 2 + extraCapacity; + /* + * If |extraCapacity| is zero (as it almost always is) this is an + * allocator-friendly doubling growth strategy. + */ + int newCapacity = m_capacity + m_capacity + extraCapacity; char* newBuffer; // Do not allow offsets to grow beyond INT_MAX / 2. This mirrors diff --git a/js/src/build/autoconf/frameptr.m4 b/js/src/build/autoconf/frameptr.m4 new file mode 100644 index 000000000000..77a6d71aedc8 --- /dev/null +++ b/js/src/build/autoconf/frameptr.m4 @@ -0,0 +1,25 @@ +dnl Set MOZ_FRAMEPTR_FLAGS to the flags that should be used for enabling or +dnl disabling frame pointers in this architecture based on the configure +dnl options + +AC_DEFUN([MOZ_SET_FRAMEPTR_FLAGS], [ + if test "$GNU_CC"; then + MOZ_ENABLE_FRAME_PTR="-fno-omit-frame-pointer" + MOZ_DISABLE_FRAME_PTR="-fomit-frame-pointer" + else + case "$target" in + *-mingw*) + MOZ_ENABLE_FRAME_PTR="-Oy-" + MOZ_DISABLE_FRAME_PTR="-Oy" + ;; + esac + fi + + # if we are debugging or profiling, we want a frame pointer. + if test -z "$MOZ_OPTIMIZE" -o \ + -n "$MOZ_PROFILING" -o -n "$MOZ_DEBUG"; then + MOZ_FRAMEPTR_FLAGS="$MOZ_ENABLE_FRAME_PTR" + else + MOZ_FRAMEPTR_FLAGS="$MOZ_DISABLE_FRAME_PTR" + fi +]) diff --git a/js/src/config/autoconf.mk.in b/js/src/config/autoconf.mk.in index e73d8a91231b..7559e848b6a8 100644 --- a/js/src/config/autoconf.mk.in +++ b/js/src/config/autoconf.mk.in @@ -143,6 +143,7 @@ WARNINGS_AS_ERRORS = @WARNINGS_AS_ERRORS@ FAIL_ON_WARNINGS = @FAIL_ON_WARNINGS@ MOZ_OPTIMIZE = @MOZ_OPTIMIZE@ +MOZ_FRAMEPTR_FLAGS = @MOZ_FRAMEPTR_FLAGS@ MOZ_OPTIMIZE_FLAGS = @MOZ_OPTIMIZE_FLAGS@ MOZ_PGO_OPTIMIZE_FLAGS = @MOZ_PGO_OPTIMIZE_FLAGS@ MOZ_OPTIMIZE_LDFLAGS = @MOZ_OPTIMIZE_LDFLAGS@ diff --git a/js/src/config/config.mk b/js/src/config/config.mk index 54c03ed8e989..bfb2c1596945 100644 --- a/js/src/config/config.mk +++ b/js/src/config/config.mk @@ -463,6 +463,9 @@ endif # MOZ_OPTIMIZE == 1 endif # MOZ_OPTIMIZE endif # CROSS_COMPILE +CFLAGS += $(MOZ_FRAMEPTR_FLAGS) +CXXFLAGS += $(MOZ_FRAMEPTR_FLAGS) + # Check for FAIL_ON_WARNINGS & FAIL_ON_WARNINGS_DEBUG (Shorthand for Makefiles # to request that we use the 'warnings as errors' compile flags) diff --git a/js/src/configure.in b/js/src/configure.in index bc07717adcc6..cc361d58fcb1 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -1972,13 +1972,7 @@ case "$target" in *-darwin*) MKSHLIB='$(CXX) $(CXXFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' MKCSHLIB='$(CC) $(CFLAGS) $(DSO_PIC_CFLAGS) $(DSO_LDOPTS) -o $@' - # If we're building with --enable-profiling, we need a frame pointer. - if test -z "$MOZ_PROFILING"; then - MOZ_FRAMEPTR_FLAGS="-fomit-frame-pointer" - else - MOZ_FRAMEPTR_FLAGS="-fno-omit-frame-pointer" - fi - MOZ_OPTIMIZE_FLAGS="-O3 $MOZ_FRAMEPTR_FLAGS -fno-stack-protector" + MOZ_OPTIMIZE_FLAGS="-O3 -fno-stack-protector" _PEDANTIC= CFLAGS="$CFLAGS -fpascal-strings -fno-common" CXXFLAGS="$CXXFLAGS -fpascal-strings -fno-common" @@ -2083,13 +2077,7 @@ ia64*-hpux*) TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"' MOZ_GFX_OPTIMIZE_MOBILE=1 - # If we're building with --enable-profiling, we need a frame pointer. - if test -z "$MOZ_PROFILING"; then - MOZ_FRAMEPTR_FLAGS="-fomit-frame-pointer" - else - MOZ_FRAMEPTR_FLAGS="-fno-omit-frame-pointer" - fi - MOZ_OPTIMIZE_FLAGS="-O3 -freorder-blocks -fno-reorder-functions $MOZ_FRAMEPTR_FLAGS" + MOZ_OPTIMIZE_FLAGS="-O3 -freorder-blocks -fno-reorder-functions" # The Maemo builders don't know about this flag MOZ_ARM_VFP_FLAGS="-mfpu=vfp" ;; @@ -2109,14 +2097,8 @@ ia64*-hpux*) # -Os is broken on gcc 4.1.x 4.2.x, 4.5.x we need to tweak it to get good results. MOZ_OPTIMIZE_SIZE_TWEAK="-finline-limit=50" esac - # If we're building with --enable-profiling, we need a frame pointer. - if test -z "$MOZ_PROFILING"; then - MOZ_FRAMEPTR_FLAGS="-fomit-frame-pointer" - else - MOZ_FRAMEPTR_FLAGS="-fno-omit-frame-pointer" - fi - MOZ_PGO_OPTIMIZE_FLAGS="-O3 $MOZ_FRAMEPTR_FLAGS" - MOZ_OPTIMIZE_FLAGS="-O3 -freorder-blocks $MOZ_OPTIMIZE_SIZE_TWEAK $MOZ_FRAMEPTR_FLAGS" + MOZ_PGO_OPTIMIZE_FLAGS="-O3" + MOZ_OPTIMIZE_FLAGS="-O3 -freorder-blocks $MOZ_OPTIMIZE_SIZE_TWEAK" MOZ_DEBUG_FLAGS="-g" fi @@ -2236,13 +2218,7 @@ ia64*-hpux*) MOZ_DEBUG_FLAGS='-Zi' MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV' WARNINGS_AS_ERRORS='-WX' - # If we're building with --enable-profiling, we need -Oy-, which forces a frame pointer. - if test -z "$MOZ_PROFILING"; then - MOZ_FRAMEPTR_FLAGS= - else - MOZ_FRAMEPTR_FLAGS='-Oy-' - fi - MOZ_OPTIMIZE_FLAGS="-O2 $MOZ_FRAMEPTR_FLAGS" + MOZ_OPTIMIZE_FLAGS="-O2" MOZ_JS_LIBS='$(libdir)/mozjs.lib' MOZ_FIX_LINK_PATHS= DYNAMIC_XPCOM_LIBS='$(LIBXUL_DIST)/lib/xpcom.lib $(LIBXUL_DIST)/lib/xpcom_core.lib $(LIBXUL_DIST)/lib/mozalloc.lib' @@ -4414,6 +4390,8 @@ else MOZ_OPTIMIZE= fi ], MOZ_OPTIMIZE=1) +MOZ_SET_FRAMEPTR_FLAGS + if test "$COMPILE_ENVIRONMENT"; then if test -n "$MOZ_OPTIMIZE"; then AC_MSG_CHECKING([for valid optimization flags]) @@ -4432,6 +4410,7 @@ fi fi # COMPILE_ENVIRONMENT AC_SUBST(MOZ_OPTIMIZE) +AC_SUBST(MOZ_FRAMEPTR_FLAGS) AC_SUBST(MOZ_OPTIMIZE_FLAGS) AC_SUBST(MOZ_OPTIMIZE_LDFLAGS) AC_SUBST(MOZ_OPTIMIZE_SIZE_TWEAK) diff --git a/js/src/jsanalyze.cpp b/js/src/jsanalyze.cpp index f0f237d2d8a7..b16535cdee78 100644 --- a/js/src/jsanalyze.cpp +++ b/js/src/jsanalyze.cpp @@ -905,9 +905,7 @@ ScriptAnalysis::analyzeLifetimes(JSContext *cx) ensureVariable(lifetimes[i], startOffset - 1); } -#ifdef DEBUG found = true; -#endif break; } } diff --git a/js/src/jsapi-tests/testConservativeGC.cpp b/js/src/jsapi-tests/testConservativeGC.cpp index a01024b978fc..0286060b157a 100644 --- a/js/src/jsapi-tests/testConservativeGC.cpp +++ b/js/src/jsapi-tests/testConservativeGC.cpp @@ -49,7 +49,7 @@ bool checkObjectFields(JSObject *savedCopy, JSObject *obj) { /* Ignore fields which are unstable across GCs. */ CHECK(savedCopy->lastProp == obj->lastProp); - CHECK(savedCopy->clasp == obj->clasp); + CHECK(savedCopy->getClass() == obj->getClass()); CHECK(savedCopy->flags == obj->flags); CHECK(savedCopy->newType == obj->newType); CHECK(savedCopy->getProto() == obj->getProto()); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 16c9766a3af7..49a259503ee6 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1552,7 +1552,7 @@ JS_InitStandardClasses(JSContext *cx, JSObject *obj) return obj->asGlobal()->initStandardClasses(cx); } -#define CLASP(name) (&js_##name##Class) +#define CLASP(name) (&name##Class) #define TYPED_ARRAY_CLASP(type) (&TypedArray::fastClasses[TypedArray::type]) #define EAGER_ATOM(name) ATOM_OFFSET(name), NULL #define EAGER_CLASS_ATOM(name) CLASS_ATOM_OFFSET(name), NULL @@ -1662,7 +1662,7 @@ static JSStdName standard_class_names[] = { #endif /* Typed Arrays */ - {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &js_ArrayBufferClass}, + {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(ArrayBuffer), &ArrayBufferClass}, {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int8Array), TYPED_ARRAY_CLASP(TYPE_INT8)}, {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Uint8Array), TYPED_ARRAY_CLASP(TYPE_UINT8)}, {js_InitTypedArrayClasses, EAGER_CLASS_ATOM(Int16Array), TYPED_ARRAY_CLASP(TYPE_INT16)}, @@ -2288,7 +2288,7 @@ JS_PrintTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, { JSObject *obj = (JSObject *)thing; Class *clasp = obj->getClass(); - if (clasp == &js_FunctionClass) { + if (clasp == &FunctionClass) { JSFunction *fun = obj->getFunctionPrivate(); if (!fun) { JS_snprintf(buf, bufsize, ""); @@ -3078,9 +3078,9 @@ JS_NewObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent) Class *clasp = Valueify(jsclasp); if (!clasp) - clasp = &js_ObjectClass; /* default class is Object */ + clasp = &ObjectClass; /* default class is Object */ - JS_ASSERT(clasp != &js_FunctionClass); + JS_ASSERT(clasp != &FunctionClass); JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); if (proto) @@ -3107,9 +3107,9 @@ JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSO Class *clasp = Valueify(jsclasp); if (!clasp) - clasp = &js_ObjectClass; /* default class is Object */ + clasp = &ObjectClass; /* default class is Object */ - JS_ASSERT(clasp != &js_FunctionClass); + JS_ASSERT(clasp != &FunctionClass); JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); JSObject *obj = NewNonFunction(cx, clasp, proto, parent); @@ -3182,7 +3182,7 @@ JS_ConstructObject(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *p assertSameCompartment(cx, proto, parent); Class *clasp = Valueify(jsclasp); if (!clasp) - clasp = &js_ObjectClass; /* default class is Object */ + clasp = &ObjectClass; /* default class is Object */ return js_ConstructObject(cx, clasp, proto, parent, 0, NULL); } @@ -3194,7 +3194,7 @@ JS_ConstructObjectWithArguments(JSContext *cx, JSClass *jsclasp, JSObject *proto assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc)); Class *clasp = Valueify(jsclasp); if (!clasp) - clasp = &js_ObjectClass; /* default class is Object */ + clasp = &ObjectClass; /* default class is Object */ return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv)); } @@ -3534,7 +3534,7 @@ JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, JSClass *jsclasp Class *clasp = Valueify(jsclasp); if (!clasp) - clasp = &js_ObjectClass; /* default class is Object */ + clasp = &ObjectClass; /* default class is Object */ JSObject *nobj = NewObject(cx, clasp, proto, obj); if (!nobj) @@ -4229,7 +4229,7 @@ JS_CloneFunctionObject(JSContext *cx, JSObject *funobj, JSObject *parent) JS_ASSERT(parent); } - if (funobj->getClass() != &js_FunctionClass) { + if (!funobj->isFunction()) { /* * We cannot clone this object, so fail (we used to return funobj, bad * idea, but we changed incompatibly to teach any abusers a lesson!). @@ -4320,7 +4320,7 @@ JS_GetFunctionArity(JSFunction *fun) JS_PUBLIC_API(JSBool) JS_ObjectIsFunction(JSContext *cx, JSObject *obj) { - return obj->getClass() == &js_FunctionClass; + return obj->isFunction(); } JS_PUBLIC_API(JSBool) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 3ac30aabdc5e..bbd60f37f09e 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -44,7 +44,7 @@ * Array objects begin as "dense" arrays, optimized for index-only property * access over a vector of slots with high load factor. Array methods * optimize for denseness by testing that the object's class is - * &js_ArrayClass, and can then directly manipulate the slots for efficiency. + * &ArrayClass, and can then directly manipulate the slots for efficiency. * * We track these pieces of metadata for arrays in dense mode: * - The array's length property as a uint32, accessible with @@ -81,7 +81,7 @@ * known to have no hole values below its initialized length, then it is a * "packed" array and can be accessed much faster by JIT code. * - * Arrays are converted to use js_SlowArrayClass when any of these conditions + * Arrays are converted to use SlowArrayClass when any of these conditions * are met: * - there are more than MIN_SPARSE_INDEX slots total and the load factor * (COUNT / capacity) is less than 0.25 @@ -93,7 +93,7 @@ * properties in the order they were created. We could instead maintain the * scope to track property enumeration order, but still use the fast slot * access. That would have the same memory cost as just using a - * js_SlowArrayClass, but have the same performance characteristics as a dense + * SlowArrayClass, but have the same performance characteristics as a dense * array for slot accesses, at some cost in code complexity. */ #include @@ -146,13 +146,6 @@ using namespace js; using namespace js::gc; using namespace js::types; -static inline bool -ENSURE_SLOW_ARRAY(JSContext *cx, JSObject *obj) -{ - return obj->getClass() == &js_SlowArrayClass || - obj->makeDenseArraySlow(cx); -} - JSBool js_GetLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp) { @@ -246,14 +239,11 @@ static JSBool BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom, jsid *idp) { - jschar buf[10], *start; - Class *clasp; - JSAtom *atom; JS_STATIC_ASSERT((jsuint)-1 == 4294967295U); - JS_ASSERT(index > JSID_INT_MAX); - start = JS_ARRAY_END(buf); + jschar buf[10]; + jschar *start = JS_ARRAY_END(buf); do { --start; *start = (jschar)('0' + index % 10); @@ -264,14 +254,11 @@ BigIndexToId(JSContext *cx, JSObject *obj, jsuint index, JSBool createAtom, * Skip the atomization if the class is known to store atoms corresponding * to big indexes together with elements. In such case we know that the * array does not have an element at the given index if its atom does not - * exist. Fast arrays (clasp == &js_ArrayClass) don't use atoms for - * any indexes, though it would be rare to see them have a big index - * in any case. + * exist. Dense arrays don't use atoms for any indexes, though it would be + * rare to see them have a big index in any case. */ - if (!createAtom && - ((clasp = obj->getClass()) == &js_SlowArrayClass || - obj->isArguments() || - clasp == &js_ObjectClass)) { + JSAtom *atom; + if (!createAtom && (obj->isSlowArray() || obj->isArguments() || obj->isObject())) { atom = js_GetExistingStringAtom(cx, start, JS_ARRAY_END(buf) - start); if (!atom) { *idp = JSID_VOID; @@ -501,13 +488,13 @@ JSBool JS_FASTCALL js_EnsureDenseArrayCapacity(JSContext *cx, JSObject *obj, jsint i) { #ifdef DEBUG - Class *origObjClasp = obj->clasp; + Class *origObjClasp = obj->getClass(); #endif jsuint u = jsuint(i); JSBool ret = (obj->ensureDenseArrayElements(cx, u, 1) == JSObject::ED_OK); /* Partially check the CallInfo's storeAccSet is correct. */ - JS_ASSERT(obj->clasp == origObjClasp); + JS_ASSERT(obj->getClass() == origObjClasp); return ret; } /* This function and its callees do not touch any object's .clasp field. */ @@ -989,7 +976,7 @@ array_fix(JSContext *cx, JSObject *obj, bool *success, AutoIdVector *props) return true; } -Class js_ArrayClass = { +Class js::ArrayClass = { "Array", Class::NON_NATIVE | JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array), PropertyStub, /* addProperty */ @@ -1024,7 +1011,7 @@ Class js_ArrayClass = { } }; -Class js_SlowArrayClass = { +Class js::SlowArrayClass = { "Array", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Array), @@ -1068,8 +1055,8 @@ JSObject::makeDenseArraySlow(JSContext *cx) js::Shape *oldMap = lastProp; /* Create a native scope. */ - js::gc::FinalizeKind kind = js::gc::FinalizeKind(arenaHeader()->getThingKind()); - if (!InitScopeForObject(cx, this, &js_SlowArrayClass, getProto()->getNewType(cx), kind)) + gc::AllocKind kind = getAllocKind(); + if (!InitScopeForObject(cx, this, &SlowArrayClass, getProto()->getNewType(cx), kind)) return false; backfillDenseArrayHoles(cx); @@ -1090,7 +1077,7 @@ JSObject::makeDenseArraySlow(JSContext *cx) JS_ASSERT(!denseArrayHasInlineSlots()); } capacity = numFixedSlots() + arrayCapacity; - clasp = &js_SlowArrayClass; + clasp = &SlowArrayClass; /* * Root all values in the array during conversion, as SlowArrayClass only @@ -1110,7 +1097,7 @@ JSObject::makeDenseArraySlow(JSContext *cx) setMap(oldMap); capacity = arrayCapacity; initializedLength = arrayInitialized; - clasp = &js_ArrayClass; + clasp = &ArrayClass; return false; } @@ -1133,7 +1120,7 @@ JSObject::makeDenseArraySlow(JSContext *cx) setMap(oldMap); capacity = arrayCapacity; initializedLength = arrayInitialized; - clasp = &js_ArrayClass; + clasp = &ArrayClass; return false; } @@ -1144,7 +1131,7 @@ JSObject::makeDenseArraySlow(JSContext *cx) /* * Finally, update class. If |this| is Array.prototype, then js_InitClass - * will create an emptyShape whose class is &js_SlowArrayClass, to ensure + * will create an emptyShape whose class is &SlowArrayClass, to ensure * that delegating instances can share shapes in the tree rooted at the * proto's empty shape. */ @@ -1211,7 +1198,7 @@ array_toSource(JSContext *cx, uintN argc, Value *vp) if (!obj) return false; if (!obj->isArray()) { - ReportIncompatibleMethod(cx, vp, &js_ArrayClass); + ReportIncompatibleMethod(cx, vp, &ArrayClass); return false; } @@ -1540,7 +1527,7 @@ InitArrayElements(JSContext *cx, JSObject *obj, jsuint start, jsuint count, Valu return JS_TRUE; /* Finish out any remaining elements past the max array index. */ - if (obj->isDenseArray() && !ENSURE_SLOW_ARRAY(cx, obj)) + if (obj->isDenseArray() && !obj->makeDenseArraySlow(cx)) return JS_FALSE; JS_ASSERT(start == MAX_ARRAY_INDEX + 1); @@ -3217,12 +3204,12 @@ js_InitArrayClass(JSContext *cx, JSObject *obj) GlobalObject *global = obj->asGlobal(); - JSObject *arrayProto = global->createBlankPrototype(cx, &js_SlowArrayClass); + JSObject *arrayProto = global->createBlankPrototype(cx, &SlowArrayClass); if (!arrayProto || !AddLengthProperty(cx, arrayProto)) return NULL; arrayProto->setArrayLength(cx, 0); - JSFunction *ctor = global->createConstructor(cx, js_Array, &js_ArrayClass, + JSFunction *ctor = global->createConstructor(cx, js_Array, &ArrayClass, CLASS_ATOM(cx, Array), 1); if (!ctor) return NULL; @@ -3256,8 +3243,8 @@ NewArray(JSContext *cx, jsuint length, JSObject *proto) { JS_ASSERT_IF(proto, proto->isArray()); - gc::FinalizeKind kind = GuessObjectGCKind(length, true); - JSObject *obj = detail::NewObject(cx, &js_ArrayClass, proto, NULL, kind); + gc::AllocKind kind = GuessObjectGCKind(length, true); + JSObject *obj = detail::NewObject(cx, &ArrayClass, proto, NULL, kind); if (!obj) return NULL; @@ -3346,7 +3333,7 @@ JS_DEFINE_CALLINFO_3(extern, OBJECT, NewDenseUnallocatedArray, CONTEXT, UINT32, JSObject * NewSlowEmptyArray(JSContext *cx) { - JSObject *obj = NewNonFunction(cx, &js_SlowArrayClass, NULL, NULL); + JSObject *obj = NewNonFunction(cx, &SlowArrayClass, NULL, NULL); if (!obj || !AddLengthProperty(cx, obj)) return NULL; diff --git a/js/src/jsbool.cpp b/js/src/jsbool.cpp index aaa74d258bdb..460675798b3e 100644 --- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -63,7 +63,7 @@ using namespace js; using namespace js::types; -Class js_BooleanClass = { +Class js::BooleanClass = { "Boolean", JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Boolean), @@ -138,7 +138,7 @@ Boolean(JSContext *cx, uintN argc, Value *vp) bool b = argc != 0 ? js_ValueToBoolean(argv[0]) : false; if (IsConstructing(vp)) { - JSObject *obj = NewBuiltinClassInstance(cx, &js_BooleanClass); + JSObject *obj = NewBuiltinClassInstance(cx, &BooleanClass); if (!obj) return false; obj->setPrimitiveThis(BooleanValue(b)); @@ -152,7 +152,7 @@ Boolean(JSContext *cx, uintN argc, Value *vp) JSObject * js_InitBooleanClass(JSContext *cx, JSObject *obj) { - JSObject *proto = js_InitClass(cx, obj, NULL, &js_BooleanClass, Boolean, 1, + JSObject *proto = js_InitClass(cx, obj, NULL, &BooleanClass, Boolean, 1, NULL, boolean_methods, NULL, NULL); if (!proto) return NULL; diff --git a/js/src/jsbool.h b/js/src/jsbool.h index 9da251e439d5..3677425afc11 100644 --- a/js/src/jsbool.h +++ b/js/src/jsbool.h @@ -46,14 +46,6 @@ #include "jsapi.h" #include "jsobj.h" -extern js::Class js_BooleanClass; - -inline bool -JSObject::isBoolean() const -{ - return getClass() == &js_BooleanClass; -} - extern JSObject * js_InitBooleanClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jsbuiltins.cpp b/js/src/jsbuiltins.cpp index 408213bfa9f6..52ec1f055437 100644 --- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -251,7 +251,7 @@ HasProperty(JSContext* cx, JSObject* obj, jsid id) if (pobj->getOps()->lookupProperty) return JS_NEITHER; Class* clasp = pobj->getClass(); - if (clasp->resolve != JS_ResolveStub && clasp != &js_StringClass) + if (clasp->resolve != JS_ResolveStub && clasp != &StringClass) return JS_NEITHER; } @@ -320,7 +320,7 @@ js_NewNullClosure(JSContext* cx, JSObject* funobj, JSObject* proto, JSObject* pa if (!closure) return NULL; - if (!closure->initSharingEmptyShape(cx, &js_FunctionClass, type, parent, + if (!closure->initSharingEmptyShape(cx, &FunctionClass, type, parent, fun, gc::FINALIZE_OBJECT2)) { return NULL; } diff --git a/js/src/jsbuiltins.h b/js/src/jsbuiltins.h index 1b47a259a25b..1f26ed191ca1 100644 --- a/js/src/jsbuiltins.h +++ b/js/src/jsbuiltins.h @@ -84,8 +84,8 @@ enum { * 'i': an integer argument * 's': a JSString* argument * 'o': a JSObject* argument - * 'r': a JSObject* argument that is of class js_RegExpClass - * 'f': a JSObject* argument that is of class js_FunctionClass + * 'r': a JSObject* argument that is of class RegExpClass + * 'f': a JSObject* argument that is of class FunctionClass * 'v': a value argument: on 32-bit, a Value*, on 64-bit, a jsval */ struct JSSpecializedNative { diff --git a/js/src/jscell.h b/js/src/jscell.h index d380a76dac72..1e5f4deeb888 100644 --- a/js/src/jscell.h +++ b/js/src/jscell.h @@ -50,6 +50,38 @@ namespace gc { struct ArenaHeader; struct Chunk; +/* The GC allocation kinds. */ +enum AllocKind { + FINALIZE_OBJECT0, + FINALIZE_OBJECT0_BACKGROUND, + FINALIZE_OBJECT2, + FINALIZE_OBJECT2_BACKGROUND, + FINALIZE_OBJECT4, + FINALIZE_OBJECT4_BACKGROUND, + FINALIZE_OBJECT8, + FINALIZE_OBJECT8_BACKGROUND, + FINALIZE_OBJECT12, + FINALIZE_OBJECT12_BACKGROUND, + FINALIZE_OBJECT16, + FINALIZE_OBJECT16_BACKGROUND, + FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND, + FINALIZE_FUNCTION, + FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION, + FINALIZE_SCRIPT, + FINALIZE_SHAPE, + FINALIZE_TYPE_OBJECT, +#if JS_HAS_XML_SUPPORT + FINALIZE_XML, +#endif + FINALIZE_SHORT_STRING, + FINALIZE_STRING, + FINALIZE_EXTERNAL_STRING, + FINALIZE_IONCODE, + FINALIZE_LAST = FINALIZE_IONCODE +}; + +const size_t FINALIZE_LIMIT = FINALIZE_LAST + 1; + /* * Live objects are marked black. How many other additional colors are available * depends on the size of the GCThing. @@ -67,6 +99,7 @@ struct Cell { inline uintptr_t address() const; inline ArenaHeader *arenaHeader() const; inline Chunk *chunk() const; + inline AllocKind getAllocKind() const; JS_ALWAYS_INLINE bool isMarked(uint32 color = BLACK) const; JS_ALWAYS_INLINE bool markIfUnmarked(uint32 color = BLACK) const; diff --git a/js/src/jsclone.cpp b/js/src/jsclone.cpp index 17301bf1c037..48f362bc2f8c 100644 --- a/js/src/jsclone.cpp +++ b/js/src/jsclone.cpp @@ -782,7 +782,7 @@ JSStructuredCloneReader::startRead(Value *vp) case SCTAG_OBJECT_OBJECT: { JSObject *obj = (tag == SCTAG_ARRAY_OBJECT) ? NewDenseEmptyArray(context()) - : NewBuiltinClassInstance(context(), &js_ObjectClass); + : NewBuiltinClassInstance(context(), &ObjectClass); if (!obj || !objs.append(ObjectValue(*obj)) || !allObjs.append(ObjectValue(*obj))) return false; diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index 15200b66c7d6..ffea9272e11e 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -427,7 +427,7 @@ struct JSRuntime { int64 gcNextFullGCTime; int64 gcJitReleaseTime; JSGCMode gcMode; - volatile bool gcIsNeeded; + volatile jsuword gcIsNeeded; js::WeakMapBase *gcWeakMapList; /* Pre-allocated space for the GC mark stacks. Pointer type ensures alignment. */ @@ -1796,17 +1796,33 @@ class AutoXMLRooter : private AutoGCRooter { class AutoLockGC { public: - explicit AutoLockGC(JSRuntime *rt + explicit AutoLockGC(JSRuntime *rt = NULL JS_GUARD_OBJECT_NOTIFIER_PARAM) - : rt(rt) + : runtime(rt) { JS_GUARD_OBJECT_NOTIFIER_INIT; + if (rt) + JS_LOCK_GC(rt); + } + + bool locked() const { + return !!runtime; + } + + void lock(JSRuntime *rt) { + JS_ASSERT(rt); + JS_ASSERT(!runtime); + runtime = rt; JS_LOCK_GC(rt); } - ~AutoLockGC() { JS_UNLOCK_GC(rt); } + + ~AutoLockGC() { + if (runtime) + JS_UNLOCK_GC(runtime); + } private: - JSRuntime *rt; + JSRuntime *runtime; JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index b189e15f8b60..24860dbb7d86 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -334,12 +334,10 @@ CallJSNativeConstructor(JSContext *cx, js::Native native, const CallArgs &args) * * (new Object(Object)) returns the callee. */ - extern JSBool proxy_Construct(JSContext *, uintN, Value *); - extern JSBool callable_Construct(JSContext *, uintN, Value *); - JS_ASSERT_IF(native != proxy_Construct && - native != callable_Construct && + JS_ASSERT_IF(native != FunctionProxyClass.construct && + native != CallableObjectClass.construct && native != js::CallOrConstructBoundFunction && - (!callee.isFunction() || callee.getFunctionPrivate()->u.n.clasp != &js_ObjectClass), + (!callee.isFunction() || callee.getFunctionPrivate()->u.n.clasp != &ObjectClass), !args.rval().isPrimitive() && callee != args.rval().toObject()); return true; diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 9a8702f29cd1..21436428adc0 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -137,9 +137,6 @@ JSCompartment::~JSCompartment() bool JSCompartment::init(JSContext *cx) { - for (unsigned i = 0; i < FINALIZE_LIMIT; i++) - arenas[i].init(); - activeAnalysis = activeInference = false; types.init(cx); @@ -148,7 +145,6 @@ JSCompartment::init(JSContext *cx) JS_InitArenaPool(&pool, "analysis", 4096 - ARENA_HEADER_SIZE_HACK, 8); - freeLists.init(); if (!crossCompartmentWrappers.init()) return false; @@ -218,16 +214,6 @@ JSCompartment::getMjitCodeStats(size_t& method, size_t& regexp, size_t& unused) } #endif -bool -JSCompartment::arenaListsAreEmpty() -{ - for (unsigned i = 0; i < FINALIZE_LIMIT; i++) { - if (!arenas[i].isEmpty()) - return false; - } - return true; -} - static bool IsCrossCompartmentWrapper(JSObject *wrapper) { @@ -291,7 +277,7 @@ JSCompartment::wrap(JSContext *cx, Value *vp) return true; /* Translate StopIteration singleton. */ - if (obj->getClass() == &js_StopIterationClass) + if (obj->isStopIteration()) return js_FindClassObject(cx, NULL, JSProto_StopIteration, vp); /* Don't unwrap an outer window proxy. */ @@ -544,10 +530,10 @@ JSCompartment::markTypes(JSTracer *trc) MarkScript(trc, script, "mark_types_script"); } - for (unsigned thingKind = FINALIZE_OBJECT0; + for (size_t thingKind = FINALIZE_OBJECT0; thingKind <= FINALIZE_FUNCTION_AND_OBJECT_LAST; thingKind++) { - for (CellIterUnderGC i(this, FinalizeKind(thingKind)); !i.done(); i.next()) { + for (CellIterUnderGC i(this, AllocKind(thingKind)); !i.done(); i.next()) { JSObject *object = i.get(); if (!object->isNewborn() && object->hasSingletonType()) MarkObject(trc, *object, "mark_types_singleton"); @@ -694,7 +680,7 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval) void JSCompartment::purge(JSContext *cx) { - freeLists.purge(); + arenas.purge(); dtoaCache.purge(); /* diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 52c972222f6a..2234b2833e97 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -397,8 +397,7 @@ struct JS_FRIEND_API(JSCompartment) { JSRuntime *rt; JSPrincipals *principals; - js::gc::ArenaList arenas[js::gc::FINALIZE_LIMIT]; - js::gc::FreeLists freeLists; + js::gc::ArenaLists arenas; uint32 gcBytes; uint32 gcTriggerBytes; @@ -539,13 +538,6 @@ struct JS_FRIEND_API(JSCompartment) { void markTypes(JSTracer *trc); void sweep(JSContext *cx, uint32 releaseInterval); void purge(JSContext *cx); - void finishArenaLists(); - void finalizeObjectArenaLists(JSContext *cx); - void finalizeStringArenaLists(JSContext *cx); - void finalizeShapeArenaLists(JSContext *cx); - void finalizeScriptArenaLists(JSContext *cx); - void finalizeIonCodeArenaLists(JSContext *cx); - bool arenaListsAreEmpty(); void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind); void reduceGCTriggerBytes(uint32 amount); diff --git a/js/src/jscrashreport.h b/js/src/jscrashreport.h index 378cbc94104f..bdc0b0bee9d0 100644 --- a/js/src/jscrashreport.h +++ b/js/src/jscrashreport.h @@ -56,11 +56,11 @@ SnapshotErrorStack(); void SaveCrashData(uint64 tag, void *ptr, size_t size); -template +template class StackBuffer { private: JS_DECL_USE_GUARD_OBJECT_NOTIFIER - volatile char buffer[size + 4]; + volatile unsigned char buffer[size + 4]; public: StackBuffer(void *data JS_GUARD_OBJECT_NOTIFIER_PARAM) { @@ -71,7 +71,7 @@ class StackBuffer { for (size_t i = 0; i < size; i++) { if (data) - buffer[i + 2] = ((char *)data)[i]; + buffer[i + 2] = ((unsigned char *)data)[i]; else buffer[i + 2] = 0; } diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 988a9c4683f4..eb7bdf168765 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -503,7 +503,7 @@ date_convert(JSContext *cx, JSObject *obj, JSType hint, Value *vp) * Other Support routines and definitions */ -Class js_DateClass = { +Class js::DateClass = { js_Date_str, JSCLASS_HAS_RESERVED_SLOTS(JSObject::DATE_CLASS_RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Date), @@ -1226,7 +1226,7 @@ GetUTCTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *dp) { if (!obj->isDate()) { if (vp) - ReportIncompatibleMethod(cx, vp, &js_DateClass); + ReportIncompatibleMethod(cx, vp, &DateClass); return false; } *dp = obj->getDateUTCTime().toNumber(); @@ -1408,7 +1408,7 @@ GetAndCacheLocalTime(JSContext *cx, JSObject *obj, Value *vp, jsdouble *time = N return false; if (!obj->isDate()) { if (vp) - ReportIncompatibleMethod(cx, vp, &js_DateClass); + ReportIncompatibleMethod(cx, vp, &DateClass); return false; } @@ -1701,7 +1701,7 @@ date_setTime(JSContext *cx, uintN argc, Value *vp) return false; if (!obj->isDate()) { - ReportIncompatibleMethod(cx, vp, &js_DateClass); + ReportIncompatibleMethod(cx, vp, &DateClass); return false; } @@ -2607,7 +2607,7 @@ js_InitDateClass(JSContext *cx, JSObject *obj) { /* set static LocalTZA */ LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond); - JSObject *proto = js_InitClass(cx, obj, NULL, &js_DateClass, js_Date, MAXARGS, + JSObject *proto = js_InitClass(cx, obj, NULL, &DateClass, js_Date, MAXARGS, NULL, date_methods, NULL, date_static_methods); if (!proto) return NULL; @@ -2638,7 +2638,7 @@ js_InitDateClass(JSContext *cx, JSObject *obj) JS_FRIEND_API(JSObject *) js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time) { - JSObject *obj = NewBuiltinClassInstance(cx, &js_DateClass); + JSObject *obj = NewBuiltinClassInstance(cx, &DateClass); if (!obj || !obj->ensureSlots(cx, JSObject::DATE_CLASS_RESERVED_SLOTS)) return NULL; if (!SetUTCTime(cx, obj, msec_time)) diff --git a/js/src/jsdate.h b/js/src/jsdate.h index ba97ddd855c4..28a27f935039 100644 --- a/js/src/jsdate.h +++ b/js/src/jsdate.h @@ -46,14 +46,6 @@ #include "jsobj.h" -extern js::Class js_DateClass; - -inline bool -JSObject::isDate() const -{ - return getClass() == &js_DateClass; -} - #define HalfTimeDomain 8.64e15 #define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \ diff --git a/js/src/jsemit.cpp b/js/src/jsemit.cpp index 765746429d27..8333b8b4ba32 100644 --- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -2000,7 +2000,7 @@ EmitEnterBlock(JSContext *cx, JSParseNode *pn, JSCodeGenerator *cg) if (depth < 0) return false; - uintN base = JSSLOT_FREE(&js_BlockClass); + uintN base = JSSLOT_FREE(&BlockClass); for (uintN slot = base, limit = base + OBJ_BLOCK_COUNT(cx, blockObj); slot < limit; slot++) { const Value &v = blockObj->getSlot(slot); @@ -4891,8 +4891,8 @@ JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp) case TOK_RC: { JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST)); - gc::FinalizeKind kind = GuessObjectGCKind(pn_count, false); - JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + gc::AllocKind kind = GuessObjectGCKind(pn_count, false); + JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind); if (!obj) return false; @@ -7084,8 +7084,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) */ JSObject *obj = NULL; if (!cg->hasSharps() && cg->compileAndGo()) { - gc::FinalizeKind kind = GuessObjectGCKind(pn->pn_count, false); - obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + gc::AllocKind kind = GuessObjectGCKind(pn->pn_count, false); + obj = NewBuiltinClassInstance(cx, &ObjectClass, kind); if (!obj) return JS_FALSE; } diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 342f8e9e370b..c3aec9f64b18 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -75,7 +75,7 @@ using namespace js; using namespace js::gc; using namespace js::types; -/* Forward declarations for js_ErrorClass's initializer. */ +/* Forward declarations for ErrorClass's initializer. */ static JSBool Exception(JSContext *cx, uintN argc, Value *vp); @@ -89,7 +89,7 @@ static JSBool exn_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); -Class js_ErrorClass = { +Class js::ErrorClass = { js_Error_str, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_Error), @@ -263,113 +263,99 @@ GetStackTraceValueBuffer(JSExnPrivate *priv) return (jsval *)(priv->stackElems + priv->stackDepth); } -static JSBool +struct SuppressErrorsGuard +{ + JSContext *cx; + JSErrorReporter prevReporter; + JSExceptionState *prevState; + + SuppressErrorsGuard(JSContext *cx) + : cx(cx), + prevReporter(JS_SetErrorReporter(cx, NULL)), + prevState(JS_SaveExceptionState(cx)) + {} + + ~SuppressErrorsGuard() + { + JS_RestoreExceptionState(cx, prevState); + JS_SetErrorReporter(cx, prevReporter); + } +}; + +struct AppendArg { + Vector &values; + AppendArg(Vector &values) : values(values) {} + bool operator()(uintN, Value *vp) { + return values.append(*vp); + } +}; + +static bool InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, JSString *filename, uintN lineno, JSErrorReport *report, intN exnType) { - JSSecurityCallbacks *callbacks; - CheckAccessOp checkAccess; - JSErrorReporter older; - JSExceptionState *state; - jsid callerid; - size_t stackDepth, valueCount, size; - JSBool overflow; - JSExnPrivate *priv; - JSStackTraceElem *elem; - jsval *values; + JS_ASSERT(exnObject->isError()); + JS_ASSERT(!exnObject->getPrivate()); - JS_ASSERT(exnObject->getClass() == &js_ErrorClass); + JSSecurityCallbacks *callbacks = JS_GetSecurityCallbacks(cx); + CheckAccessOp checkAccess = callbacks + ? Valueify(callbacks->checkObjectAccess) + : NULL; - /* - * Prepare stack trace data. - * - * Set aside any error reporter for cx and save its exception state - * so we can suppress any checkAccess failures. Such failures should stop - * the backtrace procedure, not result in a failure of this constructor. - */ - callbacks = JS_GetSecurityCallbacks(cx); - checkAccess = callbacks - ? Valueify(callbacks->checkObjectAccess) - : NULL; - older = JS_SetErrorReporter(cx, NULL); - state = JS_SaveExceptionState(cx); - - callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom); - stackDepth = 0; - valueCount = 0; - FrameRegsIter firstPass(cx); - for (; !firstPass.done(); ++firstPass) { - StackFrame *fp = firstPass.fp(); - if (fp->compartment() != cx->compartment) - break; - if (fp->isNonEvalFunctionFrame()) { - Value v = NullValue(); - if (checkAccess && - !checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v)) { + Vector frames(cx); + Vector values(cx); + { + SuppressErrorsGuard seg(cx); + for (FrameRegsIter i(cx); !i.done(); ++i) { + /* + * An exception object stores stack values from 'fp' which may be + * in a different compartment from 'exnObject'. Engine compartment + * invariants require such values to be wrapped. A simpler solution + * is to just cut off the backtrace at compartment boundaries. + * Also, avoid exposing values from different security principals. + */ + StackFrame *fp = i.fp(); + if (fp->compartment() != cx->compartment) break; + if (checkAccess && fp->isNonEvalFunctionFrame()) { + Value v = NullValue(); + jsid callerid = ATOM_TO_JSID(cx->runtime->atomState.callerAtom); + if (!checkAccess(cx, &fp->callee(), callerid, JSACC_READ, &v)) + break; } - valueCount += fp->numActualArgs(); - } - ++stackDepth; - } - JS_RestoreExceptionState(cx, state); - JS_SetErrorReporter(cx, older); - size = offsetof(JSExnPrivate, stackElems); - overflow = (stackDepth > ((size_t)-1 - size) / sizeof(JSStackTraceElem)); - size += stackDepth * sizeof(JSStackTraceElem); - overflow |= (valueCount > ((size_t)-1 - size) / sizeof(jsval)); - size += valueCount * sizeof(jsval); - if (overflow) { - js_ReportAllocationOverflow(cx); - return JS_FALSE; + if (!frames.growBy(1)) + return false; + JSStackTraceElem &frame = frames.back(); + if (fp->isNonEvalFunctionFrame()) { + frame.funName = fp->fun()->atom ? fp->fun()->atom : cx->runtime->emptyString; + frame.argc = fp->numActualArgs(); + if (!fp->forEachCanonicalActualArg(AppendArg(values))) + return false; + } else { + frame.funName = NULL; + frame.argc = 0; + } + if (fp->isScriptFrame()) { + frame.filename = fp->script()->filename; + frame.ulineno = js_FramePCToLineNumber(cx, fp, i.pc()); + } else { + frame.ulineno = 0; + frame.filename = NULL; + } + } } - priv = (JSExnPrivate *)cx->malloc_(size); + + /* Do not need overflow check: the vm stack is already bigger. */ + JS_STATIC_ASSERT(sizeof(JSStackTraceElem) <= sizeof(StackFrame)); + + size_t nbytes = offsetof(JSExnPrivate, stackElems) + + frames.length() * sizeof(JSStackTraceElem) + + values.length() * sizeof(Value); + + JSExnPrivate *priv = (JSExnPrivate *)cx->malloc_(nbytes); if (!priv) - return JS_FALSE; - - /* - * We initialize errorReport with a copy of report after setting the - * private slot, to prevent GC accessing a junk value we clear the field - * here. - */ - priv->errorReport = NULL; - priv->message = message; - priv->filename = filename; - priv->lineno = lineno; - priv->stackDepth = stackDepth; - priv->exnType = exnType; - - values = GetStackTraceValueBuffer(priv); - elem = priv->stackElems; - - for (FrameRegsIter iter(cx); iter != firstPass; ++iter) { - StackFrame *fp = iter.fp(); - if (fp->compartment() != cx->compartment) - break; - if (!fp->isNonEvalFunctionFrame()) { - elem->funName = NULL; - elem->argc = 0; - } else { - elem->funName = fp->fun()->atom - ? fp->fun()->atom - : cx->runtime->emptyString; - elem->argc = fp->numActualArgs(); - fp->forEachCanonicalActualArg(CopyTo(Valueify(values))); - values += elem->argc; - } - elem->ulineno = 0; - elem->filename = NULL; - if (fp->isScriptFrame()) { - elem->filename = fp->script()->filename; - elem->ulineno = js_FramePCToLineNumber(cx, fp, iter.pc()); - } - ++elem; - } - JS_ASSERT(priv->stackElems + stackDepth == elem); - JS_ASSERT(GetStackTraceValueBuffer(priv) + valueCount == values); - - exnObject->setPrivate(priv); + return false; if (report) { /* @@ -380,12 +366,28 @@ InitExnPrivate(JSContext *cx, JSObject *exnObject, JSString *message, */ priv->errorReport = CopyErrorReport(cx, report); if (!priv->errorReport) { - /* The finalizer realeases priv since it is in the private slot. */ - return JS_FALSE; + cx->free_(priv); + return false; } + } else { + priv->errorReport = NULL; } - return JS_TRUE; + priv->message = message; + priv->filename = filename; + priv->lineno = lineno; + priv->stackDepth = frames.length(); + priv->exnType = exnType; + + JSStackTraceElem *framesDest = priv->stackElems; + Value *valuesDest = reinterpret_cast(framesDest + frames.length()); + JS_ASSERT(valuesDest == Valueify(GetStackTraceValueBuffer(priv))); + + PodCopy(framesDest, frames.begin(), frames.length()); + PodCopy(valuesDest, values.begin(), values.length()); + + exnObject->setPrivate(priv); + return true; } static inline JSExnPrivate * @@ -429,12 +431,9 @@ exn_trace(JSTracer *trc, JSObject *obj) static void exn_finalize(JSContext *cx, JSObject *obj) { - JSExnPrivate *priv; - - priv = GetExnPrivate(obj); - if (priv) { - if (priv->errorReport) - cx->free_(priv->errorReport); + if (JSExnPrivate *priv = GetExnPrivate(obj)) { + if (JSErrorReport *report = priv->errorReport) + cx->free_(report); cx->free_(priv); } } @@ -521,7 +520,7 @@ js_ErrorFromException(JSContext *cx, jsval exn) if (JSVAL_IS_PRIMITIVE(exn)) return NULL; obj = JSVAL_TO_OBJECT(exn); - if (obj->getClass() != &js_ErrorClass) + if (!obj->isError()) return NULL; priv = GetExnPrivate(obj); if (!priv) @@ -704,6 +703,8 @@ enum { static JSBool Exception(JSContext *cx, uintN argc, Value *vp) { + CallArgs args = CallArgsFromVp(argc, vp); + /* * ECMA ed. 3, 15.11.1 requires Error, etc., to construct even when * called as functions, without operator new. But as we do not give @@ -711,36 +712,28 @@ Exception(JSContext *cx, uintN argc, Value *vp) * NewNativeClassInstance to find the class prototype, we must get the * class prototype ourselves. */ - JSObject &callee = vp[0].toObject(); Value protov; - if (!callee.getProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom), &protov)) - return JS_FALSE; + jsid protoAtom = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom); + if (!args.callee().getProperty(cx, protoAtom, &protov)) + return false; if (!protov.isObject()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE, "Error"); - return JS_FALSE; + return false; } JSObject *errProto = &protov.toObject(); - JSObject *obj = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent()); + JSObject *obj = NewNativeClassInstance(cx, &ErrorClass, errProto, errProto->getParent()); if (!obj) - return JS_FALSE; - - /* - * If it's a new object of class Exception, then null out the private - * data so that the finalizer doesn't attempt to free it. - */ - if (obj->getClass() == &js_ErrorClass) - obj->setPrivate(NULL); + return false; /* Set the 'message' property. */ - Value *argv = vp + 2; JSString *message; - if (argc != 0 && !argv[0].isUndefined()) { - message = js_ValueToString(cx, argv[0]); + if (args.argc() != 0 && !args[0].isUndefined()) { + message = js_ValueToString(cx, args[0]); if (!message) - return JS_FALSE; - argv[0].setString(message); + return false; + args[0].setString(message); } else { message = NULL; } @@ -752,16 +745,16 @@ Exception(JSContext *cx, uintN argc, Value *vp) /* Set the 'fileName' property. */ JSString *filename; - if (argc > 1) { - filename = js_ValueToString(cx, argv[1]); + if (args.argc() > 1) { + filename = js_ValueToString(cx, args[1]); if (!filename) - return JS_FALSE; - argv[1].setString(filename); + return false; + args[1].setString(filename); } else { if (!iter.done()) { filename = FilenameToString(cx, iter.fp()->script()->filename); if (!filename) - return JS_FALSE; + return false; } else { filename = cx->runtime->emptyString; } @@ -769,21 +762,19 @@ Exception(JSContext *cx, uintN argc, Value *vp) /* Set the 'lineNumber' property. */ uint32_t lineno; - if (argc > 2) { - if (!ValueToECMAUint32(cx, argv[2], &lineno)) - return JS_FALSE; + if (args.argc() > 2) { + if (!ValueToECMAUint32(cx, args[2], &lineno)) + return false; } else { lineno = iter.done() ? 0 : js_FramePCToLineNumber(cx, iter.fp(), iter.pc()); } - intN exnType = callee.getReservedSlot(JSSLOT_ERROR_EXNTYPE).toInt32(); - if (obj->getClass() == &js_ErrorClass && - !InitExnPrivate(cx, obj, message, filename, lineno, NULL, exnType)) { - return JS_FALSE; - } + intN exnType = args.callee().getReservedSlot(JSSLOT_ERROR_EXNTYPE).toInt32(); + if (!InitExnPrivate(cx, obj, message, filename, lineno, NULL, exnType)) + return false; - vp->setObject(*obj); - return JS_TRUE; + args.rval().setObject(*obj); + return true; } /* @@ -1019,7 +1010,7 @@ InitErrorClass(JSContext *cx, GlobalObject *global, intN type, JSObject &proto) { JSProtoKey key = GetExceptionProtoKey(type); JSAtom *name = cx->runtime->atomState.classAtoms[key]; - JSObject *errorProto = global->createBlankPrototypeInheriting(cx, &js_ErrorClass, proto); + JSObject *errorProto = global->createBlankPrototypeInheriting(cx, &ErrorClass, proto); if (!errorProto) return NULL; @@ -1041,7 +1032,7 @@ InitErrorClass(JSContext *cx, GlobalObject *global, intN type, JSObject &proto) } /* Create the corresponding constructor. */ - JSFunction *ctor = global->createConstructor(cx, Exception, &js_ErrorClass, name, 1); + JSFunction *ctor = global->createConstructor(cx, Exception, &ErrorClass, name, 1); if (!ctor) return NULL; ctor->setReservedSlot(JSSLOT_ERROR_EXNTYPE, Int32Value(int32(type))); @@ -1180,7 +1171,7 @@ js_ErrorToException(JSContext *cx, const char *message, JSErrorReport *reportp, goto out; tv[0] = OBJECT_TO_JSVAL(errProto); - errObject = NewNativeClassInstance(cx, &js_ErrorClass, errProto, errProto->getParent()); + errObject = NewNativeClassInstance(cx, &ErrorClass, errProto, errProto->getParent()); if (!errObject) { ok = JS_FALSE; goto out; @@ -1264,7 +1255,7 @@ js_ReportUncaughtException(JSContext *cx) } JSAutoByteString filename; - if (!reportp && exnObject && exnObject->getClass() == &js_ErrorClass) { + if (!reportp && exnObject && exnObject->isError()) { if (!JS_GetProperty(cx, exnObject, js_message_str, &roots[2])) return false; if (JSVAL_IS_STRING(roots[2])) { @@ -1368,7 +1359,7 @@ js_CopyErrorObject(JSContext *cx, JSObject *errobj, JSObject *scope) JSObject *proto; if (!js_GetClassPrototype(cx, scope->getGlobal(), GetExceptionProtoKey(copy->exnType), &proto)) return NULL; - JSObject *copyobj = NewNativeClassInstance(cx, &js_ErrorClass, proto, proto->getParent()); + JSObject *copyobj = NewNativeClassInstance(cx, &ErrorClass, proto, proto->getParent()); copyobj->setPrivate(copy); autoFree.p = NULL; return copyobj; diff --git a/js/src/jsexn.h b/js/src/jsexn.h index 3966331e3128..db26f3994798 100644 --- a/js/src/jsexn.h +++ b/js/src/jsexn.h @@ -46,14 +46,6 @@ #include "jsobj.h" -extern js::Class js_ErrorClass; - -inline bool -JSObject::isError() const -{ - return clasp == &js_ErrorClass; -} - /* * Initialize the exception constructor/prototype hierarchy. */ diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index a2b73c55accd..89a9e26d1063 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -216,8 +216,8 @@ ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee) /* Can't fail from here on, so initialize everything in argsobj. */ obj->init(cx, callee.getFunctionPrivate()->inStrictMode() - ? &StrictArgumentsObject::jsClass - : &NormalArgumentsObject::jsClass, + ? &StrictArgumentsObjectClass + : &NormalArgumentsObjectClass, type, proto->getParent(), NULL, false); obj->setMap(emptyArgumentsShape); @@ -686,18 +686,16 @@ args_trace(JSTracer *trc, JSObject *obj) MaybeMarkGenerator(trc, argsobj); } -namespace js { - /* * The classes below collaborate to lazily reflect and synchronize actual * argument values, argument count, and callee function object stored in a * StackFrame with their corresponding property values in the frame's * arguments object. */ -Class NormalArgumentsObject::jsClass = { +Class js::NormalArgumentsObjectClass = { "Arguments", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | - JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | + JSCLASS_HAS_RESERVED_SLOTS(NormalArgumentsObject::RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), PropertyStub, /* addProperty */ args_delProperty, @@ -721,10 +719,10 @@ Class NormalArgumentsObject::jsClass = { * arguments, so it is represented by a different class while sharing some * functionality. */ -Class StrictArgumentsObject::jsClass = { +Class js::StrictArgumentsObjectClass = { "Arguments", JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | - JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | + JSCLASS_HAS_RESERVED_SLOTS(StrictArgumentsObject::RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), PropertyStub, /* addProperty */ args_delProperty, @@ -743,13 +741,11 @@ Class StrictArgumentsObject::jsClass = { args_trace }; -} - /* * A Declarative Environment object stores its active StackFrame pointer in * its private slot, just as Call and Arguments objects do. */ -Class js_DeclEnvClass = { +Class js::DeclEnvClass = { js_Object_str, JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), PropertyStub, /* addProperty */ @@ -773,7 +769,7 @@ NewCallObject(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *c Bindings &bindings = script->bindings; size_t argsVars = bindings.countArgsAndVars(); size_t slots = JSObject::CALL_RESERVED_SLOTS + argsVars; - gc::FinalizeKind kind = gc::GetGCObjectKind(slots); + gc::AllocKind kind = gc::GetGCObjectKind(slots); JSObject *callobj = js_NewGCObject(cx, kind); if (!callobj) @@ -811,7 +807,7 @@ NewDeclEnvObject(JSContext *cx, StackFrame *fp) EmptyShape *emptyDeclEnvShape = EmptyShape::getEmptyDeclEnvShape(cx); if (!emptyDeclEnvShape) return NULL; - envobj->init(cx, &js_DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false); + envobj->init(cx, &DeclEnvClass, &emptyTypeObject, &fp->scopeChain(), fp, false); envobj->setMap(emptyDeclEnvShape); return envobj; @@ -952,11 +948,11 @@ js_PutCallObject(StackFrame *fp) } } - /* Clear private pointers to fp, which is about to go away (js_Invoke). */ + /* Clear private pointers to fp, which is about to go away. */ if (js_IsNamedLambda(fun)) { JSObject *env = callobj.getParent(); - JS_ASSERT(env->getClass() == &js_DeclEnvClass); + JS_ASSERT(env->isDeclEnv()); JS_ASSERT(env->getPrivate() == fp); env->setPrivate(NULL); } @@ -1176,7 +1172,7 @@ call_trace(JSTracer *trc, JSObject *obj) MaybeMarkGenerator(trc, obj); } -JS_PUBLIC_DATA(Class) js_CallClass = { +JS_PUBLIC_DATA(Class) js::CallClass = { "Call", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSObject::CALL_RESERVED_SLOTS) | @@ -1466,7 +1462,7 @@ ResolveInterpretedFunctionPrototype(JSContext *cx, JSObject *obj) JSObject *objProto; if (!js_GetClassPrototype(cx, parent, JSProto_Object, &objProto)) return NULL; - JSObject *proto = NewNativeClassInstance(cx, &js_ObjectClass, objProto, parent); + JSObject *proto = NewNativeClassInstance(cx, &ObjectClass, objProto, parent); if (!proto || !proto->setSingletonType(cx)) return NULL; @@ -1718,7 +1714,7 @@ fun_finalize(JSContext *cx, JSObject *obj) * does not bloat every instance, only those on which reserved slots are set, * and those on which ad-hoc properties are defined. */ -JS_PUBLIC_DATA(Class) js_FunctionClass = { +JS_PUBLIC_DATA(Class) js::FunctionClass = { js_Function_str, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_RESERVED_SLOTS(JSFunction::CLASS_RESERVED_SLOTS) | @@ -1831,7 +1827,7 @@ js_fun_call(JSContext *cx, uintN argc, Value *vp) Value fval = vp[1]; if (!js_IsCallable(fval)) { - ReportIncompatibleMethod(cx, vp, &js_FunctionClass); + ReportIncompatibleMethod(cx, vp, &FunctionClass); return false; } @@ -1868,7 +1864,7 @@ js_fun_apply(JSContext *cx, uintN argc, Value *vp) /* Step 1. */ Value fval = vp[1]; if (!js_IsCallable(fval)) { - ReportIncompatibleMethod(cx, vp, &js_FunctionClass); + ReportIncompatibleMethod(cx, vp, &FunctionClass); return false; } @@ -2077,7 +2073,7 @@ fun_bind(JSContext *cx, uintN argc, Value *vp) /* Step 2. */ if (!js_IsCallable(thisv)) { - ReportIncompatibleMethod(cx, vp, &js_FunctionClass); + ReportIncompatibleMethod(cx, vp, &FunctionClass); return false; } @@ -2370,7 +2366,7 @@ ThrowTypeError(JSContext *cx, uintN argc, Value *vp) JSObject * js_InitFunctionClass(JSContext *cx, JSObject *obj) { - JSObject *proto = js_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1, + JSObject *proto = js_InitClass(cx, obj, NULL, &FunctionClass, Function, 1, NULL, function_methods, NULL, NULL); if (!proto) return NULL; @@ -2477,7 +2473,7 @@ js_CloneFunctionObject(JSContext *cx, JSFunction *fun, JSObject *parent, * The cloned function object does not need the extra JSFunction members * beyond JSObject as it points to fun via the private slot. */ - clone = NewNativeClassInstance(cx, &js_FunctionClass, proto, parent); + clone = NewNativeClassInstance(cx, &FunctionClass, proto, parent); if (!clone) return NULL; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index c1861cf5720f..83e806045b47 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -170,7 +170,7 @@ struct JSFunction : public JSObject_Slots2 private: /* - * js_FunctionClass reserves two slots, which are free in JSObject::fslots + * FunctionClass reserves two slots, which are free in JSObject::fslots * without requiring dslots allocation. Null closures that can be joined to * a compiler-created function object use the first one to hold a mutable * methodAtom() state variable, needed for correct foo.caller handling. @@ -255,22 +255,6 @@ struct JSFunction : public JSObject_Slots2 JS_FN(name, fastcall, nargs, flags) #endif -extern JS_PUBLIC_DATA(js::Class) js_CallClass; -extern JS_PUBLIC_DATA(js::Class) js_FunctionClass; -extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass; - -inline bool -JSObject::isCall() const -{ - return getClass() == &js_CallClass; -} - -inline bool -JSObject::isFunction() const -{ - return getClass() == &js_FunctionClass; -} - inline JSFunction * JSObject::getFunctionPrivate() const { @@ -331,7 +315,7 @@ IsNativeFunction(const js::Value &v, Native native) /* * When we have an object of a builtin class, we don't quite know what its * valueOf/toString methods are, since these methods may have been overwritten - * or shadowed. However, we can still do better than js_TryMethod by + * or shadowed. However, we can still do better than the general case by * hard-coding the necessary properties for us to find the native we expect. * * TODO: a per-thread shape-based cache would be faster and simpler. diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 5875e45d5def..3e0147f13ba2 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -112,7 +112,7 @@ namespace js { namespace gc { /* This array should be const, but that doesn't link right under GCC. */ -FinalizeKind slotsToThingKind[] = { +AllocKind slotsToThingKind[] = { /* 0 */ FINALIZE_OBJECT0, FINALIZE_OBJECT2, FINALIZE_OBJECT2, FINALIZE_OBJECT4, /* 4 */ FINALIZE_OBJECT4, FINALIZE_OBJECT8, FINALIZE_OBJECT8, FINALIZE_OBJECT8, /* 8 */ FINALIZE_OBJECT8, FINALIZE_OBJECT12, FINALIZE_OBJECT12, FINALIZE_OBJECT12, @@ -122,7 +122,7 @@ FinalizeKind slotsToThingKind[] = { JS_STATIC_ASSERT(JS_ARRAY_LENGTH(slotsToThingKind) == SLOTS_TO_THING_KIND_LIMIT); -const uint8 GCThingSizeMap[] = { +const uint32 Arena::ThingSizes[] = { sizeof(JSObject), /* FINALIZE_OBJECT0 */ sizeof(JSObject), /* FINALIZE_OBJECT0_BACKGROUND */ sizeof(JSObject_Slots2), /* FINALIZE_OBJECT2 */ @@ -148,7 +148,35 @@ const uint8 GCThingSizeMap[] = { sizeof(ion::IonCode), /* FINALIZE_IONCODE */ }; -JS_STATIC_ASSERT(JS_ARRAY_LENGTH(GCThingSizeMap) == FINALIZE_LIMIT); +#define OFFSET(type) uint32(sizeof(ArenaHeader) + (ArenaSize - sizeof(ArenaHeader)) % sizeof(type)) + +const uint32 Arena::FirstThingOffsets[] = { + OFFSET(JSObject), /* FINALIZE_OBJECT0 */ + OFFSET(JSObject), /* FINALIZE_OBJECT0_BACKGROUND */ + OFFSET(JSObject_Slots2), /* FINALIZE_OBJECT2 */ + OFFSET(JSObject_Slots2), /* FINALIZE_OBJECT2_BACKGROUND */ + OFFSET(JSObject_Slots4), /* FINALIZE_OBJECT4 */ + OFFSET(JSObject_Slots4), /* FINALIZE_OBJECT4_BACKGROUND */ + OFFSET(JSObject_Slots8), /* FINALIZE_OBJECT8 */ + OFFSET(JSObject_Slots8), /* FINALIZE_OBJECT8_BACKGROUND */ + OFFSET(JSObject_Slots12), /* FINALIZE_OBJECT12 */ + OFFSET(JSObject_Slots12), /* FINALIZE_OBJECT12_BACKGROUND */ + OFFSET(JSObject_Slots16), /* FINALIZE_OBJECT16 */ + OFFSET(JSObject_Slots16), /* FINALIZE_OBJECT16_BACKGROUND */ + OFFSET(JSFunction), /* FINALIZE_FUNCTION */ + OFFSET(JSScript), /* FINALIZE_SCRIPT */ + OFFSET(Shape), /* FINALIZE_SHAPE */ + OFFSET(types::TypeObject), /* FINALIZE_TYPE_OBJECT */ +#if JS_HAS_XML_SUPPORT + OFFSET(JSXML), /* FINALIZE_XML */ +#endif + OFFSET(JSShortString), /* FINALIZE_SHORT_STRING */ + OFFSET(JSString), /* FINALIZE_STRING */ + OFFSET(JSExternalString), /* FINALIZE_EXTERNAL_STRING */ + OFFSET(ion::IonCode), /* FINALIZE_IONCODE */ +}; + +#undef OFFSET #ifdef DEBUG void @@ -171,7 +199,7 @@ ArenaHeader::checkSynchronizedWithFreeList() const FreeSpan firstSpan = FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets); if (firstSpan.isEmpty()) return; - FreeSpan *list = &compartment->freeLists.lists[getThingKind()]; + const FreeSpan *list = compartment->arenas.getFreeList(getAllocKind()); if (list->isEmpty() || firstSpan.arenaAddress() != list->arenaAddress()) return; @@ -183,18 +211,28 @@ ArenaHeader::checkSynchronizedWithFreeList() const } #endif +/* static */ void +Arena::staticAsserts() +{ + JS_STATIC_ASSERT(sizeof(Arena) == ArenaSize); + JS_STATIC_ASSERT(JS_ARRAY_LENGTH(ThingSizes) == FINALIZE_LIMIT); + JS_STATIC_ASSERT(JS_ARRAY_LENGTH(FirstThingOffsets) == FINALIZE_LIMIT); +} + template inline bool -Arena::finalize(JSContext *cx) +Arena::finalize(JSContext *cx, AllocKind thingKind, size_t thingSize) { /* Enforce requirements on size of T. */ - JS_STATIC_ASSERT(sizeof(T) % Cell::CellSize == 0); - JS_STATIC_ASSERT(sizeof(T) <= 255); + JS_ASSERT(thingSize % Cell::CellSize == 0); + JS_ASSERT(thingSize <= 255); JS_ASSERT(aheader.allocated()); + JS_ASSERT(thingKind == aheader.getAllocKind()); + JS_ASSERT(thingSize == aheader.getThingSize()); JS_ASSERT(!aheader.getMarkingDelay()->link); - uintptr_t thing = thingsStart(sizeof(T)); + uintptr_t thing = thingsStart(thingKind); uintptr_t lastByte = thingsEnd() - 1; FreeSpan nextFree(aheader.getFirstFreeSpan()); @@ -207,13 +245,13 @@ Arena::finalize(JSContext *cx) #ifdef DEBUG size_t nmarked = 0; #endif - for (;; thing += sizeof(T)) { + for (;; thing += thingSize) { JS_ASSERT(thing <= lastByte + 1); if (thing == nextFree.first) { JS_ASSERT(nextFree.last <= lastByte); if (nextFree.last == lastByte) break; - JS_ASSERT(Arena::isAligned(nextFree.last, sizeof(T))); + JS_ASSERT(Arena::isAligned(nextFree.last, thingSize)); if (!newFreeSpanStart) newFreeSpanStart = thing; thing = nextFree.last; @@ -227,90 +265,137 @@ Arena::finalize(JSContext *cx) nmarked++; #endif if (newFreeSpanStart) { - JS_ASSERT(thing >= thingsStart(sizeof(T)) + sizeof(T)); + JS_ASSERT(thing >= thingsStart(thingKind) + thingSize); newListTail->first = newFreeSpanStart; - newListTail->last = thing - sizeof(T); - newListTail = newListTail->nextSpanUnchecked(sizeof(T)); + newListTail->last = thing - thingSize; + newListTail = newListTail->nextSpanUnchecked(thingSize); newFreeSpanStart = 0; } } else { if (!newFreeSpanStart) newFreeSpanStart = thing; t->finalize(cx); - JS_POISON(t, JS_FREE_PATTERN, sizeof(T)); + JS_POISON(t, JS_FREE_PATTERN, thingSize); } } } if (allClear) { JS_ASSERT(newListTail == &newListHead); - JS_ASSERT(newFreeSpanStart == thingsStart(sizeof(T))); + JS_ASSERT(newFreeSpanStart == thingsStart(thingKind)); return true; } newListTail->first = newFreeSpanStart ? newFreeSpanStart : nextFree.first; - JS_ASSERT(Arena::isAligned(newListTail->first, sizeof(T))); + JS_ASSERT(Arena::isAligned(newListTail->first, thingSize)); newListTail->last = lastByte; #ifdef DEBUG size_t nfree = 0; for (const FreeSpan *span = &newListHead; span != newListTail; span = span->nextSpan()) { span->checkSpan(); - JS_ASSERT(Arena::isAligned(span->first, sizeof(T))); - JS_ASSERT(Arena::isAligned(span->last, sizeof(T))); - nfree += (span->last - span->first) / sizeof(T) + 1; - JS_ASSERT(nfree + nmarked <= thingsPerArena(sizeof(T))); + JS_ASSERT(Arena::isAligned(span->first, thingSize)); + JS_ASSERT(Arena::isAligned(span->last, thingSize)); + nfree += (span->last - span->first) / thingSize + 1; + JS_ASSERT(nfree + nmarked <= thingsPerArena(thingSize)); } - nfree += (newListTail->last + 1 - newListTail->first) / sizeof(T); - JS_ASSERT(nfree + nmarked == thingsPerArena(sizeof(T))); + nfree += (newListTail->last + 1 - newListTail->first) / thingSize; + JS_ASSERT(nfree + nmarked == thingsPerArena(thingSize)); #endif aheader.setFirstFreeSpan(&newListHead); return false; } -/* - * Finalize arenas from the list. On return listHeadp points to the list of - * non-empty arenas. - */ template -static void -FinalizeArenas(JSContext *cx, ArenaHeader **listHeadp) +inline void +FinalizeTypedArenas(JSContext *cx, ArenaLists::ArenaList *al, AllocKind thingKind) { - ArenaHeader **ap = listHeadp; + /* + * Release empty arenas and move non-full arenas with some free things into + * a separated list that we append to al after the loop to ensure that any + * arena before al->cursor is full. + */ + JS_ASSERT_IF(!al->head, al->cursor == &al->head); + ArenaLists::ArenaList available; + ArenaHeader **ap = &al->head; + size_t thingSize = Arena::thingSize(thingKind); while (ArenaHeader *aheader = *ap) { - bool allClear = aheader->getArena()->finalize(cx); + bool allClear = aheader->getArena()->finalize(cx, thingKind, thingSize); if (allClear) { *ap = aheader->next; aheader->chunk()->releaseArena(aheader); + } else if (aheader->hasFreeThings()) { + *ap = aheader->next; + *available.cursor = aheader; + available.cursor = &aheader->next; } else { ap = &aheader->next; } } + + /* Terminate the available list and append it to al. */ + *available.cursor = NULL; + *ap = available.head; + al->cursor = ap; + JS_ASSERT_IF(!al->head, al->cursor == &al->head); } -#ifdef DEBUG -bool -checkArenaListAllUnmarked(JSCompartment *comp) +/* + * Finalize the list. On return al->cursor points to the first non-empty arena + * after the al->head. + */ +static void +FinalizeArenas(JSContext *cx, ArenaLists::ArenaList *al, AllocKind thingKind) { - for (unsigned i = 0; i < FINALIZE_LIMIT; i++) { - if (comp->arenas[i].markedThingsInArenaList()) - return false; - } - return true; -} + switch(thingKind) { + case FINALIZE_OBJECT0: + case FINALIZE_OBJECT0_BACKGROUND: + case FINALIZE_OBJECT2: + case FINALIZE_OBJECT2_BACKGROUND: + case FINALIZE_OBJECT4: + case FINALIZE_OBJECT4_BACKGROUND: + case FINALIZE_OBJECT8: + case FINALIZE_OBJECT8_BACKGROUND: + case FINALIZE_OBJECT12: + case FINALIZE_OBJECT12_BACKGROUND: + case FINALIZE_OBJECT16: + case FINALIZE_OBJECT16_BACKGROUND: + case FINALIZE_FUNCTION: + FinalizeTypedArenas(cx, al, thingKind); + break; + case FINALIZE_SCRIPT: + FinalizeTypedArenas(cx, al, thingKind); + break; + case FINALIZE_SHAPE: + FinalizeTypedArenas(cx, al, thingKind); + break; + case FINALIZE_TYPE_OBJECT: + FinalizeTypedArenas(cx, al, thingKind); + break; +#if JS_HAS_XML_SUPPORT + case FINALIZE_XML: + FinalizeTypedArenas(cx, al, thingKind); + break; #endif + case FINALIZE_STRING: + FinalizeTypedArenas(cx, al, thingKind); + break; + case FINALIZE_SHORT_STRING: + FinalizeTypedArenas(cx, al, thingKind); + break; + case FINALIZE_EXTERNAL_STRING: + FinalizeTypedArenas(cx, al, thingKind); + break; + case FINALIZE_IONCODE: + FinalizeTypedArenas(cx, al, thingKind); + break; + } +} } /* namespace gc */ } /* namespace js */ -void -JSCompartment::finishArenaLists() -{ - for (unsigned i = 0; i < FINALIZE_LIMIT; i++) - arenas[i].releaseAll(i); -} - void Chunk::init(JSRuntime *rt) { @@ -379,15 +464,14 @@ Chunk::removeFromAvailableList() info.next = NULL; } -template ArenaHeader * -Chunk::allocateArena(JSContext *cx, unsigned thingKind) +Chunk::allocateArena(JSContext *cx, AllocKind thingKind) { JSCompartment *comp = cx->compartment; JS_ASSERT(hasAvailableArenas()); ArenaHeader *aheader = info.emptyArenaListHead; info.emptyArenaListHead = aheader->next; - aheader->init(comp, thingKind, thingSize); + aheader->init(comp, thingKind); --info.numFree; if (!hasAvailableArenas()) @@ -409,9 +493,9 @@ Chunk::releaseArena(ArenaHeader *aheader) JS_ASSERT(aheader->allocated()); JSRuntime *rt = info.runtime; #ifdef JS_THREADSAFE - Maybe maybeLock; + AutoLockGC maybeLock; if (rt->gcHelperThread.sweeping) - maybeLock.construct(info.runtime); + maybeLock.lock(info.runtime); #endif JSCompartment *comp = aheader->compartment; @@ -475,7 +559,8 @@ ReleaseGCChunk(JSRuntime *rt, Chunk *p) rt->gcChunkAllocator->free_(p); } -inline Chunk * +/* The caller must hold the GC lock. */ +static Chunk * PickChunk(JSContext *cx) { JSCompartment *comp = cx->compartment; @@ -654,45 +739,6 @@ InFreeList(ArenaHeader *aheader, uintptr_t addr) } } -template -inline ConservativeGCTest -MarkArenaPtrConservatively(JSTracer *trc, ArenaHeader *aheader, uintptr_t addr) -{ - JS_ASSERT(aheader->allocated()); - JS_ASSERT(sizeof(T) == aheader->getThingSize()); - - uintptr_t offset = addr & ArenaMask; - uintptr_t minOffset = Arena::thingsStartOffset(sizeof(T)); - if (offset < minOffset) - return CGCT_NOTARENA; - - /* addr can point inside the thing so we must align the address. */ - uintptr_t shift = (offset - minOffset) % sizeof(T); - addr -= shift; - - /* - * Check if the thing is free. We must use the list of free spans as at - * this point we no longer have the mark bits from the previous GC run and - * we must account for newly allocated things. - */ - if (InFreeList(aheader, addr)) - return CGCT_NOTLIVE; - - T *thing = reinterpret_cast(addr); - MarkRoot(trc, thing, "machine stack"); - -#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS - if (IS_GC_MARKING_TRACER(trc)) { - GCMarker *marker = static_cast(trc); - if (marker->conservativeDumpFileName) - marker->conservativeRoots.append(thing); - if (shift) - marker->conservativeStats.unaligned++; - } -#endif - return CGCT_VALID; -} - /* * Returns CGCT_VALID and mark it if the w can be a live GC thing and sets * thingKind accordingly. Otherwise returns the reason for rejection. @@ -740,69 +786,44 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w) if (!aheader->allocated()) return CGCT_FREEARENA; - ConservativeGCTest test; - unsigned thingKind = aheader->getThingKind(); + AllocKind thingKind = aheader->getAllocKind(); + uintptr_t offset = addr & ArenaMask; + uintptr_t minOffset = Arena::firstThingOffset(thingKind); + if (offset < minOffset) + return CGCT_NOTARENA; - switch (thingKind) { - case FINALIZE_OBJECT0: - case FINALIZE_OBJECT0_BACKGROUND: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_OBJECT2: - case FINALIZE_OBJECT2_BACKGROUND: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_OBJECT4: - case FINALIZE_OBJECT4_BACKGROUND: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_OBJECT8: - case FINALIZE_OBJECT8_BACKGROUND: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_OBJECT12: - case FINALIZE_OBJECT12_BACKGROUND: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_OBJECT16: - case FINALIZE_OBJECT16_BACKGROUND: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_STRING: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_EXTERNAL_STRING: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_SHORT_STRING: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_FUNCTION: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_SCRIPT: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_SHAPE: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - case FINALIZE_TYPE_OBJECT: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; -#if JS_HAS_XML_SUPPORT - case FINALIZE_XML: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; + /* addr can point inside the thing so we must align the address. */ + uintptr_t shift = (offset - minOffset) % Arena::thingSize(thingKind); + addr -= shift; + + /* + * Check if the thing is free. We must use the list of free spans as at + * this point we no longer have the mark bits from the previous GC run and + * we must account for newly allocated things. + */ + if (InFreeList(aheader, addr)) + return CGCT_NOTLIVE; + + void *thing = reinterpret_cast(addr); + +#ifdef DEBUG + const char pattern[] = "machine_stack %lx"; + char nameBuf[sizeof(pattern) - 3 + sizeof(addr) * 2]; + JS_snprintf(nameBuf, sizeof(nameBuf), "machine_stack %lx", (unsigned long) addr); + JS_SET_TRACING_NAME(trc, nameBuf); #endif - case FINALIZE_IONCODE: - test = MarkArenaPtrConservatively(trc, aheader, addr); - break; - default: - test = CGCT_WRONGTAG; - JS_NOT_REACHED("wrong tag"); - } + MarkKind(trc, thing, MapAllocToTraceKind(thingKind)); - return test; +#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS + if (IS_GC_MARKING_TRACER(trc)) { + GCMarker *marker = static_cast(trc); + if (marker->conservativeDumpFileName) + marker->conservativeRoots.append(thing); + if (shift) + marker->conservativeStats.unaligned++; + } +#endif + return CGCT_VALID; } static void @@ -932,11 +953,8 @@ void js_FinishGC(JSRuntime *rt) { /* Delete all remaining Compartments. */ - for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { - JSCompartment *comp = *c; - comp->finishArenaLists(); - Foreground::delete_(comp); - } + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) + Foreground::delete_(*c); rt->compartments.clear(); rt->atomsCompartment = NULL; @@ -1143,227 +1161,271 @@ JSCompartment::reduceGCTriggerBytes(uint32 amount) { namespace js { namespace gc { -inline ArenaHeader * -ArenaList::searchForFreeArena() +inline void * +ArenaLists::allocateFromArena(JSContext *cx, AllocKind thingKind) { - while (ArenaHeader *aheader = *cursor) { - cursor = &aheader->next; - if (aheader->hasFreeThings()) - return aheader; - } - return NULL; -} + Chunk *chunk = NULL; -template -inline ArenaHeader * -ArenaList::getArenaWithFreeList(JSContext *cx, unsigned thingKind) -{ - Chunk *chunk; + ArenaList *al = &arenaLists[thingKind]; + AutoLockGC maybeLock; #ifdef JS_THREADSAFE - /* - * We cannot search the arena list for free things while the - * background finalization runs and can modify head or cursor at any - * moment. - */ - if (backgroundFinalizeState == BFS_DONE) { - check_arena_list: - if (ArenaHeader *aheader = searchForFreeArena()) - return aheader; - } - - AutoLockGC lock(cx->runtime); - - for (;;) { - if (backgroundFinalizeState == BFS_JUST_FINISHED) { - /* - * Before we took the GC lock or while waiting for the background - * finalization to finish the latter added new arenas to the list. - * Check the list again for free things outside the GC lock. - */ - JS_ASSERT(*cursor); - backgroundFinalizeState = BFS_DONE; - goto check_arena_list; - } - - JS_ASSERT(!*cursor); - chunk = PickChunk(cx); - if (chunk || backgroundFinalizeState == BFS_DONE) - break; - + volatile uintptr_t *bfs = &backgroundFinalizeState[thingKind]; + if (*bfs != BFS_DONE) { /* - * If the background finalization still runs, wait for it to - * finish and retry to check if it populated the arena list or - * added new empty arenas. + * We cannot search the arena list for free things while the + * background finalization runs and can modify head or cursor at any + * moment. So we always allocate a new arena in that case. */ - JS_ASSERT(backgroundFinalizeState == BFS_RUN); - cx->runtime->gcHelperThread.waitBackgroundSweepEnd(cx->runtime, false); - JS_ASSERT(backgroundFinalizeState == BFS_JUST_FINISHED || - backgroundFinalizeState == BFS_DONE); + maybeLock.lock(cx->runtime); + for (;;) { + if (*bfs == BFS_DONE) + break; + + if (*bfs == BFS_JUST_FINISHED) { + /* + * Before we took the GC lock or while waiting for the + * background finalization to finish the latter added new + * arenas to the list. + */ + *bfs = BFS_DONE; + break; + } + + JS_ASSERT(!*al->cursor); + chunk = PickChunk(cx); + if (chunk) + break; + + /* + * If the background finalization still runs, wait for it to + * finish and retry to check if it populated the arena list or + * added new empty arenas. + */ + JS_ASSERT(*bfs == BFS_RUN); + cx->runtime->gcHelperThread.waitBackgroundSweepEnd(cx->runtime, false); + JS_ASSERT(*bfs == BFS_JUST_FINISHED || *bfs == BFS_DONE); + } } - -#else /* !JS_THREADSAFE */ - - if (ArenaHeader *aheader = searchForFreeArena()) - return aheader; - chunk = PickChunk(cx); - -#endif /* !JS_THREADSAFE */ +#endif /* JS_THREADSAFE */ if (!chunk) { - GCREASON(CHUNK); - TriggerGC(cx->runtime); - return NULL; + if (ArenaHeader *aheader = *al->cursor) { + JS_ASSERT(aheader->hasFreeThings()); + + /* + * The empty arenas are returned to the chunk and should not present on + * the list. + */ + JS_ASSERT(!aheader->isEmpty()); + al->cursor = &aheader->next; + + /* + * Move the free span stored in the arena to the free list and + * allocate from it. + */ + freeLists[thingKind] = aheader->getFirstFreeSpan(); + aheader->setAsFullyUsed(); + return freeLists[thingKind].infallibleAllocate(Arena::thingSize(thingKind)); + } + + /* Make sure we hold the GC lock before we call PickChunk. */ + if (!maybeLock.locked()) + maybeLock.lock(cx->runtime); + chunk = PickChunk(cx); + if (!chunk) + return NULL; } /* - * While we still hold the GC lock get the arena from the chunk and add it - * to the head of the list before the cursor to prevent checking the arena - * for the free things. + * While we still hold the GC lock get an arena from some chunk, mark it + * as full as its single free span is moved to the free lits, and insert + * it to the list as a fully allocated arena. + * + * We add the arena before the the head, not after the tail pointed by the + * cursor, so after the GC the most recently added arena will be used first + * for allocations improving cache locality. */ - ArenaHeader *aheader = chunk->allocateArena(cx, thingKind); - aheader->next = head; - if (cursor == &head) - cursor = &aheader->next; - head = aheader; - return aheader; + JS_ASSERT(!*al->cursor); + ArenaHeader *aheader = chunk->allocateArena(cx, thingKind); + aheader->next = al->head; + if (!al->head) { + JS_ASSERT(al->cursor == &al->head); + al->cursor = &aheader->next; + } + al->head = aheader; + + /* See comments before allocateFromNewArena about this assert. */ + JS_ASSERT(!aheader->hasFreeThings()); + uintptr_t arenaAddr = aheader->arenaAddress(); + return freeLists[thingKind].allocateFromNewArena(arenaAddr, + Arena::firstThingOffset(thingKind), + Arena::thingSize(thingKind)); } -template void -ArenaList::finalizeNow(JSContext *cx) +ArenaLists::finalizeNow(JSContext *cx, AllocKind thingKind) { #ifdef JS_THREADSAFE - JS_ASSERT(backgroundFinalizeState == BFS_DONE); + JS_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE); #endif - FinalizeArenas(cx, &head); - cursor = &head; + FinalizeArenas(cx, &arenaLists[thingKind], thingKind); } -#ifdef JS_THREADSAFE -template inline void -ArenaList::finalizeLater(JSContext *cx) +ArenaLists::finalizeLater(JSContext *cx, AllocKind thingKind) { - JS_ASSERT_IF(head, - head->getThingKind() == FINALIZE_OBJECT0_BACKGROUND || - head->getThingKind() == FINALIZE_OBJECT2_BACKGROUND || - head->getThingKind() == FINALIZE_OBJECT4_BACKGROUND || - head->getThingKind() == FINALIZE_OBJECT8_BACKGROUND || - head->getThingKind() == FINALIZE_OBJECT12_BACKGROUND || - head->getThingKind() == FINALIZE_OBJECT16_BACKGROUND || - head->getThingKind() == FINALIZE_FUNCTION || - head->getThingKind() == FINALIZE_SHORT_STRING || - head->getThingKind() == FINALIZE_STRING); + JS_ASSERT(thingKind == FINALIZE_OBJECT0_BACKGROUND || + thingKind == FINALIZE_OBJECT2_BACKGROUND || + thingKind == FINALIZE_OBJECT4_BACKGROUND || + thingKind == FINALIZE_OBJECT8_BACKGROUND || + thingKind == FINALIZE_OBJECT12_BACKGROUND || + thingKind == FINALIZE_OBJECT16_BACKGROUND || + thingKind == FINALIZE_FUNCTION || + thingKind == FINALIZE_SHORT_STRING || + thingKind == FINALIZE_STRING); + +#ifdef JS_THREADSAFE JS_ASSERT(!cx->runtime->gcHelperThread.sweeping); + ArenaList *al = &arenaLists[thingKind]; + if (!al->head) { + JS_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE); + JS_ASSERT(al->cursor == &al->head); + return; + } + /* * The state can be just-finished if we have not allocated any GC things * from the arena list after the previous background finalization. */ - JS_ASSERT(backgroundFinalizeState == BFS_DONE || - backgroundFinalizeState == BFS_JUST_FINISHED); + JS_ASSERT(backgroundFinalizeState[thingKind] == BFS_DONE || + backgroundFinalizeState[thingKind] == BFS_JUST_FINISHED); - if (head && cx->gcBackgroundFree) { + if (cx->gcBackgroundFree) { /* * To ensure the finalization order even during the background GC we * must use infallibleAppend so arenas scheduled for background * finalization would not be finalized now if the append fails. */ - cx->gcBackgroundFree->finalizeVector.infallibleAppend(head); - head = NULL; - cursor = &head; - backgroundFinalizeState = BFS_RUN; + cx->gcBackgroundFree->finalizeVector.infallibleAppend(al->head); + al->clear(); + backgroundFinalizeState[thingKind] = BFS_RUN; } else { - JS_ASSERT_IF(!head, cursor == &head); - backgroundFinalizeState = BFS_DONE; - finalizeNow(cx); + FinalizeArenas(cx, al, thingKind); + backgroundFinalizeState[thingKind] = BFS_DONE; } + +#else /* !JS_THREADSAFE */ + + finalizeNow(cx, thingKind); + +#endif } +#ifdef JS_THREADSAFE /*static*/ void -ArenaList::backgroundFinalize(JSContext *cx, ArenaHeader *listHead) +ArenaLists::backgroundFinalize(JSContext *cx, ArenaHeader *listHead) { JS_ASSERT(listHead); - unsigned thingKind = listHead->getThingKind(); + AllocKind thingKind = listHead->getAllocKind(); JSCompartment *comp = listHead->compartment; - ArenaList *al = &comp->arenas[thingKind]; - - switch (thingKind) { - default: - JS_NOT_REACHED("wrong kind"); - break; - case FINALIZE_OBJECT0_BACKGROUND: - FinalizeArenas(cx, &listHead); - break; - case FINALIZE_OBJECT2_BACKGROUND: - FinalizeArenas(cx, &listHead); - break; - case FINALIZE_OBJECT4_BACKGROUND: - FinalizeArenas(cx, &listHead); - break; - case FINALIZE_OBJECT8_BACKGROUND: - FinalizeArenas(cx, &listHead); - break; - case FINALIZE_OBJECT12_BACKGROUND: - FinalizeArenas(cx, &listHead); - break; - case FINALIZE_OBJECT16_BACKGROUND: - FinalizeArenas(cx, &listHead); - break; - case FINALIZE_FUNCTION: - FinalizeArenas(cx, &listHead); - break; - case FINALIZE_STRING: - FinalizeArenas(cx, &listHead); - break; - case FINALIZE_SHORT_STRING: - FinalizeArenas(cx, &listHead); - break; - } + ArenaList finalized; + finalized.head = listHead; + FinalizeArenas(cx, &finalized, thingKind); /* * After we finish the finalization al->cursor must point to the end of * the head list as we emptied the list before the background finalization * and the allocation adds new arenas before the cursor. */ + ArenaLists *lists = &comp->arenas; + ArenaList *al = &lists->arenaLists[thingKind]; + AutoLockGC lock(cx->runtime); - JS_ASSERT(al->backgroundFinalizeState == BFS_RUN); + JS_ASSERT(lists->backgroundFinalizeState[thingKind] == BFS_RUN); JS_ASSERT(!*al->cursor); - if (listHead) { - *al->cursor = listHead; - al->backgroundFinalizeState = BFS_JUST_FINISHED; + + /* + * We must set the state to BFS_JUST_FINISHED if we touch arenaList list, + * even if we add to the list only fully allocated arenas without any free + * things. It ensures that the allocation thread takes the GC lock and all + * writes to the free list elements are propagated. As we always take the + * GC lock when allocating new arenas from the chunks we can set the state + * to BFS_DONE if we have released all finalized arenas back to their + * chunks. + */ + if (finalized.head) { + *al->cursor = finalized.head; + if (finalized.cursor != &finalized.head) + al->cursor = finalized.cursor; + lists->backgroundFinalizeState[thingKind] = BFS_JUST_FINISHED; } else { - al->backgroundFinalizeState = BFS_DONE; + lists->backgroundFinalizeState[thingKind] = BFS_DONE; } } - #endif /* JS_THREADSAFE */ -#ifdef DEBUG -bool -CheckAllocation(JSContext *cx) +void +ArenaLists::finalizeObjects(JSContext *cx) { + finalizeNow(cx, FINALIZE_OBJECT0); + finalizeNow(cx, FINALIZE_OBJECT2); + finalizeNow(cx, FINALIZE_OBJECT4); + finalizeNow(cx, FINALIZE_OBJECT8); + finalizeNow(cx, FINALIZE_OBJECT12); + finalizeNow(cx, FINALIZE_OBJECT16); + #ifdef JS_THREADSAFE - JS_ASSERT(cx->thread()); -#endif - JS_ASSERT(!cx->runtime->gcRunning); - return true; -} + finalizeLater(cx, FINALIZE_OBJECT0_BACKGROUND); + finalizeLater(cx, FINALIZE_OBJECT2_BACKGROUND); + finalizeLater(cx, FINALIZE_OBJECT4_BACKGROUND); + finalizeLater(cx, FINALIZE_OBJECT8_BACKGROUND); + finalizeLater(cx, FINALIZE_OBJECT12_BACKGROUND); + finalizeLater(cx, FINALIZE_OBJECT16_BACKGROUND); #endif -inline bool -NeedLastDitchGC(JSContext *cx) + /* + * We must finalize Function instances after finalizing any other objects + * even if we use the background finalization for the latter. See comments + * in JSObject::finalizeUpvarsIfFlatClosure. + */ + finalizeLater(cx, FINALIZE_FUNCTION); + +#if JS_HAS_XML_SUPPORT + finalizeNow(cx, FINALIZE_XML); +#endif +} + +void +ArenaLists::finalizeStrings(JSContext *cx) { - JSRuntime *rt = cx->runtime; - return rt->gcIsNeeded; + finalizeLater(cx, FINALIZE_SHORT_STRING); + finalizeLater(cx, FINALIZE_STRING); + + finalizeNow(cx, FINALIZE_EXTERNAL_STRING); } -/* - * Return false only if the GC run but could not bring its memory usage under - * JSRuntime::gcMaxBytes. - */ -static bool +void +ArenaLists::finalizeShapes(JSContext *cx) +{ + finalizeNow(cx, FINALIZE_SHAPE); + finalizeNow(cx, FINALIZE_TYPE_OBJECT); +} + +void +ArenaLists::finalizeScripts(JSContext *cx) +{ + finalizeNow(cx, FINALIZE_SCRIPT); +} + +void +ArenaLists::finalizeIonCode(JSContext *cx) +{ + finalizeNow(cx, FINALIZE_IONCODE); +} + +static void RunLastDitchGC(JSContext *cx) { JSRuntime *rt = cx->runtime; @@ -1381,37 +1443,35 @@ RunLastDitchGC(JSContext *cx) if (rt->gcBytes >= rt->gcMaxBytes) cx->runtime->gcHelperThread.waitBackgroundSweepEnd(cx->runtime); #endif - - return rt->gcBytes < rt->gcMaxBytes; } -static inline bool +inline bool IsGCAllowed(JSContext *cx) { return !JS_ON_TRACE(cx) && !JS_THREAD_DATA(cx)->waiveGCQuota; } -template -inline void * -RefillTypedFreeList(JSContext *cx, unsigned thingKind) +/* static */ void * +ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind) { - JS_ASSERT(!cx->runtime->gcRunning); + JS_ASSERT(cx->compartment->arenas.freeLists[thingKind].isEmpty()); /* * For compatibility with older code we tolerate calling the allocator * during the GC in optimized builds. */ - if (cx->runtime->gcRunning) + JSRuntime *rt = cx->runtime; + JS_ASSERT(!rt->gcRunning); + if (rt->gcRunning) return NULL; - JSCompartment *compartment = cx->compartment; - JS_ASSERT(compartment->freeLists.lists[thingKind].isEmpty()); - - bool canGC = IsGCAllowed(cx); - bool runGC = canGC && JS_UNLIKELY(NeedLastDitchGC(cx)); + bool runGC = !!rt->gcIsNeeded; for (;;) { - if (runGC) { - if (!RunLastDitchGC(cx)) + if (JS_UNLIKELY(runGC) && IsGCAllowed(cx)) { + RunLastDitchGC(cx); + + /* Report OOM of the GC failed to free enough memory. */ + if (rt->gcBytes > rt->gcMaxBytes) break; /* @@ -1419,22 +1479,24 @@ RefillTypedFreeList(JSContext *cx, unsigned thingKind) * things and populate the free list. If that happens, just * return that list head. */ - if (void *thing = compartment->freeLists.getNext(thingKind, sizeof(T))) + size_t thingSize = Arena::thingSize(thingKind); + if (void *thing = cx->compartment->arenas.allocateFromFreeList(thingKind, thingSize)) return thing; } - ArenaHeader *aheader = - compartment->arenas[thingKind].getArenaWithFreeList(cx, thingKind); - if (aheader) { - JS_ASSERT(sizeof(T) == aheader->getThingSize()); - return compartment->freeLists.populate(aheader, thingKind, sizeof(T)); - } + void *thing = cx->compartment->arenas.allocateFromArena(cx, thingKind); + if (JS_LIKELY(!!thing)) + return thing; /* - * We failed to allocate any arena. Run the GC if we can unless we - * have done it already. + * We failed to allocate. Run the GC if we can unless we have done it + * already. Otherwise report OOM but first schedule a new GC soon. */ - if (!canGC || runGC) + if (runGC || !IsGCAllowed(cx)) { + AutoLockGC lock(rt); + GCREASON(REFILL); + TriggerGC(rt); break; + } runGC = true; } @@ -1442,54 +1504,6 @@ RefillTypedFreeList(JSContext *cx, unsigned thingKind) return NULL; } -void * -RefillFinalizableFreeList(JSContext *cx, unsigned thingKind) -{ - switch (thingKind) { - case FINALIZE_OBJECT0: - case FINALIZE_OBJECT0_BACKGROUND: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_OBJECT2: - case FINALIZE_OBJECT2_BACKGROUND: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_OBJECT4: - case FINALIZE_OBJECT4_BACKGROUND: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_OBJECT8: - case FINALIZE_OBJECT8_BACKGROUND: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_OBJECT12: - case FINALIZE_OBJECT12_BACKGROUND: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_OBJECT16: - case FINALIZE_OBJECT16_BACKGROUND: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_STRING: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_EXTERNAL_STRING: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_SHORT_STRING: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_FUNCTION: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_SCRIPT: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_SHAPE: - return RefillTypedFreeList(cx, thingKind); - case FINALIZE_TYPE_OBJECT: - return RefillTypedFreeList(cx, thingKind); -#if JS_HAS_XML_SUPPORT - case FINALIZE_XML: - return RefillTypedFreeList(cx, thingKind); -#endif - case FINALIZE_IONCODE: - return RefillTypedFreeList(cx, thingKind); - default: - JS_NOT_REACHED("bad finalize kind"); - return 0; - } -} - } /* namespace gc */ } /* namespace js */ @@ -1592,11 +1606,12 @@ GCMarker::delayMarkingChildren(const void *thing) static void MarkDelayedChildren(JSTracer *trc, ArenaHeader *aheader) { - JSGCTraceKind traceKind = GetFinalizableTraceKind(aheader->getThingKind()); + AllocKind thingKind = aheader->getAllocKind(); + JSGCTraceKind traceKind = MapAllocToTraceKind(thingKind); size_t thingSize = aheader->getThingSize(); Arena *a = aheader->getArena(); uintptr_t end = a->thingsEnd(); - for (uintptr_t thing = a->thingsStart(thingSize); thing != end; thing += thingSize) { + for (uintptr_t thing = a->thingsStart(thingKind); thing != end; thing += thingSize) { Cell *t = reinterpret_cast(thing); if (t->isMarked()) JS_TraceChildren(trc, t, traceKind); @@ -1996,73 +2011,6 @@ MaybeGC(JSContext *cx) } /* namespace js */ -void -JSCompartment::finalizeObjectArenaLists(JSContext *cx) -{ - arenas[FINALIZE_OBJECT0]. finalizeNow(cx); - arenas[FINALIZE_OBJECT2]. finalizeNow(cx); - arenas[FINALIZE_OBJECT4]. finalizeNow(cx); - arenas[FINALIZE_OBJECT8]. finalizeNow(cx); - arenas[FINALIZE_OBJECT12].finalizeNow(cx); - arenas[FINALIZE_OBJECT16].finalizeNow(cx); - -#ifdef JS_THREADSAFE - arenas[FINALIZE_OBJECT0_BACKGROUND]. finalizeLater(cx); - arenas[FINALIZE_OBJECT2_BACKGROUND]. finalizeLater(cx); - arenas[FINALIZE_OBJECT4_BACKGROUND]. finalizeLater(cx); - arenas[FINALIZE_OBJECT8_BACKGROUND]. finalizeLater(cx); - arenas[FINALIZE_OBJECT12_BACKGROUND].finalizeLater(cx); - arenas[FINALIZE_OBJECT16_BACKGROUND].finalizeLater(cx); -#endif - - /* - * We must finalize Function instances after finalizing any other objects - * even if we use the background finalization for the latter. See comments - * in JSObject::finalizeUpvarsIfFlatClosure. - */ -#ifdef JS_THREADSAFE - arenas[FINALIZE_FUNCTION].finalizeLater(cx); -#else - arenas[FINALIZE_FUNCTION].finalizeNow(cx); -#endif - -#if JS_HAS_XML_SUPPORT - arenas[FINALIZE_XML].finalizeNow(cx); -#endif -} - -void -JSCompartment::finalizeStringArenaLists(JSContext *cx) -{ -#ifdef JS_THREADSAFE - arenas[FINALIZE_SHORT_STRING].finalizeLater(cx); - arenas[FINALIZE_STRING].finalizeLater(cx); -#else - arenas[FINALIZE_SHORT_STRING].finalizeNow(cx); - arenas[FINALIZE_STRING].finalizeNow(cx); -#endif - arenas[FINALIZE_EXTERNAL_STRING].finalizeNow(cx); -} - -void -JSCompartment::finalizeShapeArenaLists(JSContext *cx) -{ - arenas[FINALIZE_TYPE_OBJECT].finalizeNow(cx); - arenas[FINALIZE_SHAPE].finalizeNow(cx); -} - -void -JSCompartment::finalizeScriptArenaLists(JSContext *cx) -{ - arenas[FINALIZE_SCRIPT].finalizeNow(cx); -} - -void -JSCompartment::finalizeIonCodeArenaLists(JSContext *cx) -{ - arenas[FINALIZE_IONCODE].finalizeNow(cx); -} - #ifdef JS_THREADSAFE namespace js { @@ -2154,9 +2102,9 @@ GCHelperThread::startBackgroundSweep(JSRuntime *rt, JSGCInvocationKind gckind) void GCHelperThread::waitBackgroundSweepEnd(JSRuntime *rt, bool gcUnlocked) { - Maybe lock; + AutoLockGC maybeLock; if (gcUnlocked) - lock.construct(rt); + maybeLock.lock(rt); while (sweeping) PR_WaitCondVar(sweepingDone, PR_INTERVAL_NO_TIMEOUT); } @@ -2187,10 +2135,10 @@ GCHelperThread::doSweep() /* * We must finalize in the insert order, see comments in - * finalizeObjectArenaLists. + * finalizeObjects. */ for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i) - ArenaList::backgroundFinalize(cx, *i); + ArenaLists::backgroundFinalize(cx, *i); finalizeVector.resize(0); ExpireGCChunks(cx->runtime, lastGCKind); cx = NULL; @@ -2261,9 +2209,9 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind) JSCompartment *compartment = *read++; if (!compartment->hold && - (compartment->arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT)) + (compartment->arenas.arenaListsAreEmpty() || gckind == GC_LAST_CONTEXT)) { - compartment->freeLists.checkEmpty(); + compartment->arenas.checkEmptyFreeLists(); if (callback) JS_ALWAYS_TRUE(callback(cx, compartment, JSCOMPARTMENT_DESTROY)); if (compartment->principals) @@ -2363,7 +2311,8 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM /* Make sure that we didn't mark an object in another compartment */ if (comp) { for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) - JS_ASSERT_IF(*c != comp && *c != rt->atomsCompartment, checkArenaListAllUnmarked(*c)); + JS_ASSERT_IF(*c != comp && *c != rt->atomsCompartment, + (*c)->arenas.checkArenaListAllUnmarked()); } #endif @@ -2401,15 +2350,15 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM if (comp) { Probes::GCStartSweepPhase(comp); comp->sweep(cx, 0); - comp->finalizeObjectArenaLists(cx); + comp->arenas.finalizeObjects(cx); GCTIMESTAMP(sweepObjectEnd); - comp->finalizeStringArenaLists(cx); + comp->arenas.finalizeStrings(cx); GCTIMESTAMP(sweepStringEnd); - comp->finalizeScriptArenaLists(cx); + comp->arenas.finalizeScripts(cx); GCTIMESTAMP(sweepScriptEnd); - comp->finalizeIonCodeArenaLists(cx); + comp->arenas.finalizeIonCode(cx); GCTIMESTAMP(sweepIonCodeEnd); - comp->finalizeShapeArenaLists(cx); + comp->arenas.finalizeShapes(cx); GCTIMESTAMP(sweepShapeEnd); Probes::GCEndSweepPhase(comp); } else { @@ -2424,28 +2373,29 @@ MarkAndSweep(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIM SweepCrossCompartmentWrappers(cx); for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) { Probes::GCStartSweepPhase(*c); - (*c)->finalizeObjectArenaLists(cx); + (*c)->arenas.finalizeObjects(cx); } GCTIMESTAMP(sweepObjectEnd); for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) - (*c)->finalizeStringArenaLists(cx); + (*c)->arenas.finalizeStrings(cx); GCTIMESTAMP(sweepStringEnd); for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) { - (*c)->finalizeScriptArenaLists(cx); + (*c)->arenas.finalizeScripts(cx); } GCTIMESTAMP(sweepScriptEnd); + for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) - (*c)->finalizeIonCodeArenaLists(cx); + (*c)->arenas.finalizeIonCode(cx); GCTIMESTAMP(sweepIonCodeEnd); for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); c++) { - (*c)->finalizeShapeArenaLists(cx); + (*c)->arenas.finalizeShapes(cx); Probes::GCEndSweepPhase(*c); } @@ -2843,12 +2793,12 @@ class AutoCopyFreeListToArenas { AutoCopyFreeListToArenas(JSRuntime *rt) : rt(rt) { for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) - (*c)->freeLists.copyToArenas(); + (*c)->arenas.copyFreeListsToArenas(); } ~AutoCopyFreeListToArenas() { for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) - (*c)->freeLists.clearInArenas(); + (*c)->arenas.clearFreeListsInArenas(); } }; @@ -2939,19 +2889,18 @@ IterateCompartmentsArenasCells(JSContext *cx, void *data, JSCompartment *compartment = *c; (*compartmentCallback)(cx, data, compartment); - for (unsigned thingKind = 0; thingKind < FINALIZE_LIMIT; thingKind++) { - JSGCTraceKind traceKind = GetFinalizableTraceKind(thingKind); - size_t thingSize = GCThingSizeMap[thingKind]; + for (size_t thingKind = 0; thingKind != FINALIZE_LIMIT; thingKind++) { + JSGCTraceKind traceKind = MapAllocToTraceKind(AllocKind(thingKind)); + size_t thingSize = Arena::thingSize(AllocKind(thingKind)); IterateArenaCallbackOp arenaOp(cx, data, arenaCallback, traceKind, thingSize); IterateCellCallbackOp cellOp(cx, data, cellCallback, traceKind, thingSize); - - ForEachArenaAndCell(compartment, (FinalizeKind) thingKind, arenaOp, cellOp); + ForEachArenaAndCell(compartment, AllocKind(thingKind), arenaOp, cellOp); } } } void -IterateCells(JSContext *cx, JSCompartment *compartment, FinalizeKind thingKind, +IterateCells(JSContext *cx, JSCompartment *compartment, AllocKind thingKind, void *data, IterateCellCallback cellCallback) { /* :XXX: Any way to common this preamble with IterateCompartmentsArenasCells? */ @@ -2971,8 +2920,8 @@ IterateCells(JSContext *cx, JSCompartment *compartment, FinalizeKind thingKind, AutoCopyFreeListToArenas copy(rt); - JSGCTraceKind traceKind = GetFinalizableTraceKind(thingKind); - size_t thingSize = GCThingSizeMap[thingKind]; + JSGCTraceKind traceKind = MapAllocToTraceKind(thingKind); + size_t thingSize = Arena::thingSize(thingKind); if (compartment) { for (CellIterUnderGC i(compartment, thingKind); !i.done(); i.next()) diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 6d40697535e5..fb6e6fb43a84 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -83,45 +83,12 @@ namespace gc { struct Arena; struct MarkingDelay; - -/* The kind of GC thing with a finalizer. */ -enum FinalizeKind { - FINALIZE_OBJECT0, - FINALIZE_OBJECT0_BACKGROUND, - FINALIZE_OBJECT2, - FINALIZE_OBJECT2_BACKGROUND, - FINALIZE_OBJECT4, - FINALIZE_OBJECT4_BACKGROUND, - FINALIZE_OBJECT8, - FINALIZE_OBJECT8_BACKGROUND, - FINALIZE_OBJECT12, - FINALIZE_OBJECT12_BACKGROUND, - FINALIZE_OBJECT16, - FINALIZE_OBJECT16_BACKGROUND, - FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND, - FINALIZE_FUNCTION, - FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION, - FINALIZE_SCRIPT, - FINALIZE_SHAPE, - FINALIZE_TYPE_OBJECT, -#if JS_HAS_XML_SUPPORT - FINALIZE_XML, -#endif - FINALIZE_SHORT_STRING, - FINALIZE_STRING, - FINALIZE_EXTERNAL_STRING, - FINALIZE_IONCODE, - FINALIZE_LIMIT -}; - /* * This must be an upper bound, but we do not need the least upper bound, so * we just exclude non-background objects. */ const size_t MAX_BACKGROUND_FINALIZE_KINDS = FINALIZE_LIMIT - (FINALIZE_OBJECT_LAST + 1) / 2; -extern JS_FRIEND_DATA(const uint8) GCThingSizeMap[]; - const size_t ArenaShift = 12; const size_t ArenaSize = size_t(1) << ArenaShift; const size_t ArenaMask = ArenaSize - 1; @@ -179,7 +146,7 @@ struct FreeSpan { * To minimize the size of the arena header the first span is encoded * there as offsets from the arena start. */ - static size_t encodeOffsets(size_t firstOffset, size_t lastOffset = ArenaSize - 1) { + static size_t encodeOffsets(size_t firstOffset, size_t lastOffset) { /* Check that we can pack the offsets into uint16. */ JS_STATIC_ASSERT(ArenaShift < 16); JS_ASSERT(firstOffset <= ArenaSize); @@ -188,7 +155,11 @@ struct FreeSpan { return firstOffset | (lastOffset << 16); } - static const size_t EmptyOffsets = ArenaSize | ((ArenaSize - 1) << 16); + /* + * Encoded offsets for a full arena when its first span is the last one + * and empty. + */ + static const size_t FullArenaOffsets = ArenaSize | ((ArenaSize - 1) << 16); static FreeSpan decodeOffsets(uintptr_t arenaAddr, size_t offsets) { JS_ASSERT(!(arenaAddr & ArenaMask)); @@ -292,6 +263,37 @@ struct FreeSpan { return reinterpret_cast(thing); } + /* A version of allocate when we know that the span is not empty. */ + JS_ALWAYS_INLINE void *infallibleAllocate(size_t thingSize) { + JS_ASSERT(thingSize % Cell::CellSize == 0); + checkSpan(); + uintptr_t thing = first; + if (thing < last) { + first = thing + thingSize; + } else { + JS_ASSERT(thing == last); + *this = *reinterpret_cast(thing); + } + checkSpan(); + return reinterpret_cast(thing); + } + + /* + * Allocate from a newly allocated arena. We do not move the free list + * from the arena. Rather we set the arena up as fully used during the + * initialization so to allocate we simply return the first thing in the + * arena and set the free list to point to the second. + */ + JS_ALWAYS_INLINE void *allocateFromNewArena(uintptr_t arenaAddr, size_t firstThingOffset, + size_t thingSize) { + JS_ASSERT(!(arenaAddr & ArenaMask)); + uintptr_t thing = arenaAddr | firstThingOffset; + first = thing + thingSize; + last = arenaAddr | ArenaMask; + checkSpan(); + return reinterpret_cast(thing); + } + void checkSpan() const { #ifdef DEBUG /* We do not allow spans at the end of the address space. */ @@ -370,13 +372,13 @@ struct ArenaHeader { size_t firstFreeSpanOffsets; /* - * One of FinalizeKind constants or FINALIZE_LIMIT when the arena does not + * One of AllocKind constants or FINALIZE_LIMIT when the arena does not * contain any GC things and is on the list of empty arenas in the GC - * chunk. The later allows to quickly check if the arena is allocated + * chunk. The latter allows to quickly check if the arena is allocated * during the conservative GC scanning without searching the arena in the * list. */ - unsigned thingKind; + unsigned allocKind; friend struct FreeLists; @@ -385,14 +387,15 @@ struct ArenaHeader { inline Chunk *chunk() const; void setAsNotAllocated() { - thingKind = FINALIZE_LIMIT; + allocKind = FINALIZE_LIMIT; } bool allocated() const { - return thingKind < FINALIZE_LIMIT; + JS_ASSERT(allocKind <= FINALIZE_LIMIT); + return allocKind < FINALIZE_LIMIT; } - inline void init(JSCompartment *comp, unsigned thingKind, size_t thingSize); + inline void init(JSCompartment *comp, AllocKind kind); uintptr_t arenaAddress() const { return address(); @@ -402,17 +405,21 @@ struct ArenaHeader { return reinterpret_cast(arenaAddress()); } - unsigned getThingKind() const { + AllocKind getAllocKind() const { JS_ASSERT(allocated()); - return thingKind; + return AllocKind(allocKind); } + inline size_t getThingSize() const; + bool hasFreeThings() const { - return firstFreeSpanOffsets != FreeSpan::EmptyOffsets; + return firstFreeSpanOffsets != FreeSpan::FullArenaOffsets; } + inline bool isEmpty() const; + void setAsFullyUsed() { - firstFreeSpanOffsets = FreeSpan::EmptyOffsets; + firstFreeSpanOffsets = FreeSpan::FullArenaOffsets; } FreeSpan getFirstFreeSpan() const { @@ -429,10 +436,6 @@ struct ArenaHeader { inline MarkingDelay *getMarkingDelay() const; - size_t getThingSize() const { - return GCThingSizeMap[getThingKind()]; - } - #ifdef DEBUG void checkSynchronizedWithFreeList() const; #endif @@ -451,13 +454,24 @@ struct Arena { * +-------------+-----+----+----+-----+----+ * * <----------------------------------------> = ArenaSize bytes - * <-------------------> = thingsStartOffset + * <-------------------> = first thing offset */ ArenaHeader aheader; uint8_t data[ArenaSize - sizeof(ArenaHeader)]; - static void staticAsserts() { - JS_STATIC_ASSERT(sizeof(Arena) == ArenaSize); + private: + static JS_FRIEND_DATA(const uint32) ThingSizes[]; + static JS_FRIEND_DATA(const uint32) FirstThingOffsets[]; + + public: + static void staticAsserts(); + + static size_t thingSize(AllocKind kind) { + return ThingSizes[kind]; + } + + static size_t firstThingOffset(AllocKind kind) { + return FirstThingOffsets[kind]; } static size_t thingsPerArena(size_t thingSize) { @@ -466,9 +480,6 @@ struct Arena { /* We should be able to fit FreeSpan in any GC thing. */ JS_ASSERT(thingSize >= sizeof(FreeSpan)); - /* GCThingSizeMap assumes that any thing fits uint8. */ - JS_ASSERT(thingSize < 256); - return (ArenaSize - sizeof(ArenaHeader)) / thingSize; } @@ -476,10 +487,6 @@ struct Arena { return thingsPerArena(thingSize) * thingSize; } - static size_t thingsStartOffset(size_t thingSize) { - return ArenaSize - thingsSpan(thingSize); - } - static bool isAligned(uintptr_t thing, size_t thingSize) { /* Things ends at the arena end. */ uintptr_t tailOffset = (ArenaSize - thing) & ArenaMask; @@ -490,8 +497,8 @@ struct Arena { return aheader.address(); } - uintptr_t thingsStart(size_t thingSize) { - return address() | thingsStartOffset(thingSize); + uintptr_t thingsStart(AllocKind thingKind) { + return address() | firstThingOffset(thingKind); } uintptr_t thingsEnd() { @@ -499,7 +506,7 @@ struct Arena { } template - bool finalize(JSContext *cx); + bool finalize(JSContext *cx, AllocKind thingKind, size_t thingSize); }; /* @@ -646,8 +653,7 @@ struct Chunk { inline void addToAvailableList(JSCompartment *compartment); inline void removeFromAvailableList(); - template - ArenaHeader *allocateArena(JSContext *cx, unsigned thingKind); + ArenaHeader *allocateArena(JSContext *cx, AllocKind kind); void releaseArena(ArenaHeader *aheader); }; @@ -681,6 +687,12 @@ Cell::chunk() const return reinterpret_cast(addr); } +AllocKind +Cell::getAllocKind() const +{ + return arenaHeader()->getAllocKind(); +} + #ifdef DEBUG inline bool Cell::isAligned() const @@ -690,13 +702,15 @@ Cell::isAligned() const #endif inline void -ArenaHeader::init(JSCompartment *comp, unsigned kind, size_t thingSize) +ArenaHeader::init(JSCompartment *comp, AllocKind kind) { JS_ASSERT(!allocated()); JS_ASSERT(!getMarkingDelay()->link); compartment = comp; - thingKind = kind; - firstFreeSpanOffsets = FreeSpan::encodeOffsets(Arena::thingsStartOffset(thingSize)); + allocKind = kind; + + /* See comments in FreeSpan::allocateFromNewArena. */ + firstFreeSpanOffsets = FreeSpan::FullArenaOffsets; } inline uintptr_t @@ -714,6 +728,22 @@ ArenaHeader::chunk() const return Chunk::fromAddress(address()); } +inline bool +ArenaHeader::isEmpty() const +{ + /* Arena is empty if its first span covers the whole arena. */ + JS_ASSERT(allocated()); + size_t firstThingOffset = Arena::firstThingOffset(getAllocKind()); + return firstFreeSpanOffsets == FreeSpan::encodeOffsets(firstThingOffset, ArenaMask); +} + +inline size_t +ArenaHeader::getThingSize() const +{ + JS_ASSERT(allocated()); + return Arena::thingSize(getAllocKind()); +} + JS_ALWAYS_INLINE void ChunkBitmap::getMarkWordAndMask(const Cell *cell, uint32 color, uintptr_t **wordp, uintptr_t *maskp) @@ -784,7 +814,7 @@ const float GC_HEAP_GROWTH_FACTOR = 3.0f; static const int64 GC_IDLE_FULL_SPAN = 20 * 1000 * 1000; static inline JSGCTraceKind -GetFinalizableTraceKind(size_t thingKind) +MapAllocToTraceKind(AllocKind thingKind) { static const JSGCTraceKind map[FINALIZE_LIMIT] = { JSTRACE_OBJECT, /* FINALIZE_OBJECT0 */ @@ -811,8 +841,6 @@ GetFinalizableTraceKind(size_t thingKind) JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING */ JSTRACE_IONCODE, /* FINALIZE_IONCODE */ }; - - JS_ASSERT(thingKind < FINALIZE_LIMIT); return map[thingKind]; } @@ -825,11 +853,46 @@ GetGCThingRuntime(void *thing) return reinterpret_cast(thing)->chunk()->info.runtime; } -/* The arenas in a list have uniform kind. */ -class ArenaList { +struct ArenaLists { + + /* + * ArenaList::head points to the start of the list. Normally cursor points + * to the first arena in the list with some free things and all arenas + * before cursor are fully allocated. However, as the arena currently being + * allocated from is considered full while its list of free spans is moved + * into the freeList, during the GC or cell enumeration, when an + * unallocated freeList is moved back to the arena, we can see an arena + * with some free cells before the cursor. The cursor is an indirect + * pointer to allow for efficient list insertion at the cursor point and + * other list manipulations. + */ + struct ArenaList { + ArenaHeader *head; + ArenaHeader **cursor; + + ArenaList() { + clear(); + } + + void clear() { + head = NULL; + cursor = &head; + } + }; + private: - ArenaHeader *head; /* list start */ - ArenaHeader **cursor; /* arena with free things */ + /* + * For each arena kind its free list is represented as the first span with + * free things. Initially all the spans are initialized as empty. After we + * find a new arena with available things we move its first free span into + * the list and set the arena as fully allocated. way we do not need to + * update the arena header after the initial allocation. When starting the + * GC we only move the head of the of the list of spans back to the arena + * only for the arena that was not fully allocated. + */ + FreeSpan freeLists[FINALIZE_LIMIT]; + + ArenaList arenaLists[FINALIZE_LIMIT]; #ifdef JS_THREADSAFE /* @@ -854,116 +917,95 @@ class ArenaList { BFS_JUST_FINISHED }; - volatile BackgroundFinalizeState backgroundFinalizeState; + volatile uintptr_t backgroundFinalizeState[FINALIZE_LIMIT]; #endif public: - void init() { - head = NULL; - cursor = &head; + ArenaLists() { + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) + freeLists[i].initAsEmpty(); #ifdef JS_THREADSAFE - backgroundFinalizeState = BFS_DONE; + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) + backgroundFinalizeState[i] = BFS_DONE; #endif } - ArenaHeader *getHead() { return head; } - - inline ArenaHeader *searchForFreeArena(); - - template - inline ArenaHeader *getArenaWithFreeList(JSContext *cx, unsigned thingKind); - - template - void finalizeNow(JSContext *cx); - + ~ArenaLists() { + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) { #ifdef JS_THREADSAFE - template - inline void finalizeLater(JSContext *cx); - - static void backgroundFinalize(JSContext *cx, ArenaHeader *listHead); - - bool willBeFinalizedLater() const { - return backgroundFinalizeState == BFS_RUN; - } - - bool doneBackgroundFinalize() const { - return backgroundFinalizeState == BFS_DONE; - } + /* + * We can only call this during the shutdown after the last GC when + * the background finalization is disabled. + */ + JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE); #endif + ArenaHeader **headp = &arenaLists[i].head; + while (ArenaHeader *aheader = *headp) { + *headp = aheader->next; + aheader->chunk()->releaseArena(aheader); + } + } + } + + const FreeSpan *getFreeList(AllocKind thingKind) const { + return &freeLists[thingKind]; + } + + ArenaHeader *getFirstArena(AllocKind thingKind) const { + return arenaLists[thingKind].head; + } + + bool arenaListsAreEmpty() const { + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) { +#ifdef JS_THREADSAFE + /* + * The arena cannot be empty if the background finalization is not yet + * done. + */ + if (backgroundFinalizeState[i] != BFS_DONE) + return false; +#endif + if (arenaLists[i].head) + return false; + } + return true; + } #ifdef DEBUG - bool markedThingsInArenaList() { + bool checkArenaListAllUnmarked() const { + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) { # ifdef JS_THREADSAFE - /* The background finalization must have stopped at this point. */ - JS_ASSERT(backgroundFinalizeState == BFS_DONE || - backgroundFinalizeState == BFS_JUST_FINISHED); + /* The background finalization must have stopped at this point. */ + JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE || + backgroundFinalizeState[i] == BFS_JUST_FINISHED); # endif - for (ArenaHeader *aheader = head; aheader; aheader = aheader->next) { - if (!aheader->chunk()->bitmap.noBitsSet(aheader)) - return true; + for (ArenaHeader *aheader = arenaLists[i].head; aheader; aheader = aheader->next) { + if (!aheader->chunk()->bitmap.noBitsSet(aheader)) + return false; + } } - return false; + return true; } -#endif /* DEBUG */ - - void releaseAll(unsigned thingKind) { -# ifdef JS_THREADSAFE - /* - * We can only call this during the shutdown after the last GC when - * the background finalization is disabled. - */ - JS_ASSERT(backgroundFinalizeState == BFS_DONE); -# endif - while (ArenaHeader *aheader = head) { - head = aheader->next; - aheader->chunk()->releaseArena(aheader); - } - cursor = &head; - } - - bool isEmpty() const { -#ifdef JS_THREADSAFE - /* - * The arena cannot be empty if the background finalization is not yet - * done. - */ - if (backgroundFinalizeState != BFS_DONE) - return false; #endif - return !head; - } -}; -struct FreeLists { - /* - * For each arena kind its free list is represented as the first span with - * free things. Initially all the spans are zeroed to be treated as empty - * spans by the allocation code. After we find a new arena with available - * things we copy its first free span into the list and set the arena as - * if it has no free things. This way we do not need to update the arena - * header after the initial allocation. When starting the GC We only move - * the head of the of the list of spans back to the arena only for the - * arena that was not fully allocated. - */ - FreeSpan lists[FINALIZE_LIMIT]; - - void init() { - for (size_t i = 0; i != JS_ARRAY_LENGTH(lists); ++i) - lists[i].initAsEmpty(); +#ifdef JS_THREADSAFE + bool doneBackgroundFinalize(AllocKind kind) const { + return backgroundFinalizeState[kind] == BFS_DONE; } +#endif /* * Return the free list back to the arena so the GC finalization will not * run the finalizers over unitialized bytes from free things. */ void purge() { - for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i) { - FreeSpan *list = &lists[i]; - if (!list->isEmpty()) { - ArenaHeader *aheader = list->arenaHeader(); + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) { + FreeSpan *headSpan = &freeLists[i]; + if (!headSpan->isEmpty()) { + ArenaHeader *aheader = headSpan->arenaHeader(); JS_ASSERT(!aheader->hasFreeThings()); - aheader->setFirstFreeSpan(list); - list->initAsEmpty(); + aheader->setFirstFreeSpan(headSpan); + headSpan->initAsEmpty(); } } } @@ -973,17 +1015,17 @@ struct FreeLists { * the proper value in ArenaHeader::freeList when accessing the latter * outside the GC. */ - void copyToArenas() { - for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i) - copyToArena(FinalizeKind(i)); + void copyFreeListsToArenas() { + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) + copyFreeListToArena(AllocKind(i)); } - void copyToArena(FinalizeKind thingKind) { - FreeSpan *list = &lists[thingKind]; - if (!list->isEmpty()) { - ArenaHeader *aheader = list->arenaHeader(); + void copyFreeListToArena(AllocKind thingKind) { + FreeSpan *headSpan = &freeLists[thingKind]; + if (!headSpan->isEmpty()) { + ArenaHeader *aheader = headSpan->arenaHeader(); JS_ASSERT(!aheader->hasFreeThings()); - aheader->setFirstFreeSpan(list); + aheader->setFirstFreeSpan(headSpan); } } @@ -991,17 +1033,17 @@ struct FreeLists { * Clear the free lists in arenas that were temporarily set there using * copyToArenas. */ - void clearInArenas() { - for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i) - clearInArena(FinalizeKind(i)); + void clearFreeListsInArenas() { + for (size_t i = 0; i != FINALIZE_LIMIT; ++i) + clearFreeListInArena(AllocKind(i)); } - void clearInArena(FinalizeKind thingKind) { - FreeSpan *list = &lists[thingKind]; - if (!list->isEmpty()) { - ArenaHeader *aheader = list->arenaHeader(); - JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list)); + void clearFreeListInArena(AllocKind kind) { + FreeSpan *headSpan = &freeLists[kind]; + if (!headSpan->isEmpty()) { + ArenaHeader *aheader = headSpan->arenaHeader(); + JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan)); aheader->setAsFullyUsed(); } } @@ -1010,45 +1052,55 @@ struct FreeLists { * Check that the free list is either empty or were synchronized with the * arena using copyToArena(). */ - bool isSynchronizedWithArena(FinalizeKind thingKind) { - FreeSpan *list = &lists[thingKind]; - if (list->isEmpty()) + bool isSynchronizedFreeList(AllocKind kind) { + FreeSpan *headSpan = &freeLists[kind]; + if (headSpan->isEmpty()) return true; - ArenaHeader *aheader = list->arenaHeader(); + ArenaHeader *aheader = headSpan->arenaHeader(); if (aheader->hasFreeThings()) { /* * If the arena has a free list, it must be the same as one in * lists. - */ - JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list)); + */ + JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan)); return true; } return false; } - JS_ALWAYS_INLINE void *getNext(unsigned thingKind, size_t thingSize) { - return lists[thingKind].allocate(thingSize); + JS_ALWAYS_INLINE void *allocateFromFreeList(AllocKind thingKind, size_t thingSize) { + return freeLists[thingKind].allocate(thingSize); } - void *populate(ArenaHeader *aheader, unsigned thingKind, size_t thingSize) { - FreeSpan *list = &lists[thingKind]; - *list = aheader->getFirstFreeSpan(); - aheader->setAsFullyUsed(); - void *t = list->allocate(thingSize); - JS_ASSERT(t); - return t; - } + static void *refillFreeList(JSContext *cx, AllocKind thingKind); - void checkEmpty() { + void checkEmptyFreeLists() { #ifdef DEBUG - for (size_t i = 0; i != JS_ARRAY_LENGTH(lists); ++i) - JS_ASSERT(lists[i].isEmpty()); + for (size_t i = 0; i != JS_ARRAY_LENGTH(freeLists); ++i) + JS_ASSERT(freeLists[i].isEmpty()); #endif } -}; -extern void * -RefillFinalizableFreeList(JSContext *cx, unsigned thingKind); + void checkEmptyFreeList(AllocKind kind) { + JS_ASSERT(freeLists[kind].isEmpty()); + } + + void finalizeObjects(JSContext *cx); + void finalizeStrings(JSContext *cx); + void finalizeShapes(JSContext *cx); + void finalizeScripts(JSContext *cx); + void finalizeIonCode(JSContext *cx); + +#ifdef JS_THREADSAFE + static void backgroundFinalize(JSContext *cx, ArenaHeader *listHead); +#endif + + private: + inline void finalizeNow(JSContext *cx, AllocKind thingKind); + inline void finalizeLater(JSContext *cx, AllocKind thingKind); + + inline void *allocateFromArena(JSContext *cx, AllocKind thingKind); +}; /* * Initial allocation size for data structures holding chunks is set to hold @@ -1260,7 +1312,7 @@ class GCHelperThread { Vector finalizeVector; - friend class js::gc::ArenaList; + friend struct js::gc::ArenaLists; JS_FRIEND_API(void) replenishAndFreeLater(void *ptr); @@ -1534,7 +1586,7 @@ IterateCompartmentsArenasCells(JSContext *cx, void *data, * the given compartment or for all compartments if it is null. */ extern JS_FRIEND_API(void) -IterateCells(JSContext *cx, JSCompartment *compartment, gc::FinalizeKind thingKind, +IterateCells(JSContext *cx, JSCompartment *compartment, gc::AllocKind thingKind, void *data, IterateCellCallback cellCallback); } /* namespace js */ diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index a215a4835f4c..ff64de8fc32f 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -119,17 +119,17 @@ GetGCThingTraceKind(const void *thing) if (JSAtom::isStatic(thing)) return JSTRACE_STRING; const Cell *cell = reinterpret_cast(thing); - return GetFinalizableTraceKind(cell->arenaHeader()->getThingKind()); + return MapAllocToTraceKind(cell->getAllocKind()); } /* Capacity for slotsToThingKind */ const size_t SLOTS_TO_THING_KIND_LIMIT = 17; /* Get the best kind to use when making an object with the given slot count. */ -static inline FinalizeKind +static inline AllocKind GetGCObjectKind(size_t numSlots, bool isArray = false) { - extern FinalizeKind slotsToThingKind[]; + extern AllocKind slotsToThingKind[]; if (numSlots >= SLOTS_TO_THING_KIND_LIMIT) { /* @@ -144,37 +144,36 @@ GetGCObjectKind(size_t numSlots, bool isArray = false) } static inline bool -IsBackgroundFinalizeKind(FinalizeKind kind) +IsBackgroundAllocKind(AllocKind kind) { JS_ASSERT(kind <= FINALIZE_OBJECT_LAST); return kind % 2 == 1; } -static inline FinalizeKind -GetBackgroundFinalizeKind(FinalizeKind kind) +static inline AllocKind +GetBackgroundAllocKind(AllocKind kind) { - JS_ASSERT(!IsBackgroundFinalizeKind(kind)); - return (FinalizeKind) (kind + 1); + JS_ASSERT(!IsBackgroundAllocKind(kind)); + return (AllocKind) (kind + 1); } +/* + * Try to get the next larger size for an object, keeping BACKGROUND + * consistent. + */ static inline bool -CanBumpFinalizeKind(FinalizeKind kind) +TryIncrementAllocKind(AllocKind *kindp) { - JS_ASSERT(kind <= FINALIZE_OBJECT_LAST); - return (kind + 2) <= FINALIZE_OBJECT_LAST; -} - -/* Get the next larger size for an object, keeping BACKGROUND consistent. */ -static inline FinalizeKind -BumpFinalizeKind(FinalizeKind kind) -{ - JS_ASSERT(CanBumpFinalizeKind(kind)); - return (FinalizeKind) (kind + 2); + size_t next = size_t(*kindp) + 2; + if (next > size_t(FINALIZE_OBJECT_LAST)) + return false; + *kindp = AllocKind(next); + return true; } /* Get the number of fixed slots and initial capacity associated with a kind. */ static inline size_t -GetGCKindSlots(FinalizeKind thingKind) +GetGCKindSlots(AllocKind thingKind) { /* Using a switch in hopes that thingKind will usually be a compile-time constant. */ switch (thingKind) { @@ -229,11 +228,11 @@ GCPoke(JSContext *cx, Value oldval) */ template void -ForEachArenaAndCell(JSCompartment *compartment, FinalizeKind thingKind, +ForEachArenaAndCell(JSCompartment *compartment, AllocKind thingKind, ArenaOp arenaOp, CellOp cellOp) { - size_t thingSize = GCThingSizeMap[thingKind]; - ArenaHeader *aheader = compartment->arenas[thingKind].getHead(); + size_t thingSize = Arena::thingSize(thingKind); + ArenaHeader *aheader = compartment->arenas.getFirstArena(thingKind); for (; aheader; aheader = aheader->next) { Arena *arena = aheader->getArena(); @@ -241,7 +240,7 @@ ForEachArenaAndCell(JSCompartment *compartment, FinalizeKind thingKind, FreeSpan firstSpan(aheader->getFirstFreeSpan()); const FreeSpan *span = &firstSpan; - for (uintptr_t thing = arena->thingsStart(thingSize); ; thing += thingSize) { + for (uintptr_t thing = arena->thingsStart(thingKind); ; thing += thingSize) { JS_ASSERT(thing <= arena->thingsEnd()); if (thing == span->first) { if (!span->hasNext()) @@ -258,6 +257,7 @@ ForEachArenaAndCell(JSCompartment *compartment, FinalizeKind thingKind, class CellIterImpl { + size_t firstThingOffset; size_t thingSize; ArenaHeader *aheader; FreeSpan firstSpan; @@ -269,9 +269,10 @@ class CellIterImpl CellIterImpl() { } - void init(JSCompartment *comp, FinalizeKind thingKind) { - thingSize = GCThingSizeMap[thingKind]; - aheader = comp->arenas[thingKind].getHead(); + void init(JSCompartment *comp, AllocKind kind) { + firstThingOffset = Arena::firstThingOffset(kind); + thingSize = Arena::thingSize(kind); + aheader = comp->arenas.getFirstArena(kind); firstSpan.initAsEmpty(); span = &firstSpan; thing = span->first; @@ -308,7 +309,7 @@ class CellIterImpl } firstSpan = aheader->getFirstFreeSpan(); span = &firstSpan; - thing = aheader->getArena()->thingsStart(thingSize); + thing = aheader->arenaAddress() | firstThingOffset; aheader = aheader->next; } cell = reinterpret_cast(thing); @@ -319,10 +320,10 @@ class CellIterImpl class CellIterUnderGC : public CellIterImpl { public: - CellIterUnderGC(JSCompartment *comp, FinalizeKind thingKind) { + CellIterUnderGC(JSCompartment *comp, AllocKind kind) { JS_ASSERT(comp->rt->gcRunning); - JS_ASSERT(comp->freeLists.lists[thingKind].isEmpty()); - init(comp, thingKind); + comp->arenas.checkEmptyFreeList(kind); + init(comp, kind); } }; @@ -333,29 +334,29 @@ class CellIterUnderGC : public CellIterImpl { */ class CellIter: public CellIterImpl { - FreeLists *lists; - FinalizeKind thingKind; + ArenaLists *lists; + AllocKind kind; #ifdef DEBUG size_t *counter; #endif public: - CellIter(JSContext *cx, JSCompartment *comp, FinalizeKind thingKind) - : lists(&comp->freeLists), - thingKind(thingKind) { + CellIter(JSContext *cx, JSCompartment *comp, AllocKind kind) + : lists(&comp->arenas), + kind(kind) { #ifdef JS_THREADSAFE - JS_ASSERT(comp->arenas[thingKind].doneBackgroundFinalize()); + JS_ASSERT(comp->arenas.doneBackgroundFinalize(kind)); #endif - if (lists->isSynchronizedWithArena(thingKind)) { + if (lists->isSynchronizedFreeList(kind)) { lists = NULL; } else { JS_ASSERT(!comp->rt->gcRunning); - lists->copyToArena(thingKind); + lists->copyFreeListToArena(kind); } #ifdef DEBUG counter = &JS_THREAD_DATA(cx)->noGCOrAllocationCheck; ++*counter; #endif - init(comp, thingKind); + init(comp, kind); } ~CellIter() { @@ -364,7 +365,7 @@ class CellIter: public CellIterImpl --*counter; #endif if (lists) - lists->clearInArena(thingKind); + lists->clearFreeListInArena(kind); } }; @@ -385,14 +386,12 @@ inline void EmptyCellOp(Cell *t) {} template inline T * -NewGCThing(JSContext *cx, unsigned thingKind, size_t thingSize) +NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize) { - JS_ASSERT(thingKind < js::gc::FINALIZE_LIMIT); - JS_ASSERT(thingSize == js::gc::GCThingSizeMap[thingKind]); + JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind)); #ifdef JS_THREADSAFE JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment), - (thingKind == js::gc::FINALIZE_STRING) || - (thingKind == js::gc::FINALIZE_SHORT_STRING)); + kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING); #endif JS_ASSERT(!cx->runtime->gcRunning); JS_ASSERT(!JS_THREAD_DATA(cx)->noGCOrAllocationCheck); @@ -402,15 +401,15 @@ NewGCThing(JSContext *cx, unsigned thingKind, size_t thingSize) js::gc::RunDebugGC(cx); #endif - void *t = cx->compartment->freeLists.getNext(thingKind, thingSize); - return static_cast(t ? t : js::gc::RefillFinalizableFreeList(cx, thingKind)); + void *t = cx->compartment->arenas.allocateFromFreeList(kind, thingSize); + return static_cast(t ? t : js::gc::ArenaLists::refillFreeList(cx, kind)); } inline JSObject * -js_NewGCObject(JSContext *cx, js::gc::FinalizeKind kind) +js_NewGCObject(JSContext *cx, js::gc::AllocKind kind) { JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST); - JSObject *obj = NewGCThing(cx, kind, js::gc::GCThingSizeMap[kind]); + JSObject *obj = NewGCThing(cx, kind, js::gc::Arena::thingSize(kind)); if (obj) obj->earlyInit(js::gc::GetGCKindSlots(kind)); return obj; diff --git a/js/src/jsgcmark.cpp b/js/src/jsgcmark.cpp index ed265cbfcf5c..e240bbd03847 100644 --- a/js/src/jsgcmark.cpp +++ b/js/src/jsgcmark.cpp @@ -67,7 +67,7 @@ * MarkString, etc. These functions check if an object is in the compartment * currently being GCed. If it is, they call PushMarkStack. Roots are pushed * this way as well as pointers traversed inside trace hooks (for things like - * js_IteratorClass). It it always valid to call a MarkX function instead of + * IteratorClass). It it always valid to call a MarkX function instead of * PushMarkStack, although it may be slower. * * The MarkX functions also handle non-GC object traversal. In this case, they @@ -739,7 +739,7 @@ ScanObject(GCMarker *gcmarker, JSObject *obj) */ Class *clasp = obj->getClass(); if (clasp->trace) { - if (clasp == &js_ArrayClass) { + if (clasp == &ArrayClass) { if (obj->getDenseArrayInitializedLength() > LARGE_OBJECT_CHUNK_SIZE) { if (!gcmarker->largeStack.push(LargeMarkItem(obj))) clasp->trace(gcmarker, obj); diff --git a/js/src/jsgcstats.cpp b/js/src/jsgcstats.cpp index 4ba1744bf54c..28cea7caf37f 100644 --- a/js/src/jsgcstats.cpp +++ b/js/src/jsgcstats.cpp @@ -71,7 +71,6 @@ ConservativeGCStats::dump(FILE *fp) fprintf(fp, " not withing a chunk: %lu\n", ULSTAT(counter[CGCT_NOTCHUNK])); fprintf(fp, " not within arena range: %lu\n", ULSTAT(counter[CGCT_NOTARENA])); fprintf(fp, " points to free arena: %lu\n", ULSTAT(counter[CGCT_FREEARENA])); - fprintf(fp, " excluded, wrong tag: %lu\n", ULSTAT(counter[CGCT_WRONGTAG])); fprintf(fp, " excluded, not live: %lu\n", ULSTAT(counter[CGCT_NOTLIVE])); fprintf(fp, " valid GC things: %lu\n", ULSTAT(counter[CGCT_VALID])); fprintf(fp, " valid but not aligned: %lu\n", ULSTAT(unaligned)); @@ -190,6 +189,10 @@ GCMarker::dumpConservativeRoots() break; } # endif + case JSTRACE_IONCODE: { + fprintf(fp, "ioncode"); + break; + } } fputc('\n', fp); } @@ -204,7 +207,7 @@ GCMarker::dumpConservativeRoots() volatile GCTimer::JSGCReason gcReason = GCTimer::NOREASON; const char *gcReasons[] = {" API", "Maybe", "LastC", "DestC", "Compa", "LastD", - "Malloc", "Alloc", "Chunk", "Shape", " None"}; + "Malloc", "Refill", "Chunk", "Shape", " None"}; jsrefcount newChunkCount = 0; jsrefcount destroyChunkCount = 0; diff --git a/js/src/jsgcstats.h b/js/src/jsgcstats.h index 76dde1572051..6a131bb5b3ac 100644 --- a/js/src/jsgcstats.h +++ b/js/src/jsgcstats.h @@ -99,7 +99,6 @@ enum ConservativeGCTest CGCT_NOTARENA, /* not within arena range in a chunk */ CGCT_NOTCHUNK, /* not within a valid chunk */ CGCT_FREEARENA, /* within arena containing only free things */ - CGCT_WRONGTAG, /* tagged pointer but wrong type */ CGCT_NOTLIVE, /* gcthing is not allocated */ CGCT_END }; @@ -163,7 +162,7 @@ struct GCTimer LASTDITCH, TOOMUCHMALLOC, ALLOCTRIGGER, - CHUNK, + REFILL, SHAPE, NOREASON }; diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index d45a70a96a34..80cfd2170449 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -2042,9 +2042,9 @@ TypeCompartment::nukeTypes(JSContext *cx) */ #ifdef JS_THREADSAFE - Maybe maybeLock; + AutoLockGC maybeLock; if (!cx->runtime->gcMarkAndSweep) - maybeLock.construct(cx->runtime); + maybeLock.lock(cx->runtime); #endif inferenceEnabled = false; @@ -4385,7 +4385,7 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script) return; /* Strawman object to add properties to and watch for duplicates. */ - JSObject *baseobj = NewBuiltinClassInstance(cx, &js_ObjectClass, gc::FINALIZE_OBJECT16); + JSObject *baseobj = NewBuiltinClassInstance(cx, &ObjectClass, gc::FINALIZE_OBJECT16); if (!baseobj) { if (type->newScript) type->clearNewScript(cx); @@ -4411,7 +4411,7 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script) return; } - gc::FinalizeKind kind = gc::GetGCObjectKind(baseobj->slotSpan()); + gc::AllocKind kind = gc::GetGCObjectKind(baseobj->slotSpan()); /* We should not have overflowed the maximum number of fixed slots for an object. */ JS_ASSERT(gc::GetGCKindSlots(kind) >= baseobj->slotSpan()); @@ -4441,7 +4441,7 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script) } type->newScript->script = script; - type->newScript->finalizeKind = unsigned(kind); + type->newScript->allocKind = kind; type->newScript->shape = baseobj->lastProperty(); type->newScript->initializerList = (TypeNewScript::Initializer *) @@ -5480,7 +5480,7 @@ TypeCompartment::sweep(JSContext *cx) const AllocationSiteKey &key = e.front().key; TypeObject *object = e.front().value; - if (key.script->isAboutToBeFinalized(cx) || !object->isMarked()) + if (IsAboutToBeFinalized(cx, key.script) || !object->isMarked()) e.removeFront(); } } @@ -5520,7 +5520,7 @@ TypeScript::Sweep(JSContext *cx, JSScript *script) unsigned num = NumTypeSets(script); TypeSet *typeArray = script->types->typeArray(); - if (script->isAboutToBeFinalized(cx)) { + if (IsAboutToBeFinalized(cx, script)) { /* Release all memory associated with the persistent type sets. */ for (unsigned i = 0; i < num; i++) typeArray[i].clearObjects(); diff --git a/js/src/jsinfer.h b/js/src/jsinfer.h index 99ed6309ea95..90e3506d078a 100644 --- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -646,8 +646,8 @@ struct TypeNewScript { JSScript *script; - /* Finalize kind to use for newly constructed objects. */ - /* gc::FinalizeKind */ unsigned finalizeKind; + /* Allocation kind to use for newly constructed objects. */ + gc::AllocKind allocKind; /* * Shape to use for newly constructed objects. Reflects all definite @@ -806,8 +806,7 @@ struct TypeObject : gc::Cell * used as the scope of a new object whose prototype is |proto|. */ inline bool canProvideEmptyShape(js::Class *clasp); - inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp, - /* gc::FinalizeKind */ unsigned kind); + inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp, gc::AllocKind kind); /* * Get or create a property of this object. Only call this for properties which diff --git a/js/src/jsinferinlines.h b/js/src/jsinferinlines.h index f7b1239a9ad9..7f3b30d04acc 100644 --- a/js/src/jsinferinlines.h +++ b/js/src/jsinferinlines.h @@ -1218,14 +1218,6 @@ TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key) } } /* namespace js::types */ -inline bool -JSScript::isAboutToBeFinalized(JSContext *cx) -{ - return isCachedEval || - (u.object && IsAboutToBeFinalized(cx, u.object)) || - (hasFunction && IsAboutToBeFinalized(cx, function())); -} - inline bool JSScript::ensureHasTypes(JSContext *cx) { diff --git a/js/src/jsinterp.cpp b/js/src/jsinterp.cpp index 5e81930dbb9e..e6ef4169d6d0 100644 --- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -301,7 +301,7 @@ GetScopeChainFull(JSContext *cx, StackFrame *fp, JSObject *blockChain) * to, but not including, that prototype. */ limitClone = &fp->scopeChain(); - while (limitClone->getClass() == &js_WithClass) + while (limitClone->isWith()) limitClone = limitClone->getParent(); JS_ASSERT(limitClone); @@ -403,10 +403,8 @@ CallThisObjectHook(JSContext *cx, JSObject *obj, Value *argv) return thisp; } -namespace js { - void -ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp) +js::ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp) { Value &thisv = vp[1]; @@ -414,11 +412,11 @@ ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp) if (thisv.isObject()) { JS_ASSERT(thisv.toObject().getClass() != clasp); } else if (thisv.isString()) { - JS_ASSERT(clasp != &js_StringClass); + JS_ASSERT(clasp != &StringClass); } else if (thisv.isNumber()) { - JS_ASSERT(clasp != &js_NumberClass); + JS_ASSERT(clasp != &NumberClass); } else if (thisv.isBoolean()) { - JS_ASSERT(clasp != &js_BooleanClass); + JS_ASSERT(clasp != &BooleanClass); } else { JS_ASSERT(thisv.isUndefined() || thisv.isNull()); } @@ -449,7 +447,7 @@ ReportIncompatibleMethod(JSContext *cx, Value *vp, Class *clasp) * The alert should display "true". */ bool -BoxNonStrictThis(JSContext *cx, const CallReceiver &call) +js::BoxNonStrictThis(JSContext *cx, const CallReceiver &call) { /* * Check for SynthesizeFrame poisoning and fast constructors which @@ -477,8 +475,6 @@ BoxNonStrictThis(JSContext *cx, const CallReceiver &call) return true; } -} - #if JS_HAS_NO_SUCH_METHOD const uint32 JSSLOT_FOUND_FUNCTION = 0; @@ -525,8 +521,8 @@ Class js_NoSuchMethodClass = { * call by name, and args is an Array containing this invocation's actual * parameters. */ -JSBool -js_OnUnknownMethod(JSContext *cx, Value *vp) +bool +js::OnUnknownMethod(JSContext *cx, Value *vp) { JS_ASSERT(!vp[1].isPrimitive()); @@ -587,10 +583,8 @@ NoSuchMethod(JSContext *cx, uintN argc, Value *vp) #endif /* JS_HAS_NO_SUCH_METHOD */ -namespace js { - JS_REQUIRES_STACK bool -RunScript(JSContext *cx, JSScript *script, StackFrame *fp) +js::RunScript(JSContext *cx, JSScript *script, StackFrame *fp) { JS_ASSERT(script); JS_ASSERT(fp == cx->fp()); @@ -635,8 +629,8 @@ RunScript(JSContext *cx, JSScript *script, StackFrame *fp) * required arguments, allocate declared local variables, and pop everything * when done. Then push the return value. */ -JS_REQUIRES_STACK bool -InvokeKernel(JSContext *cx, const CallArgs &argsRef, MaybeConstruct construct) +bool +js::InvokeKernel(JSContext *cx, const CallArgs &argsRef, MaybeConstruct construct) { /* N.B. Must be kept in sync with InvokeSessionGuard::start/invoke */ @@ -657,7 +651,7 @@ InvokeKernel(JSContext *cx, const CallArgs &argsRef, MaybeConstruct construct) Class *clasp = callee.getClass(); /* Invoke non-functions. */ - if (JS_UNLIKELY(clasp != &js_FunctionClass)) { + if (JS_UNLIKELY(clasp != &FunctionClass)) { #if JS_HAS_NO_SUCH_METHOD if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass)) return NoSuchMethod(cx, args.argc(), args.base()); @@ -676,22 +670,6 @@ InvokeKernel(JSContext *cx, const CallArgs &argsRef, MaybeConstruct construct) if (fun->isNative()) return CallJSNative(cx, fun->u.n.native, args); - /* Handle the empty-script special case. */ - JSScript *script = fun->script(); - if (JS_UNLIKELY(script->isEmpty())) { - if (construct) { - bool newType = cx->typeInferenceEnabled() && cx->fp()->isScriptFrame() && - UseNewType(cx, cx->fp()->script(), cx->regs().pc); - JSObject *obj = js_CreateThisForFunction(cx, &callee, newType); - if (!obj) - return false; - args.rval().setObject(*obj); - } else { - args.rval().setUndefined(); - } - return true; - } - TypeMonitorCall(cx, args, construct); /* Get pointer to new frame/slots, prepare arguments. */ @@ -708,7 +686,7 @@ InvokeKernel(JSContext *cx, const CallArgs &argsRef, MaybeConstruct construct) JSBool ok; { AutoPreserveEnumerators preserve(cx); - ok = RunScript(cx, script, fp); + ok = RunScript(cx, fun->script(), fp); } args.rval() = fp->returnValue(); @@ -742,13 +720,13 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this if (!calleev.isObject()) break; JSObject &callee = calleev.toObject(); - if (callee.getClass() != &js_FunctionClass) + if (callee.getClass() != &FunctionClass) break; JSFunction *fun = callee.getFunctionPrivate(); if (fun->isNative()) break; script_ = fun->script(); - if (fun->isHeavyweight() || script_->isEmpty()) + if (fun->isHeavyweight()) break; /* @@ -815,8 +793,8 @@ InvokeSessionGuard::start(JSContext *cx, const Value &calleev, const Value &this } bool -Invoke(JSContext *cx, const Value &thisv, const Value &fval, uintN argc, Value *argv, - Value *rval) +js::Invoke(JSContext *cx, const Value &thisv, const Value &fval, uintN argc, Value *argv, + Value *rval) { LeaveTrace(cx); @@ -848,7 +826,7 @@ Invoke(JSContext *cx, const Value &thisv, const Value &fval, uintN argc, Value * } bool -InvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv, Value *rval) +js::InvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv, Value *rval) { LeaveTrace(cx); @@ -868,8 +846,8 @@ InvokeConstructor(JSContext *cx, const Value &fval, uintN argc, Value *argv, Val } bool -InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, uintN argc, Value *argv, - Value *rval) +js::InvokeGetterOrSetter(JSContext *cx, JSObject *obj, const Value &fval, uintN argc, Value *argv, + Value *rval) { LeaveTrace(cx); @@ -911,8 +889,8 @@ InitSharpSlots(JSContext *cx, StackFrame *fp) #endif bool -ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &thisv, - ExecuteType type, StackFrame *evalInFrame, Value *result) +js::ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value &thisv, + ExecuteType type, StackFrame *evalInFrame, Value *result) { JS_ASSERT_IF(evalInFrame, type == EXECUTE_DEBUG); @@ -953,7 +931,7 @@ ExecuteKernel(JSContext *cx, JSScript *script, JSObject &scopeChain, const Value } bool -Execute(JSContext *cx, JSScript *script, JSObject &scopeChainArg, Value *rval) +js::Execute(JSContext *cx, JSScript *script, JSObject &scopeChainArg, Value *rval) { /* The scope chain could be anything, so innerize just in case. */ JSObject *scopeChain = &scopeChainArg; @@ -983,7 +961,7 @@ Execute(JSContext *cx, JSScript *script, JSObject &scopeChainArg, Value *rval) } bool -CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs) +js::CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs) { JSObject *obj2; JSProperty *prop; @@ -1054,7 +1032,7 @@ CheckRedeclaration(JSContext *cx, JSObject *obj, jsid id, uintN attrs) } JSBool -HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) +js::HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) { Class *clasp = obj->getClass(); if (clasp->hasInstance) @@ -1065,7 +1043,7 @@ HasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) } bool -LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *result) +js::LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *result) { #if JS_HAS_XML_SUPPORT if (JS_UNLIKELY(lval.isObject() && lval.toObject().isXML()) || @@ -1136,7 +1114,7 @@ LooselyEqual(JSContext *cx, const Value &lval, const Value &rval, JSBool *result } bool -StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, JSBool *equal) +js::StrictlyEqual(JSContext *cx, const Value &lref, const Value &rref, JSBool *equal) { Value lval = lref, rval = rref; if (SameType(lval, rval)) { @@ -1188,7 +1166,7 @@ IsNaN(const Value &v) } bool -SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same) +js::SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same) { if (IsNegativeZero(v1)) { *same = IsNegativeZero(v2); @@ -1206,7 +1184,7 @@ SameValue(JSContext *cx, const Value &v1, const Value &v2, JSBool *same) } JSType -TypeOfValue(JSContext *cx, const Value &vref) +js::TypeOfValue(JSContext *cx, const Value &vref) { Value v = vref; if (v.isNumber()) @@ -1223,24 +1201,24 @@ TypeOfValue(JSContext *cx, const Value &vref) return JSTYPE_BOOLEAN; } -JS_REQUIRES_STACK bool -InvokeConstructorKernel(JSContext *cx, const CallArgs &argsRef) +bool +js::InvokeConstructorKernel(JSContext *cx, const CallArgs &argsRef) { - JS_ASSERT(!js_FunctionClass.construct); + JS_ASSERT(!FunctionClass.construct); CallArgs args = argsRef; if (args.calleev().isObject()) { JSObject *callee = &args.callee(); Class *clasp = callee->getClass(); - if (clasp == &js_FunctionClass) { + if (clasp == &FunctionClass) { JSFunction *fun = callee->getFunctionPrivate(); if (fun->isConstructor()) { args.thisv().setMagicWithObjectOrNullPayload(NULL); - Probes::calloutBegin(cx, fun); - bool ok = CallJSNativeConstructor(cx, fun->u.n.native, args); - Probes::calloutEnd(cx, fun); - return ok; + Probes::calloutBegin(cx, fun); + bool ok = CallJSNativeConstructor(cx, fun->u.n.native, args); + Probes::calloutEnd(cx, fun); + return ok; } if (!fun->isInterpretedConstructor()) @@ -1264,8 +1242,8 @@ error: } bool -InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval, - uintN argc, Value *argv, Value *rval) +js::InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fval, + uintN argc, Value *argv, Value *rval) { LeaveTrace(cx); @@ -1282,7 +1260,7 @@ InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fv Class *clasp = callee.getClass(); JSFunction *fun; bool ok; - if (clasp == &js_FunctionClass && (fun = callee.getFunctionPrivate())->isConstructor()) { + if (clasp == &FunctionClass && (fun = callee.getFunctionPrivate())->isConstructor()) { args.thisv().setMagicWithObjectOrNullPayload(thisobj); Probes::calloutBegin(cx, fun); ok = CallJSNativeConstructor(cx, fun->u.n.native, args); @@ -1300,7 +1278,7 @@ InvokeConstructorWithGivenThis(JSContext *cx, JSObject *thisobj, const Value &fv } bool -ValueToId(JSContext *cx, const Value &v, jsid *idp) +js::ValueToId(JSContext *cx, const Value &v, jsid *idp) { int32_t i; if (ValueFitsInInt32(v, &i) && INT_FITS_IN_JSID(i)) { @@ -1321,14 +1299,12 @@ ValueToId(JSContext *cx, const Value &v, jsid *idp) return js_ValueToStringId(cx, v, idp); } -} /* namespace js */ - /* * Enter the new with scope using an object at sp[-1] and associate the depth * of the with block with sp + stackIndex. */ -JS_REQUIRES_STACK JSBool -js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen) +static bool +EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen) { StackFrame *fp = cx->fp(); Value *sp = cx->regs().sp; @@ -1362,55 +1338,47 @@ js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen) return JS_TRUE; } -JS_REQUIRES_STACK void -js_LeaveWith(JSContext *cx) +static void +LeaveWith(JSContext *cx) { JSObject *withobj; withobj = &cx->fp()->scopeChain(); - JS_ASSERT(withobj->getClass() == &js_WithClass); + JS_ASSERT(withobj->getClass() == &WithClass); JS_ASSERT(withobj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp())); JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0); withobj->setPrivate(NULL); cx->fp()->setScopeChainNoCallObj(*withobj->getParent()); } -JS_REQUIRES_STACK Class * -js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth) +bool +js::IsActiveWithOrBlock(JSContext *cx, JSObject &obj, int stackDepth) { - Class *clasp; - - clasp = obj->getClass(); - if ((clasp == &js_WithClass || clasp == &js_BlockClass) && - obj->getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()) && - OBJ_BLOCK_DEPTH(cx, obj) >= stackDepth) { - return clasp; - } - return NULL; + return (obj.isWith() || obj.isBlock()) && + obj.getPrivate() == js_FloatingFrameIfGenerator(cx, cx->fp()) && + OBJ_BLOCK_DEPTH(cx, &obj) >= stackDepth; } /* * Unwind block and scope chains to match the given depth. The function sets * fp->sp on return to stackDepth. */ -JS_REQUIRES_STACK JSBool -js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind) +bool +js::UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind) { - Class *clasp; - JS_ASSERT(stackDepth >= 0); JS_ASSERT(cx->fp()->base() + stackDepth <= cx->regs().sp); StackFrame *fp = cx->fp(); for (;;) { - clasp = js_IsActiveWithOrBlock(cx, &fp->scopeChain(), stackDepth); - if (!clasp) + JSObject &scopeChain = fp->scopeChain(); + if (!IsActiveWithOrBlock(cx, scopeChain, stackDepth)) break; - if (clasp == &js_BlockClass) { + if (scopeChain.isBlock()) { /* Don't fail until after we've updated all stacks. */ normalUnwind &= js_PutBlockObject(cx, normalUnwind); } else { - js_LeaveWith(cx); + LeaveWith(cx); } } @@ -1418,8 +1386,14 @@ js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind) return normalUnwind; } -JSBool -js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, Value *vp, Value *vp2) +/* + * Find the results of incrementing or decrementing *vp. For pre-increments, + * both *vp and *vp2 will contain the result on return. For post-increments, + * vp will contain the original value converted to a number and vp2 will get + * the result. Both vp and vp2 must be roots. + */ +static bool +DoIncDec(JSContext *cx, const JSCodeSpec *cs, Value *vp, Value *vp2) { if (cs->format & JOF_POST) { double d; @@ -1694,7 +1668,7 @@ JS_STATIC_ASSERT(JSOP_INCNAME_LENGTH == JSOP_NAMEDEC_LENGTH); static inline bool IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval) { - if (iterobj->getClass() == &js_IteratorClass) { + if (iterobj->isIterator()) { NativeIterator *ni = iterobj->getNativeIterator(); if (ni->isKeyIter()) { *cond = (ni->props_cursor < ni->props_end); @@ -1710,7 +1684,7 @@ IteratorMore(JSContext *cx, JSObject *iterobj, bool *cond, Value *rval) static inline bool IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval) { - if (iterobj->getClass() == &js_IteratorClass) { + if (iterobj->isIterator()) { NativeIterator *ni = iterobj->getNativeIterator(); if (ni->isKeyIter()) { JS_ASSERT(ni->props_cursor < ni->props_end); @@ -1742,10 +1716,8 @@ TypeCheckNextBytecode(JSContext *cx, JSScript *script, unsigned n, const FrameRe #endif } -namespace js { - -JS_REQUIRES_STACK JS_NEVER_INLINE bool -Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) +JS_NEVER_INLINE bool +js::Interpret(JSContext *cx, StackFrame *entryFrame, InterpMode interpMode) { #ifdef MOZ_TRACEVIS TraceVisStateObj tvso(cx, S_INTERP); @@ -2380,15 +2352,12 @@ BEGIN_CASE(JSOP_POPN) OBJ_BLOCK_DEPTH(cx, obj) + OBJ_BLOCK_COUNT(cx, obj) <= (size_t) (regs.sp - regs.fp()->base())); for (obj = ®s.fp()->scopeChain(); obj; obj = obj->getParent()) { - Class *clasp = obj->getClass(); - if (clasp != &js_BlockClass && clasp != &js_WithClass) + if (!obj->isBlock() || !obj->isWith()) continue; if (obj->getPrivate() != js_FloatingFrameIfGenerator(cx, regs.fp())) break; JS_ASSERT(regs.fp()->base() + OBJ_BLOCK_DEPTH(cx, obj) - + ((clasp == &js_BlockClass) - ? OBJ_BLOCK_COUNT(cx, obj) - : 1) + + (obj->isBlock() ? OBJ_BLOCK_COUNT(cx, obj) : 1) <= regs.sp); } #endif @@ -2401,7 +2370,7 @@ BEGIN_CASE(JSOP_POPV) END_CASE(JSOP_POPV) BEGIN_CASE(JSOP_ENTERWITH) - if (!js_EnterWith(cx, -1, JSOP_ENTERWITH, JSOP_ENTERWITH_LENGTH)) + if (!EnterWith(cx, -1, JSOP_ENTERWITH, JSOP_ENTERWITH_LENGTH)) goto error; /* @@ -2419,7 +2388,7 @@ END_CASE(JSOP_ENTERWITH) BEGIN_CASE(JSOP_LEAVEWITH) JS_ASSERT(regs.sp[-1].toObject() == regs.fp()->scopeChain()); regs.sp--; - js_LeaveWith(cx); + LeaveWith(cx); END_CASE(JSOP_LEAVEWITH) BEGIN_CASE(JSOP_RETURN) @@ -2460,7 +2429,7 @@ BEGIN_CASE(JSOP_STOP) inline_return: { JS_ASSERT(!regs.fp()->hasImacropc()); - JS_ASSERT(!js_IsActiveWithOrBlock(cx, ®s.fp()->scopeChain(), 0)); + JS_ASSERT(!IsActiveWithOrBlock(cx, regs.fp()->scopeChain(), 0)); interpReturnOK = ScriptEpilogue(cx, regs.fp(), interpReturnOK); /* The JIT inlines ScriptEpilogue. */ @@ -3540,7 +3509,7 @@ do_incop: } else { /* We need an extra root for the result. */ PUSH_NULL(); - if (!js_DoIncDec(cx, cs, ®s.sp[-2], ®s.sp[-1])) + if (!DoIncDec(cx, cs, ®s.sp[-2], ®s.sp[-1])) goto error; { @@ -3612,7 +3581,7 @@ BEGIN_CASE(JSOP_LOCALINC) PUSH_INT32(tmp + incr2); } else { PUSH_COPY(*vp); - if (!js_DoIncDec(cx, &js_CodeSpec[op], ®s.sp[-1], vp)) + if (!DoIncDec(cx, &js_CodeSpec[op], ®s.sp[-1], vp)) goto error; TypeScript::MonitorOverflow(cx, script, regs.pc); } @@ -3818,7 +3787,7 @@ BEGIN_CASE(JSOP_CALLPROP) if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) { LOAD_ATOM(0, atom); regs.sp[-2].setString(atom); - if (!js_OnUnknownMethod(cx, regs.sp - 2)) + if (!OnUnknownMethod(cx, regs.sp - 2)) goto error; } #endif @@ -4094,10 +4063,10 @@ BEGIN_CASE(JSOP_CALLELEM) #if JS_HAS_NO_SUCH_METHOD if (JS_UNLIKELY(regs.sp[-2].isPrimitive()) && thisv.isObject()) { - /* For js_OnUnknownMethod, sp[-2] is the index, and sp[-1] is the object missing it. */ + /* For OnUnknownMethod, sp[-2] is the index, and sp[-1] is the object missing it. */ regs.sp[-2] = regs.sp[-1]; regs.sp[-1].setObject(*thisObj); - if (!js_OnUnknownMethod(cx, regs.sp - 2)) + if (!OnUnknownMethod(cx, regs.sp - 2)) goto error; } else #endif @@ -4343,7 +4312,7 @@ BEGIN_CASE(JSOP_CALLNAME) } else { shape = (Shape *)prop; JSObject *normalized = obj; - if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter()) + if (normalized->getClass() == &WithClass && !shape->hasDefaultGetter()) normalized = js_UnwrapWithObject(cx, normalized); NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval); } @@ -5041,7 +5010,7 @@ BEGIN_CASE(JSOP_LAMBDA) const Value &lref = regs.sp[-1]; JS_ASSERT(lref.isObject()); JSObject *obj2 = &lref.toObject(); - JS_ASSERT(obj2->getClass() == &js_ObjectClass); + JS_ASSERT(obj2->isObject()); #endif fun->setMethodAtom(script->getAtom(GET_FULL_INDEX(pc2 - regs.pc))); @@ -5257,8 +5226,8 @@ BEGIN_CASE(JSOP_NEWINIT) if (i == JSProto_Array) { obj = NewDenseEmptyArray(cx); } else { - gc::FinalizeKind kind = GuessObjectGCKind(0, false); - obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + gc::AllocKind kind = GuessObjectGCKind(0, false); + obj = NewBuiltinClassInstance(cx, &ObjectClass, kind); } if (!obj) @@ -5844,7 +5813,7 @@ BEGIN_CASE(JSOP_ENDFILTER) bool cond = !regs.sp[-1].isMagic(); if (cond) { /* Exit the "with" block left from the previous iteration. */ - js_LeaveWith(cx); + LeaveWith(cx); } if (!js_StepXMLListFilter(cx, cond)) goto error; @@ -5854,7 +5823,7 @@ BEGIN_CASE(JSOP_ENDFILTER) * temporaries. */ JS_ASSERT(IsXML(regs.sp[-1])); - if (!js_EnterWith(cx, -2, JSOP_ENDFILTER, JSOP_ENDFILTER_LENGTH)) + if (!EnterWith(cx, -2, JSOP_ENDFILTER, JSOP_ENDFILTER_LENGTH)) goto error; regs.sp--; len = GET_JUMP_OFFSET(regs.pc); @@ -5981,10 +5950,9 @@ BEGIN_CASE(JSOP_ENTERBLOCK) * static scope. */ JSObject *obj2 = ®s.fp()->scopeChain(); - Class *clasp; - while ((clasp = obj2->getClass()) == &js_WithClass) + while (obj2->isWith()) obj2 = obj2->getParent(); - if (clasp == &js_BlockClass && + if (obj2->isBlock() && obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, regs.fp())) { JSObject *youngestProto = obj2->getProto(); JS_ASSERT(youngestProto->isStaticBlock()); @@ -6249,7 +6217,7 @@ END_CASE(JSOP_ARRAYPUSH) */ regs.pc = (script)->main() + tn->start + tn->length; - JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE); + JSBool ok = UnwindScope(cx, tn->stackDepth, JS_TRUE); JS_ASSERT(regs.sp == regs.fp()->base() + tn->stackDepth); if (!ok) { /* @@ -6319,12 +6287,12 @@ END_CASE(JSOP_ARRAYPUSH) forced_return: /* * Unwind the scope making sure that interpReturnOK stays false even when - * js_UnwindScope returns true. + * UnwindScope returns true. * * When a trap handler returns JSTRAP_RETURN, we jump here with * interpReturnOK set to true bypassing any finally blocks. */ - interpReturnOK &= js_UnwindScope(cx, 0, interpReturnOK || cx->isExceptionPending()); + interpReturnOK &= UnwindScope(cx, 0, interpReturnOK || cx->isExceptionPending()); JS_ASSERT(regs.sp == regs.fp()->base()); if (entryFrame != regs.fp()) @@ -6358,7 +6326,7 @@ END_CASE(JSOP_ARRAYPUSH) #endif JS_ASSERT_IF(!regs.fp()->isGeneratorFrame(), - !js_IsActiveWithOrBlock(cx, ®s.fp()->scopeChain(), 0)); + !IsActiveWithOrBlock(cx, regs.fp()->scopeChain(), 0)); #ifdef JS_METHODJIT /* @@ -6378,5 +6346,3 @@ END_CASE(JSOP_ARRAYPUSH) } goto error; } - -} /* namespace js */ diff --git a/js/src/jsinterp.h b/js/src/jsinterp.h index 9ed9761e8d1f..6b51eb3489b7 100644 --- a/js/src/jsinterp.h +++ b/js/src/jsinterp.h @@ -361,34 +361,19 @@ class InterpreterFrames { const InterruptEnablerBase &enabler; }; -} /* namespace js */ - -extern JS_REQUIRES_STACK JSBool -js_EnterWith(JSContext *cx, jsint stackIndex, JSOp op, size_t oplen); - -extern JS_REQUIRES_STACK void -js_LeaveWith(JSContext *cx); - -/* - * Find the results of incrementing or decrementing *vp. For pre-increments, - * both *vp and *vp2 will contain the result on return. For post-increments, - * vp will contain the original value converted to a number and vp2 will get - * the result. Both vp and vp2 must be roots. - */ -extern JSBool -js_DoIncDec(JSContext *cx, const JSCodeSpec *cs, js::Value *vp, js::Value *vp2); - /* * Unwind block and scope chains to match the given depth. The function sets * fp->sp on return to stackDepth. */ -extern JS_REQUIRES_STACK JSBool -js_UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind); +extern bool +UnwindScope(JSContext *cx, jsint stackDepth, JSBool normalUnwind); -extern JSBool -js_OnUnknownMethod(JSContext *cx, js::Value *vp); +extern bool +OnUnknownMethod(JSContext *cx, js::Value *vp); -extern JS_REQUIRES_STACK js::Class * -js_IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth); +extern bool +IsActiveWithOrBlock(JSContext *cx, JSObject &obj, int stackDepth); + +} /* namespace js */ #endif /* jsinterp_h___ */ diff --git a/js/src/jsinterpinlines.h b/js/src/jsinterpinlines.h index 2b2d507d9ceb..4667700a9e9b 100644 --- a/js/src/jsinterpinlines.h +++ b/js/src/jsinterpinlines.h @@ -182,7 +182,7 @@ class PrimitiveBehavior { public: static inline bool isType(const Value &v) { return v.isString(); } static inline JSString *extract(const Value &v) { return v.toString(); } - static inline Class *getClass() { return &js_StringClass; } + static inline Class *getClass() { return &StringClass; } }; template<> @@ -190,7 +190,7 @@ class PrimitiveBehavior { public: static inline bool isType(const Value &v) { return v.isBoolean(); } static inline bool extract(const Value &v) { return v.toBoolean(); } - static inline Class *getClass() { return &js_BooleanClass; } + static inline Class *getClass() { return &BooleanClass; } }; template<> @@ -198,7 +198,7 @@ class PrimitiveBehavior { public: static inline bool isType(const Value &v) { return v.isNumber(); } static inline double extract(const Value &v) { return v.toNumber(); } - static inline Class *getClass() { return &js_NumberClass; } + static inline Class *getClass() { return &NumberClass; } }; } // namespace detail diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index b0293da57187..edf2a5fcdf35 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -90,7 +90,7 @@ static void iterator_finalize(JSContext *cx, JSObject *obj); static void iterator_trace(JSTracer *trc, JSObject *obj); static JSObject *iterator_iterator(JSContext *cx, JSObject *obj, JSBool keysonly); -Class js_IteratorClass = { +Class js::IteratorClass = { "Iterator", JSCLASS_HAS_PRIVATE | JSCLASS_CONCURRENT_FINALIZER | @@ -130,7 +130,7 @@ NativeIterator::mark(JSTracer *trc) static void iterator_finalize(JSContext *cx, JSObject *obj) { - JS_ASSERT(obj->getClass() == &js_IteratorClass); + JS_ASSERT(obj->isIterator()); NativeIterator *ni = obj->getNativeIterator(); if (ni) { @@ -418,12 +418,12 @@ NewIteratorObject(JSContext *cx, uintN flags) EmptyShape *emptyEnumeratorShape = EmptyShape::getEmptyEnumeratorShape(cx); if (!emptyEnumeratorShape) return NULL; - obj->init(cx, &js_IteratorClass, &types::emptyTypeObject, NULL, NULL, false); + obj->init(cx, &IteratorClass, &types::emptyTypeObject, NULL, NULL, false); obj->setMap(emptyEnumeratorShape); return obj; } - return NewBuiltinClassInstance(cx, &js_IteratorClass); + return NewBuiltinClassInstance(cx, &IteratorClass); } NativeIterator * @@ -571,7 +571,7 @@ GetIterator(JSContext *cx, JSObject *obj, uintN flags, Value *vp) if (obj) { /* Enumerate Iterator.prototype directly. */ JSIteratorOp op = obj->getClass()->ext.iteratorObject; - if (op && (obj->getClass() != &js_IteratorClass || obj->getNativeIterator())) { + if (op && (obj->getClass() != &IteratorClass || obj->getNativeIterator())) { JSObject *iterobj = op(cx, obj, !(flags & JSITER_FOREACH)); if (!iterobj) return false; @@ -718,8 +718,8 @@ iterator_next(JSContext *cx, uintN argc, Value *vp) JSObject *obj = ToObject(cx, &vp[1]); if (!obj) return false; - if (obj->getClass() != &js_IteratorClass) { - ReportIncompatibleMethod(cx, vp, &js_IteratorClass); + if (!obj->isIterator()) { + ReportIncompatibleMethod(cx, vp, &IteratorClass); return false; } @@ -792,8 +792,7 @@ js_CloseIterator(JSContext *cx, JSObject *obj) { cx->iterValue.setMagic(JS_NO_ITER_VALUE); - Class *clasp = obj->getClass(); - if (clasp == &js_IteratorClass) { + if (obj->isIterator()) { /* Remove enumerators from the active list, which is a stack. */ NativeIterator *ni = obj->getNativeIterator(); @@ -812,7 +811,7 @@ js_CloseIterator(JSContext *cx, JSObject *obj) } } #if JS_HAS_GENERATORS - else if (clasp == &js_GeneratorClass) { + else if (obj->isGenerator()) { return CloseGenerator(cx, obj); } #endif @@ -943,7 +942,7 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval) { /* Fast path for native iterators */ NativeIterator *ni = NULL; - if (iterobj->getClass() == &js_IteratorClass) { + if (iterobj->isIterator()) { /* Key iterators are handled by fast-paths. */ ni = iterobj->getNativeIterator(); if (ni) { @@ -971,7 +970,7 @@ js_IteratorMore(JSContext *cx, JSObject *iterobj, Value *rval) return false; if (!Invoke(cx, ObjectValue(*iterobj), *rval, 0, NULL, rval)) { /* Check for StopIteration. */ - if (!cx->isExceptionPending() || !js_ValueIsStopIteration(cx->getPendingException())) + if (!cx->isExceptionPending() || !IsStopIteration(cx->getPendingException())) return false; cx->clearPendingException(); @@ -1000,7 +999,7 @@ JSBool js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval) { /* Fast path for native iterators */ - if (iterobj->getClass() == &js_IteratorClass) { + if (iterobj->isIterator()) { /* * Implement next directly as all the methods of the native iterator are * read-only and permanent. @@ -1039,11 +1038,11 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval) static JSBool stopiter_hasInstance(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) { - *bp = js_ValueIsStopIteration(*v); + *bp = IsStopIteration(*v); return JS_TRUE; } -Class js_StopIterationClass = { +Class js::StopIterationClass = { js_StopIteration_str, JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration) | JSCLASS_FREEZE_PROTO, @@ -1111,7 +1110,7 @@ generator_trace(JSTracer *trc, JSObject *obj) MarkStackRangeConservatively(trc, fp->slots(), gen->regs.sp); } -Class js_GeneratorClass = { +Class js::GeneratorClass = { js_Generator_str, JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Generator) | JSCLASS_IS_ANONYMOUS, @@ -1150,7 +1149,7 @@ Class js_GeneratorClass = { JS_REQUIRES_STACK JSObject * js_NewGenerator(JSContext *cx) { - JSObject *obj = NewBuiltinClassInstance(cx, &js_GeneratorClass); + JSObject *obj = NewBuiltinClassInstance(cx, &GeneratorClass); if (!obj) return NULL; @@ -1309,7 +1308,7 @@ SendToGenerator(JSContext *cx, JSGeneratorOp op, JSObject *obj, static JS_REQUIRES_STACK JSBool CloseGenerator(JSContext *cx, JSObject *obj) { - JS_ASSERT(obj->getClass() == &js_GeneratorClass); + JS_ASSERT(obj->isGenerator()); JSGenerator *gen = (JSGenerator *) obj->getPrivate(); if (!gen) { @@ -1334,8 +1333,8 @@ generator_op(JSContext *cx, JSGeneratorOp op, Value *vp, uintN argc) JSObject *obj = ToObject(cx, &vp[1]); if (!obj) return JS_FALSE; - if (obj->getClass() != &js_GeneratorClass) { - ReportIncompatibleMethod(cx, vp, &js_GeneratorClass); + if (!obj->isGenerator()) { + ReportIncompatibleMethod(cx, vp, &GeneratorClass); return JS_FALSE; } @@ -1426,11 +1425,11 @@ static JSFunctionSpec generator_methods[] = { static bool InitIteratorClass(JSContext *cx, GlobalObject *global) { - JSObject *iteratorProto = global->createBlankPrototype(cx, &js_IteratorClass); + JSObject *iteratorProto = global->createBlankPrototype(cx, &IteratorClass); if (!iteratorProto) return false; - JSFunction *ctor = global->createConstructor(cx, Iterator, &js_IteratorClass, + JSFunction *ctor = global->createConstructor(cx, Iterator, &IteratorClass, CLASS_ATOM(cx, Iterator), 2); if (!ctor) return false; @@ -1448,7 +1447,7 @@ static bool InitGeneratorClass(JSContext *cx, GlobalObject *global) { #if JS_HAS_GENERATORS - JSObject *proto = global->createBlankPrototype(cx, &js_GeneratorClass); + JSObject *proto = global->createBlankPrototype(cx, &GeneratorClass); if (!proto) return false; @@ -1465,7 +1464,7 @@ InitGeneratorClass(JSContext *cx, GlobalObject *global) static JSObject * InitStopIterationClass(JSContext *cx, GlobalObject *global) { - JSObject *proto = global->createBlankPrototype(cx, &js_StopIterationClass); + JSObject *proto = global->createBlankPrototype(cx, &StopIterationClass); if (!proto || !proto->freeze(cx)) return NULL; @@ -1473,7 +1472,7 @@ InitStopIterationClass(JSContext *cx, GlobalObject *global) if (!DefineConstructorAndPrototype(cx, global, JSProto_StopIteration, proto, proto)) return NULL; - MarkStandardClassInitializedNoProto(global, &js_StopIterationClass); + MarkStandardClassInitializedNoProto(global, &StopIterationClass); return proto; } diff --git a/js/src/jsiter.h b/js/src/jsiter.h index 0605d7bed5c6..7939df660f3a 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -231,16 +231,16 @@ js_LiveFrameIfGenerator(js::StackFrame *fp) #endif -extern js::Class js_GeneratorClass; -extern js::Class js_IteratorClass; -extern js::Class js_StopIterationClass; +namespace js { static inline bool -js_ValueIsStopIteration(const js::Value &v) +IsStopIteration(const js::Value &v) { - return v.isObject() && v.toObject().getClass() == &js_StopIterationClass; + return v.isObject() && v.toObject().isStopIteration(); } +} /* namespace js */ + extern JSObject * js_InitIteratorClasses(JSContext *cx, JSObject *obj); diff --git a/js/src/jsmath.cpp b/js/src/jsmath.cpp index 463a1a43c004..c56741691df0 100644 --- a/js/src/jsmath.cpp +++ b/js/src/jsmath.cpp @@ -106,7 +106,7 @@ MathCache::MathCache() { JS_ASSERT(hash(-0.0) != hash(+0.0)); } -Class js_MathClass = { +Class js::MathClass = { js_Math_str, JSCLASS_HAS_CACHED_PROTO(JSProto_Math), PropertyStub, /* addProperty */ @@ -865,7 +865,7 @@ js_IsMathFunction(JSNative native) JSObject * js_InitMathClass(JSContext *cx, JSObject *obj) { - JSObject *Math = NewNonFunction(cx, &js_MathClass, NULL, obj); + JSObject *Math = NewNonFunction(cx, &MathClass, NULL, obj); if (!Math || !Math->setSingletonType(cx)) return NULL; @@ -879,7 +879,7 @@ js_InitMathClass(JSContext *cx, JSObject *obj) if (!JS_DefineConstDoubles(cx, Math, math_constants)) return NULL; - MarkStandardClassInitializedNoProto(obj, &js_MathClass); + MarkStandardClassInitializedNoProto(obj, &MathClass); return Math; } diff --git a/js/src/jsmath.h b/js/src/jsmath.h index bb9e3c1a8b31..20c61ece9f4e 100644 --- a/js/src/jsmath.h +++ b/js/src/jsmath.h @@ -82,8 +82,6 @@ class MathCache * JS math functions. */ -extern js::Class js_MathClass; - extern JSObject * js_InitMathClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp index dfa1b99ee4c4..37de586d9ad8 100644 --- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -559,7 +559,7 @@ static JSFunctionSpec number_functions[] = { JS_FS_END }; -Class js_NumberClass = { +Class js::NumberClass = { js_Number_str, JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_HAS_CACHED_PROTO(JSProto_Number), PropertyStub, /* addProperty */ @@ -588,7 +588,7 @@ Number(JSContext *cx, uintN argc, Value *vp) if (!isConstructing) return true; - JSObject *obj = NewBuiltinClassInstance(cx, &js_NumberClass); + JSObject *obj = NewBuiltinClassInstance(cx, &NumberClass); if (!obj) return false; obj->setPrimitiveThis(vp[0]); @@ -612,7 +612,7 @@ num_toSource(JSContext *cx, uintN argc, Value *vp) } char buf[64]; - JS_snprintf(buf, sizeof buf, "(new %s(%s))", js_NumberClass.name, numStr); + JS_snprintf(buf, sizeof buf, "(new %s(%s))", NumberClass.name, numStr); JSString *str = js_NewStringCopyZ(cx, buf); if (!str) return false; @@ -1106,7 +1106,7 @@ js_InitNumberClass(JSContext *cx, JSObject *obj) /* XXX must do at least once per new thread, so do it per JSContext... */ FIX_FPU(); - proto = js_InitClass(cx, obj, NULL, &js_NumberClass, Number, 1, + proto = js_InitClass(cx, obj, NULL, &NumberClass, Number, 1, NULL, number_methods, NULL, NULL); if (!proto || !(ctor = JS_GetConstructor(cx, proto))) return NULL; diff --git a/js/src/jsnum.h b/js/src/jsnum.h index 792968bf0a0e..a12866238c65 100644 --- a/js/src/jsnum.h +++ b/js/src/jsnum.h @@ -160,14 +160,6 @@ FinishRuntimeNumberState(JSRuntime *rt); } /* namespace js */ /* Initialize the Number class, returning its prototype object. */ -extern js::Class js_NumberClass; - -inline bool -JSObject::isNumber() const -{ - return getClass() == &js_NumberClass; -} - extern JSObject * js_InitNumberClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 54ba25276b8a..ae09e2dc86a6 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -115,7 +115,7 @@ using namespace js::types; JS_FRIEND_DATA(js::Shape) Shape::sharedNonNative(SHAPELESS); -Class js_ObjectClass = { +Class js::ObjectClass = { js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_Object), PropertyStub, /* addProperty */ @@ -1800,7 +1800,7 @@ PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc) bool PropDesc::makeObject(JSContext *cx) { - JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass); + JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass); if (!obj) return false; @@ -2630,7 +2630,7 @@ obj_create(JSContext *cx, uintN argc, Value *vp) * Use the callee's global as the parent of the new object to avoid dynamic * scoping (i.e., using the caller's global). */ - JSObject *obj = NewNonFunction(cx, &js_ObjectClass, proto, + JSObject *obj = NewNonFunction(cx, &ObjectClass, proto, vp->toObject().getGlobal()); if (!obj) return JS_FALSE; @@ -2717,6 +2717,15 @@ obj_preventExtensions(JSContext *cx, uintN argc, Value *vp) return obj->preventExtensions(cx, &props); } +size_t +JSObject::sizeOfSlotsArray(size_t(*mus)(void *)) +{ + if (!hasSlotsArray()) + return 0; + size_t usable = mus((void *)slots); + return usable ? usable : numSlots() * sizeof(js::Value); +} + bool JSObject::sealOrFreeze(JSContext *cx, ImmutabilityType it) { @@ -2913,8 +2922,8 @@ js_Object(JSContext *cx, uintN argc, Value *vp) if (!obj) { /* Make an object whether this was called with 'new' or not. */ JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined()); - gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass); - obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass); + obj = NewBuiltinClassInstance(cx, &ObjectClass, kind); if (!obj) return JS_FALSE; TypeObject *type = GetTypeCallerInitObject(cx, JSProto_Object); @@ -2928,7 +2937,7 @@ js_Object(JSContext *cx, uintN argc, Value *vp) JSObject * js::NewReshapedObject(JSContext *cx, TypeObject *type, JSObject *parent, - gc::FinalizeKind kind, const Shape *shape) + gc::AllocKind kind, const Shape *shape) { JSObject *res = NewObjectWithType(cx, type, parent, kind); if (!res) @@ -2966,8 +2975,8 @@ js_CreateThis(JSContext *cx, JSObject *callee) { Class *clasp = callee->getClass(); - Class *newclasp = &js_ObjectClass; - if (clasp == &js_FunctionClass) { + Class *newclasp = &ObjectClass; + if (clasp == &FunctionClass) { JSFunction *fun = callee->getFunctionPrivate(); if (fun->isNative() && fun->u.n.clasp) newclasp = fun->u.n.clasp; @@ -2979,7 +2988,7 @@ js_CreateThis(JSContext *cx, JSObject *callee) JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL; JSObject *parent = callee->getParent(); - gc::FinalizeKind kind = NewObjectGCKind(cx, newclasp); + gc::AllocKind kind = NewObjectGCKind(cx, newclasp); JSObject *obj = NewObject(cx, newclasp, proto, parent, kind); if (obj) obj->syncSpecialEquality(); @@ -2995,14 +3004,14 @@ CreateThisForFunctionWithType(JSContext *cx, types::TypeObject *type, JSObject * * which reflects any properties that will definitely be added to the * object before it is read from. */ - gc::FinalizeKind kind = gc::FinalizeKind(type->newScript->finalizeKind); + gc::AllocKind kind = type->newScript->allocKind; JSObject *res = NewObjectWithType(cx, type, parent, kind); if (res) res->setMap((Shape *) type->newScript->shape); return res; } - gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass); + gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass); return NewObjectWithType(cx, type, parent, kind); } @@ -3018,8 +3027,8 @@ js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *pro return NULL; res = CreateThisForFunctionWithType(cx, type, callee->getParent()); } else { - gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass); - res = NewNonFunction(cx, &js_ObjectClass, proto, callee->getParent(), kind); + gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass); + res = NewNonFunction(cx, &ObjectClass, proto, callee->getParent(), kind); } if (res && cx->typeInferenceEnabled()) @@ -3065,8 +3074,8 @@ js_CreateThisForFunction(JSContext *cx, JSObject *callee, bool newType) JSObject* FASTCALL js_Object_tn(JSContext* cx, JSObject* proto) { - JS_ASSERT(!(js_ObjectClass.flags & JSCLASS_HAS_PRIVATE)); - return NewObjectWithClassProto(cx, &js_ObjectClass, proto, FINALIZE_OBJECT8); + JS_ASSERT(!(ObjectClass.flags & JSCLASS_HAS_PRIVATE)); + return NewObjectWithClassProto(cx, &ObjectClass, proto, FINALIZE_OBJECT8); } JS_DEFINE_TRCINFO_1(js_Object, @@ -3077,8 +3086,8 @@ JSObject* FASTCALL js_InitializerObject(JSContext* cx, JSObject *proto, JSObject *baseobj) { if (!baseobj) { - gc::FinalizeKind kind = GuessObjectGCKind(0, false); - return NewObjectWithClassProto(cx, &js_ObjectClass, proto, kind); + gc::AllocKind kind = GuessObjectGCKind(0, false); + return NewObjectWithClassProto(cx, &ObjectClass, proto, kind); } /* :FIXME: bug 637856 new Objects do not have the right type when created on trace. */ @@ -3129,8 +3138,8 @@ js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot) return NULL; } - gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass); - return NewNativeClassInstance(cx, &js_ObjectClass, proto, parent, kind); + gc::AllocKind kind = NewObjectGCKind(cx, &ObjectClass); + return NewNativeClassInstance(cx, &ObjectClass, proto, parent, kind); } JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, OBJECT, UINTN, 0, nanojit::ACCSET_STORE_ANY) @@ -3309,7 +3318,7 @@ with_ThisObject(JSContext *cx, JSObject *obj) return obj->getWithThis(); } -Class js_WithClass = { +Class js::WithClass = { "With", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(2) | JSCLASS_IS_ANONYMOUS, PropertyStub, /* addProperty */ @@ -3359,7 +3368,7 @@ js_NewWithObject(JSContext *cx, JSObject *proto, JSObject *parent, jsint depth) StackFrame *priv = js_FloatingFrameIfGenerator(cx, cx->fp()); - obj->init(cx, &js_WithClass, type, parent, priv, false); + obj->init(cx, &WithClass, type, parent, priv, false); EmptyShape *emptyWithShape = EmptyShape::getEmptyWithShape(cx); if (!emptyWithShape) @@ -3393,7 +3402,7 @@ js_NewBlockObject(JSContext *cx) EmptyShape *emptyBlockShape = EmptyShape::getEmptyBlockShape(cx); if (!emptyBlockShape) return NULL; - blockObj->init(cx, &js_BlockClass, &emptyTypeObject, NULL, NULL, false); + blockObj->init(cx, &BlockClass, &emptyTypeObject, NULL, NULL, false); blockObj->setMap(emptyBlockShape); return blockObj; @@ -3405,7 +3414,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp) JS_ASSERT(proto->isStaticBlock()); size_t count = OBJ_BLOCK_COUNT(cx, proto); - gc::FinalizeKind kind = gc::GetGCObjectKind(count + 1); + gc::AllocKind kind = gc::GetGCObjectKind(count + 1); TypeObject *type = proto->getNewType(cx); if (!type) @@ -3483,7 +3492,7 @@ block_getProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp) } /* Values are in slots immediately following the class-reserved ones. */ - JS_ASSERT(obj->getSlot(JSSLOT_FREE(&js_BlockClass) + index) == *vp); + JS_ASSERT(obj->getSlot(JSSLOT_FREE(&BlockClass) + index) == *vp); return true; } @@ -3516,7 +3525,7 @@ JSObject::defineBlockVariable(JSContext *cx, jsid id, intN index) JS_ASSERT(isStaticBlock()); /* Use JSPROP_ENUMERATE to aid the disassembler. */ - uint32 slot = JSSLOT_FREE(&js_BlockClass) + index; + uint32 slot = JSSLOT_FREE(&BlockClass) + index; const Shape *shape = addProperty(cx, id, block_getProperty, block_setProperty, slot, JSPROP_ENUMERATE | JSPROP_PERMANENT, @@ -3615,9 +3624,7 @@ JSObject::clone(JSContext *cx, JSObject *proto, JSObject *parent) return NULL; } } - JSObject *clone = NewObject(cx, getClass(), - proto, parent, - gc::FinalizeKind(finalizeKind())); + JSObject *clone = NewObject(cx, getClass(), proto, parent, getAllocKind()); if (!clone) return NULL; if (isNative()) { @@ -3987,7 +3994,7 @@ js_XDRBlockObject(JSXDRState *xdr, JSObject **objp) #endif -Class js_BlockClass = { +Class js::BlockClass = { "Block", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1) | JSCLASS_IS_ANONYMOUS, PropertyStub, /* addProperty */ @@ -4002,7 +4009,7 @@ Class js_BlockClass = { JSObject * js_InitObjectClass(JSContext *cx, JSObject *obj) { - JSObject *proto = js_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1, + JSObject *proto = js_InitClass(cx, obj, NULL, &ObjectClass, js_Object, 1, object_props, object_methods, NULL, object_static_methods); if (!proto) return NULL; @@ -4104,10 +4111,10 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt * otherwise-uninitialized global. * * 3. NewObject allocating a JSFunction-sized GC-thing when clasp is - * &js_FunctionClass, not a JSObject-sized (smaller) GC-thing. + * &FunctionClass, not a JSObject-sized (smaller) GC-thing. * * The JS_NewObjectForGivenProto and JS_NewObject APIs also allow clasp to - * be &js_FunctionClass (we could break compatibility easily). But fixing + * be &FunctionClass (we could break compatibility easily). But fixing * (3) is not enough without addressing the bootstrapping dependency on (1) * and (2). */ @@ -4126,7 +4133,7 @@ DefineConstructorAndPrototype(JSContext *cx, JSObject *obj, JSProtoKey key, JSAt if (!proto->setSingletonType(cx)) return NULL; - if (clasp == &js_ArrayClass && !proto->makeDenseArraySlow(cx)) + if (clasp == &ArrayClass && !proto->makeDenseArraySlow(cx)) return NULL; TypeObject *type = proto->getNewType(cx); @@ -4364,16 +4371,15 @@ JSObject::allocSlots(JSContext *cx, size_t newcap) * objects are constructed. */ if (!hasLazyType() && type()->newScript) { - gc::FinalizeKind kind = gc::FinalizeKind(type()->newScript->finalizeKind); + gc::AllocKind kind = type()->newScript->allocKind; unsigned newScriptSlots = gc::GetGCKindSlots(kind); - if (newScriptSlots == numFixedSlots() && gc::CanBumpFinalizeKind(kind)) { - kind = gc::BumpFinalizeKind(kind); + if (newScriptSlots == numFixedSlots() && gc::TryIncrementAllocKind(&kind)) { JSObject *obj = NewReshapedObject(cx, type(), getParent(), kind, type()->newScript->shape); if (!obj) return false; - type()->newScript->finalizeKind = kind; + type()->newScript->allocKind = kind; type()->newScript->shape = obj->lastProperty(); type()->markStateChange(cx); } @@ -5101,7 +5107,7 @@ DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, const Value &value, if (!shape) { /* Add a new property, or replace an existing one of the same id. */ if (defineHow & DNP_SET_METHOD) { - JS_ASSERT(clasp == &js_ObjectClass); + JS_ASSERT(clasp == &ObjectClass); JS_ASSERT(IsFunctionObject(value)); JS_ASSERT(!(attrs & (JSPROP_GETTER | JSPROP_SETTER))); JS_ASSERT(!getter && !setter); @@ -5403,10 +5409,9 @@ js_FindPropertyHelper(JSContext *cx, jsid id, bool cacheResult, bool global, if (prop) { #ifdef DEBUG if (parent) { - Class *clasp = obj->getClass(); JS_ASSERT(pobj->isNative()); - JS_ASSERT(pobj->getClass() == clasp); - if (clasp == &js_BlockClass) { + JS_ASSERT(pobj->getClass() == obj->getClass()); + if (obj->isBlock()) { /* * A block instance on the scope chain is immutable and * shares its shape with the compile-time prototype. Thus @@ -6299,9 +6304,9 @@ DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp) Class *clasp = obj->getClass(); if (hint == JSTYPE_STRING) { /* Optimize (new String(...)).toString(). */ - if (clasp == &js_StringClass && + if (clasp == &StringClass && ClassMethodIsNative(cx, obj, - &js_StringClass, + &StringClass, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), js_str_toString)) { *vp = obj->getPrimitiveThis(); @@ -6319,12 +6324,12 @@ DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp) return true; } else { /* Optimize (new String(...)).valueOf(). */ - if ((clasp == &js_StringClass && - ClassMethodIsNative(cx, obj, &js_StringClass, + if ((clasp == &StringClass && + ClassMethodIsNative(cx, obj, &StringClass, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), js_str_toString)) || - (clasp == &js_NumberClass && - ClassMethodIsNative(cx, obj, &js_NumberClass, + (clasp == &NumberClass && + ClassMethodIsNative(cx, obj, &NumberClass, ATOM_TO_JSID(cx->runtime->atomState.valueOfAtom), js_num_valueOf))) { *vp = obj->getPrimitiveThis(); @@ -6393,7 +6398,7 @@ CheckAccess(JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, JSSecurityCallbacks *callbacks; CheckAccessOp check; - while (JS_UNLIKELY(obj->getClass() == &js_WithClass)) + while (JS_UNLIKELY(obj->isWith())) obj = obj->getProto(); writing = (mode & JSACC_WRITE) != 0; @@ -6545,7 +6550,7 @@ PrimitiveToObject(JSContext *cx, const Value &v) return StringObject::create(cx, v.toString()); JS_ASSERT(v.isNumber() || v.isBoolean()); - Class *clasp = v.isNumber() ? &js_NumberClass : &js_BooleanClass; + Class *clasp = v.isNumber() ? &NumberClass : &BooleanClass; JSObject *obj = NewBuiltinClassInstance(cx, clasp); if (!obj) return NULL; @@ -6943,7 +6948,7 @@ dumpValue(const Value &v) Class *clasp = obj->getClass(); fprintf(stderr, "<%s%s at %p>", clasp->name, - (clasp == &js_ObjectClass) ? "" : " object", + (clasp == &ObjectClass) ? "" : " object", (void *) obj); } else if (v.isBoolean()) { if (v.toBoolean()) diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 540bf04c388d..380e4f84efea 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -59,11 +59,15 @@ #include "jsvector.h" #include "jscell.h" +namespace nanojit { class ValidateWriter; } + namespace js { -class JSProxyHandler; class AutoPropDescArrayRooter; +class JSProxyHandler; +class RegExp; struct GCMarker; +struct NativeIterator; namespace mjit { class Compiler; } @@ -284,26 +288,54 @@ js_TypeOf(JSContext *cx, JSObject *obj); namespace js { -struct NativeIterator; -class RegExp; - -class GlobalObject; -class ArgumentsObject; -class NormalArgumentsObject; -class StrictArgumentsObject; -class StringObject; - /* ES5 8.12.8. */ extern JSBool DefaultValue(JSContext *cx, JSObject *obj, JSType hint, Value *vp); -} +extern JS_FRIEND_DATA(Class) AnyNameClass; +extern JS_FRIEND_DATA(Class) AttributeNameClass; +extern JS_FRIEND_DATA(Class) CallClass; +extern JS_FRIEND_DATA(Class) DeclEnvClass; +extern JS_FRIEND_DATA(Class) FunctionClass; +extern JS_FRIEND_DATA(Class) FunctionProxyClass; +extern JS_FRIEND_DATA(Class) NamespaceClass; +extern JS_FRIEND_DATA(Class) OuterWindowProxyClass; +extern JS_FRIEND_DATA(Class) ObjectProxyClass; +extern JS_FRIEND_DATA(Class) QNameClass; +extern JS_FRIEND_DATA(Class) ScriptClass; +extern JS_FRIEND_DATA(Class) XMLClass; -struct JSFunction; +extern Class ArrayClass; +extern Class ArrayBufferClass; +extern Class BlockClass; +extern Class BooleanClass; +extern Class CallableObjectClass; +extern Class DateClass; +extern Class ErrorClass; +extern Class GeneratorClass; +extern Class IteratorClass; +extern Class JSONClass; +extern Class MathClass; +extern Class NumberClass; +extern Class NormalArgumentsObjectClass; +extern Class ObjectClass; +extern Class ProxyClass; +extern Class RegExpClass; +extern Class SlowArrayClass; +extern Class StopIterationClass; +extern Class StringClass; +extern Class StrictArgumentsObjectClass; +extern Class WeakMapClass; +extern Class WithClass; +extern Class XMLFilterClass; -namespace nanojit { -class ValidateWriter; -} +class ArgumentsObject; +class GlobalObject; +class NormalArgumentsObject; +class StrictArgumentsObject; +class StringObject; + +} /* namespace js */ /* * JSObject struct, with members sized to fit in 32 bytes on 32-bit targets, @@ -376,9 +408,9 @@ struct JSObject : js::gc::Cell { */ js::Shape *lastProp; + private: js::Class *clasp; - private: inline void setLastProperty(const js::Shape *shape); inline void removeLastProperty(); @@ -446,6 +478,8 @@ struct JSObject : js::gc::Cell { jsuword initializedLength; }; + JS_FRIEND_API(size_t) sizeOfSlotsArray(size_t(*mus)(void *)); + JSObject *parent; /* object's parent */ void *privateData; /* private data */ jsuword capacity; /* total number of available slots */ @@ -470,6 +504,7 @@ struct JSObject : js::gc::Cell { inline bool isNative() const; inline bool isNewborn() const; + void setClass(js::Class *c) { clasp = c; } js::Class *getClass() const { return clasp; } JSClass *getJSClass() const { return Jsvalify(clasp); } @@ -664,8 +699,6 @@ struct JSObject : js::gc::Cell { inline bool hasPropertyTable() const; - /* gc::FinalizeKind */ unsigned finalizeKind() const; - uint32 numSlots() const { return uint32(capacity); } inline size_t structSize() const; @@ -1200,10 +1233,10 @@ struct JSObject : js::gc::Cell { /* * Slots for XML-related classes are as follows: - * - js_NamespaceClass.base reserves the *_NAME_* and *_NAMESPACE_* slots. - * - js_QNameClass.base, js_AttributeNameClass, js_AnyNameClass reserve + * - NamespaceClass.base reserves the *_NAME_* and *_NAMESPACE_* slots. + * - QNameClass.base, AttributeNameClass, AnyNameClass reserve * the *_NAME_* and *_QNAME_* slots. - * - Others (js_XMLClass, js_XMLFilterClass) don't reserve any slots. + * - Others (XMLClass, js_XMLFilterClass) don't reserve any slots. */ private: static const uint32 JSSLOT_NAME_PREFIX = 0; // shared @@ -1279,7 +1312,7 @@ struct JSObject : js::gc::Cell { js::types::TypeObject *type, JSObject *parent, void *priv, - /* gc::FinalizeKind */ unsigned kind); + js::gc::AllocKind kind); inline bool hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags = 0); @@ -1433,43 +1466,57 @@ struct JSObject : js::gc::Cell { inline bool canHaveMethodBarrier() const; - inline bool isArguments() const; - inline bool isNormalArguments() const; - inline bool isStrictArguments() const; - inline bool isArray() const; - inline bool isDenseArray() const; - inline bool isSlowArray() const; - inline bool isNumber() const; - inline bool isBoolean() const; - inline bool isString() const; - inline bool isPrimitive() const; - inline bool isDate() const; - inline bool isFunction() const; - inline bool isObject() const; - inline bool isWith() const; - inline bool isBlock() const; - inline bool isStaticBlock() const; - inline bool isClonedBlock() const; - inline bool isCall() const; - inline bool isRegExp() const; - inline bool isScript() const; - inline bool isError() const; - inline bool isXML() const; - inline bool isXMLId() const; - inline bool isNamespace() const; - inline bool isQName() const; - inline bool isWeakMap() const; + inline bool isArguments() const { return isNormalArguments() || isStrictArguments(); } + inline bool isArrayBuffer() const { return clasp == &js::ArrayBufferClass; } + inline bool isNormalArguments() const { return clasp == &js::NormalArgumentsObjectClass; } + inline bool isStrictArguments() const { return clasp == &js::StrictArgumentsObjectClass; } + inline bool isArray() const { return isSlowArray() || isDenseArray(); } + inline bool isDenseArray() const { return clasp == &js::ArrayClass; } + inline bool isSlowArray() const { return clasp == &js::SlowArrayClass; } + inline bool isNumber() const { return clasp == &js::NumberClass; } + inline bool isBoolean() const { return clasp == &js::BooleanClass; } + inline bool isString() const { return clasp == &js::StringClass; } + inline bool isPrimitive() const { return isNumber() || isString() || isBoolean(); } + inline bool isDate() const { return clasp == &js::DateClass; } + inline bool isFunction() const { return clasp == &js::FunctionClass; } + inline bool isObject() const { return clasp == &js::ObjectClass; } + inline bool isWith() const { return clasp == &js::WithClass; } + inline bool isBlock() const { return clasp == &js::BlockClass; } + inline bool isStaticBlock() const { return isBlock() && !getProto(); } + inline bool isClonedBlock() const { return isBlock() && !!getProto(); } + inline bool isCall() const { return clasp == &js::CallClass; } + inline bool isDeclEnv() const { return clasp == &js::DeclEnvClass; } + inline bool isRegExp() const { return clasp == &js::RegExpClass; } + inline bool isScript() const { return clasp == &js::ScriptClass; } + inline bool isGenerator() const { return clasp == &js::GeneratorClass; } + inline bool isIterator() const { return clasp == &js::IteratorClass; } + inline bool isStopIteration() const { return clasp == &js::StopIterationClass; } + inline bool isError() const { return clasp == &js::ErrorClass; } + inline bool isXML() const { return clasp == &js::XMLClass; } + inline bool isNamespace() const { return clasp == &js::NamespaceClass; } + inline bool isWeakMap() const { return clasp == &js::WeakMapClass; } + inline bool isFunctionProxy() const { return clasp == &js::FunctionProxyClass; } + inline bool isProxy() const { return isObjectProxy() || isFunctionProxy(); } - inline bool isProxy() const; - inline bool isObjectProxy() const; - inline bool isFunctionProxy() const; - inline bool isArrayBuffer() const; + inline bool isXMLId() const { + return clasp == &js::QNameClass || clasp == &js::AttributeNameClass || clasp == &js::AnyNameClass; + } + inline bool isQName() const { + return clasp == &js::QNameClass || clasp == &js::AttributeNameClass || clasp == &js::AnyNameClass; + } + inline bool isObjectProxy() const { + return clasp == &js::ObjectProxyClass || clasp == &js::OuterWindowProxyClass; + } JS_FRIEND_API(bool) isWrapper() const; bool isCrossCompartmentWrapper() const; JS_FRIEND_API(JSObject *) unwrap(uintN *flagsp = NULL); inline void initArrayClass(); + + /*** For jit compiler: ***/ + + static size_t offsetOfClassPointer() { return offsetof(JSObject, clasp); } }; /* Check alignment for any fixed slots allocated after the object. */ @@ -1568,42 +1615,8 @@ class ValueArray { ValueArray(js::Value *v, size_t c) : array(v), length(c) {} }; -extern js::Class js_ArrayClass, js_SlowArrayClass, js_ArrayBufferClass; - -inline bool -JSObject::isDenseArray() const -{ - return getClass() == &js_ArrayClass; -} - -inline bool -JSObject::isSlowArray() const -{ - return getClass() == &js_SlowArrayClass; -} - -inline bool -JSObject::isArray() const -{ - return isDenseArray() || isSlowArray(); -} - -inline bool -JSObject::isArrayBuffer() const -{ - return getClass() == &js_ArrayBufferClass; -} - -extern js::Class js_ObjectClass; -extern js::Class js_WithClass; -extern js::Class js_BlockClass; - -inline bool JSObject::isObject() const { return getClass() == &js_ObjectClass; } -inline bool JSObject::isWith() const { return getClass() == &js_WithClass; } -inline bool JSObject::isBlock() const { return getClass() == &js_BlockClass; } - /* - * Block scope object macros. The slots reserved by js_BlockClass are: + * Block scope object macros. The slots reserved by BlockClass are: * * private StackFrame * active frame pointer or null * JSSLOT_BLOCK_DEPTH int depth of block slots in frame @@ -1827,9 +1840,6 @@ extern JSBool js_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, const js::Value &descriptor, JSBool *bp); -extern JS_FRIEND_DATA(js::Class) js_CallClass; -extern JS_FRIEND_DATA(js::Class) js_DeclEnvClass; - namespace js { /* @@ -1898,9 +1908,9 @@ IsCacheableNonGlobalScope(JSObject *obj) JS_ASSERT(obj->getParent()); js::Class *clasp = obj->getClass(); - bool cacheable = (clasp == &js_CallClass || - clasp == &js_BlockClass || - clasp == &js_DeclEnvClass); + bool cacheable = (clasp == &CallClass || + clasp == &BlockClass || + clasp == &DeclEnvClass); JS_ASSERT_IF(cacheable, !obj->getOps()->lookupProperty); return cacheable; diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 8fcc22281d1a..ea9a15e8d62d 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -198,7 +198,7 @@ JSObject::finalize(JSContext *cx) inline void JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent) { - init(cx, &js_CallClass, &js::types::emptyTypeObject, parent, NULL, false); + init(cx, &js::CallClass, &js::types::emptyTypeObject, parent, NULL, false); lastProp = bindings.lastShape(); /* @@ -218,7 +218,7 @@ JSObject::initCall(JSContext *cx, const js::Bindings &bindings, JSObject *parent inline void JSObject::initClonedBlock(JSContext *cx, js::types::TypeObject *type, js::StackFrame *frame) { - init(cx, &js_BlockClass, type, NULL, frame, false); + init(cx, &js::BlockClass, type, NULL, frame, false); /* Cloned blocks copy their prototype's map; it had better be shareable. */ JS_ASSERT(!getProto()->inDictionaryMode() || getProto()->lastProp->frozen()); @@ -382,12 +382,6 @@ JSObject::canHaveMethodBarrier() const return isObject() || isFunction() || isPrimitive() || isDate(); } -inline bool -JSObject::isPrimitive() const -{ - return isNumber() || isString() || isBoolean(); -} - inline const js::Value & JSObject::getPrimitiveThis() const { @@ -402,12 +396,6 @@ JSObject::setPrimitiveThis(const js::Value &pthis) setFixedSlot(JSSLOT_PRIMITIVE_THIS, pthis); } -inline /* gc::FinalizeKind */ unsigned -JSObject::finalizeKind() const -{ - return js::gc::FinalizeKind(arenaHeader()->getThingKind()); -} - inline bool JSObject::hasSlotsArray() const { @@ -917,7 +905,7 @@ JSObject::init(JSContext *cx, js::Class *aclasp, js::types::TypeObject *type, clasp = aclasp; flags = capacity << FIXED_SLOTS_SHIFT; - JS_ASSERT(denseArray == (aclasp == &js_ArrayClass)); + JS_ASSERT(denseArray == (aclasp == &js::ArrayClass)); #ifdef DEBUG /* @@ -964,7 +952,7 @@ JSObject::initSharingEmptyShape(JSContext *cx, js::types::TypeObject *type, JSObject *parent, void *privateValue, - /* js::gc::FinalizeKind */ unsigned kind) + js::gc::AllocKind kind) { init(cx, aclasp, type, parent, privateValue, false); @@ -1174,22 +1162,10 @@ js_IsCallable(const js::Value &v) return v.isObject() && v.toObject().isCallable(); } -inline bool -JSObject::isStaticBlock() const -{ - return isBlock() && !getProto(); -} - -inline bool -JSObject::isClonedBlock() const -{ - return isBlock() && !!getProto(); -} - inline JSObject * js_UnwrapWithObject(JSContext *cx, JSObject *withobj) { - JS_ASSERT(withobj->getClass() == &js_WithClass); + JS_ASSERT(withobj->isWith()); return withobj->getProto(); } @@ -1245,7 +1221,7 @@ class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescri static inline bool InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, js::types::TypeObject *type, - gc::FinalizeKind kind) + gc::AllocKind kind) { JS_ASSERT(clasp->isNative()); @@ -1273,7 +1249,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, js::types::Ty } static inline bool -CanBeFinalizedInBackground(gc::FinalizeKind kind, Class *clasp) +CanBeFinalizedInBackground(gc::AllocKind kind, Class *clasp) { #ifdef JS_THREADSAFE JS_ASSERT(kind <= gc::FINALIZE_OBJECT_LAST); @@ -1281,10 +1257,10 @@ CanBeFinalizedInBackground(gc::FinalizeKind kind, Class *clasp) * a different thread, we change the finalize kind. For example, * FINALIZE_OBJECT0 calls the finalizer on the main thread, * FINALIZE_OBJECT0_BACKGROUND calls the finalizer on the gcHelperThread. - * IsBackgroundFinalizeKind is called to prevent recursively incrementing + * IsBackgroundAllocKind is called to prevent recursively incrementing * the finalize kind; kind may already be a background finalize kind. */ - if (!gc::IsBackgroundFinalizeKind(kind) && + if (!gc::IsBackgroundAllocKind(kind) && (!clasp->finalize || clasp->flags & JSCLASS_CONCURRENT_FINALIZER)) { return true; } @@ -1300,7 +1276,7 @@ CanBeFinalizedInBackground(gc::FinalizeKind kind, Class *clasp) */ static inline JSObject * NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, - JSObject *parent, gc::FinalizeKind kind) + JSObject *parent, gc::AllocKind kind) { JS_ASSERT(proto); JS_ASSERT(parent); @@ -1316,7 +1292,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, */ if (CanBeFinalizedInBackground(kind, clasp)) - kind = GetBackgroundFinalizeKind(kind); + kind = GetBackgroundAllocKind(kind); JSObject* obj = js_NewGCObject(cx, kind); @@ -1325,7 +1301,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, * Default parent to the parent of the prototype, which was set from * the parent of the prototype's constructor. */ - bool denseArray = (clasp == &js_ArrayClass); + bool denseArray = (clasp == &ArrayClass); obj->init(cx, clasp, type, parent, NULL, denseArray); JS_ASSERT(type->canProvideEmptyShape(clasp)); @@ -1343,7 +1319,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, static inline JSObject * NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent) { - gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); + gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); return NewNativeClassInstance(cx, clasp, proto, parent, kind); } @@ -1358,7 +1334,7 @@ FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject * right default proto and parent for clasp in cx. */ static inline JSObject * -NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::FinalizeKind kind) +NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::AllocKind kind) { VOUCH_DOES_NOT_REQUIRE_STACK(); @@ -1392,7 +1368,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::FinalizeKind kind) static inline JSObject * NewBuiltinClassInstance(JSContext *cx, Class *clasp) { - gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); + gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); return NewBuiltinClassInstance(cx, clasp, kind); } @@ -1457,7 +1433,7 @@ namespace detail template static JS_ALWAYS_INLINE JSObject * NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, - gc::FinalizeKind kind) + gc::AllocKind kind) { /* Bootstrap the ur-object, and make it the default prototype object. */ if (withProto == WithProto::Class && !proto) { @@ -1478,7 +1454,7 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, */ if (!isFunction && CanBeFinalizedInBackground(kind, clasp)) - kind = GetBackgroundFinalizeKind(kind); + kind = GetBackgroundAllocKind(kind); JSObject* obj = isFunction ? js_NewGCFunction(cx) : js_NewGCObject(cx, kind); if (!obj) @@ -1493,7 +1469,7 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, */ obj->init(cx, clasp, type, (!parent && proto) ? proto->getParent() : parent, - NULL, clasp == &js_ArrayClass); + NULL, clasp == &ArrayClass); if (clasp->isNative()) { if (!InitScopeForObject(cx, obj, clasp, type, kind)) { @@ -1516,21 +1492,21 @@ NewFunction(JSContext *cx, js::GlobalObject &global) JSObject *proto; if (!js_GetClassPrototype(cx, &global, JSProto_Function, &proto)) return NULL; - return detail::NewObject(cx, &js_FunctionClass, proto, &global, + return detail::NewObject(cx, &FunctionClass, proto, &global, gc::FINALIZE_OBJECT2); } static JS_ALWAYS_INLINE JSObject * NewFunction(JSContext *cx, JSObject *parent) { - return detail::NewObject(cx, &js_FunctionClass, NULL, parent, + return detail::NewObject(cx, &FunctionClass, NULL, parent, gc::FINALIZE_OBJECT2); } template static JS_ALWAYS_INLINE JSObject * NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, - gc::FinalizeKind kind) + gc::AllocKind kind) { return detail::NewObject(cx, clasp, proto, parent, kind); } @@ -1539,16 +1515,16 @@ template static JS_ALWAYS_INLINE JSObject * NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent) { - gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); + gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); return detail::NewObject(cx, clasp, proto, parent, kind); } template static JS_ALWAYS_INLINE JSObject * NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent, - gc::FinalizeKind kind) + gc::AllocKind kind) { - if (clasp == &js_FunctionClass) + if (clasp == &FunctionClass) return detail::NewObject(cx, clasp, proto, parent, kind); return detail::NewObject(cx, clasp, proto, parent, kind); } @@ -1557,7 +1533,7 @@ template static JS_ALWAYS_INLINE JSObject * NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent) { - gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); + gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp)); return NewObject(cx, clasp, proto, parent, kind); } @@ -1566,12 +1542,12 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent) * avoid losing creation site information for objects made by scripted 'new'. */ static JS_ALWAYS_INLINE JSObject * -NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::FinalizeKind kind) +NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind) { JS_ASSERT(type == type->proto->newType); - if (CanBeFinalizedInBackground(kind, &js_ObjectClass)) - kind = GetBackgroundFinalizeKind(kind); + if (CanBeFinalizedInBackground(kind, &ObjectClass)) + kind = GetBackgroundAllocKind(kind); JSObject* obj = js_NewGCObject(cx, kind); if (!obj) @@ -1581,11 +1557,11 @@ NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc:: * Default parent to the parent of the prototype, which was set from * the parent of the prototype's constructor. */ - obj->init(cx, &js_ObjectClass, type, + obj->init(cx, &ObjectClass, type, (!parent && type->proto) ? type->proto->getParent() : parent, NULL, false); - if (!InitScopeForObject(cx, obj, &js_ObjectClass, type, kind)) { + if (!InitScopeForObject(cx, obj, &ObjectClass, type, kind)) { obj = NULL; goto out; } @@ -1597,14 +1573,14 @@ out: extern JSObject * NewReshapedObject(JSContext *cx, js::types::TypeObject *type, JSObject *parent, - gc::FinalizeKind kind, const Shape *shape); + gc::AllocKind kind, const Shape *shape); /* * As for gc::GetGCObjectKind, where numSlots is a guess at the final size of * the object, zero if the final size is unknown. This should only be used for * objects that do not require any fixed slots. */ -static inline gc::FinalizeKind +static inline gc::AllocKind GuessObjectGCKind(size_t numSlots, bool isArray) { if (numSlots) @@ -1616,29 +1592,28 @@ GuessObjectGCKind(size_t numSlots, bool isArray) * Get the GC kind to use for scripted 'new' on the given class. * FIXME bug 547327: estimate the size from the allocation site. */ -static inline gc::FinalizeKind +static inline gc::AllocKind NewObjectGCKind(JSContext *cx, js::Class *clasp) { - if (clasp == &js_ArrayClass || clasp == &js_SlowArrayClass) + if (clasp == &ArrayClass || clasp == &SlowArrayClass) return gc::FINALIZE_OBJECT8; - if (clasp == &js_FunctionClass) + if (clasp == &FunctionClass) return gc::FINALIZE_OBJECT2; return gc::FINALIZE_OBJECT4; } static JS_ALWAYS_INLINE JSObject* NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto, - /*gc::FinalizeKind*/ unsigned _kind) + gc::AllocKind kind) { JS_ASSERT(clasp->isNative()); - gc::FinalizeKind kind = gc::FinalizeKind(_kind); types::TypeObject *type = proto->getNewType(cx); if (!type) return NULL; if (CanBeFinalizedInBackground(kind, clasp)) - kind = GetBackgroundFinalizeKind(kind); + kind = GetBackgroundAllocKind(kind); JSObject* obj = js_NewGCObject(cx, kind); if (!obj) @@ -1653,11 +1628,10 @@ NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto, static inline JSObject * CopyInitializerObject(JSContext *cx, JSObject *baseobj, types::TypeObject *type) { - JS_ASSERT(baseobj->getClass() == &js_ObjectClass); + JS_ASSERT(baseobj->getClass() == &ObjectClass); JS_ASSERT(!baseobj->inDictionaryMode()); - gc::FinalizeKind kind = gc::FinalizeKind(baseobj->finalizeKind()); - JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, baseobj->getAllocKind()); if (!obj || !obj->ensureSlots(cx, baseobj->numSlots())) return NULL; diff --git a/js/src/json.cpp b/js/src/json.cpp index bead7654433b..8ddb33cf5d0a 100644 --- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -74,7 +74,7 @@ using namespace js; using namespace js::gc; using namespace js::types; -Class js_JSONClass = { +Class js::JSONClass = { js_JSON_str, JSCLASS_HAS_CACHED_PROTO(JSProto_JSON), PropertyStub, /* addProperty */ @@ -344,17 +344,17 @@ PreprocessValue(JSContext *cx, JSObject *holder, jsid key, Value *vp, StringifyC if (vp->isObject()) { JSObject *obj = &vp->toObject(); Class *clasp = obj->getClass(); - if (clasp == &js_NumberClass) { + if (clasp == &NumberClass) { double d; if (!ToNumber(cx, *vp, &d)) return false; vp->setNumber(d); - } else if (clasp == &js_StringClass) { + } else if (clasp == &StringClass) { JSString *str = js_ValueToString(cx, *vp); if (!str) return false; vp->setString(str); - } else if (clasp == &js_BooleanClass) { + } else if (clasp == &BooleanClass) { *vp = obj->getPrimitiveThis(); JS_ASSERT(vp->isBoolean()); } @@ -725,7 +725,7 @@ js_Stringify(JSContext *cx, Value *vp, JSObject *replacer, Value space, StringBu } /* Step 9. */ - JSObject *wrapper = NewBuiltinClassInstance(cx, &js_ObjectClass); + JSObject *wrapper = NewBuiltinClassInstance(cx, &ObjectClass); if (!wrapper) return false; @@ -856,7 +856,7 @@ static bool Revive(JSContext *cx, const Value &reviver, Value *vp) { - JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass); + JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass); if (!obj) return false; @@ -910,7 +910,7 @@ static JSFunctionSpec json_static_methods[] = { JSObject * js_InitJSONClass(JSContext *cx, JSObject *obj) { - JSObject *JSON = NewNonFunction(cx, &js_JSONClass, NULL, obj); + JSObject *JSON = NewNonFunction(cx, &JSONClass, NULL, obj); if (!JSON || !JSON->setSingletonType(cx)) return NULL; @@ -921,7 +921,7 @@ js_InitJSONClass(JSContext *cx, JSObject *obj) if (!JS_DefineFunctions(cx, JSON, json_static_methods)) return NULL; - MarkStandardClassInitializedNoProto(obj, &js_JSONClass); + MarkStandardClassInitializedNoProto(obj, &JSONClass); return JSON; } diff --git a/js/src/json.h b/js/src/json.h index 907038473b58..d1b9d0e1f321 100644 --- a/js/src/json.h +++ b/js/src/json.h @@ -46,8 +46,6 @@ #define JSON_MAX_DEPTH 2048 #define JSON_PARSER_BUFSIZE 1024 -extern js::Class js_JSONClass; - extern JSObject * js_InitJSONClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jsonparser.cpp b/js/src/jsonparser.cpp index 3c240be91c07..7ba941aeac03 100644 --- a/js/src/jsonparser.cpp +++ b/js/src/jsonparser.cpp @@ -634,7 +634,7 @@ JSONParser::parse(Value *vp) } case ObjectOpen: { - JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass); + JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass); if (!obj || !valueStack.append(ObjectValue(*obj))) return false; token = advanceAfterObjectOpen(); diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 04480ebd528e..f47fbcfb94f5 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -366,7 +366,7 @@ ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes) JSObject *obj = JSVAL_TO_OBJECT(v); Class *clasp = obj->getClass(); - if (clasp == &js_BlockClass) { + if (clasp == &BlockClass) { char *source = JS_sprintf_append(NULL, "depth %d {", OBJ_BLOCK_DEPTH(cx, obj)); if (!source) return false; @@ -393,7 +393,7 @@ ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes) return true; } - if (clasp == &js_FunctionClass) { + if (clasp == &FunctionClass) { JSFunction *fun = obj->getFunctionPrivate(); JSString *str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT); if (!str) @@ -401,7 +401,7 @@ ToDisassemblySource(JSContext *cx, jsval v, JSAutoByteString *bytes) return bytes->encode(cx, str); } - if (clasp == &js_RegExpClass) { + if (clasp == &RegExpClass) { AutoValueRooter tvr(cx); if (!js_regexp_toString(cx, obj, tvr.addr())) return false; diff --git a/js/src/jsprobes.h b/js/src/jsprobes.h index dce663a23fab..ac3f55164b8d 100644 --- a/js/src/jsprobes.h +++ b/js/src/jsprobes.h @@ -354,13 +354,13 @@ Probes::resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize) #ifdef INCLUDE_MOZILLA_DTRACE static const char *ObjectClassname(JSObject *obj) { - if (! obj) + if (!obj) return "(null object)"; Class *clasp = obj->getClass(); - if (! clasp) + if (!clasp) return "(null)"; const char *class_name = clasp->name; - if (! class_name) + if (!class_name) return "(null class name)"; return class_name; } diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 44f157bdd270..7e7392f6307c 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -57,8 +57,6 @@ using namespace js; using namespace js::gc; -namespace js { - static inline const Value & GetCall(JSObject *proxy) { JS_ASSERT(proxy->isFunctionProxy()); @@ -413,7 +411,7 @@ ValueToBool(JSContext *cx, const Value &v, bool *bp) return true; } -bool +static bool ArrayToIdVector(JSContext *cx, const Value &array, AutoIdVector &props) { JS_ASSERT(props.length() == 0); @@ -1027,7 +1025,7 @@ proxy_TypeOf(JSContext *cx, JSObject *proxy) return JSProxy::typeOf(cx, proxy); } -JS_FRIEND_API(Class) ObjectProxyClass = { +JS_FRIEND_DATA(Class) js::ObjectProxyClass = { "Proxy", Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(3), PropertyStub, /* addProperty */ @@ -1062,7 +1060,7 @@ JS_FRIEND_API(Class) ObjectProxyClass = { } }; -JS_FRIEND_API(Class) OuterWindowProxyClass = { +JS_FRIEND_DATA(Class) js::OuterWindowProxyClass = { "Proxy", Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(3), PropertyStub, /* addProperty */ @@ -1102,7 +1100,7 @@ JS_FRIEND_API(Class) OuterWindowProxyClass = { } }; -JSBool +static JSBool proxy_Call(JSContext *cx, uintN argc, Value *vp) { JSObject *proxy = &JS_CALLEE(cx, vp).toObject(); @@ -1110,7 +1108,7 @@ proxy_Call(JSContext *cx, uintN argc, Value *vp) return JSProxy::call(cx, proxy, argc, vp); } -JSBool +static JSBool proxy_Construct(JSContext *cx, uintN argc, Value *vp) { JSObject *proxy = &JS_CALLEE(cx, vp).toObject(); @@ -1119,7 +1117,7 @@ proxy_Construct(JSContext *cx, uintN argc, Value *vp) return ok; } -JS_FRIEND_API(Class) FunctionProxyClass = { +JS_FRIEND_DATA(Class) js::FunctionProxyClass = { "Proxy", Class::NON_NATIVE | JSCLASS_HAS_RESERVED_SLOTS(5), PropertyStub, /* addProperty */ @@ -1135,7 +1133,7 @@ JS_FRIEND_API(Class) FunctionProxyClass = { proxy_Call, proxy_Construct, NULL, /* xdrObject */ - js_FunctionClass.hasInstance, + FunctionClass.hasInstance, proxy_TraceFunction, /* trace */ JS_NULL_CLASS_EXT, { @@ -1155,7 +1153,7 @@ JS_FRIEND_API(Class) FunctionProxyClass = { }; JS_FRIEND_API(JSObject *) -NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObject *proto, +js::NewProxyObject(JSContext *cx, JSProxyHandler *handler, const Value &priv, JSObject *proto, JSObject *parent, JSObject *call, JSObject *construct) { JS_ASSERT_IF(proto, cx->compartment == proto->compartment()); @@ -1311,8 +1309,6 @@ static JSFunctionSpec static_methods[] = { JS_FS_END }; -extern Class CallableObjectClass; - static const uint32 JSSLOT_CALLABLE_CALL = 0; static const uint32 JSSLOT_CALLABLE_CONSTRUCT = 1; @@ -1355,7 +1351,7 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp) return false; } - JSObject *newobj = NewNativeClassInstance(cx, &js_ObjectClass, proto, proto->getParent()); + JSObject *newobj = NewNativeClassInstance(cx, &ObjectClass, proto, proto->getParent()); if (!newobj) return false; @@ -1376,7 +1372,7 @@ callable_Construct(JSContext *cx, uintN argc, Value *vp) return ok; } -Class CallableObjectClass = { +Class js::CallableObjectClass = { "Function", JSCLASS_HAS_RESERVED_SLOTS(2), PropertyStub, /* addProperty */ @@ -1394,7 +1390,7 @@ Class CallableObjectClass = { }; JS_FRIEND_API(JSBool) -FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp) +js::FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp) { if (OperationInProgress(cx, proxy)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROXY_FIX); @@ -1415,13 +1411,13 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp) JSObject *proto = proxy->getProto(); JSObject *parent = proxy->getParent(); - Class *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &js_ObjectClass; + Class *clasp = proxy->isFunctionProxy() ? &CallableObjectClass : &ObjectClass; /* * Make a blank object from the recipe fix provided to us. This must have * number of fixed slots as the proxy so that we can swap their contents. */ - gc::FinalizeKind kind = gc::FinalizeKind(proxy->arenaHeader()->getThingKind()); + gc::AllocKind kind = proxy->getAllocKind(); JSObject *newborn = NewNonFunction(cx, clasp, proto, parent, kind); if (!newborn) return false; @@ -1448,9 +1444,7 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp) return true; } -} - -Class js_ProxyClass = { +Class js::ProxyClass = { "Proxy", JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy), PropertyStub, /* addProperty */ @@ -1465,7 +1459,7 @@ Class js_ProxyClass = { JS_FRIEND_API(JSObject *) js_InitProxyClass(JSContext *cx, JSObject *obj) { - JSObject *module = NewNonFunction(cx, &js_ProxyClass, NULL, obj); + JSObject *module = NewNonFunction(cx, &ProxyClass, NULL, obj); if (!module || !module->setSingletonType(cx)) return NULL; @@ -1476,7 +1470,7 @@ js_InitProxyClass(JSContext *cx, JSObject *obj) if (!JS_DefineFunctions(cx, module, static_methods)) return NULL; - MarkStandardClassInitializedNoProto(obj, &js_ProxyClass); + MarkStandardClassInitializedNoProto(obj, &ProxyClass); return module; } diff --git a/js/src/jsproxy.h b/js/src/jsproxy.h index 5f7b2769cfdd..078cd8c78f36 100644 --- a/js/src/jsproxy.h +++ b/js/src/jsproxy.h @@ -142,30 +142,6 @@ const uint32 JSSLOT_PROXY_EXTRA = 2; const uint32 JSSLOT_PROXY_CALL = 3; const uint32 JSSLOT_PROXY_CONSTRUCT = 4; -extern JS_FRIEND_API(js::Class) ObjectProxyClass; -extern JS_FRIEND_API(js::Class) FunctionProxyClass; -extern JS_FRIEND_API(js::Class) OuterWindowProxyClass; -extern js::Class CallableObjectClass; - -} - -inline bool -JSObject::isObjectProxy() const -{ - return getClass() == &js::ObjectProxyClass || - getClass() == &js::OuterWindowProxyClass; -} - -inline bool -JSObject::isFunctionProxy() const -{ - return getClass() == &js::FunctionProxyClass; -} - -inline bool -JSObject::isProxy() const -{ - return isObjectProxy() || isFunctionProxy(); } inline js::JSProxyHandler * @@ -217,8 +193,6 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp); JS_BEGIN_EXTERN_C -extern js::Class js_ProxyClass; - extern JS_FRIEND_API(JSObject *) js_InitProxyClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jsreflect.cpp b/js/src/jsreflect.cpp index a59a1b68c74e..d35de1776d69 100644 --- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -323,7 +323,7 @@ class NodeBuilder } bool newObject(JSObject **dst) { - JSObject *nobj = NewNonFunction(cx, &js_ObjectClass, NULL, NULL); + JSObject *nobj = NewNonFunction(cx, &ObjectClass, NULL, NULL); if (!nobj) return false; @@ -633,7 +633,7 @@ NodeBuilder::newNode(ASTType type, TokenPos *pos, JSObject **dst) Value tv; - JSObject *node = NewNonFunction(cx, &js_ObjectClass, NULL, NULL); + JSObject *node = NewNonFunction(cx, &ObjectClass, NULL, NULL); if (!node || !setNodeLoc(node, pos) || !atomValue(nodeTypeNames[type], &tv) || @@ -3238,7 +3238,7 @@ JS_BEGIN_EXTERN_C JS_PUBLIC_API(JSObject *) JS_InitReflect(JSContext *cx, JSObject *obj) { - JSObject *Reflect = NewNonFunction(cx, &js_ObjectClass, NULL, obj); + JSObject *Reflect = NewNonFunction(cx, &ObjectClass, NULL, obj); if (!Reflect || !Reflect->setSingletonType(cx)) return NULL; diff --git a/js/src/jsregexp.cpp b/js/src/jsregexp.cpp index 56c9bd8dc414..83fbdc8f7114 100644 --- a/js/src/jsregexp.cpp +++ b/js/src/jsregexp.cpp @@ -141,11 +141,10 @@ SwapObjectRegExp(JSContext *cx, JSObject *obj, AlreadyIncRefed newRegExp JSObject * JS_FASTCALL js_CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto) { - JS_ASSERT(obj->getClass() == &js_RegExpClass); - JS_ASSERT(proto); - JS_ASSERT(proto->getClass() == &js_RegExpClass); + JS_ASSERT(obj->isRegExp()); + JS_ASSERT(proto->isRegExp()); - JSObject *clone = NewNativeClassInstance(cx, &js_RegExpClass, proto, proto->getParent()); + JSObject *clone = NewNativeClassInstance(cx, &RegExpClass, proto, proto->getParent()); if (!clone) return NULL; @@ -432,7 +431,7 @@ js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp) if (!JS_XDRString(xdr, &source) || !JS_XDRUint32(xdr, &flagsword)) return false; if (xdr->mode == JSXDR_DECODE) { - JSObject *obj = NewBuiltinClassInstance(xdr->cx, &js_RegExpClass); + JSObject *obj = NewBuiltinClassInstance(xdr->cx, &RegExpClass); if (!obj) return false; obj->clearParent(); @@ -460,7 +459,7 @@ js_XDRRegExpObject(JSXDRState *xdr, JSObject **objp) #endif /* !JS_HAS_XDR */ -js::Class js_RegExpClass = { +Class js::RegExpClass = { js_RegExp_str, JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSObject::REGEXP_CLASS_RESERVED_SLOTS) | @@ -490,7 +489,7 @@ JSBool js_regexp_toString(JSContext *cx, JSObject *obj, Value *vp) { if (!obj->isRegExp()) { - ReportIncompatibleMethod(cx, vp, &js_RegExpClass); + ReportIncompatibleMethod(cx, vp, &RegExpClass); return false; } @@ -609,7 +608,7 @@ ExecuteRegExp(JSContext *cx, ExecType execType, uintN argc, Value *vp) if (!obj) return false; if (!obj->isRegExp()) { - ReportIncompatibleMethod(cx, vp, &js_RegExpClass); + ReportIncompatibleMethod(cx, vp, &RegExpClass); return false; } @@ -703,7 +702,7 @@ CompileRegExpAndSwap(JSContext *cx, JSObject *obj, uintN argc, Value *argv, Valu return SwapRegExpInternals(cx, obj, rval, cx->runtime->emptyString); Value sourceValue = argv[0]; - if (sourceValue.isObject() && sourceValue.toObject().getClass() == &js_RegExpClass) { + if (sourceValue.isObject() && sourceValue.toObject().isRegExp()) { /* * If we get passed in a RegExp object we return a new object with the * same RegExp (internal matcher program) guts. @@ -759,7 +758,7 @@ regexp_compile(JSContext *cx, uintN argc, Value *vp) if (!obj) return false; if (!obj->isRegExp()) { - ReportIncompatibleMethod(cx, vp, &js_RegExpClass); + ReportIncompatibleMethod(cx, vp, &RegExpClass); return false; } @@ -784,7 +783,7 @@ regexp_construct(JSContext *cx, uintN argc, Value *vp) } } - JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass); + JSObject *obj = NewBuiltinClassInstance(cx, &RegExpClass); if (!obj) return false; @@ -809,7 +808,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj) GlobalObject *global = obj->asGlobal(); - JSObject *proto = global->createBlankPrototype(cx, &js_RegExpClass); + JSObject *proto = global->createBlankPrototype(cx, &RegExpClass); if (!proto) return NULL; @@ -831,7 +830,7 @@ js_InitRegExpClass(JSContext *cx, JSObject *obj) if (!DefinePropertiesAndBrand(cx, proto, NULL, regexp_methods)) return NULL; - JSFunction *ctor = global->createConstructor(cx, regexp_construct, &js_RegExpClass, + JSFunction *ctor = global->createConstructor(cx, regexp_construct, &RegExpClass, CLASS_ATOM(cx, RegExp), 2); if (!ctor) return NULL; diff --git a/js/src/jsregexp.h b/js/src/jsregexp.h index 429cbd5df4c4..e1e85a4c8d76 100644 --- a/js/src/jsregexp.h +++ b/js/src/jsregexp.h @@ -52,8 +52,6 @@ #include "jsdhash.h" #endif -extern js::Class js_RegExpClass; - namespace js { class RegExpStatics @@ -388,12 +386,6 @@ JSObject::setRegExpSticky(bool sticky) namespace js { class AutoStringRooter; } -inline bool -JSObject::isRegExp() const -{ - return getClass() == &js_RegExpClass; -} - extern JS_FRIEND_API(JSBool) js_ObjectIsRegExp(JSObject *obj); diff --git a/js/src/jsregexpinlines.h b/js/src/jsregexpinlines.h index 78cb55fd2258..2a1cea9d6d7c 100644 --- a/js/src/jsregexpinlines.h +++ b/js/src/jsregexpinlines.h @@ -448,7 +448,7 @@ RegExp::createObjectNoStatics(JSContext *cx, const jschar *chars, size_t length, AlreadyIncRefed re = RegExp::create(cx, str, flags, ts); if (!re) return NULL; - JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass); + JSObject *obj = NewBuiltinClassInstance(cx, &RegExpClass); if (!obj || !obj->initRegExp(cx, re.get())) { re->decref(cx); return NULL; diff --git a/js/src/jsscope.h b/js/src/jsscope.h index e4ed68c0d135..354d2a5a60b8 100644 --- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -251,7 +251,12 @@ struct PropertyTable { /* Computes the size of the entries array for a given capacity. */ static size_t sizeOfEntries(size_t cap) { return cap * sizeof(Shape *); } - size_t sizeOf() const { + size_t sizeOf(size_t(*mus)(void *)) const { + if (mus) { + size_t usable = mus((void*)this) + mus(entries); + if (usable) + return usable; + } return sizeOfEntries(capacity()) + sizeof(PropertyTable); } diff --git a/js/src/jsscopeinlines.h b/js/src/jsscopeinlines.h index ea13c6943a02..d0ba58f1af69 100644 --- a/js/src/jsscopeinlines.h +++ b/js/src/jsscopeinlines.h @@ -68,7 +68,7 @@ js::Shape::freeTable(JSContext *cx) inline js::EmptyShape * js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp, - /* gc::FinalizeKind */ unsigned kind) + gc::AllocKind kind) { JS_ASSERT(!singleton); @@ -288,7 +288,7 @@ Shape::get(JSContext* cx, JSObject *receiver, JSObject* obj, JSObject *pobj, js: * |with (it) color;| ends up here, as do XML filter-expressions. * Avoid exposing the With object to native getters. */ - if (obj->getClass() == &js_WithClass) + if (obj->isWith()) obj = js_UnwrapWithObject(cx, obj); return js::CallJSPropertyOp(cx, getterOp(), receiver, SHAPE_USERID(this), vp); } @@ -307,7 +307,7 @@ Shape::set(JSContext* cx, JSObject* obj, bool strict, js::Value* vp) const return js_ReportGetterOnlyAssignment(cx); /* See the comment in js::Shape::get as to why we check for With. */ - if (obj->getClass() == &js_WithClass) + if (obj->isWith()) obj = js_UnwrapWithObject(cx, obj); return js::CallJSPropertyOpSetter(cx, setterOp(), obj, SHAPE_USERID(this), strict, vp); } @@ -364,37 +364,37 @@ EmptyShape::EmptyShape(JSCompartment *comp, js::Class *aclasp) /* static */ inline EmptyShape * EmptyShape::getEmptyArgumentsShape(JSContext *cx) { - return ensure(cx, &NormalArgumentsObject::jsClass, &cx->compartment->emptyArgumentsShape); + return ensure(cx, &NormalArgumentsObjectClass, &cx->compartment->emptyArgumentsShape); } /* static */ inline EmptyShape * EmptyShape::getEmptyBlockShape(JSContext *cx) { - return ensure(cx, &js_BlockClass, &cx->compartment->emptyBlockShape); + return ensure(cx, &BlockClass, &cx->compartment->emptyBlockShape); } /* static */ inline EmptyShape * EmptyShape::getEmptyCallShape(JSContext *cx) { - return ensure(cx, &js_CallClass, &cx->compartment->emptyCallShape); + return ensure(cx, &CallClass, &cx->compartment->emptyCallShape); } /* static */ inline EmptyShape * EmptyShape::getEmptyDeclEnvShape(JSContext *cx) { - return ensure(cx, &js_DeclEnvClass, &cx->compartment->emptyDeclEnvShape); + return ensure(cx, &DeclEnvClass, &cx->compartment->emptyDeclEnvShape); } /* static */ inline EmptyShape * EmptyShape::getEmptyEnumeratorShape(JSContext *cx) { - return ensure(cx, &js_IteratorClass, &cx->compartment->emptyEnumeratorShape); + return ensure(cx, &IteratorClass, &cx->compartment->emptyEnumeratorShape); } /* static */ inline EmptyShape * EmptyShape::getEmptyWithShape(JSContext *cx) { - return ensure(cx, &js_WithClass, &cx->compartment->emptyWithShape); + return ensure(cx, &WithClass, &cx->compartment->emptyWithShape); } } /* namespace js */ diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 313934cfcba1..5721c6a411b7 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -669,9 +669,9 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp) uint32 isBlock; if (xdr->mode == JSXDR_ENCODE) { Class *clasp = (*objp)->getClass(); - JS_ASSERT(clasp == &js_FunctionClass || - clasp == &js_BlockClass); - isBlock = (clasp == &js_BlockClass) ? 1 : 0; + JS_ASSERT(clasp == &FunctionClass || + clasp == &BlockClass); + isBlock = (clasp == &BlockClass) ? 1 : 0; } if (!JS_XDRUint32(xdr, &isBlock)) goto error; @@ -779,7 +779,7 @@ script_trace(JSTracer *trc, JSObject *obj) } } -Class js_ScriptClass = { +Class js::ScriptClass = { "Script", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object), @@ -1392,7 +1392,7 @@ js_NewScriptObject(JSContext *cx, JSScript *script) { JS_ASSERT(!script->u.object); - JSObject *obj = NewNonFunction(cx, &js_ScriptClass, NULL, NULL); + JSObject *obj = NewNonFunction(cx, &ScriptClass, NULL, NULL); if (!obj) return NULL; obj->setPrivate(script); diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 55a846c919fc..34dc1e22a5b3 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -559,7 +559,7 @@ struct JSScript : public js::gc::Cell { union { /* - * A script object of class js_ScriptClass, to ensure the script is GC'd. + * A script object of class ScriptClass, to ensure the script is GC'd. * - All scripts returned by JSAPI functions (JS_CompileScript, * JS_CompileFile, etc.) have these objects. * - Function scripts never have script objects; such scripts are owned @@ -643,8 +643,6 @@ struct JSScript : public js::gc::Cell { inline bool hasAnalysis(); inline js::analyze::ScriptAnalysis *analysis(); - inline bool isAboutToBeFinalized(JSContext *cx); - private: bool makeTypes(JSContext *cx); bool makeAnalysis(JSContext *cx); @@ -690,8 +688,9 @@ struct JSScript : public js::gc::Cell { return JITScript_Valid; } - // This method is implemented in MethodJIT.h. - JS_FRIEND_API(size_t) jitDataSize();/* Size of the JITScript and all sections */ + /* Size of the JITScript and all sections. (This method is implemented in MethodJIT.h.) */ + JS_FRIEND_API(size_t) jitDataSize(size_t(*mus)(void *)); + #endif jsbytecode *main() { @@ -859,7 +858,6 @@ StackDepth(JSScript *script) } \ JS_END_MACRO -extern JS_FRIEND_DATA(js::Class) js_ScriptClass; extern JSObject * js_InitScriptClass(JSContext *cx, JSObject *obj); @@ -982,12 +980,6 @@ js_CloneScript(JSContext *cx, JSScript *script); extern JSBool js_XDRScript(JSXDRState *xdr, JSScript **scriptp); -inline bool -JSObject::isScript() const -{ - return getClass() == &js_ScriptClass; -} - inline JSScript * JSObject::getScript() const { diff --git a/js/src/jsscriptinlines.h b/js/src/jsscriptinlines.h index d05dc38208cc..cf2f963a6b41 100644 --- a/js/src/jsscriptinlines.h +++ b/js/src/jsscriptinlines.h @@ -153,7 +153,7 @@ JSScript::getRegExp(size_t index) JSObjectArray *arr = regexps(); JS_ASSERT((uint32) index < arr->length); JSObject *obj = arr->vector[index]; - JS_ASSERT(obj->getClass() == &js_RegExpClass); + JS_ASSERT(obj->isRegExp()); return obj; } diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 4ca3f40d5651..03c5d75e3549 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -384,7 +384,7 @@ str_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, return JS_TRUE; } -Class js_StringClass = { +Class js::StringClass = { js_String_str, JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) | JSCLASS_NEW_RESOLVE | JSCLASS_HAS_CACHED_PROTO(JSProto_String), @@ -401,7 +401,7 @@ Class js_StringClass = { * Returns a JSString * for the |this| value associated with vp, or throws a * TypeError if |this| is null or undefined. This algorithm is the same as * calling CheckObjectCoercible(this), then returning ToString(this), as all - * String.prototype.* methods do. + * String.prototype.* methods do (other than toString and valueOf). */ static JS_ALWAYS_INLINE JSString * ThisToStringForStringProto(JSContext *cx, Value *vp) @@ -413,9 +413,9 @@ ThisToStringForStringProto(JSContext *cx, Value *vp) if (vp[1].isObject()) { JSObject *obj = &vp[1].toObject(); - if (obj->getClass() == &js_StringClass && + if (obj->isString() && ClassMethodIsNative(cx, obj, - &js_StringClass, + &StringClass, ATOM_TO_JSID(cx->runtime->atomState.toStringAtom), js_str_toString)) { @@ -3191,12 +3191,12 @@ js_InitStringClass(JSContext *cx, JSObject *obj) GlobalObject *global = obj->asGlobal(); - JSObject *proto = global->createBlankPrototype(cx, &js_StringClass); + JSObject *proto = global->createBlankPrototype(cx, &StringClass); if (!proto || !proto->asString()->init(cx, cx->runtime->emptyString)) return NULL; /* Now create the String function. */ - JSFunction *ctor = global->createConstructor(cx, js_String, &js_StringClass, + JSFunction *ctor = global->createConstructor(cx, js_String, &StringClass, CLASS_ATOM(cx, String), 1); if (!ctor) return NULL; diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 3a86972d7301..dff8c49371e9 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -101,14 +101,6 @@ extern JSSubString js_EmptySubString; #define JS7_ISLET(c) ((c) < 128 && isalpha(c)) /* Initialize the String class, returning its prototype object. */ -extern js::Class js_StringClass; - -inline bool -JSObject::isString() const -{ - return getClass() == &js_StringClass; -} - extern JSObject * js_InitStringClass(JSContext *cx, JSObject *obj); diff --git a/js/src/jstracer.cpp b/js/src/jstracer.cpp index 7521cd5fc664..8b3cff512a1b 100644 --- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -183,9 +183,9 @@ using namespace js::tjit; * * FIXME: Bug 624590 is open to get rid of all this. */ -static const size_t DataReserveSize = 12500 * sizeof(uintptr_t); -static const size_t TraceReserveSize = 5000 * sizeof(uintptr_t); -static const size_t TempReserveSize = 1000 * sizeof(uintptr_t); +static const size_t DataReserveSize = 8192 * sizeof(uintptr_t); +static const size_t TraceReserveSize = 512 * sizeof(uintptr_t); +static const size_t TempReserveSize = 4096 * sizeof(uintptr_t); void* nanojit::Allocator::allocChunk(size_t nbytes, bool fallible) @@ -9836,9 +9836,9 @@ TraceRecorder::unbox_object(Address addr, LIns* tag_ins, JSValueType type, VMSid guard(true, w.name(w.eqi(tag_ins, w.nameImmui(JSVAL_TAG_OBJECT)), "isObj"), exit); LIns *payload_ins = w.ldiValuePayload(addr); if (type == JSVAL_TYPE_FUNOBJ) - guardClass(payload_ins, &js_FunctionClass, exit, LOAD_NORMAL); + guardClass(payload_ins, &FunctionClass, exit, LOAD_NORMAL); else - guardNotClass(payload_ins, &js_FunctionClass, exit, LOAD_NORMAL); + guardNotClass(payload_ins, &FunctionClass, exit, LOAD_NORMAL); return payload_ins; } @@ -9989,9 +9989,9 @@ TraceRecorder::unbox_object(LIns* v_ins, JSValueType type, VMSideExit* exit) exit); v_ins = unpack_ptr(v_ins); if (type == JSVAL_TYPE_FUNOBJ) - guardClass(v_ins, &js_FunctionClass, exit, LOAD_NORMAL); + guardClass(v_ins, &FunctionClass, exit, LOAD_NORMAL); else - guardNotClass(v_ins, &js_FunctionClass, exit, LOAD_NORMAL); + guardNotClass(v_ins, &FunctionClass, exit, LOAD_NORMAL); return v_ins; } @@ -10198,13 +10198,13 @@ TraceRecorder::guardNotClass(LIns* obj_ins, Class* clasp, VMSideExit* exit, Load JS_REQUIRES_STACK void TraceRecorder::guardDenseArray(LIns* obj_ins, ExitType exitType) { - guardClass(obj_ins, &js_ArrayClass, snapshot(exitType), LOAD_NORMAL); + guardClass(obj_ins, &ArrayClass, snapshot(exitType), LOAD_NORMAL); } JS_REQUIRES_STACK void TraceRecorder::guardDenseArray(LIns* obj_ins, VMSideExit* exit) { - guardClass(obj_ins, &js_ArrayClass, exit, LOAD_NORMAL); + guardClass(obj_ins, &ArrayClass, exit, LOAD_NORMAL); } JS_REQUIRES_STACK bool @@ -11069,7 +11069,7 @@ TraceRecorder::getClassPrototype(JSObject* ctor, LIns*& proto_ins) JS_ASSERT(!pval.isPrimitive()); JSObject *proto = &pval.toObject(); JS_ASSERT(!proto->isDenseArray()); - JS_ASSERT_IF(clasp != &js_ArrayClass, proto->getNewType(cx)->emptyShapes[0]->getClass() == clasp); + JS_ASSERT_IF(clasp != &ArrayClass, proto->getNewType(cx)->emptyShapes[0]->getClass() == clasp); proto_ins = w.immpObjGC(proto); return RECORD_CONTINUE; @@ -11612,15 +11612,15 @@ TraceRecorder::callNative(uintN argc, JSOp mode) LIns* this_ins; if (mode == JSOP_NEW) { Class* clasp = fun->u.n.clasp; - JS_ASSERT(clasp != &js_SlowArrayClass); + JS_ASSERT(clasp != &SlowArrayClass); if (!clasp) - clasp = &js_ObjectClass; + clasp = &ObjectClass; JS_ASSERT(((jsuword) clasp & 3) == 0); // Abort on |new Function|. (FIXME: This restriction might not // unnecessary now that the constructor creates the new function object // itself.) - if (clasp == &js_FunctionClass) + if (clasp == &FunctionClass) RETURN_STOP("new Function"); if (!IsFastTypedArrayClass(clasp) && !clasp->isNative()) @@ -12498,7 +12498,7 @@ TraceRecorder::recordInitPropertyOp(jsbytecode op) Value& l = stackval(-2); JSObject* obj = &l.toObject(); LIns* obj_ins = get(&l); - JS_ASSERT(obj->getClass() == &js_ObjectClass); + JS_ASSERT(obj->getClass() == &ObjectClass); Value& v = stackval(-1); LIns* v_ins = get(&v); @@ -12773,7 +12773,7 @@ GetPropertyWithNativeGetter(JSContext* cx, JSObject* obj, Shape* shape, Value* v // Shape::get contains a special case for With objects. We can elide it // here because With objects are, we claim, never on the operand stack // while recording. - JS_ASSERT(obj->getClass() != &js_WithClass); + JS_ASSERT(obj->getClass() != &WithClass); vp->setUndefined(); if (!shape->getterOp()(cx, obj, SHAPE_USERID(shape), vp)) { @@ -14827,8 +14827,8 @@ TraceRecorder::record_JSOP_MOREITER() * ni->flags (nor do we in unboxNextValue), because the different iteration * type will guarantee a different entry typemap. */ - if (iterobj->hasClass(&js_IteratorClass)) { - guardClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + if (iterobj->hasClass(&IteratorClass)) { + guardClass(iterobj_ins, &IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); if (ni->isKeyIter()) { @@ -14841,7 +14841,7 @@ TraceRecorder::record_JSOP_MOREITER() return ARECORD_CONTINUE; } } else { - guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + guardNotClass(iterobj_ins, &IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); } enterDeepBailCall(); @@ -14926,8 +14926,8 @@ TraceRecorder::unboxNextValue(Value &iterobj_val, LIns* &v_ins) JSObject *iterobj = &iterobj_val.toObject(); LIns* iterobj_ins = get(&iterobj_val); - if (iterobj->hasClass(&js_IteratorClass)) { - guardClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + if (iterobj->hasClass(&IteratorClass)) { + guardClass(iterobj_ins, &IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); NativeIterator *ni = (NativeIterator *) iterobj->getPrivate(); LIns *ni_ins = w.ldpObjPrivate(iterobj_ins); @@ -14970,7 +14970,7 @@ TraceRecorder::unboxNextValue(Value &iterobj_val, LIns* &v_ins) return ARECORD_CONTINUE; } } else { - guardNotClass(iterobj_ins, &js_IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + guardNotClass(iterobj_ins, &IteratorClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); } @@ -16344,7 +16344,7 @@ TraceRecorder::record_JSOP_LENGTH() guardDenseArray(obj_ins, BRANCH_EXIT); } else { JS_ASSERT(obj->isSlowArray()); - guardClass(obj_ins, &js_SlowArrayClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); + guardClass(obj_ins, &SlowArrayClass, snapshot(BRANCH_EXIT), LOAD_NORMAL); } v_ins = w.lduiObjPrivate(obj_ins); if (obj->getArrayLength() <= JSVAL_INT_MAX) { diff --git a/js/src/jstypedarray.cpp b/js/src/jstypedarray.cpp index c3b9b04a0295..b5f14e231929 100644 --- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -186,7 +186,7 @@ static JSObject * DelegateObject(JSContext *cx, JSObject *obj) { if (!obj->getPrivate()) { - JSObject *delegate = NewNonFunction(cx, &js_ObjectClass, obj->getProto(), NULL); + JSObject *delegate = NewNonFunction(cx, &ObjectClass, obj->getProto(), NULL); obj->setPrivate(delegate); return delegate; } @@ -212,7 +212,7 @@ ArrayBuffer::create(JSContext *cx, int32 nbytes) JS_ASSERT(obj->getClass() == &ArrayBuffer::slowClass); obj->setSharedNonNativeMap(); - obj->clasp = &js_ArrayBufferClass; + obj->setClass(&ArrayBufferClass); /* * The first 8 bytes hold the length. @@ -980,7 +980,7 @@ class TypedArrayTemplate JS_ASSERT(obj->getClass() == slowClass()); obj->setSharedNonNativeMap(); - obj->clasp = fastClass(); + obj->setClass(fastClass()); // FIXME Bug 599008: make it ok to call preventExtensions here. obj->flags |= JSObject::NOT_EXTENSIBLE; @@ -1694,7 +1694,7 @@ Class ArrayBuffer::slowClass = { FinalizeStub }; -Class js_ArrayBufferClass = { +Class js::ArrayBufferClass = { "ArrayBuffer", JSCLASS_HAS_PRIVATE | Class::NON_NATIVE | @@ -1902,7 +1902,7 @@ InitArrayBufferClass(JSContext *cx, GlobalObject *global) return NULL; JSFunction *ctor = - global->createConstructor(cx, ArrayBuffer::class_constructor, &js_ArrayBufferClass, + global->createConstructor(cx, ArrayBuffer::class_constructor, &ArrayBufferClass, CLASS_ATOM(cx, ArrayBuffer), 1); if (!ctor) return NULL; @@ -1953,7 +1953,7 @@ JS_FRIEND_API(JSBool) js_IsArrayBuffer(JSObject *obj) { JS_ASSERT(obj); - return obj->getClass() == &js_ArrayBufferClass; + return obj->isArrayBuffer(); } namespace js { diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index d7774d1ee3cd..91ba39010a00 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -78,12 +78,6 @@ WeakMapBase::sweepAll(JSTracer *tracer) } /* namespace js */ -bool -JSObject::isWeakMap() const -{ - return getClass() == &WeakMapClass; -} - typedef WeakMap ObjectValueMap; static ObjectValueMap * @@ -264,9 +258,7 @@ WeakMap_construct(JSContext *cx, uintN argc, Value *vp) return true; } -namespace js { - -Class WeakMapClass = { +Class js::WeakMapClass = { "WeakMap", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap), @@ -287,8 +279,6 @@ Class WeakMapClass = { WeakMap_mark }; -} - static JSFunctionSpec weak_map_methods[] = { JS_FN("has", WeakMap_has, 1, 0), JS_FN("get", WeakMap_get, 2, 0), diff --git a/js/src/jsweakmap.h b/js/src/jsweakmap.h index 29a3a7038dca..aba994dd839f 100644 --- a/js/src/jsweakmap.h +++ b/js/src/jsweakmap.h @@ -317,9 +317,6 @@ class DefaultMarkPolicy { // typedef DefaultMarkPolicy CrossCompartmentMarkPolicy; -// The class of JavaScript WeakMap objects. -extern Class WeakMapClass; - } extern JSObject * diff --git a/js/src/jswrapper.cpp b/js/src/jswrapper.cpp index 085afb6c586c..c61301ef2660 100644 --- a/js/src/jswrapper.cpp +++ b/js/src/jswrapper.cpp @@ -632,7 +632,7 @@ CanReify(Value *vp) { JSObject *obj; return vp->isObject() && - (obj = &vp->toObject())->getClass() == &js_IteratorClass && + (obj = &vp->toObject())->getClass() == &IteratorClass && (obj->getNativeIterator()->flags & JSITER_ENUMERATE); } diff --git a/js/src/jsxml.cpp b/js/src/jsxml.cpp index ec813da912ae..d89bb650338f 100644 --- a/js/src/jsxml.cpp +++ b/js/src/jsxml.cpp @@ -153,7 +153,7 @@ IsDeclared(const JSObject *obj) { jsval v; - JS_ASSERT(obj->getClass() == &js_NamespaceClass); + JS_ASSERT(obj->getClass() == &NamespaceClass); v = obj->getNamespaceDeclared(); JS_ASSERT(JSVAL_IS_VOID(v) || v == JSVAL_TRUE); return v == JSVAL_TRUE; @@ -197,9 +197,9 @@ NewBuiltinClassInstanceXML(JSContext *cx, Class *clasp) * Namespace class and library functions. */ DEFINE_GETTER(NamePrefix_getter, - if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNamePrefixVal()) + if (obj->getClass() == &NamespaceClass) *vp = obj->getNamePrefixVal()) DEFINE_GETTER(NameURI_getter, - if (obj->getClass() == &js_NamespaceClass) *vp = obj->getNameURIVal()) + if (obj->getClass() == &NamespaceClass) *vp = obj->getNameURIVal()) static JSBool namespace_equality(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) @@ -208,13 +208,13 @@ namespace_equality(JSContext *cx, JSObject *obj, const Value *v, JSBool *bp) JS_ASSERT(v->isObjectOrNull()); obj2 = v->toObjectOrNull(); - *bp = (!obj2 || obj2->getClass() != &js_NamespaceClass) + *bp = (!obj2 || obj2->getClass() != &NamespaceClass) ? JS_FALSE : EqualStrings(obj->getNameURI(), obj2->getNameURI()); return JS_TRUE; } -JS_FRIEND_DATA(Class) js_NamespaceClass = { +JS_FRIEND_DATA(Class) js::NamespaceClass = { "Namespace", JSCLASS_HAS_RESERVED_SLOTS(JSObject::NAMESPACE_CLASS_RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Namespace), @@ -258,7 +258,7 @@ namespace_toString(JSContext *cx, uintN argc, Value *vp) if (!obj) return JS_FALSE; if (!obj->isNamespace()) { - ReportIncompatibleMethod(cx, vp, &js_NamespaceClass); + ReportIncompatibleMethod(cx, vp, &NamespaceClass); return JS_FALSE; } *vp = Valueify(obj->getNameURIVal()); @@ -275,7 +275,7 @@ NewXMLNamespace(JSContext *cx, JSLinearString *prefix, JSLinearString *uri, JSBo { JSObject *obj; - obj = NewBuiltinClassInstanceXML(cx, &js_NamespaceClass); + obj = NewBuiltinClassInstanceXML(cx, &NamespaceClass); if (!obj) return NULL; JS_ASSERT(JSVAL_IS_VOID(obj->getNamePrefixVal())); @@ -299,10 +299,10 @@ NewXMLNamespace(JSContext *cx, JSLinearString *prefix, JSLinearString *uri, JSBo * QName class and library functions. */ DEFINE_GETTER(QNameNameURI_getter, - if (obj->getClass() == &js_QNameClass) + if (obj->getClass() == &QNameClass) *vp = JSVAL_IS_VOID(obj->getNameURIVal()) ? JSVAL_NULL : obj->getNameURIVal()) DEFINE_GETTER(QNameLocalName_getter, - if (obj->getClass() == &js_QNameClass) + if (obj->getClass() == &QNameClass) *vp = obj->getQNameLocalNameVal()) static JSBool @@ -324,13 +324,13 @@ qname_equality(JSContext *cx, JSObject *qn, const Value *v, JSBool *bp) JSObject *obj2; obj2 = v->toObjectOrNull(); - *bp = (!obj2 || obj2->getClass() != &js_QNameClass) + *bp = (!obj2 || obj2->getClass() != &QNameClass) ? JS_FALSE : qname_identity(qn, obj2); return JS_TRUE; } -JS_FRIEND_DATA(Class) js_QNameClass = { +JS_FRIEND_DATA(Class) js::QNameClass = { "QName", JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_CLASS_RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_QName), @@ -364,7 +364,7 @@ JS_FRIEND_DATA(Class) js_QNameClass = { * qname_toString method, and therefore are exposed as constructable objects * in this implementation. */ -JS_FRIEND_DATA(Class) js_AttributeNameClass = { +JS_FRIEND_DATA(Class) js::AttributeNameClass = { js_AttributeName_str, JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_CLASS_RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS, @@ -378,7 +378,7 @@ JS_FRIEND_DATA(Class) js_AttributeNameClass = { FinalizeStub }; -JS_FRIEND_DATA(Class) js_AnyNameClass = { +JS_FRIEND_DATA(Class) js::AnyNameClass = { js_AnyName_str, JSCLASS_HAS_RESERVED_SLOTS(JSObject::QNAME_CLASS_RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS, @@ -422,7 +422,7 @@ ConvertQNameToString(JSContext *cx, JSObject *obj) if (!str) return NULL; - if (obj->getClass() == &js_AttributeNameClass) { + if (obj->getClass() == &AttributeNameClass) { JS::Anchor anchor(str); size_t length = str->length(); jschar *chars = (jschar *) cx->malloc_((length + 2) * sizeof(jschar)); @@ -453,7 +453,7 @@ qname_toString(JSContext *cx, uintN argc, Value *vp) return false; if (!obj->isQName()) { - ReportIncompatibleMethod(cx, vp, &js_QNameClass); + ReportIncompatibleMethod(cx, vp, &QNameClass); return false; } @@ -497,7 +497,7 @@ static JSObject * NewXMLQName(JSContext *cx, JSLinearString *uri, JSLinearString *prefix, JSAtom *localName) { - JSObject *obj = NewBuiltinClassInstanceXML(cx, &js_QNameClass); + JSObject *obj = NewBuiltinClassInstanceXML(cx, &QNameClass); if (!obj) return NULL; if (!InitXMLQName(cx, obj, uri, prefix, localName)) @@ -514,7 +514,7 @@ NewXMLAttributeName(JSContext *cx, JSLinearString *uri, JSLinearString *prefix, * exposed to scripts. */ JSObject *parent = GetGlobalForScopeChain(cx); - JSObject *obj = NewNonFunction(cx, &js_AttributeNameClass, NULL, parent); + JSObject *obj = NewNonFunction(cx, &AttributeNameClass, NULL, parent); if (!obj) return NULL; JS_ASSERT(obj->isQName()); @@ -534,13 +534,13 @@ js_ConstructXMLQNameObject(JSContext *cx, const Value &nsval, const Value &lnval * production, step 2. */ if (nsval.isObject() && - nsval.toObject().getClass() == &js_AnyNameClass) { + nsval.toObject().getClass() == &AnyNameClass) { argv[0].setNull(); } else { argv[0] = nsval; } argv[1] = lnval; - return js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, argv); + return js_ConstructObject(cx, &QNameClass, NULL, NULL, 2, argv); } static JSBool @@ -616,8 +616,8 @@ NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, if (!JSVAL_IS_PRIMITIVE(urival)) { uriobj = JSVAL_TO_OBJECT(urival); clasp = uriobj->getClass(); - isNamespace = (clasp == &js_NamespaceClass); - isQName = (clasp == &js_QNameClass); + isNamespace = (clasp == &NamespaceClass); + isQName = (clasp == &QNameClass); } } @@ -629,7 +629,7 @@ NamespaceHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, return JS_TRUE; } - obj = NewBuiltinClassInstanceXML(cx, &js_NamespaceClass); + obj = NewBuiltinClassInstanceXML(cx, &NamespaceClass); if (!obj) return JS_FALSE; } @@ -732,7 +732,7 @@ QNameHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, jsval *rval) nameval = argv[argc > 1]; isQName = !JSVAL_IS_PRIMITIVE(nameval) && - JSVAL_TO_OBJECT(nameval)->getClass() == &js_QNameClass; + JSVAL_TO_OBJECT(nameval)->getClass() == &QNameClass; } if (!obj) { @@ -744,7 +744,7 @@ QNameHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, jsval *rval) } /* Create and return a new QName object exactly as if constructed. */ - obj = NewBuiltinClassInstanceXML(cx, &js_QNameClass); + obj = NewBuiltinClassInstanceXML(cx, &QNameClass); if (!obj) return JS_FALSE; } @@ -782,7 +782,7 @@ QNameHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, jsval *rval) return JS_FALSE; JS_ASSERT(!JSVAL_IS_PRIMITIVE(nsval)); JS_ASSERT(JSVAL_TO_OBJECT(nsval)->getClass() == - &js_NamespaceClass); + &NamespaceClass); } if (JSVAL_IS_NULL(nsval)) { @@ -799,8 +799,8 @@ QNameHelper(JSContext *cx, JSObject *obj, intN argc, jsval *argv, jsval *rval) isNamespace = isQName = JS_FALSE; if (!JSVAL_IS_PRIMITIVE(nsval)) { obj2 = JSVAL_TO_OBJECT(nsval); - isNamespace = (obj2->getClass() == &js_NamespaceClass); - isQName = (obj2->getClass() == &js_QNameClass); + isNamespace = (obj2->getClass() == &NamespaceClass); + isQName = (obj2->getClass() == &QNameClass); } #ifdef __GNUC__ /* suppress bogus gcc warnings */ else obj2 = NULL; @@ -1852,9 +1852,9 @@ ToXML(JSContext *cx, jsval v) JS_ASSERT(0); } - if (clasp != &js_StringClass && - clasp != &js_NumberClass && - clasp != &js_BooleanClass) { + if (clasp != &StringClass && + clasp != &NumberClass && + clasp != &BooleanClass) { goto bad; } } @@ -1933,9 +1933,9 @@ ToXMLList(JSContext *cx, jsval v) JS_ASSERT(0); } - if (clasp != &js_StringClass && - clasp != &js_NumberClass && - clasp != &js_BooleanClass) { + if (clasp != &StringClass && + clasp != &NumberClass && + clasp != &BooleanClass) { goto bad; } } @@ -2230,7 +2230,7 @@ GetNamespace(JSContext *cx, JSObject *qn, const JSXMLArray *inScopeNSes) if (!match) { argv[0] = prefix ? STRING_TO_JSVAL(prefix) : JSVAL_VOID; argv[1] = STRING_TO_JSVAL(uri); - ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, + ns = js_ConstructObject(cx, &NamespaceClass, NULL, NULL, 2, Valueify(argv)); if (!ns) return NULL; @@ -2783,16 +2783,16 @@ ToAttributeName(JSContext *cx, jsval v) obj = JSVAL_TO_OBJECT(v); clasp = obj->getClass(); - if (clasp == &js_AttributeNameClass) + if (clasp == &AttributeNameClass) return obj; - if (clasp == &js_QNameClass) { + if (clasp == &QNameClass) { qn = obj; uri = qn->getNameURI(); prefix = qn->getNamePrefix(); name = qn->getQNameLocalName(); } else { - if (clasp == &js_AnyNameClass) { + if (clasp == &AnyNameClass) { name = cx->runtime->atomState.starAtom; } else { if (!js_ValueToAtom(cx, Valueify(v), &name)) @@ -2853,9 +2853,9 @@ ToXMLName(JSContext *cx, jsval v, jsid *funidp) obj = JSVAL_TO_OBJECT(v); clasp = obj->getClass(); - if (clasp == &js_AttributeNameClass || clasp == &js_QNameClass) + if (clasp == &AttributeNameClass || clasp == &QNameClass) goto out; - if (clasp == &js_AnyNameClass) { + if (clasp == &AnyNameClass) { name = cx->runtime->atomState.starAtom; goto construct; } @@ -2894,7 +2894,7 @@ ToXMLName(JSContext *cx, jsval v, jsid *funidp) construct: v = STRING_TO_JSVAL(name); - obj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&v)); + obj = js_ConstructObject(cx, &QNameClass, NULL, NULL, 1, Valueify(&v)); if (!obj) return NULL; @@ -3207,7 +3207,7 @@ DescendantsHelper(JSContext *cx, JSXML *xml, JSObject *nameqn, JSXML *list) JS_CHECK_RECURSION(cx, return JS_FALSE); if (xml->xml_class == JSXML_CLASS_ELEMENT && - nameqn->getClass() == &js_AttributeNameClass) { + nameqn->getClass() == &AttributeNameClass) { for (i = 0, n = xml->xml_attrs.length; i < n; i++) { attr = XMLARRAY_MEMBER(&xml->xml_attrs, i, JSXML); if (attr && MatchAttrName(nameqn, attr)) { @@ -3221,7 +3221,7 @@ DescendantsHelper(JSContext *cx, JSXML *xml, JSObject *nameqn, JSXML *list) kid = XMLARRAY_MEMBER(&xml->xml_kids, i, JSXML); if (!kid) continue; - if (nameqn->getClass() != &js_AttributeNameClass && + if (nameqn->getClass() != &AttributeNameClass && MatchElemName(nameqn, kid)) { if (!Append(cx, list, kid)) return JS_FALSE; @@ -3670,7 +3670,7 @@ GetNamedProperty(JSContext *cx, JSXML *xml, JSObject* nameqn, JSXML *list) } } } else if (xml->xml_class == JSXML_CLASS_ELEMENT) { - attrs = (nameqn->getClass() == &js_AttributeNameClass); + attrs = (nameqn->getClass() == &AttributeNameClass); if (attrs) { array = &xml->xml_attrs; matcher = MatchAttrName; @@ -3921,7 +3921,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) goto bad; } else { nameobj = targetprop; - if (nameobj->getClass() == &js_AttributeNameClass) { + if (nameobj->getClass() == &AttributeNameClass) { /* * 2(c)(iii)(1-3). * Note that rxml can't be null here, because target @@ -4017,7 +4017,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) parent = kid->parent; if (kid->xml_class == JSXML_CLASS_ATTRIBUTE) { nameobj = kid->name; - if (nameobj->getClass() != &js_AttributeNameClass) { + if (nameobj->getClass() != &AttributeNameClass) { nameobj = NewXMLAttributeName(cx, nameobj->getNameURI(), nameobj->getNamePrefix(), nameobj->getQNameLocalName()); if (!nameobj) @@ -4224,7 +4224,7 @@ PutProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) if (!ok) goto out; - if (nameobj->getClass() == &js_AttributeNameClass) { + if (nameobj->getClass() == &AttributeNameClass) { /* 7(a). */ if (!js_IsXMLName(cx, OBJECT_TO_JSVAL(nameobj))) goto out; @@ -4477,7 +4477,7 @@ ResolveValue(JSContext *cx, JSXML *list, JSXML **result) return JS_TRUE; } - if (targetprop->getClass() == &js_AttributeNameClass) { + if (targetprop->getClass() == &AttributeNameClass) { *result = NULL; return JS_TRUE; } @@ -4533,7 +4533,7 @@ HasNamedProperty(JSXML *xml, JSObject *nameqn) } if (xml->xml_class == JSXML_CLASS_ELEMENT) { - if (nameqn->getClass() == &js_AttributeNameClass) { + if (nameqn->getClass() == &AttributeNameClass) { array = &xml->xml_attrs; matcher = MatchAttrName; } else { @@ -4572,7 +4572,7 @@ HasFunctionProperty(JSContext *cx, JSObject *obj, jsid funid, JSBool *found) JSProperty *prop; JSXML *xml; - JS_ASSERT(obj->getClass() == &js_XMLClass); + JS_ASSERT(obj->getClass() == &XMLClass); if (!js_LookupProperty(cx, obj, funid, &pobj, &prop)) return false; @@ -4818,7 +4818,7 @@ xml_deleteProperty(JSContext *cx, JSObject *obj, jsid id, Value *rval, JSBool st return js_DeleteProperty(cx, obj, funid, rval, false); DeleteNamedProperty(cx, xml, nameqn, - nameqn->getClass() == &js_AttributeNameClass); + nameqn->getClass() == &AttributeNameClass); } /* @@ -5112,7 +5112,7 @@ out: return ok; } -JS_FRIEND_DATA(Class) js_XMLClass = { +JS_FRIEND_DATA(Class) js::XMLClass = { js_XML_str, JSCLASS_HAS_PRIVATE | JSCLASS_HAS_CACHED_PROTO(JSProto_XML), @@ -5162,7 +5162,7 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp) if (!*objp) return NULL; if (!(*objp)->isXML()) { - ReportIncompatibleMethod(cx, Valueify(vp), &js_XMLClass); + ReportIncompatibleMethod(cx, Valueify(vp), &XMLClass); return NULL; } xml = (JSXML *) (*objp)->getPrivate(); @@ -5196,7 +5196,7 @@ StartNonListXMLMethod(JSContext *cx, jsval *vp, JSObject **objp) if (!obj) \ return JS_FALSE; \ if (!obj->isXML()) { \ - ReportIncompatibleMethod(cx, Valueify(vp), &js_XMLClass); \ + ReportIncompatibleMethod(cx, Valueify(vp), &XMLClass); \ return JS_FALSE; \ } \ JSXML *xml = (JSXML *)obj->getPrivate(); \ @@ -5683,7 +5683,7 @@ xml_hasOwnProperty(JSContext *cx, uintN argc, jsval *vp) if (!obj) return JS_FALSE; if (!obj->isXML()) { - ReportIncompatibleMethod(cx, Valueify(vp), &js_XMLClass); + ReportIncompatibleMethod(cx, Valueify(vp), &XMLClass); return JS_FALSE; } @@ -6480,13 +6480,13 @@ xml_setName(JSContext *cx, uintN argc, jsval *vp) } else { name = vp[2]; if (!JSVAL_IS_PRIMITIVE(name) && - JSVAL_TO_OBJECT(name)->getClass() == &js_QNameClass && + JSVAL_TO_OBJECT(name)->getClass() == &QNameClass && !(nameqn = JSVAL_TO_OBJECT(name))->getNameURI()) { name = vp[2] = nameqn->getQNameLocalNameVal(); } } - nameqn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, Valueify(&name)); + nameqn = js_ConstructObject(cx, &QNameClass, NULL, NULL, 1, Valueify(&name)); if (!nameqn) return JS_FALSE; @@ -6588,7 +6588,7 @@ xml_setNamespace(JSContext *cx, uintN argc, jsval *vp) if (!xml) return JS_FALSE; - ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj, + ns = js_ConstructObject(cx, &NamespaceClass, NULL, obj, argc == 0 ? 0 : 1, Valueify(vp + 2)); if (!ns) return JS_FALSE; @@ -6597,7 +6597,7 @@ xml_setNamespace(JSContext *cx, uintN argc, jsval *vp) qnargv[0] = OBJECT_TO_JSVAL(ns); qnargv[1] = OBJECT_TO_JSVAL(xml->name); - qn = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 2, Valueify(qnargv)); + qn = js_ConstructObject(cx, &QNameClass, NULL, NULL, 2, Valueify(qnargv)); if (!qn) return JS_FALSE; @@ -6925,7 +6925,7 @@ XML(JSContext *cx, uintN argc, Value *vp) if (IsConstructing(vp) && !JSVAL_IS_PRIMITIVE(v)) { vobj = JSVAL_TO_OBJECT(v); clasp = vobj->getClass(); - if (clasp == &js_XMLClass || + if (clasp == &XMLClass || (clasp->flags & JSCLASS_DOCUMENT_OBSERVER)) { copy = DeepCopy(cx, xml, NULL, 0); if (!copy) @@ -7071,7 +7071,7 @@ NewXMLObject(JSContext *cx, JSXML *xml) JSObject *obj; JSObject *parent = GetGlobalForScopeChain(cx); - obj = NewNonFunction(cx, &js_XMLClass, NULL, parent); + obj = NewNonFunction(cx, &XMLClass, NULL, parent); if (!obj) return NULL; obj->setPrivate(xml); @@ -7103,7 +7103,7 @@ js_InitNamespaceClass(JSContext *cx, JSObject *obj) GlobalObject *global = obj->asGlobal(); - JSObject *namespaceProto = global->createBlankPrototype(cx, &js_NamespaceClass); + JSObject *namespaceProto = global->createBlankPrototype(cx, &NamespaceClass); if (!namespaceProto) return NULL; JSFlatString *empty = cx->runtime->emptyString; @@ -7112,7 +7112,7 @@ js_InitNamespaceClass(JSContext *cx, JSObject *obj) namespaceProto->syncSpecialEquality(); const uintN NAMESPACE_CTOR_LENGTH = 2; - JSFunction *ctor = global->createConstructor(cx, Namespace, &js_NamespaceClass, + JSFunction *ctor = global->createConstructor(cx, Namespace, &NamespaceClass, CLASS_ATOM(cx, Namespace), NAMESPACE_CTOR_LENGTH); if (!ctor) @@ -7137,7 +7137,7 @@ js_InitQNameClass(JSContext *cx, JSObject *obj) GlobalObject *global = obj->asGlobal(); - JSObject *qnameProto = global->createBlankPrototype(cx, &js_QNameClass); + JSObject *qnameProto = global->createBlankPrototype(cx, &QNameClass); if (!qnameProto) return NULL; JSAtom *empty = cx->runtime->emptyString; @@ -7146,7 +7146,7 @@ js_InitQNameClass(JSContext *cx, JSObject *obj) qnameProto->syncSpecialEquality(); const uintN QNAME_CTOR_LENGTH = 2; - JSFunction *ctor = global->createConstructor(cx, QName, &js_QNameClass, + JSFunction *ctor = global->createConstructor(cx, QName, &QNameClass, CLASS_ATOM(cx, QName), QNAME_CTOR_LENGTH); if (!ctor) return NULL; @@ -7170,7 +7170,7 @@ js_InitXMLClass(JSContext *cx, JSObject *obj) GlobalObject *global = obj->asGlobal(); - JSObject *xmlProto = global->createBlankPrototype(cx, &js_XMLClass); + JSObject *xmlProto = global->createBlankPrototype(cx, &XMLClass); if (!xmlProto) return NULL; JSXML *xml = js_NewXML(cx, JSXML_CLASS_TEXT); @@ -7186,7 +7186,7 @@ js_InitXMLClass(JSContext *cx, JSObject *obj) } const uintN XML_CTOR_LENGTH = 1; - JSFunction *ctor = global->createConstructor(cx, XML, &js_XMLClass, CLASS_ATOM(cx, XML), + JSFunction *ctor = global->createConstructor(cx, XML, &XMLClass, CLASS_ATOM(cx, XML), XML_CTOR_LENGTH); if (!ctor) return NULL; @@ -7293,7 +7293,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) obj = NULL; for (tmp = scopeChain; tmp; tmp = tmp->getParent()) { Class *clasp = tmp->getClass(); - if (clasp == &js_BlockClass || clasp == &js_WithClass) + if (clasp == &BlockClass || clasp == &WithClass) continue; if (!tmp->getProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(&v))) return JS_FALSE; @@ -7304,7 +7304,7 @@ js_GetDefaultXMLNamespace(JSContext *cx, jsval *vp) obj = tmp; } - ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj, 0, NULL); + ns = js_ConstructObject(cx, &NamespaceClass, NULL, obj, 0, NULL); if (!ns) return JS_FALSE; v = OBJECT_TO_JSVAL(ns); @@ -7322,7 +7322,7 @@ js_SetDefaultXMLNamespace(JSContext *cx, const Value &v) Value argv[2]; argv[0].setString(cx->runtime->emptyString); argv[1] = v; - JSObject *ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv); + JSObject *ns = js_ConstructObject(cx, &NamespaceClass, NULL, NULL, 2, argv); if (!ns) return JS_FALSE; @@ -7407,7 +7407,7 @@ js_GetAnyName(JSContext *cx, jsid *idp) JSObject *global = cx->hasfp() ? cx->fp()->scopeChain().getGlobal() : cx->globalObject; Value v = global->getReservedSlot(JSProto_AnyName); if (v.isUndefined()) { - JSObject *obj = NewNonFunction(cx, &js_AnyNameClass, NULL, global); + JSObject *obj = NewNonFunction(cx, &AnyNameClass, NULL, global); if (!obj) return false; @@ -7439,15 +7439,15 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i JS_ASSERT(nameval.isObject()); nameobj = &nameval.toObject(); - if (nameobj->getClass() == &js_AnyNameClass) { + if (nameobj->getClass() == &AnyNameClass) { v = STRING_TO_JSVAL(cx->runtime->atomState.starAtom); - nameobj = js_ConstructObject(cx, &js_QNameClass, NULL, NULL, 1, + nameobj = js_ConstructObject(cx, &QNameClass, NULL, NULL, 1, Valueify(&v)); if (!nameobj) return JS_FALSE; } else { - JS_ASSERT(nameobj->getClass() == &js_AttributeNameClass || - nameobj->getClass() == &js_QNameClass); + JS_ASSERT(nameobj->getClass() == &AttributeNameClass || + nameobj->getClass() == &QNameClass); } qn = nameobj; @@ -7458,7 +7458,7 @@ js_FindXMLProperty(JSContext *cx, const Value &nameval, JSObject **objp, jsid *i do { /* Skip any With object that can wrap XML. */ target = obj; - while (target->getClass() == &js_WithClass) { + while (target->getClass() == &WithClass) { proto = target->getProto(); if (!proto) break; diff --git a/js/src/jsxml.h b/js/src/jsxml.h index 4f5ac22cac20..b8ef86fd3cdf 100644 --- a/js/src/jsxml.h +++ b/js/src/jsxml.h @@ -219,48 +219,12 @@ js_NewXMLObject(JSContext *cx, JSXMLClass xml_class); extern JSObject * js_GetXMLObject(JSContext *cx, JSXML *xml); -extern JS_FRIEND_DATA(js::Class) js_XMLClass; -extern JS_FRIEND_DATA(js::Class) js_NamespaceClass; -extern JS_FRIEND_DATA(js::Class) js_QNameClass; -extern JS_FRIEND_DATA(js::Class) js_AttributeNameClass; -extern JS_FRIEND_DATA(js::Class) js_AnyNameClass; -extern js::Class js_XMLFilterClass; - /* * Methods to test whether an object or a value is of type "xml" (per typeof). */ -inline bool -JSObject::isXML() const -{ - return getClass() == &js_XMLClass; -} - -inline bool -JSObject::isXMLId() const -{ - js::Class *clasp = getClass(); - return clasp == &js_QNameClass || - clasp == &js_AttributeNameClass || - clasp == &js_AnyNameClass; -} #define VALUE_IS_XML(v) (!JSVAL_IS_PRIMITIVE(v) && JSVAL_TO_OBJECT(v)->isXML()) -inline bool -JSObject::isNamespace() const -{ - return getClass() == &js_NamespaceClass; -} - -inline bool -JSObject::isQName() const -{ - js::Class* clasp = getClass(); - return clasp == &js_QNameClass || - clasp == &js_AttributeNameClass || - clasp == &js_AnyNameClass; -} - static inline bool IsXML(const js::Value &v) { diff --git a/js/src/methodjit/BaseAssembler.h b/js/src/methodjit/BaseAssembler.h index 5c4ad7c3dcfe..40466df6e07a 100644 --- a/js/src/methodjit/BaseAssembler.h +++ b/js/src/methodjit/BaseAssembler.h @@ -204,8 +204,8 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist } Jump testFunction(Condition cond, RegisterID fun) { - return branchPtr(cond, Address(fun, offsetof(JSObject, clasp)), - ImmPtr(&js_FunctionClass)); + return branchPtr(cond, Address(fun, JSObject::offsetOfClassPointer()), + ImmPtr(&FunctionClass)); } /* @@ -811,7 +811,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist } void loadObjClass(RegisterID objReg, RegisterID destReg) { - loadPtr(Address(objReg, offsetof(JSObject, clasp)), destReg); + loadPtr(Address(objReg, JSObject::offsetOfClassPointer()), destReg); } Jump testClass(Condition cond, RegisterID claspReg, js::Class *clasp) { @@ -819,7 +819,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist } Jump testObjClass(Condition cond, RegisterID objReg, js::Class *clasp) { - return branchPtr(cond, Address(objReg, offsetof(JSObject, clasp)), ImmPtr(clasp)); + return branchPtr(cond, Address(objReg, JSObject::offsetOfClassPointer()), ImmPtr(clasp)); } void branchValue(Condition cond, RegisterID reg, int32 value, RegisterID result) @@ -1236,10 +1236,10 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist */ Jump getNewObject(JSContext *cx, RegisterID result, JSObject *templateObject) { - unsigned thingKind = templateObject->arenaHeader()->getThingKind(); + gc::AllocKind allocKind = templateObject->getAllocKind(); - JS_ASSERT(thingKind >= gc::FINALIZE_OBJECT0 && thingKind <= gc::FINALIZE_OBJECT_LAST); - size_t thingSize = gc::GCThingSizeMap[thingKind]; + JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST); + size_t thingSize = gc::Arena::thingSize(allocKind); JS_ASSERT(cx->typeInferenceEnabled()); JS_ASSERT(!templateObject->hasSlotsArray()); @@ -1253,7 +1253,8 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist * Inline FreeSpan::allocate. Only the case where the current freelist * span is not empty is handled. */ - gc::FreeSpan *list = &cx->compartment->freeLists.lists[thingKind]; + gc::FreeSpan *list = const_cast + (cx->compartment->arenas.getFreeList(allocKind)); loadPtr(&list->first, result); Jump jump = branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(&list->last), result); @@ -1288,7 +1289,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist } storePtr(ImmPtr(templateObject->lastProp), Address(result, offsetof(JSObject, lastProp))); - storePtr(ImmPtr(templateObject->clasp), Address(result, offsetof(JSObject, clasp))); + storePtr(ImmPtr(templateObject->getClass()), Address(result, JSObject::offsetOfClassPointer())); store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags))); store32(Imm32(templateObject->objShape), Address(result, offsetof(JSObject, objShape))); storePtr(ImmPtr(templateObject->newType), Address(result, offsetof(JSObject, newType))); diff --git a/js/src/methodjit/Compiler.cpp b/js/src/methodjit/Compiler.cpp index 539f7f25810a..180e794722dd 100644 --- a/js/src/methodjit/Compiler.cpp +++ b/js/src/methodjit/Compiler.cpp @@ -1328,7 +1328,8 @@ mjit::Compiler::finishThisUp(JITScript **jitp) #endif JS_ASSERT(size_t(cursor - (uint8*)jit) == dataSize); - JS_ASSERT(jit->scriptDataSize() == dataSize); + /* Pass in NULL here -- we don't want slop bytes to be counted. */ + JS_ASSERT(jit->scriptDataSize(NULL) == dataSize); /* Link fast and slow paths together. */ stubcc.fixCrossJumps(result, masm.size(), masm.size() + stubcc.size()); @@ -5594,7 +5595,7 @@ mjit::Compiler::iterNext(ptrdiff_t offset) frame.unpinReg(reg); /* Test clasp */ - Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &js_IteratorClass); + Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass); stubcc.linkExit(notFast, Uses(1)); /* Get private from iter obj. */ @@ -5649,7 +5650,7 @@ mjit::Compiler::iterMore(jsbytecode *target) RegisterID tempreg = frame.allocReg(); /* Test clasp */ - Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &js_IteratorClass); + Jump notFast = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass); stubcc.linkExitForBranch(notFast); /* Get private from iter obj. */ @@ -5688,7 +5689,7 @@ mjit::Compiler::iterEnd() frame.unpinReg(reg); /* Test clasp */ - Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, &js_IteratorClass); + Jump notIterator = masm.testObjClass(Assembler::NotEqual, reg, &IteratorClass); stubcc.linkExit(notIterator, Uses(1)); /* Get private from iter obj. */ diff --git a/js/src/methodjit/FastBuiltins.cpp b/js/src/methodjit/FastBuiltins.cpp index 454335b18a3c..acbf79342c7a 100644 --- a/js/src/methodjit/FastBuiltins.cpp +++ b/js/src/methodjit/FastBuiltins.cpp @@ -508,7 +508,7 @@ mjit::Compiler::compileArrayWithArgs(uint32 argc) stubcc.linkExit(emptyFreeList, Uses(0)); for (unsigned i = 0; i < argc; i++) { - FrameEntry *arg = frame.peek(-argc + i); + FrameEntry *arg = frame.peek(-(int)argc + i); frame.storeTo(arg, Address(result, JSObject::getFixedSlotOffset(i)), /* popped = */ true); } diff --git a/js/src/methodjit/FastOps.cpp b/js/src/methodjit/FastOps.cpp index 72dd8f2d3c87..91c8fda2d9bd 100644 --- a/js/src/methodjit/FastOps.cpp +++ b/js/src/methodjit/FastOps.cpp @@ -793,83 +793,69 @@ mjit::Compiler::jsop_typeof() bool mjit::Compiler::booleanJumpScript(JSOp op, jsbytecode *target) { + // JSOP_AND and JSOP_OR may leave the value on the stack (despite + // the frame.pop() below), so we need to sync it. + if (op == JSOP_AND || op == JSOP_OR) { + frame.syncForBranch(target, Uses(0)); + } else { + JS_ASSERT(op == JSOP_IFEQ || op == JSOP_IFEQX || + op == JSOP_IFNE || op == JSOP_IFNEX); + frame.syncForBranch(target, Uses(1)); + } + FrameEntry *fe = frame.peek(-1); - - MaybeRegisterID type; - MaybeRegisterID data; - - if (!fe->isTypeKnown() && !frame.shouldAvoidTypeRemat(fe)) - type.setReg(frame.copyTypeIntoReg(fe)); - if (!fe->isType(JSVAL_TYPE_DOUBLE)) - data.setReg(frame.copyDataIntoReg(fe)); - - frame.syncAndForgetEverything(); - Assembler::Condition cond = (op == JSOP_IFNE || op == JSOP_IFNEX || op == JSOP_OR) ? Assembler::NonZero : Assembler::Zero; - Assembler::Condition ncond = (op == JSOP_IFNE || op == JSOP_IFNEX || op == JSOP_OR) - ? Assembler::Zero - : Assembler::NonZero; - /* Inline path: Boolean guard + call script. */ - MaybeJump jmpNotBool; - MaybeJump jmpNotExecScript; - if (type.isSet()) { - jmpNotBool.setJump(masm.testBoolean(Assembler::NotEqual, type.reg())); - } else { - if (!fe->isTypeKnown()) { - jmpNotBool.setJump(masm.testBoolean(Assembler::NotEqual, - frame.addressOf(fe))); - } else if (fe->isNotType(JSVAL_TYPE_BOOLEAN) && - fe->isNotType(JSVAL_TYPE_INT32)) { - jmpNotBool.setJump(masm.jump()); - } + // Load data register and pin it so that frame.testBoolean + // below cannot evict it. + MaybeRegisterID data; + if (!fe->isType(JSVAL_TYPE_DOUBLE)) { + data = frame.tempRegForData(fe); + frame.pinReg(data.reg()); } - /* - * TODO: We don't need the second jump if - * jumpInScript() can go from ool path to inline path. - */ + // Test for boolean if needed. + bool needStub = false; + if (!fe->isType(JSVAL_TYPE_BOOLEAN) && !fe->isType(JSVAL_TYPE_INT32)) { + Jump notBool; + if (fe->mightBeType(JSVAL_TYPE_BOOLEAN)) + notBool = frame.testBoolean(Assembler::NotEqual, fe); + else + notBool = masm.jump(); + + stubcc.linkExitForBranch(notBool); + needStub = true; + } + if (data.isSet()) + frame.unpinReg(data.reg()); + + // Test + branch. + Jump branch; if (!fe->isType(JSVAL_TYPE_DOUBLE)) - jmpNotExecScript.setJump(masm.branchTest32(ncond, data.reg(), data.reg())); - Label lblExecScript = masm.label(); - Jump j = masm.jump(); + branch = masm.branchTest32(cond, data.reg()); + else + branch = masm.jump(); // dummy jump + // OOL path: call ValueToBoolean and branch. + if (needStub) { + stubcc.leave(); - /* OOL path: Conversion to boolean. */ - MaybeJump jmpCvtExecScript; - MaybeJump jmpCvtRejoin; - Label lblCvtPath = stubcc.masm.label(); - - if (!fe->isTypeKnown() || - !(fe->isType(JSVAL_TYPE_BOOLEAN) || fe->isType(JSVAL_TYPE_INT32))) { - /* Note: this cannot overwrite slots holding loop invariants. */ + // Note: this cannot overwrite slots holding loop invariants. stubcc.masm.infallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stubs::ValueToBoolean), frame.totalDepth()); - - jmpCvtExecScript.setJump(stubcc.masm.branchTest32(cond, Registers::ReturnReg, - Registers::ReturnReg)); - jmpCvtRejoin.setJump(stubcc.masm.jump()); } - /* Rejoin tag. */ - Label lblAfterScript = masm.label(); + Jump stubBranch = stubcc.masm.branchTest32(cond, Registers::ReturnReg); - /* Patch up jumps. */ - if (jmpNotBool.isSet()) - stubcc.linkExitDirect(jmpNotBool.getJump(), lblCvtPath); - if (jmpNotExecScript.isSet()) - jmpNotExecScript.getJump().linkTo(lblAfterScript, &masm); - - if (jmpCvtExecScript.isSet()) - stubcc.crossJump(jmpCvtExecScript.getJump(), lblExecScript); - if (jmpCvtRejoin.isSet()) - stubcc.crossJump(jmpCvtRejoin.getJump(), lblAfterScript); + // Rejoin from the stub call fallthrough. + if (needStub) + stubcc.rejoin(Changes(0)); frame.pop(); - return jumpAndTrace(j, target); + return jumpAndTrace(branch, target, &stubBranch); } bool @@ -1570,7 +1556,7 @@ mjit::Compiler::jsop_setelem(bool popGuaranteed) ic.slowPathStart = stubcc.syncExit(Uses(3)); // Guard obj is a dense array. - ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &js_ArrayClass); + ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass); stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); // Guard in range of initialized length. @@ -2120,7 +2106,7 @@ mjit::Compiler::jsop_getelem(bool isCall) } // Guard on the clasp. - ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &js_ArrayClass); + ic.claspGuard = masm.testObjClass(Assembler::NotEqual, ic.objReg, &ArrayClass); stubcc.linkExitDirect(ic.claspGuard, ic.slowPathStart); Int32Key key = id->isConstant() diff --git a/js/src/methodjit/InvokeHelpers.cpp b/js/src/methodjit/InvokeHelpers.cpp index c678042d0aae..fb33abfee249 100644 --- a/js/src/methodjit/InvokeHelpers.cpp +++ b/js/src/methodjit/InvokeHelpers.cpp @@ -115,7 +115,7 @@ top: jsbytecode *pc = script->main() + tn->start + tn->length; cx->regs().pc = pc; - JSBool ok = js_UnwindScope(cx, tn->stackDepth, JS_TRUE); + JSBool ok = UnwindScope(cx, tn->stackDepth, JS_TRUE); JS_ASSERT(cx->regs().sp == fp->base() + tn->stackDepth); switch (tn->kind) { @@ -178,7 +178,7 @@ static void InlineReturn(VMFrame &f) { JS_ASSERT(f.fp() != f.entryfp); - JS_ASSERT(!js_IsActiveWithOrBlock(f.cx, &f.fp()->scopeChain(), 0)); + JS_ASSERT(!IsActiveWithOrBlock(f.cx, f.fp()->scopeChain(), 0)); f.cx->stack.popInlineFrame(f.regs); DebugOnly op = js_GetOpcode(f.cx, f.fp()->script(), f.regs.pc); @@ -603,7 +603,7 @@ js_InternalThrow(VMFrame &f) // and epilogues. RunTracer(), Interpret(), and Invoke() all // rely on this property. JS_ASSERT(!f.fp()->finishedInInterpreter()); - js_UnwindScope(cx, 0, cx->isExceptionPending()); + UnwindScope(cx, 0, cx->isExceptionPending()); ScriptEpilogue(f.cx, f.fp(), false); // Don't remove the last frame, this is the responsibility of @@ -782,7 +782,7 @@ HandleErrorInExcessFrame(VMFrame &f, StackFrame *stopFp, bool searchedTopmostFra break; /* Unwind and return. */ - returnOK &= bool(js_UnwindScope(cx, 0, returnOK || cx->isExceptionPending())); + returnOK &= UnwindScope(cx, 0, returnOK || cx->isExceptionPending()); returnOK = ScriptEpilogue(cx, fp, returnOK); InlineReturn(f); } diff --git a/js/src/methodjit/MethodJIT.cpp b/js/src/methodjit/MethodJIT.cpp index f796039c1f98..194293f31bab 100644 --- a/js/src/methodjit/MethodJIT.cpp +++ b/js/src/methodjit/MethodJIT.cpp @@ -1137,21 +1137,23 @@ mjit::JITScript::~JITScript() } size_t -JSScript::jitDataSize() +JSScript::jitDataSize(size_t(*mus)(void *)) { size_t n = 0; if (jitNormal) - n += jitNormal->scriptDataSize(); + n += jitNormal->scriptDataSize(mus); if (jitCtor) - n += jitCtor->scriptDataSize(); + n += jitCtor->scriptDataSize(mus); return n; } /* Please keep in sync with Compiler::finishThisUp! */ size_t -mjit::JITScript::scriptDataSize() +mjit::JITScript::scriptDataSize(size_t(*mus)(void *)) { - return sizeof(JITScript) + + size_t usable = mus ? mus(this) : 0; + return usable ? usable : + sizeof(JITScript) + sizeof(NativeMapEntry) * nNmapPairs + sizeof(InlineFrame) * nInlineFrames + sizeof(CallSite) * nCallSites + diff --git a/js/src/methodjit/MethodJIT.h b/js/src/methodjit/MethodJIT.h index 6e250ebf3d01..7ae3fe3c125a 100644 --- a/js/src/methodjit/MethodJIT.h +++ b/js/src/methodjit/MethodJIT.h @@ -640,7 +640,7 @@ struct JITScript { void trace(JSTracer *trc); - size_t scriptDataSize(); + size_t scriptDataSize(size_t(*mus)(void *)); jsbytecode *nativeToPC(void *returnAddress, CallSite **pinline) const; @@ -687,9 +687,9 @@ inline void ReleaseScriptCode(JSContext *cx, JSScript *script) { if (script->jitCtor) - mjit::ReleaseScriptCode(cx, script, CONSTRUCT); + mjit::ReleaseScriptCode(cx, script, true); if (script->jitNormal) - mjit::ReleaseScriptCode(cx, script, NO_CONSTRUCT); + mjit::ReleaseScriptCode(cx, script, false); } // Expand all stack frames inlined by the JIT within a compartment. diff --git a/js/src/methodjit/MonoIC.cpp b/js/src/methodjit/MonoIC.cpp index 1db197b18f65..b28c717ab57b 100644 --- a/js/src/methodjit/MonoIC.cpp +++ b/js/src/methodjit/MonoIC.cpp @@ -775,7 +775,7 @@ class CallCompiler : public BaseCompiler RegisterID t0 = tempRegs.takeAnyReg().reg(); /* Guard that it's actually a function object. */ - Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, &js_FunctionClass); + Jump claspGuard = masm.testObjClass(Assembler::NotEqual, ic.funObjReg, &FunctionClass); /* Guard that it's the same function. */ JSFunction *fun = obj->getFunctionPrivate(); @@ -1354,7 +1354,7 @@ ic::GenerateArgumentCheckStub(VMFrame &f) JSC::CodeLocationLabel cs = linker.finalize(); JaegerSpew(JSpew_PICs, "generated ARGS CHECK stub %p (%lu bytes)\n", - cs.executableAddress(), masm.size()); + cs.executableAddress(), (unsigned long)masm.size()); Repatcher repatch(jit); repatch.relink(jit->argsCheckJump, cs); diff --git a/js/src/methodjit/PolyIC.cpp b/js/src/methodjit/PolyIC.cpp index 7576e2cf5752..24b5e3bb3376 100644 --- a/js/src/methodjit/PolyIC.cpp +++ b/js/src/methodjit/PolyIC.cpp @@ -323,7 +323,7 @@ class SetPropCompiler : public PICStubCompiler return error(); } - JS_ASSERT_IF(!shape->hasDefaultSetter(), obj->getClass() == &js_CallClass); + JS_ASSERT_IF(!shape->hasDefaultSetter(), obj->isCall()); MaybeJump skipOver; @@ -914,8 +914,8 @@ class GetPropCompiler : public PICStubCompiler Assembler masm; masm.loadObjClass(pic.objReg, pic.shapeReg); - Jump isDense = masm.testClass(Assembler::Equal, pic.shapeReg, &js_ArrayClass); - Jump notArray = masm.testClass(Assembler::NotEqual, pic.shapeReg, &js_SlowArrayClass); + Jump isDense = masm.testClass(Assembler::Equal, pic.shapeReg, &ArrayClass); + Jump notArray = masm.testClass(Assembler::NotEqual, pic.shapeReg, &SlowArrayClass); isDense.linkTo(masm.label(), &masm); masm.load32(Address(pic.objReg, offsetof(JSObject, privateData)), pic.objReg); @@ -1494,7 +1494,7 @@ class ScopeNameCompiler : public PICStubCompiler * tree in ComputeImplicitThis. */ if (pic.kind == ic::PICInfo::CALLNAME) { - JS_ASSERT(obj->getClass() == &js_CallClass); + JS_ASSERT(obj->isCall()); Value *thisVp = &cx->regs().sp[1]; Address thisSlot(JSFrameReg, StackFrame::offsetOfFixed(thisVp - cx->fp()->slots())); masm.storeValue(UndefinedValue(), thisSlot); @@ -1597,7 +1597,7 @@ class ScopeNameCompiler : public PICStubCompiler if (obj != getprop.holder) return disable("property is on proto of a scope object"); - if (obj->getClass() == &js_CallClass) + if (obj->isCall()) return generateCallStub(obj); LookupStatus status = getprop.testForGet(); @@ -1641,7 +1641,7 @@ class ScopeNameCompiler : public PICStubCompiler const Shape *shape = getprop.shape; JSObject *normalized = obj; - if (obj->getClass() == &js_WithClass && !shape->hasDefaultGetter()) + if (obj->isWith() && !shape->hasDefaultGetter()) normalized = js_UnwrapWithObject(cx, obj); NATIVE_GET(cx, normalized, holder, shape, JSGET_METHOD_BARRIER, vp, return false); if (thisvp) @@ -2049,7 +2049,7 @@ ic::CallProp(VMFrame &f, ic::PICInfo *pic) #if JS_HAS_NO_SUCH_METHOD if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) { regs.sp[-2].setString(JSID_TO_STRING(id)); - if (!js_OnUnknownMethod(cx, regs.sp - 2)) + if (!OnUnknownMethod(cx, regs.sp - 2)) THROW(); } #endif @@ -2805,7 +2805,7 @@ ic::CallElement(VMFrame &f, ic::GetElementIC *ic) if (JS_UNLIKELY(f.regs.sp[-2].isPrimitive()) && thisv.isObject()) { f.regs.sp[-2] = f.regs.sp[-1]; f.regs.sp[-1].setObject(*thisObj); - if (!js_OnUnknownMethod(cx, f.regs.sp - 2)) + if (!OnUnknownMethod(cx, f.regs.sp - 2)) THROW(); } else #endif diff --git a/js/src/methodjit/StubCalls.cpp b/js/src/methodjit/StubCalls.cpp index 752680127f99..772a71e9ed6c 100644 --- a/js/src/methodjit/StubCalls.cpp +++ b/js/src/methodjit/StubCalls.cpp @@ -389,7 +389,7 @@ NameOp(VMFrame &f, JSObject *obj, bool callname) } else { shape = (Shape *)prop; JSObject *normalized = obj; - if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter()) + if (normalized->isWith() && !shape->hasDefaultGetter()) normalized = js_UnwrapWithObject(cx, normalized); NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval, return NULL); } @@ -552,7 +552,7 @@ stubs::CallElem(VMFrame &f) if (JS_UNLIKELY(regs.sp[-2].isPrimitive()) && thisv.isObject()) { regs.sp[-2] = regs.sp[-1]; regs.sp[-1].setObject(*thisObj); - if (!js_OnUnknownMethod(cx, regs.sp - 2)) + if (!OnUnknownMethod(cx, regs.sp - 2)) THROW(); } else #endif @@ -1350,8 +1350,8 @@ stubs::NewInitObject(VMFrame &f, JSObject *baseobj) TypeObject *type = (TypeObject *) f.scratch; if (!baseobj) { - gc::FinalizeKind kind = GuessObjectGCKind(0, false); - JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind); + gc::AllocKind kind = GuessObjectGCKind(0, false); + JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass, kind); if (!obj) THROW(); if (type) @@ -1740,7 +1740,7 @@ stubs::CallProp(VMFrame &f, JSAtom *origAtom) #if JS_HAS_NO_SUCH_METHOD if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) { regs.sp[-2].setString(origAtom); - if (!js_OnUnknownMethod(cx, regs.sp - 2)) + if (!OnUnknownMethod(cx, regs.sp - 2)) THROW(); } #endif @@ -2016,10 +2016,9 @@ stubs::EnterBlock(VMFrame &f, JSObject *obj) * static scope. */ JSObject *obj2 = &fp->scopeChain(); - Class *clasp; - while ((clasp = obj2->getClass()) == &js_WithClass) + while (obj2->isWith()) obj2 = obj2->getParent(); - if (clasp == &js_BlockClass && + if (obj2->isBlock() && obj2->getPrivate() == js_FloatingFrameIfGenerator(cx, fp)) { JSObject *youngestProto = obj2->getProto(); JS_ASSERT(youngestProto->isStaticBlock()); @@ -2049,7 +2048,7 @@ stubs::LeaveBlock(VMFrame &f, JSObject *blockChain) */ JSObject *obj = &fp->scopeChain(); if (obj->getProto() == blockChain) { - JS_ASSERT(obj->getClass() == &js_BlockClass); + JS_ASSERT(obj->isBlock()); if (!js_PutBlockObject(cx, JS_TRUE)) THROW(); } diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index d08f5eaa5491..88f5e6c16f4c 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1561,9 +1561,9 @@ ValueToScript(JSContext *cx, jsval v) JSObject *obj = JSVAL_TO_OBJECT(v); JSClass *clasp = JS_GET_CLASS(cx, obj); - if (clasp == Jsvalify(&js_ScriptClass)) { + if (clasp == Jsvalify(&ScriptClass)) { script = (JSScript *) JS_GetPrivate(cx, obj); - } else if (clasp == Jsvalify(&js_GeneratorClass)) { + } else if (clasp == Jsvalify(&GeneratorClass)) { JSGenerator *gen = (JSGenerator *) JS_GetPrivate(cx, obj); fun = gen->floatingFrame()->fun(); script = fun->script(); @@ -1621,8 +1621,8 @@ GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp, v = argv[0]; intarg = 0; if (!JSVAL_IS_PRIMITIVE(v) && - (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&js_FunctionClass) || - JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&js_ScriptClass))) { + (JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&FunctionClass) || + JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == Jsvalify(&ScriptClass))) { script = ValueToScript(cx, v); if (!script) return JS_FALSE; @@ -4071,13 +4071,13 @@ MJitCodeStats(JSContext *cx, uintN argc, jsval *vp) #ifdef JS_METHODJIT static void -SumJitDataSizeCallabck(JSContext *cx, void *data, void *thing, +SumJitDataSizeCallback(JSContext *cx, void *data, void *thing, JSGCTraceKind traceKind, size_t thingSize) { size_t *sump = static_cast(data); JS_ASSERT(traceKind == JSTRACE_SCRIPT); JSScript *script = static_cast(thing); - *sump += script->jitDataSize(); + *sump += script->jitDataSize(NULL); } #endif @@ -4087,7 +4087,7 @@ MJitDataStats(JSContext *cx, uintN argc, jsval *vp) { #ifdef JS_METHODJIT size_t n = 0; - IterateCells(cx, NULL, gc::FINALIZE_TYPE_OBJECT, &n, SumJitDataSizeCallabck); + IterateCells(cx, NULL, gc::FINALIZE_TYPE_OBJECT, &n, SumJitDataSizeCallback); JS_SET_RVAL(cx, vp, INT_TO_JSVAL(n)); #else JS_SET_RVAL(cx, vp, JSVAL_VOID); @@ -4872,6 +4872,7 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) if (!report) { fprintf(gErrFile, "%s\n", message); + fflush(gErrFile); return; } @@ -4934,6 +4935,7 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) } fputs("^\n", gErrFile); out: + fflush(gErrFile); if (!JSREPORT_IS_WARNING(report->flags)) { if (report->errorNumber == JSMSG_OUT_OF_MEMORY) { gExitCode = EXITCODE_OUT_OF_MEMORY; @@ -5110,7 +5112,7 @@ env_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) ToString valstr(cx, *vp, JS_TRUE); if (valstr.threw()) return JS_FALSE; -#if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX +#if defined XP_WIN || defined HPUX || defined OSF1 { char *waste = JS_smprintf("%s=%s", idstr.getBytes(), valstr.getBytes()); if (!waste) { diff --git a/js/src/shell/jsheaptools.cpp b/js/src/shell/jsheaptools.cpp index 812a7289ebd0..cacc165dee79 100644 --- a/js/src/shell/jsheaptools.cpp +++ b/js/src/shell/jsheaptools.cpp @@ -368,12 +368,12 @@ class ReferenceFinder { JSObject *object = static_cast(cell); /* Certain classes of object are for internal use only. */ - JSClass *clasp = JS_GET_CLASS(context, object); - if (clasp == Jsvalify(&js_BlockClass) || - clasp == Jsvalify(&js_CallClass) || - clasp == Jsvalify(&js_WithClass) || - clasp == Jsvalify(&js_DeclEnvClass)) + if (object->isBlock() || + object->isCall() || + object->isWith() || + object->isDeclEnv()) { return JSVAL_VOID; + } /* Internal function objects should also not be revealed. */ if (JS_ObjectIsFunction(context, object) && IsInternalFunctionObject(object)) diff --git a/js/src/tracejit/Writer.h b/js/src/tracejit/Writer.h index fed6d7b5ea2c..6ffb161d7234 100644 --- a/js/src/tracejit/Writer.h +++ b/js/src/tracejit/Writer.h @@ -479,7 +479,7 @@ class Writer } nj::LIns *ldpObjClasp(nj::LIns *obj, nj::LoadQual loadQual) const { - return name(lir->insLoad(nj::LIR_ldp, obj, offsetof(JSObject, clasp), ACCSET_OBJ_CLASP, + return name(lir->insLoad(nj::LIR_ldp, obj, JSObject::offsetOfClassPointer(), ACCSET_OBJ_CLASP, loadQual), "clasp"); } diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index 7e07cd59bc71..7e401db8f669 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -151,7 +151,7 @@ class ArgumentsObject : public ::JSObject static const uint32 INITIAL_LENGTH_SLOT = 0; static const uint32 DATA_SLOT = 1; - protected: + public: static const uint32 RESERVED_SLOTS = 2; private: @@ -240,8 +240,6 @@ class ArgumentsObject : public ::JSObject */ class NormalArgumentsObject : public ArgumentsObject { - static js::Class jsClass; - friend bool JSObject::isNormalArguments() const; friend struct EmptyShape; // for EmptyShape::getEmptyArgumentsShape friend ArgumentsObject * @@ -266,8 +264,6 @@ class NormalArgumentsObject : public ArgumentsObject */ class StrictArgumentsObject : public ArgumentsObject { - static js::Class jsClass; - friend bool JSObject::isStrictArguments() const; friend ArgumentsObject * ArgumentsObject::create(JSContext *cx, uint32 argc, JSObject &callee); @@ -275,12 +271,6 @@ class StrictArgumentsObject : public ArgumentsObject } // namespace js -inline bool -JSObject::isNormalArguments() const -{ - return getClass() == &js::NormalArgumentsObject::jsClass; -} - js::NormalArgumentsObject * JSObject::asNormalArguments() { @@ -288,12 +278,6 @@ JSObject::asNormalArguments() return reinterpret_cast(this); } -inline bool -JSObject::isStrictArguments() const -{ - return getClass() == &js::StrictArgumentsObject::jsClass; -} - js::StrictArgumentsObject * JSObject::asStrictArguments() { @@ -301,12 +285,6 @@ JSObject::asStrictArguments() return reinterpret_cast(this); } -inline bool -JSObject::isArguments() const -{ - return isNormalArguments() || isStrictArguments(); -} - js::ArgumentsObject * JSObject::asArguments() { diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index d2b3b1ee9915..b950ca392f61 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -347,9 +347,9 @@ JS_STATIC_ASSERT(uintN(JSSLOT_DEBUGFRAME_OWNER) == uintN(JSSLOT_DEBUGSCRIPT_OWNE Debugger * Debugger::fromChildJSObject(JSObject *obj) { - JS_ASSERT(obj->clasp == &DebuggerFrame_class || - obj->clasp == &DebuggerObject_class || - obj->clasp == &DebuggerScript_class); + JS_ASSERT(obj->getClass() == &DebuggerFrame_class || + obj->getClass() == &DebuggerObject_class || + obj->getClass() == &DebuggerScript_class); JSObject *dbgobj = &obj->getReservedSlot(JSSLOT_DEBUGOBJECT_OWNER).toObject(); return fromJSObject(dbgobj); } @@ -523,9 +523,9 @@ Debugger::unwrapDebuggeeValue(JSContext *cx, Value *vp) assertSameCompartment(cx, object, *vp); if (vp->isObject()) { JSObject *dobj = &vp->toObject(); - if (dobj->clasp != &DebuggerObject_class) { + if (dobj->getClass() != &DebuggerObject_class) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_EXPECTED_TYPE, - "Debugger", "Debugger.Object", dobj->clasp->name); + "Debugger", "Debugger.Object", dobj->getClass()->name); return false; } @@ -587,7 +587,7 @@ Debugger::newCompletionValue(AutoCompartment &ac, bool ok, Value val, Value *vp) return true; } - JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass); + JSObject *obj = NewBuiltinClassInstance(cx, &ObjectClass); if (!obj || !wrapDebuggeeValue(cx, &val) || !DefineNativeProperty(cx, obj, key, val, PropertyStub, StrictPropertyStub, @@ -1479,7 +1479,7 @@ Debugger::unwrapDebuggeeArgument(JSContext *cx, const Value &v) */ JSObject *obj = NonNullObject(cx, v); if (obj) { - if (obj->clasp == &DebuggerObject_class) { + if (obj->getClass() == &DebuggerObject_class) { Value rv = v; if (!unwrapDebuggeeValue(cx, &rv)) return NULL; @@ -1977,7 +1977,7 @@ DebuggerScript_check(JSContext *cx, const Value &v, const char *clsname, const c return NULL; } JSObject *thisobj = &v.toObject(); - if (thisobj->clasp != &DebuggerScript_class) { + if (thisobj->getClass() != &DebuggerScript_class) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, clsname, fnname, thisobj->getClass()->name); return NULL; @@ -2947,7 +2947,7 @@ DebuggerFrameEval(JSContext *cx, uintN argc, Value *vp, EvalBindingsMode mode) /* If evalWithBindings, create the inner scope object. */ if (mode == WithBindings) { /* TODO - Should probably create a With object here. */ - scobj = NewNonFunction(cx, &js_ObjectClass, NULL, scobj); + scobj = NewNonFunction(cx, &ObjectClass, NULL, scobj); if (!scobj) return false; for (size_t i = 0; i < keys.length(); i++) { @@ -3040,7 +3040,7 @@ DebuggerObject_checkThis(JSContext *cx, const CallArgs &args, const char *fnname return NULL; } JSObject *thisobj = &args.thisv().toObject(); - if (thisobj->clasp != &DebuggerObject_class) { + if (thisobj->getClass() != &DebuggerObject_class) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_INCOMPATIBLE_PROTO, "Debugger.Object", fnname, thisobj->getClass()->name); return NULL; @@ -3098,7 +3098,7 @@ static JSBool DebuggerObject_getClass(JSContext *cx, uintN argc, Value *vp) { THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "get class", args, refobj); - const char *s = refobj->clasp->name; + const char *s = refobj->getClass()->name; JSAtom *str = js_Atomize(cx, s, strlen(s)); if (!str) return false; diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index c00f07c6e232..69c5cf215c73 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -227,8 +227,8 @@ GlobalObject::createConstructor(JSContext *cx, Native ctor, Class *clasp, JSAtom static JSObject * CreateBlankProto(JSContext *cx, Class *clasp, JSObject &proto, GlobalObject &global) { - JS_ASSERT(clasp != &js_ObjectClass); - JS_ASSERT(clasp != &js_FunctionClass); + JS_ASSERT(clasp != &ObjectClass); + JS_ASSERT(clasp != &FunctionClass); JSObject *blankProto = NewNonFunction(cx, clasp, &proto, &global); if (!blankProto || !blankProto->setSingletonType(cx)) @@ -300,7 +300,7 @@ GlobalObject::getDebuggers() Value debuggers = getReservedSlot(DEBUGGERS); if (debuggers.isUndefined()) return NULL; - JS_ASSERT(debuggers.toObject().clasp == &GlobalDebuggees_class); + JS_ASSERT(debuggers.toObject().getClass() == &GlobalDebuggees_class); return (DebuggerVector *) debuggers.toObject().getPrivate(); } diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 2c79e9b16e06..68ed681ebd32 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -358,7 +358,7 @@ StackFrame::callObj() const JS_ASSERT_IF(isNonEvalFunctionFrame() || isStrictEvalFrame(), hasCallObj()); JSObject *pobj = &scopeChain(); - while (JS_UNLIKELY(pobj->getClass() != &js_CallClass)) { + while (JS_UNLIKELY(!pobj->isCall())) { JS_ASSERT(IsCacheableNonGlobalScope(pobj) || pobj->isWith()); pobj = pobj->getParent(); } diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index 0d026bdf7bb3..5c6df8ef468e 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -152,7 +152,7 @@ StackFrame::stealFrameAndSlots(Value *vp, StackFrame *otherfp, otherfp->flags_ &= ~HAS_CALL_OBJ; if (js_IsNamedLambda(fun())) { JSObject *env = obj.getParent(); - JS_ASSERT(env->getClass() == &js_DeclEnvClass); + JS_ASSERT(env->isDeclEnv()); env->setPrivate(this); } } diff --git a/js/src/vm/String-inl.h b/js/src/vm/String-inl.h index 5feff3947567..827e18ec29d8 100644 --- a/js/src/vm/String-inl.h +++ b/js/src/vm/String-inl.h @@ -416,10 +416,10 @@ inline void JSAtom::finalize(JSRuntime *rt) { JS_ASSERT(isAtom()); - if (arenaHeader()->getThingKind() == js::gc::FINALIZE_STRING) + if (getAllocKind() == js::gc::FINALIZE_STRING) asFlat().finalize(rt); else - JS_ASSERT(arenaHeader()->getThingKind() == js::gc::FINALIZE_SHORT_STRING); + JS_ASSERT(getAllocKind() == js::gc::FINALIZE_SHORT_STRING); } inline void diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index 0974c65e64b6..daad19597dd3 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=4 sw=4 et tw=79 ft=cpp: * * ***** BEGIN LICENSE BLOCK ***** @@ -49,7 +49,7 @@ using namespace js; bool JSString::isShort() const { - bool is_short = arenaHeader()->getThingKind() == gc::FINALIZE_SHORT_STRING; + bool is_short = (getAllocKind() == gc::FINALIZE_SHORT_STRING); JS_ASSERT_IF(is_short, isFlat()); return is_short; } @@ -69,7 +69,7 @@ JSString::isInline() const bool JSString::isExternal() const { - bool is_external = arenaHeader()->getThingKind() == gc::FINALIZE_EXTERNAL_STRING; + bool is_external = (getAllocKind() == gc::FINALIZE_EXTERNAL_STRING); JS_ASSERT_IF(is_external, isFixed()); return is_external; } diff --git a/js/src/vm/StringObject-inl.h b/js/src/vm/StringObject-inl.h index db0f2b1b1434..b8068546ae44 100644 --- a/js/src/vm/StringObject-inl.h +++ b/js/src/vm/StringObject-inl.h @@ -55,7 +55,7 @@ namespace js { inline StringObject * StringObject::create(JSContext *cx, JSString *str) { - JSObject *obj = NewBuiltinClassInstance(cx, &js_StringClass); + JSObject *obj = NewBuiltinClassInstance(cx, &StringClass); if (!obj) return NULL; StringObject *strobj = obj->asString(); @@ -67,8 +67,8 @@ StringObject::create(JSContext *cx, JSString *str) inline StringObject * StringObject::createWithProto(JSContext *cx, JSString *str, JSObject &proto) { - JS_ASSERT(gc::FINALIZE_OBJECT2 == gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(&js_StringClass))); - JSObject *obj = NewObjectWithClassProto(cx, &js_StringClass, &proto, gc::FINALIZE_OBJECT2); + JS_ASSERT(gc::FINALIZE_OBJECT2 == gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(&StringClass))); + JSObject *obj = NewObjectWithClassProto(cx, &StringClass, &proto, gc::FINALIZE_OBJECT2); if (!obj) return NULL; StringObject *strobj = obj->asString(); diff --git a/js/src/xpconnect/shell/xpcshell.cpp b/js/src/xpconnect/shell/xpcshell.cpp index aa7034f828bc..ec26d2d6f12b 100644 --- a/js/src/xpconnect/shell/xpcshell.cpp +++ b/js/src/xpconnect/shell/xpcshell.cpp @@ -879,8 +879,7 @@ env_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) JSAutoByteString value(cx, valstr); if (!value) return JS_FALSE; -#if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX \ - || defined SCO +#if defined XP_WIN || defined HPUX || defined OSF1 || defined SCO { char *waste = JS_smprintf("%s=%s", name.ptr(), value.ptr()); if (!waste) { diff --git a/js/src/xpconnect/src/dom_quickstubs.qsconf b/js/src/xpconnect/src/dom_quickstubs.qsconf index d85a156dc80e..5cd451c3a869 100644 --- a/js/src/xpconnect/src/dom_quickstubs.qsconf +++ b/js/src/xpconnect/src/dom_quickstubs.qsconf @@ -839,6 +839,12 @@ customMethodCalls = { 'thisType': 'nsINode', 'canFail': False }, + 'nsIDOMNode_Contains': { + 'thisType': 'nsINode', + 'arg0Type': 'nsINode', + 'code': ' PRBool result = self->Contains(arg0);', + 'canFail': False + }, 'nsIDOMNSHTMLElement_': { 'thisType': 'nsGenericHTMLElement' }, diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index a82aad49fce7..13fd0a1065da 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -733,8 +733,8 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) JSContext *cx = mCycleCollectionContext->GetJSContext(); JSGCTraceKind traceKind = js_GetGCThingTraceKind(p); - JSObject *obj; - js::Class *clazz; + JSObject *obj = nsnull; + js::Class *clazz = nsnull; // We do not want to add wrappers to the cycle collector if they're not // explicitly marked as main thread only, because the cycle collector isn't @@ -794,8 +794,6 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) char name[72]; if(traceKind == JSTRACE_OBJECT) { - JSObject *obj = static_cast(p); - js::Class *clazz = obj->getClass(); XPCNativeScriptableInfo* si = nsnull; if(IS_PROTO_CLASS(clazz)) { @@ -808,7 +806,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) JS_snprintf(name, sizeof(name), "JS Object (%s - %s)", clazz->name, si->GetJSClass()->name); } - else if(clazz == &js_ScriptClass) + else if(clazz == &js::ScriptClass) { JSScript* script = (JSScript*) xpc_GetJSPrivate(obj); if(script->filename) @@ -822,7 +820,7 @@ nsXPConnect::Traverse(void *p, nsCycleCollectionTraversalCallback &cb) JS_snprintf(name, sizeof(name), "JS Object (Script)"); } } - else if(clazz == &js_FunctionClass) + else if(clazz == &js::FunctionClass) { JSFunction* fun = (JSFunction*) xpc_GetJSPrivate(obj); JSString* str = JS_GetFunctionId(fun); diff --git a/js/src/xpconnect/src/xpcconvert.cpp b/js/src/xpconnect/src/xpcconvert.cpp index 67b6d7ea5a66..a7f85bb1aa94 100644 --- a/js/src/xpconnect/src/xpcconvert.cpp +++ b/js/src/xpconnect/src/xpcconvert.cpp @@ -2119,7 +2119,8 @@ XPCConvert::JSArray2Native(XPCCallContext& ccx, void** d, jsval s, #define POPULATE(_mode, _t) \ PR_BEGIN_MACRO \ cleanupMode = _mode; \ - if (capacity > PR_UINT32_MAX / sizeof(_t) || \ + size_t max = PR_UINT32_MAX / sizeof(_t); \ + if (capacity > max || \ nsnull == (array = nsMemory::Alloc(capacity * sizeof(_t)))) \ { \ if(pErr) \ diff --git a/js/src/xpconnect/src/xpcjsruntime.cpp b/js/src/xpconnect/src/xpcjsruntime.cpp index 8ba371b73e84..3860dce81ddb 100644 --- a/js/src/xpconnect/src/xpcjsruntime.cpp +++ b/js/src/xpconnect/src/xpcjsruntime.cpp @@ -1324,13 +1324,14 @@ ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena, IterateData *data = static_cast(vdata); data->currCompartmentStats->gcHeapArenaHeaders += sizeof(js::gc::ArenaHeader); + size_t allocationSpace = arena->thingsSpan(thingSize); data->currCompartmentStats->gcHeapArenaPadding += - arena->thingsStartOffset(thingSize) - sizeof(js::gc::ArenaHeader); + js::gc::ArenaSize - allocationSpace - sizeof(js::gc::ArenaHeader); // We don't call the callback on unused things. So we compute the // unused space like this: arenaUnused = maxArenaUnused - arenaUsed. // We do this by setting arenaUnused to maxArenaUnused here, and then // subtracting thingSize for every used cell, in CellCallback(). - data->currCompartmentStats->gcHeapArenaUnused += arena->thingsSpan(thingSize); + data->currCompartmentStats->gcHeapArenaUnused += allocationSpace; } void @@ -1345,7 +1346,7 @@ CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind, case JSTRACE_OBJECT: { JSObject *obj = static_cast(thing); - curr->objectSlots += JS_ObjectCountDynamicSlots(obj) * sizeof(js::Value); + curr->objectSlots += obj->sizeOfSlotsArray(moz_malloc_usable_size); break; } case JSTRACE_STRING: @@ -1358,15 +1359,19 @@ CellCallback(JSContext *cx, void *vdata, void *thing, JSGCTraceKind traceKind, { js::Shape *shape = static_cast(thing); if(shape->hasTable()) - curr->propertyTables += shape->getTable()->sizeOf(); + curr->propertyTables += + shape->getTable()->sizeOf(moz_malloc_usable_size); break; } case JSTRACE_SCRIPT: { JSScript *script = static_cast(thing); - curr->scriptData += script->dataSize(); + if (script->data != script->inlineData) { + size_t usable = moz_malloc_usable_size(script->data); + curr->scriptData += usable ? usable : script->dataSize(); + } #ifdef JS_METHODJIT - curr->mjitData += script->jitDataSize(); + curr->mjitData += script->jitDataSize(moz_malloc_usable_size); #endif break; } @@ -1627,6 +1632,8 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data) for(js::ThreadDataIter i(rt); !i.empty(); i.popFront()) data->stackSize += i.threadData()->stackSpace.committedSize(); + size_t usable = moz_malloc_usable_size(rt); + data->runtimeObjectSize += usable ? usable : sizeof(JSRuntime); data->atomsTableSize += rt->atomState.atoms.tableSize(); } @@ -1673,6 +1680,9 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data) return true; } +#define SLOP_BYTES_STRING \ + " The measurement includes slop bytes caused by the heap allocator rounding up request sizes." + static void ReportCompartmentStats(const CompartmentStats &stats, const nsACString &pathPrefix, @@ -1735,7 +1745,7 @@ ReportCompartmentStats(const CompartmentStats &stats, callback, closure); ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name, - "gc-heap/shapes"), + "gc-heap/type-objects"), JS_GC_HEAP_KIND, stats.gcHeapKinds[JSTRACE_TYPE_OBJECT], "Memory on the compartment's garbage-collected JavaScript heap that holds " "type inference information.", @@ -1755,7 +1765,7 @@ ReportCompartmentStats(const CompartmentStats &stats, "which are used to represent object properties. Some objects also " "contain a fixed number of slots which are stored on the compartment's " "JavaScript heap; those slots are not counted here, but in " - "'gc-heap/objects' instead.", + "'gc-heap/objects' instead." SLOP_BYTES_STRING, callback, closure); ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name, @@ -1773,7 +1783,7 @@ ReportCompartmentStats(const CompartmentStats &stats, nsIMemoryReporter::KIND_HEAP, stats.propertyTables, "Memory allocated for the compartment's property tables. A property " "table is an internal data structure that makes JavaScript property " - "accesses fast.", + "accesses fast." SLOP_BYTES_STRING, callback, closure); ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name, @@ -1783,20 +1793,11 @@ ReportCompartmentStats(const CompartmentStats &stats, "Arrays attached to prototype JS objects managing shape information.", callback, closure); - ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name, - "scripts"), - nsIMemoryReporter::KIND_HEAP, - stats.gcHeapKinds[JSTRACE_SCRIPT], - "Memory allocated for the compartment's JSScripts. A JSScript is created " - "for each user-defined function in a script. One is also created for " - "the top-level code in a script.", - callback, closure); - ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name, "script-data"), nsIMemoryReporter::KIND_HEAP, stats.scriptData, "Memory allocated for JSScript bytecode and various variable-length " - "tables.", + "tables." SLOP_BYTES_STRING, callback, closure); #ifdef JS_METHODJIT @@ -1823,7 +1824,7 @@ ReportCompartmentStats(const CompartmentStats &stats, "mjit-data"), nsIMemoryReporter::KIND_HEAP, stats.mjitData, "Memory used by the method JIT for the compartment's compilation data: " - "JITScripts, native maps, and inline cache structs.", + "JITScripts, native maps, and inline cache structs." SLOP_BYTES_STRING, callback, closure); #endif #ifdef JS_TRACER @@ -1883,11 +1884,11 @@ ReportCompartmentStats(const CompartmentStats &stats, callback, closure); ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name, - "type-inference-temporary"), + "analysis-temporary"), nsIMemoryReporter::KIND_HEAP, stats.typeInferenceMemory.temporary, - "Memory used during type inference to hold transient analysis " - "information. Cleared on GC.", + "Memory used during type inference and compilation to hold transient " + "analysis information. Cleared on GC.", callback, closure); } @@ -1905,8 +1906,8 @@ ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix, } ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/runtime-object"), - nsIMemoryReporter::KIND_NONHEAP, sizeof(JSRuntime), - "Memory used by the JSRuntime object.", + nsIMemoryReporter::KIND_NONHEAP, data.runtimeObjectSize, + "Memory used by the JSRuntime object." SLOP_BYTES_STRING, callback, closure); ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("runtime/atoms-table"), diff --git a/js/src/xpconnect/src/xpcpublic.h b/js/src/xpconnect/src/xpcpublic.h index b1f037efc7b8..520f2f7a2ab7 100644 --- a/js/src/xpconnect/src/xpcpublic.h +++ b/js/src/xpconnect/src/xpcpublic.h @@ -227,7 +227,8 @@ struct CompartmentStats struct IterateData { IterateData() - : atomsTableSize(0), + : runtimeObjectSize(0), + atomsTableSize(0), stackSize(0), gcHeapChunkTotal(0), gcHeapChunkCleanUnused(0), @@ -238,6 +239,7 @@ struct IterateData compartmentStatsVector(), currCompartmentStats(NULL) { } + PRInt64 runtimeObjectSize; PRInt64 atomsTableSize; PRInt64 stackSize; PRInt64 gcHeapChunkTotal; diff --git a/js/src/xpconnect/src/xpcwrappedjs.cpp b/js/src/xpconnect/src/xpcwrappedjs.cpp index 981f842fcbc5..79666f5df140 100644 --- a/js/src/xpconnect/src/xpcwrappedjs.cpp +++ b/js/src/xpconnect/src/xpcwrappedjs.cpp @@ -281,7 +281,7 @@ nsXPCWrappedJS::GetNewOrUsed(XPCCallContext& ccx, { JSObject2WrappedJSMap* map; JSObject* rootJSObj; - nsXPCWrappedJS* root; + nsXPCWrappedJS* root = nsnull; nsXPCWrappedJS* wrapper = nsnull; nsXPCWrappedJSClass* clazz = nsnull; XPCJSRuntime* rt = ccx.GetRuntime(); diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 6a61f5e107d6..fe66b836516a 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2484,8 +2484,8 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame, aFrame->PresContext(), dummy, bounds, aFactor); } else { - NS_ASSERTION(aFrame->Preserves3DChildren(), - "If we don't have a transform, then we must be at least preserving transforms of our children"); + NS_ASSERTION(aFrame->GetStyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D, + "If we don't have a transform, then we must be at least attempting to preserve the transforms of our children"); } const nsStyleDisplay* parentDisp = nsnull; diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 7f604d8d9ad0..9221d2916ac4 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2080,6 +2080,7 @@ public: nsDisplayItem(aBuilder, aFrame), mStoredList(aBuilder, aFrame, aList) { MOZ_COUNT_CTOR(nsDisplayTransform); + NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); } nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame, @@ -2087,6 +2088,7 @@ public: nsDisplayItem(aBuilder, aFrame), mStoredList(aBuilder, aFrame, aItem) { MOZ_COUNT_CTOR(nsDisplayTransform); + NS_ABORT_IF_FALSE(aFrame, "Must have a frame!"); } #ifdef NS_BUILD_REFCNT_LOGGING diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 126dd9967c78..bacda5c31e00 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -6988,6 +6988,43 @@ static PRBool CanHandleContextMenuEvent(nsMouseEvent* aMouseEvent, return PR_TRUE; } +static PRBool +IsFullScreenAndRestrictedKeyEvent(nsIContent* aTarget, const nsEvent* aEvent) +{ + NS_ABORT_IF_FALSE(aEvent, "Must have an event to check."); + + // Bail out if the event is not a key event, or the target's document is + // not in DOM full screen mode, or full-screen key input is not restricted. + nsIDocument *doc; + if (!aTarget || + (aEvent->message != NS_KEY_DOWN && + aEvent->message != NS_KEY_UP && + aEvent->message != NS_KEY_PRESS) || + !(doc = aTarget->GetOwnerDoc()) || + !doc->IsFullScreenDoc() || + !nsContentUtils::IsFullScreenKeyInputRestricted()) { + return PR_FALSE; + } + + // Key input is restricted. Determine if the key event has a restricted + // key code. Non-restricted codes are: + // DOM_VK_CANCEL to DOM_VK_CAPS_LOCK, inclusive + // DOM_VK_SPACE to DOM_VK_DELETE, inclusive + // DOM_VK_SEMICOLON to DOM_VK_EQUALS, inclusive + // DOM_VK_MULTIPLY to DOM_VK_META, inclusive + int key = static_cast(aEvent)->keyCode; + if ((key >= NS_VK_CANCEL && key <= NS_VK_CAPS_LOCK) || + (key >= NS_VK_SPACE && key <= NS_VK_DELETE) || + (key >= NS_VK_SEMICOLON && key <= NS_VK_EQUALS) || + (key >= NS_VK_MULTIPLY && key <= NS_VK_META)) { + return PR_FALSE; + } + + // Otherwise, fullscreen is enabled, key input is restricted, and the key + // code is not an allowed key code. + return PR_TRUE; +} + nsresult PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView, nsEventStatus* aStatus) @@ -7029,11 +7066,21 @@ PresShell::HandleEventInternal(nsEvent* aEvent, nsIView *aView, // XXX How about IME events and input events for plugins? if (NS_IS_TRUSTED_EVENT(aEvent)) { switch (aEvent->message) { - case NS_MOUSE_BUTTON_DOWN: - case NS_MOUSE_BUTTON_UP: case NS_KEY_PRESS: case NS_KEY_DOWN: case NS_KEY_UP: + if (IsFullScreenAndRestrictedKeyEvent(mCurrentEventContent, aEvent) && + aEvent->message == NS_KEY_DOWN) { + // We're in DOM full-screen mode, and a key with a restricted key + // code has been pressed. Exit full-screen mode. + NS_DispatchToCurrentThread( + NS_NewRunnableMethod(mCurrentEventContent->GetOwnerDoc(), + &nsIDocument::CancelFullScreen)); + } + // Else not full-screen mode or key code is unrestricted, fall + // through to normal handling. + case NS_MOUSE_BUTTON_DOWN: + case NS_MOUSE_BUTTON_UP: isHandlingUserInput = PR_TRUE; break; case NS_DRAGDROP_DROP: diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index c9e39a01f9dc..0e1816e8922b 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -786,7 +786,17 @@ nsIFrame::IsTransformed() const PRBool nsIFrame::Preserves3DChildren() const { - return GetStyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D && IsTransformed(); + if (GetStyleDisplay()->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D || !IsTransformed()) + return PR_FALSE; + + // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d. + if (GetType() == nsGkAtoms::scrollFrame) + return PR_FALSE; + + nsRect temp; + return (!ApplyOverflowClipping(nsnull, this, GetStyleDisplay(), &temp) && + !ApplyAbsPosClipping(nsnull, GetStyleDisplay(), this, &temp) && + !nsSVGIntegrationUtils::UsingEffectsForFrame(this)); } PRBool @@ -795,11 +805,7 @@ nsIFrame::Preserves3D() const if (!GetParent() || !GetParent()->Preserves3DChildren() || !IsTransformed()) { return PR_FALSE; } - - nsRect temp; - return (!ApplyOverflowClipping(nsnull, this, GetStyleDisplay(), &temp) && - !ApplyAbsPosClipping(nsnull, GetStyleDisplay(), this, &temp) && - !nsSVGIntegrationUtils::UsingEffectsForFrame(this)); + return PR_TRUE; } nsRect @@ -1477,12 +1483,14 @@ WrapPreserve3DList(nsIFrame *aFrame, nsDisplayListBuilder *aBuilder, nsDisplayLi nsresult rv = NS_OK; nsDisplayList newList; while (nsDisplayItem *item = aList->RemoveBottom()) { - if (item->GetUnderlyingFrame() && item->GetUnderlyingFrame()->GetParent()->Preserves3DChildren()) { + nsIFrame *childFrame = item->GetUnderlyingFrame(); + NS_ASSERTION(childFrame, "All display items to be wrapped must have a frame!"); + if (childFrame->GetParent()->Preserves3DChildren()) { switch (item->GetType()) { case nsDisplayItem::TYPE_TRANSFORM: { // The child transform frame should always preserve 3d. In the cases where preserve-3d is disabled // such as clipping, this would be wrapped in a clip display object, and we wouldn't reach this point. - NS_ASSERTION(item->GetUnderlyingFrame()->Preserves3D(), "Child transform frame must preserve 3d!"); + NS_ASSERTION(childFrame->Preserves3D(), "Child transform frame must preserve 3d!"); break; } case nsDisplayItem::TYPE_WRAP_LIST: { @@ -1496,12 +1504,12 @@ WrapPreserve3DList(nsIFrame *aFrame, nsDisplayListBuilder *aBuilder, nsDisplayLi break; } default: { - item = new (aBuilder) nsDisplayTransform(aBuilder, item->GetUnderlyingFrame(), item); + item = new (aBuilder) nsDisplayTransform(aBuilder, childFrame, item); break; } } } else { - item = new (aBuilder) nsDisplayTransform(aBuilder, item->GetUnderlyingFrame(), item); + item = new (aBuilder) nsDisplayTransform(aBuilder, childFrame, item); } if (NS_FAILED(rv) || !item) diff --git a/layout/reftests/font-matching/font-stretch-1-ref.html b/layout/reftests/font-matching/font-stretch-1-ref.html new file mode 100644 index 000000000000..2fe8f2cf31d5 --- /dev/null +++ b/layout/reftests/font-matching/font-stretch-1-ref.html @@ -0,0 +1,73 @@ + + + + + + + +
ultra-condensed italic bold italic light italic
+
extra-condensed italic bold italic light italic
+
condensed italic bold italic light italic
+
semi-condensed italic bold italic light italic
+ +
normal italic bold italic light italic
+
semi-expanded italic bold italic light italic
+
expanded italic bold italic light italic
+
extra-expanded italic bold italic light italic
+
ultra-expanded italic bold italic light italic
+ + + diff --git a/layout/reftests/font-matching/font-stretch-1.html b/layout/reftests/font-matching/font-stretch-1.html new file mode 100644 index 000000000000..ca86a08ed99b --- /dev/null +++ b/layout/reftests/font-matching/font-stretch-1.html @@ -0,0 +1,79 @@ + + + + + + + +
ultra-condensed italic bold italic light italic
+
extra-condensed italic bold italic light italic
+
condensed italic bold italic light italic
+
semi-condensed italic bold italic light italic
+ +
normal italic bold italic light italic
+
semi-expanded italic bold italic light italic
+
expanded italic bold italic light italic
+
extra-expanded italic bold italic light italic
+
ultra-expanded italic bold italic light italic
+ + + diff --git a/layout/reftests/font-matching/reftest.list b/layout/reftests/font-matching/reftest.list index 73e95de52ff7..c9cfadff5b47 100644 --- a/layout/reftests/font-matching/reftest.list +++ b/layout/reftests/font-matching/reftest.list @@ -62,3 +62,6 @@ HTTP(..) == weightmapping-478.html weightmapping-478-ref.html HTTP(..) == weightmapping-7.html weightmapping-7-ref.html HTTP(..) == weightmapping-12579.html weightmapping-12579-ref.html +# test for font-stretch using @font-face +HTTP(..) == font-stretch-1.html font-stretch-1-ref.html + diff --git a/layout/reftests/fonts/csstest-widths-wd1.ttf b/layout/reftests/fonts/csstest-widths-wd1.ttf new file mode 100644 index 000000000000..efcc7ab33da0 Binary files /dev/null and b/layout/reftests/fonts/csstest-widths-wd1.ttf differ diff --git a/layout/reftests/fonts/csstest-widths-wd2.ttf b/layout/reftests/fonts/csstest-widths-wd2.ttf new file mode 100644 index 000000000000..20ecf37570ed Binary files /dev/null and b/layout/reftests/fonts/csstest-widths-wd2.ttf differ diff --git a/layout/reftests/fonts/csstest-widths-wd3.ttf b/layout/reftests/fonts/csstest-widths-wd3.ttf new file mode 100644 index 000000000000..28a9e311dee0 Binary files /dev/null and b/layout/reftests/fonts/csstest-widths-wd3.ttf differ diff --git a/layout/reftests/fonts/csstest-widths-wd4.ttf b/layout/reftests/fonts/csstest-widths-wd4.ttf new file mode 100644 index 000000000000..e40c65d54e24 Binary files /dev/null and b/layout/reftests/fonts/csstest-widths-wd4.ttf differ diff --git a/layout/reftests/fonts/csstest-widths-wd5.ttf b/layout/reftests/fonts/csstest-widths-wd5.ttf new file mode 100644 index 000000000000..7bf4fcb5401a Binary files /dev/null and b/layout/reftests/fonts/csstest-widths-wd5.ttf differ diff --git a/layout/reftests/fonts/csstest-widths-wd6.ttf b/layout/reftests/fonts/csstest-widths-wd6.ttf new file mode 100644 index 000000000000..b240d9bc8b62 Binary files /dev/null and b/layout/reftests/fonts/csstest-widths-wd6.ttf differ diff --git a/layout/reftests/fonts/csstest-widths-wd7.ttf b/layout/reftests/fonts/csstest-widths-wd7.ttf new file mode 100644 index 000000000000..39afcea20f79 Binary files /dev/null and b/layout/reftests/fonts/csstest-widths-wd7.ttf differ diff --git a/layout/reftests/fonts/csstest-widths-wd8.ttf b/layout/reftests/fonts/csstest-widths-wd8.ttf new file mode 100644 index 000000000000..82f500400b2f Binary files /dev/null and b/layout/reftests/fonts/csstest-widths-wd8.ttf differ diff --git a/layout/reftests/fonts/csstest-widths-wd9.ttf b/layout/reftests/fonts/csstest-widths-wd9.ttf new file mode 100644 index 000000000000..4050a117133d Binary files /dev/null and b/layout/reftests/fonts/csstest-widths-wd9.ttf differ diff --git a/layout/reftests/fonts/dejavu-sans/DejaVuSans-Bold.ttf b/layout/reftests/fonts/dejavu-sans/DejaVuSans-Bold.ttf new file mode 100644 index 000000000000..99f323d75029 Binary files /dev/null and b/layout/reftests/fonts/dejavu-sans/DejaVuSans-Bold.ttf differ diff --git a/layout/reftests/fonts/dejavu-sans/DejaVuSans-BoldOblique.ttf b/layout/reftests/fonts/dejavu-sans/DejaVuSans-BoldOblique.ttf new file mode 100644 index 000000000000..b78275876753 Binary files /dev/null and b/layout/reftests/fonts/dejavu-sans/DejaVuSans-BoldOblique.ttf differ diff --git a/layout/reftests/fonts/dejavu-sans/DejaVuSans-ExtraLight.ttf b/layout/reftests/fonts/dejavu-sans/DejaVuSans-ExtraLight.ttf new file mode 100644 index 000000000000..013c0ec9def8 Binary files /dev/null and b/layout/reftests/fonts/dejavu-sans/DejaVuSans-ExtraLight.ttf differ diff --git a/layout/reftests/fonts/dejavu-sans/DejaVuSans-Oblique.ttf b/layout/reftests/fonts/dejavu-sans/DejaVuSans-Oblique.ttf new file mode 100644 index 000000000000..8459dc8cabb7 Binary files /dev/null and b/layout/reftests/fonts/dejavu-sans/DejaVuSans-Oblique.ttf differ diff --git a/layout/reftests/fonts/dejavu-sans/DejaVuSans.ttf b/layout/reftests/fonts/dejavu-sans/DejaVuSans.ttf new file mode 100644 index 000000000000..84ca1d750389 Binary files /dev/null and b/layout/reftests/fonts/dejavu-sans/DejaVuSans.ttf differ diff --git a/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed-Bold.ttf b/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed-Bold.ttf new file mode 100644 index 000000000000..a12913762a3a Binary files /dev/null and b/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed-Bold.ttf differ diff --git a/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed-BoldOblique.ttf b/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed-BoldOblique.ttf new file mode 100644 index 000000000000..b93b02a1ca4b Binary files /dev/null and b/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed-BoldOblique.ttf differ diff --git a/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed-Oblique.ttf b/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed-Oblique.ttf new file mode 100644 index 000000000000..68a783e969c7 Binary files /dev/null and b/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed-Oblique.ttf differ diff --git a/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed.ttf b/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed.ttf new file mode 100644 index 000000000000..d2a5e439eca9 Binary files /dev/null and b/layout/reftests/fonts/dejavu-sans/DejaVuSansCondensed.ttf differ diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list index fe59e9be52f2..f436df92ee41 100644 --- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -49,7 +49,7 @@ skip-if(!(d2d||cocoaWidget)) random-if(d2d) != subpixel-glyphs-x-2a.html subpixe == subpixel-glyphs-y-1a.html subpixel-glyphs-y-1b.html == subpixel-lineheight-1a.html subpixel-lineheight-1b.html == swash-1.html swash-1-ref.html -fails-if(Android) HTTP(..) != synthetic-bold-metrics-01.html synthetic-bold-metrics-01-notref.html +HTTP(..) != synthetic-bold-metrics-01.html synthetic-bold-metrics-01-notref.html == variation-selector-unsupported-1.html variation-selector-unsupported-1-ref.html == white-space-1a.html white-space-1-ref.html == white-space-1b.html white-space-1-ref.html diff --git a/layout/reftests/transform-3d/preserve3d-clipped.html b/layout/reftests/transform-3d/preserve3d-clipped.html new file mode 100644 index 000000000000..4647fd56d639 --- /dev/null +++ b/layout/reftests/transform-3d/preserve3d-clipped.html @@ -0,0 +1,10 @@ + + +
+
+ x +
+
+ + + diff --git a/layout/reftests/transform-3d/reftest.list b/layout/reftests/transform-3d/reftest.list index 837e6afa6f23..a5fb50d91dab 100644 --- a/layout/reftests/transform-3d/reftest.list +++ b/layout/reftests/transform-3d/reftest.list @@ -11,6 +11,7 @@ == scalez-1a.html scalez-1-ref.html fails == preserve3d-1a.html preserve3d-1-ref.html == preserve3d-1b.html about:blank +== preserve3d-clipped.html about:blank == scale3d-z.html scalez-1-ref.html == scale3d-all.html scale3d-1-ref.html == scale3d-xz.html scale3d-2-ref.html diff --git a/layout/style/html.css b/layout/style/html.css index 6c0b0bc4d51b..acadb5d22cfb 100644 --- a/layout/style/html.css +++ b/layout/style/html.css @@ -715,6 +715,11 @@ area { display: none ! important; } +iframe:-moz-full-screen { + /* iframes in full-screen mode don't show a border. */ + border: none; +} + /* media elements */ video > xul|videocontrols, audio > xul|videocontrols { display: -moz-box; diff --git a/layout/style/nsCSSPseudoClassList.h b/layout/style/nsCSSPseudoClassList.h index 5904c837382e..dbd9197247ad 100644 --- a/layout/style/nsCSSPseudoClassList.h +++ b/layout/style/nsCSSPseudoClassList.h @@ -140,6 +140,10 @@ CSS_STATE_PSEUDO_CLASS(target, ":target", NS_EVENT_STATE_URLTARGET) CSS_STATE_PSEUDO_CLASS(indeterminate, ":indeterminate", NS_EVENT_STATE_INDETERMINATE) +// Matches the element which is being displayed full-screen, and +// any containing frames. +CSS_STATE_PSEUDO_CLASS(mozFullScreen, ":-moz-full-screen", NS_EVENT_STATE_FULL_SCREEN) + // Matches if the element is focused and should show a focus ring CSS_STATE_PSEUDO_CLASS(mozFocusRing, ":-moz-focusring", NS_EVENT_STATE_FOCUSRING) diff --git a/layout/style/ua.css b/layout/style/ua.css index d764fca8ba79..8e10fd4b335c 100644 --- a/layout/style/ua.css +++ b/layout/style/ua.css @@ -240,6 +240,18 @@ } +*|*:-moz-full-screen { + position:fixed; + top:0; + left:0; + right:0; + bottom:0; + z-index:2147483647; + background:black; + width: 100% !important; + height: 100% !important; +} + /* XML parse error reporting */ parsererror|parsererror { diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 6494d1aa9e09..25448d5713b6 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -69,7 +69,6 @@ #include "nsGenericElement.h" #include "nsSVGGraphicElement.h" #include "nsAttrValue.h" -#include "nsSVGGeometryFrame.h" #include "nsIScriptError.h" #include "gfxContext.h" #include "gfxMatrix.h" @@ -85,6 +84,7 @@ #include "nsSVGGeometryFrame.h" #include "nsComputedDOMStyle.h" #include "nsSVGPathGeometryFrame.h" +#include "nsSVGPathGeometryElement.h" #include "prdtoa.h" #include "mozilla/dom/Element.h" #include "gfxUtils.h" @@ -1431,26 +1431,14 @@ nsSVGUtils::WritePPM(const char *fname, gfxImageSurface *aSurface) } #endif -/*static*/ gfxRect -nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, - nsSVGGeometryFrame* aFrame) +// The logic here comes from _cairo_stroke_style_max_distance_from_path +static gfxRect +PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, + nsSVGGeometryFrame* aFrame, + double styleExpansionFactor) { - // The logic here comes from _cairo_stroke_style_max_distance_from_path - - double style_expansion = 0.5; - - const nsStyleSVG* style = aFrame->GetStyleSVG(); - - if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) { - style_expansion = M_SQRT1_2; - } - - if (style->mStrokeLinejoin == NS_STYLE_STROKE_LINEJOIN_MITER && - style_expansion < style->mStrokeMiterlimit) { - style_expansion = style->mStrokeMiterlimit; - } - - style_expansion *= aFrame->GetStrokeWidth(); + double style_expansion = + styleExpansionFactor * aFrame->GetStrokeWidth(); gfxMatrix ctm = aFrame->GetCanvasTM(); @@ -1462,6 +1450,38 @@ nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, return strokeExtents; } +/*static*/ gfxRect +nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, + nsSVGGeometryFrame* aFrame) +{ + return ::PathExtentsToMaxStrokeExtents(aPathExtents, aFrame, 0.5); +} + +/*static*/ gfxRect +nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, + nsSVGPathGeometryFrame* aFrame) +{ + double styleExpansionFactor = 0.5; + + if (static_cast(aFrame->GetContent())->IsMarkable()) { + const nsStyleSVG* style = aFrame->GetStyleSVG(); + + if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) { + styleExpansionFactor = M_SQRT1_2; + } + + if (style->mStrokeLinejoin == NS_STYLE_STROKE_LINEJOIN_MITER && + styleExpansionFactor < style->mStrokeMiterlimit && + aFrame->GetContent()->Tag() != nsGkAtoms::line) { + styleExpansionFactor = style->mStrokeMiterlimit; + } + } + + return ::PathExtentsToMaxStrokeExtents(aPathExtents, + aFrame, + styleExpansionFactor); +} + // ---------------------------------------------------------------------- nsSVGRenderState::nsSVGRenderState(nsRenderingContext *aContext) : diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index 3e911a13b3df..26874f543a5c 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -76,6 +76,7 @@ struct nsStyleFont; class nsSVGEnum; class nsISVGChildFrame; class nsSVGGeometryFrame; +class nsSVGPathGeometryFrame; class nsSVGDisplayContainerFrame; namespace mozilla { @@ -564,6 +565,8 @@ public: */ static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, nsSVGGeometryFrame* aFrame); + static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, + nsSVGPathGeometryFrame* aFrame); /** * Convert a floating-point value to a 32-bit integer value, clamping to diff --git a/mfbt/Util.h b/mfbt/Util.h index 448dec3502f7..43794197b1ec 100644 --- a/mfbt/Util.h +++ b/mfbt/Util.h @@ -174,7 +174,7 @@ struct DebugOnly #else DebugOnly() {} DebugOnly(const T&) {} - DebugOnly& operator=(const T&) {} + DebugOnly& operator=(const T&) { return *this; } #endif /* diff --git a/mobile/app/mobile.js b/mobile/app/mobile.js index 428fa582c3e7..39495aed9354 100644 --- a/mobile/app/mobile.js +++ b/mobile/app/mobile.js @@ -217,6 +217,7 @@ pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCAL /* preference for the locale picker */ pref("extensions.getLocales.get.url", ""); +pref("extensions.compatability.locales.buildid", "0"); /* blocklist preferences */ pref("extensions.blocklist.enabled", true); diff --git a/mobile/chrome/content/AppMenu.js b/mobile/chrome/content/AppMenu.js index 754281934d90..78133b7707f2 100644 --- a/mobile/chrome/content/AppMenu.js +++ b/mobile/chrome/content/AppMenu.js @@ -50,7 +50,7 @@ var AppMenu = { item.onclick = function() { child.click(); } let label = document.createElement("label"); - label.setAttribute("value", child.label); + label.textContent = child.label; item.appendChild(label); if (item.classList.contains("appmenu-pageaction")) @@ -58,14 +58,8 @@ var AppMenu = { else listbox.appendChild(item); } - - this.popup.top = menuButton.getBoundingClientRect().bottom; - - let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); - this.popup.setAttribute(chromeReg.isLocaleRTL("global") ? "left" : "right", this.offset); - this.popup.hidden = false; - this.popup.anchorTo(menuButton); + this.popup.anchorTo(menuButton, "after_end"); BrowserUI.lockToolbar(); BrowserUI.pushPopup(this, [this.popup, menuButton]); diff --git a/mobile/chrome/content/BookmarkPopup.js b/mobile/chrome/content/BookmarkPopup.js index d49f67723ecc..c552dde4e27b 100644 --- a/mobile/chrome/content/BookmarkPopup.js +++ b/mobile/chrome/content/BookmarkPopup.js @@ -19,20 +19,18 @@ var BookmarkPopup = { show : function show() { // Set the box position. let button = document.getElementById("tool-star"); + let anchorPosition = ""; if (getComputedStyle(button).visibility == "visible") { let [tabsSidebar, controlsSidebar] = [Elements.tabs.getBoundingClientRect(), Elements.controls.getBoundingClientRect()]; this.box.setAttribute(tabsSidebar.left < controlsSidebar.left ? "right" : "left", controlsSidebar.width - this.box.offset); this.box.top = button.getBoundingClientRect().top - this.box.offset; } else { button = document.getElementById("tool-star2"); - this.box.top = button.getBoundingClientRect().bottom - this.box.offset; - - let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); - this.box.setAttribute(chromeReg.isLocaleRTL("global") ? "left" : "right", this.box.offset); + anchorPosition = "after_start"; } this.box.hidden = false; - this.box.anchorTo(button); + this.box.anchorTo(button, anchorPosition); // include the star button here, so that click-to-dismiss works as expected BrowserUI.pushPopup(this, [this.box, button]); diff --git a/mobile/chrome/content/bindings.xml b/mobile/chrome/content/bindings.xml index b61002e2f5a7..8cc18199d176 100644 --- a/mobile/chrome/content/bindings.xml +++ b/mobile/chrome/content/bindings.xml @@ -707,7 +707,6 @@ - @@ -1854,4 +1852,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mobile/chrome/content/bindings/arrowbox.xml b/mobile/chrome/content/bindings/arrowbox.xml index 17ddaca2704e..9d8962680663 100644 --- a/mobile/chrome/content/bindings/arrowbox.xml +++ b/mobile/chrome/content/bindings/arrowbox.xml @@ -149,6 +149,7 @@ null + = Math.round(anchorRect.right - offset)) ? 1 : 0; - let vertPos = (Math.round(popupRect.bottom) <= Math.round(anchorRect.top + offset)) ? -1 : - (Math.round(popupRect.top) >= Math.round(anchorRect.bottom - offset)) ? 1 : 0; + if (aPosition) { + let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); + let isRtl = chromeReg.isLocaleRTL("global"); + let left = 0; + let top = 0; + + switch (aPosition) { + case "before_start": + left = isRtl ? anchorRect.right - popupRect.width : anchorRect.left; + top = anchorRect.top + offset - popupRect.height; + vertPos = -1; + break; + case "before_end": + left = isRtl ? anchorRect.left : anchorRect.right - popupRect.width; + top = anchorRect.top + offset - popupRect.height; + vertPos = -1; + break; + case "after_start": + left = isRtl ? anchorRect.right - popupRect.width : anchorRect.left; + top = anchorRect.bottom - offset; + vertPos = 1; + break; + case "after_end": + left = isRtl ? anchorRect.left : anchorRect.right - popupRect.width; + top = anchorRect.bottom - offset; + vertPos = 1; + break; + case "start_before": + left = isRtl ? anchorRect.right : anchorRect.left - popupRect.width - offset; + top = anchorRect.top; + horizPos = -1; + break; + case "start_after": + left = isRtl ? anchorRect.right : anchorRect.left - popupRect.width - offset; + top = anchorRect.bottom - popupRect.height; + horizPos = -1; + break; + case "end_before": + left = isRtl ? anchorRect.left - popupRect.width - offset : anchorRect.right; + top = anchorRect.top; + horizPos = 1; + break; + case "end_after": + left = isRtl ? anchorRect.left - popupRect.width - offset : anchorRect.right; + top = anchorRect.bottom - popupRect.height; + horizPos = 1; + break; + case "overlap": + left = isRtl ? anchorRect.right - popupRect.width + offset : anchorRect.left + offset ; + top = anchorRect.top + offset ; + break; + } + if (top == 0) top = 1; + if (left == 0) left = 1; + + if (left + popupRect.width > window.innerWidth) + left = window.innerWidth - popupRect.width; + else if (left < 0) + left = 1; + + popupRect.left = left; + this.setAttribute("left", left); + popupRect.top = top; + this.setAttribute("top", top); + } else { + horizPos = (Math.round(popupRect.right) <= Math.round(anchorRect.left + offset)) ? -1 : + (Math.round(popupRect.left) >= Math.round(anchorRect.right - offset)) ? 1 : 0; + vertPos = (Math.round(popupRect.bottom) <= Math.round(anchorRect.top + offset)) ? -1 : + (Math.round(popupRect.top) >= Math.round(anchorRect.bottom - offset)) ? 1 : 0; + } this._updateArrow(popupRect, anchorRect, horizPos, vertPos); ]]> diff --git a/mobile/chrome/content/bindings/browser.js b/mobile/chrome/content/bindings/browser.js index 6f9e0732274a..8a2a6fd6111f 100644 --- a/mobile/chrome/content/bindings/browser.js +++ b/mobile/chrome/content/bindings/browser.js @@ -629,7 +629,7 @@ let ContentScroll = { sendAsyncMessage("MozScrolledAreaChanged", { width: aEvent.width, height: aEvent.height, - left: aEvent.x + left: aEvent.x + content.scrollX }); // Send event only after painting to make sure content views in the parent process have diff --git a/mobile/chrome/content/browser.css b/mobile/chrome/content/browser.css index f9a8b3113e10..a2a7ba4f1b15 100644 --- a/mobile/chrome/content/browser.css +++ b/mobile/chrome/content/browser.css @@ -27,15 +27,15 @@ settings { } setting[type="bool"] { - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-bool"); + -moz-binding: url("chrome://browser/content/bindings.xml#setting-fulltoggle-bool"); } setting[type="bool"][localized="true"] { - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-localized-bool"); + -moz-binding: url("chrome://browser/content/bindings.xml#setting-fulltoggle-localized-bool"); } setting[type="boolint"] { - -moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-boolint"); + -moz-binding: url("chrome://browser/content/bindings.xml#setting-fulltoggle-boolint"); } setting[type="integer"] { diff --git a/mobile/chrome/content/browser.js b/mobile/chrome/content/browser.js index 60e85a0180a3..41a57fba1fc0 100644 --- a/mobile/chrome/content/browser.js +++ b/mobile/chrome/content/browser.js @@ -182,7 +182,7 @@ var Browser = { /* handles web progress management for open browsers */ Elements.browsers.webProgress = new Browser.WebProgress(); - this.keyFilter = new KeyFilter(Elements.browsers); + this.keySender = new ContentCustomKeySender(Elements.browsers); let mouseModule = new MouseModule(); let gestureModule = new GestureModule(Elements.browsers); let scrollWheelModule = new ScrollwheelModule(Elements.browsers); @@ -1226,19 +1226,14 @@ var Browser = { break; } - case "Browser:KeyPress": { - let keyset = document.getElementById("mainKeyset"); - keyset.setAttribute("disabled", "false"); - if (json.preventDefault) - break; - + case "Browser:KeyPress": let event = document.createEvent("KeyEvents"); event.initKeyEvent("keypress", true, true, null, json.ctrlKey, json.altKey, json.shiftKey, json.metaKey, json.keyCode, json.charCode); - keyset.dispatchEvent(event); + document.getElementById("mainKeyset").dispatchEvent(event); break; - } + case "Browser:ZoomToPoint:Return": if (json.zoomTo) { let rect = Rect.fromRect(json.zoomTo); @@ -1979,26 +1974,47 @@ const ContentTouchHandler = { }; -/** Prevent chrome from consuming key events before remote content has a chance. */ -function KeyFilter(container) { +/** Watches for mouse events in chrome and sends them to content. */ +function ContentCustomKeySender(container) { container.addEventListener("keypress", this, false); container.addEventListener("keyup", this, false); container.addEventListener("keydown", this, false); } -KeyFilter.prototype = { +ContentCustomKeySender.prototype = { handleEvent: function handleEvent(aEvent) { if (Elements.contentShowing.getAttribute("disabled") == "true") return; let browser = getBrowser(); if (browser && browser.active && browser.getAttribute("remote") == "true") { - document.getElementById("mainKeyset").setAttribute("disabled", "true"); + aEvent.stopPropagation(); + aEvent.preventDefault(); + + let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader; + fl.sendCrossProcessKeyEvent(aEvent.type, + aEvent.keyCode, + (aEvent.type != "keydown") ? aEvent.charCode : null, + this._parseModifiers(aEvent)); } }, + _parseModifiers: function _parseModifiers(aEvent) { + const masks = Ci.nsIDOMNSEvent; + let mval = 0; + if (aEvent.shiftKey) + mval |= masks.SHIFT_MASK; + if (aEvent.ctrlKey) + mval |= masks.CONTROL_MASK; + if (aEvent.altKey) + mval |= masks.ALT_MASK; + if (aEvent.metaKey) + mval |= masks.META_MASK; + return mval; + }, + toString: function toString() { - return "[KeyFilter] { }"; + return "[ContentCustomKeySender] { }"; } }; @@ -2901,6 +2917,7 @@ Tab.prototype = { let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader; fl.renderMode = Ci.nsIFrameLoader.RENDER_MODE_ASYNC_SCROLL; + fl.eventMode = Ci.nsIFrameLoader.EVENT_MODE_DONT_FORWARD_TO_CHILD; return browser; }, diff --git a/mobile/chrome/content/common-ui.js b/mobile/chrome/content/common-ui.js index ee169f3a8381..b3739834eefa 100644 --- a/mobile/chrome/content/common-ui.js +++ b/mobile/chrome/content/common-ui.js @@ -87,23 +87,12 @@ var BrowserSearch = { popup.hidden = false; popup.top = BrowserUI.toolbarH - popup.offset; let searchButton = document.getElementById("tool-search"); - if (Util.isTablet()) { - let width = list.getBoundingClientRect().width; - let searchButtonRect = searchButton.getBoundingClientRect(); - let left = searchButtonRect.left; - if (Util.localeDir > 0) { - if (left + width > window.innerWidth) - left = window.innerWidth - width; - } else { - left = searchButtonRect.right - width; - if (left < 0) - left = 0; - } - popup.left = left; - } else if (popup.hasAttribute("left")) { + let anchorPosition = ""; + if (Util.isTablet()) + anchorPosition = "after_start"; + else if (popup.hasAttribute("left")) popup.removeAttribute("left"); - } - popup.anchorTo(searchButton); + popup.anchorTo(searchButton, anchorPosition); document.getElementById("urlbar-icons").setAttribute("open", "true"); BrowserUI.pushPopup(this, [popup, this._button]); @@ -827,7 +816,7 @@ var FormHelperUI = { if (focusedElement && focusedElement.localName == "browser") return; - Browser.keyFilter.handleEvent(aEvent); + Browser.keySender.handleEvent(aEvent); break; case "SizeChanged": diff --git a/mobile/chrome/content/content.js b/mobile/chrome/content/content.js index 79ac4cbea571..64bde448072e 100644 --- a/mobile/chrome/content/content.js +++ b/mobile/chrome/content/content.js @@ -299,14 +299,16 @@ let Content = { // let's send it back to the chrome process to have it handle shortcuts case "keypress": let timer = new Util.Timeout(function() { + if(aEvent.getPreventDefault()) + return; + let eventData = { ctrlKey: aEvent.ctrlKey, altKey: aEvent.altKey, shiftKey: aEvent.shiftKey, metaKey: aEvent.metaKey, keyCode: aEvent.keyCode, - charCode: aEvent.charCode, - preventDefault: aEvent.getPreventDefault() + charCode: aEvent.charCode }; sendAsyncMessage("Browser:KeyPress", eventData); }); @@ -495,8 +497,13 @@ let Content = { if (uri) sendAsyncMessage("Browser:OpenURI", { uri: uri, referrer: element.ownerDocument.documentURIObject.spec }); - } else if (!this._formAssistant.open(element) && this._highlightElement) { + break; + } + + if (!this._formAssistant.open(element)) sendAsyncMessage("FindAssist:Hide", { }); + + if (this._highlightElement) { this._sendMouseEvent("mousemove", this._highlightElement, x, y); this._sendMouseEvent("mousedown", this._highlightElement, x, y); this._sendMouseEvent("mouseup", this._highlightElement, x, y); diff --git a/mobile/chrome/content/extensions.js b/mobile/chrome/content/extensions.js index de5abc51f1d7..2f3165a0c334 100644 --- a/mobile/chrome/content/extensions.js +++ b/mobile/chrome/content/extensions.js @@ -430,6 +430,10 @@ var ExtensionsView = { } else if (aItem.getAttribute("type") == "theme") { aItem.addon.userDisabled = true; aItem.setAttribute("isDisabled", true); + } else if (aItem.getAttribute("type") == "locale") { + Services.prefs.clearUserPref("general.useragent.locale"); + aItem.addon.userDisabled = true; + aItem.setAttribute("isDisabled", true); } else { aItem.addon.userDisabled = true; opType = this._getOpTypeForOperations(aItem.addon.pendingOperations); diff --git a/mobile/chrome/content/localePicker.js b/mobile/chrome/content/localePicker.js index 7f83ea322050..58e36b08d83f 100644 --- a/mobile/chrome/content/localePicker.js +++ b/mobile/chrome/content/localePicker.js @@ -8,15 +8,16 @@ Cu.import("resource://gre/modules/AddonManager.jsm"); Cu.import("resource:///modules/LocaleRepository.jsm"); let stringPrefs = [ - { selector: "#continue-in-button", pref: "continueIn", data: ["CURRENT_LANGUAGE"] }, + { selector: "#continue-in-button", pref: "continueIn", data: ["CURRENT_LOCALE"] }, { selector: "#change-language", pref: "choose", data: null }, { selector: "#picker-title", pref: "chooseLanguage", data: null }, { selector: "#continue-button", pref: "continue", data: null }, { selector: "#cancel-button", pref: "cancel", data: null }, - { selector: "#intalling-message", pref: "installing", data: ["CURRENT_LANGUAGE"] }, + { selector: "#intalling-message", pref: "installing", data: ["CURRENT_LOCALE"] }, { selector: "#cancel-install-button", pref: "cancel", data: null }, { selector: "#installing-error", pref: "installerror", data: null }, - { selector: "#install-continue", pref: "continue", data: null } + { selector: "#install-continue", pref: "continue", data: null }, + { selector: "#loading-label", pref: "loading", data: null } ]; let LocaleUI = { @@ -52,6 +53,26 @@ let LocaleUI = { return this._deck = document.getElementById("language-deck"); }, + _availableLocales: null, + get availableLocales() { + if (!this._availableLocales) { + let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); + chrome.QueryInterface(Ci.nsIToolkitChromeRegistry); + let strings = Services.strings.createBundle("chrome://browser/content/languages.properties"); + let availableLocales = chrome.getLocalesForPackage("browser"); + + this._availableLocales = []; + while (availableLocales.hasMore()) { + let locale = availableLocales.getNext(); + let label = locale; + try { label = strings.GetStringFromName(locale); } + catch (e) { } + this._availableLocales.push({ addon: { id: locale, name: label, targetLocale: locale }}); + } + } + return this._availableLocales; + }, + _currentInstall: null, // used to cancel an install get selectedPanel() { @@ -75,7 +96,7 @@ let LocaleUI = { description.appendChild(document.createTextNode(aText)); description.setAttribute('flex', 1); item.appendChild(description); - item.setAttribute("locale", getTargetLanguage(aLocale.addon)); + item.setAttribute("locale", getTargetLocale(aLocale.addon)); if (aLocale) { item.locale = aLocale.addon; @@ -94,12 +115,12 @@ let LocaleUI = { let bestMatch = NO_MATCH; for each (let locale in aLocales) { - let targetLang = getTargetLanguage(locale.addon); - if (document.querySelector('[locale="' + targetLang + '"]')) + let targetLocale = getTargetLocale(locale.addon); + if (document.querySelector('[locale="' + targetLocale + '"]')) continue; - let item = this._createItem(targetLang, locale.addon.name, locale); - let match = localesMatch(targetLang, this.language); + let item = this._createItem(targetLocale, locale.addon.name, locale); + let match = localesMatch(targetLocale, this.locale); if (match > bestMatch) { bestMatch = match; selectedItem = item; @@ -126,27 +147,27 @@ let LocaleUI = { closePicker: function() { if (this._currentInstall) { Services.prefs.setBoolPref("intl.locale.matchOS", false); - Services.prefs.setCharPref("general.useragent.locale", getTargetLanguage(this._currentInstall)); + Services.prefs.setCharPref("general.useragent.locale", getTargetLocale(this._currentInstall)); } this.selectedPanel = this._mainPage; }, - _language: "", + _locale: "", - set language(aVal) { - if (aVal == this._language) + set locale(aVal) { + if (aVal == this._locale) return; Services.prefs.setBoolPref("intl.locale.matchOS", false); Services.prefs.setCharPref("general.useragent.locale", aVal); - this._language = aVal; + this._locale = aVal; this.strings = null; this.updateStrings(); }, - get language() { - return this._language; + get locale() { + return this._locale; }, set installStatus(aVal) { @@ -158,13 +179,13 @@ let LocaleUI = { this.selectedPanel = this._pickerPage; }, - selectLanguage: function(aEvent) { + selectLocale: function(aEvent) { let locale = this.list.selectedItem.locale; if (locale.install) { LocaleUI.strings = new FakeStringBundle(locale); this.updateStrings(); } else { - this.language = getTargetLanguage(locale); + this.locale = getTargetLocale(locale); if (this._currentInstall) this._currentInstall = null; } @@ -187,12 +208,14 @@ let LocaleUI = { if (this._currentInstall) this._currentInstall = null; // restore the last known "good" locale - this.language = this.defaultLanguage; + this.locale = this.defaultLocale; this.updateStrings(); this.closePicker(); }, closeWindow : function() { + var buildID = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).platformBuildID; + Services.prefs.setCharPref("extensions.compatability.locales.buildid", buildID); // Trying to close this window and open a new one results in a corrupt UI. if (LocaleUI._currentInstall) { // a new locale was installed, restart the browser @@ -202,7 +225,6 @@ let LocaleUI = { if (cancelQuit.data == false) { let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup); appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eForceQuit); - Services.prefs.setBoolPref("browser.sessionstore.resume_session_once", false); } } else { // selected locale is already installed, just open the window @@ -223,7 +245,7 @@ let LocaleUI = { catch(ex) { } LocaleUI._currentInstall = null; - this.language = this.defaultLanguage; + this.locale = this.defaultLocale; } }, @@ -241,10 +263,10 @@ let LocaleUI = { } } -// Gets the target language for a locale addon +// Gets the target locale for an addon // For now this returns the targetLocale, although if and addon doesn't // specify a targetLocale we could attempt to guess the locale from the addon's name -function getTargetLanguage(aAddon) { +function getTargetLocale(aAddon) { return aAddon.targetLocale; } @@ -256,7 +278,7 @@ function getString(aStringName, aDataSet, aAddon) { if (aDataSet) { let databundle = aDataSet.map(function(aData) { switch (aData) { - case "CURRENT_LANGUAGE" : + case "CURRENT_LOCALE" : if (aAddon) return aAddon.name; try { return LocaleUI.strings.GetStringFromName("name"); } @@ -289,8 +311,8 @@ let installListener = { }, onInstallStarted: function(install) { }, onInstallEnded: function(install, addon) { - LocaleUI.updateStrings(); - LocaleUI.closePicker(); + LocaleUI.locale = getTargetLocale(LocaleUI._currentInstall); + LocaleUI.closeWindow(); }, onInstallCancelled: function(install) { LocaleUI.cancelInstall(); @@ -322,25 +344,68 @@ function start() { // if we have gotten this far, we can assume that we don't have anything matching the system // locale and we should show the locale picker + LocaleUI._mainPage.setAttribute("mode", "loading"); let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry); chrome.QueryInterface(Ci.nsIToolkitChromeRegistry); - let availableLocales = chrome.getLocalesForPackage("browser"); - let strings = Services.strings.createBundle("chrome://browser/content/languages.properties"); - LocaleUI.availableLocales = []; - while (availableLocales.hasMore()) { - let locale = availableLocales.getNext(); - - let label = locale; - try { label = strings.GetStringFromName(locale); } - catch (e) { } - LocaleUI.availableLocales.push({addon: { id: locale, name: label, targetLocale: locale }}); - } - - LocaleUI._language = chrome.getSelectedLocale("browser"); + LocaleUI._locale = chrome.getSelectedLocale("browser"); LocaleUI.updateStrings(); + // if we haven't gotten the list of available locales from AMO within 5 seconds, we give up + // users can try downloading the list again by selecting "Choose another locale" + let timeout = setTimeout(function() { + LocaleUI._mainPage.removeAttribute("mode"); + timeout = null; + }, 5000); + + // Look on AMO for something that matches the system locale + LocaleRepository.getLocales(function lp_initalDownload(aLocales) { + if (!LocaleUI._mainPage.hasAttribute("mode")) return; + + clearTimeout(timeout); + LocaleUI._mainPage.removeAttribute("mode"); + + let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService); + let currentLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE"); + if (Services.prefs.prefHasUserValue("general.useragent.locale")) { + currentLocale = Services.prefs.getCharPref("general.useragent.locale"); + } + + let match = NO_MATCH; + let matchingLocale = null; + + for each (let locale in aLocales) { + let targetLocale = getTargetLocale(locale.addon); + let newMatch = localesMatch(targetLocale, currentLocale); + if (newMatch > match) { + matchingLocale = locale; + match = newMatch; + } + } + + if (matchingLocale) { + // if we found something, try to install it automatically + AddonManager.getAddonByID(matchingLocale.addon.id, function (aAddon) { + // if this locale is already installed, but is user disabled, + // bail out of here. + if (aAddon && aAddon.userDisabled) { + Services.prefs.clearUserPref("general.useragent.locale"); + LocaleUI.closeWindow(); + return; + } + // if we found something, try to install it automatically + LocaleUI.strings = new FakeStringBundle(matchingLocale.addon); + LocaleUI.updateStrings(); + LocaleUI._currentInstall = matchingLocale.addon; + + LocaleUI.selectedPanel = LocaleUI._installerPage; + matchingLocale.addon.install.addListener(installListener); + matchingLocale.addon.install.install(); + }); + } + }); + // update the page strings and show the correct page - LocaleUI.defaultLanguage = LocaleUI._language; + LocaleUI.defaultLocale = LocaleUI._locale; window.addEventListener("resize", resizeHandler, false); } diff --git a/mobile/chrome/content/localePicker.xul b/mobile/chrome/content/localePicker.xul index e0da34a88183..0a64d0b7e443 100644 --- a/mobile/chrome/content/localePicker.xul +++ b/mobile/chrome/content/localePicker.xul @@ -15,12 +15,13 @@