author | Philipp von Weitershausen <philipp@weitershausen.de> |
Wed, 12 Oct 2011 12:52:55 -0700 | |
changeset 78608 | fee22c85ed19173fae01ee3a6371d695ef355edb |
parent 78607 | 72ceb8048b70d9644200e80a568bac6b6afa537c (current diff) |
parent 78602 | 1354c018705372ac81c1f9a014a672c32331bec7 (diff) |
child 78609 | 46a6d0fd13d591805cd4b857450985fbd3895198 |
child 79063 | f15a17ef38dd73dd123a9279b9e0533124ee2c72 |
push id | 21317 |
push user | pweitershausen@mozilla.com |
push date | Wed, 12 Oct 2011 19:53:22 +0000 |
treeherder | mozilla-central@fee22c85ed19 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 10.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
embedding/components/windowwatcher/src/nsWWJSUtils.cpp | file | annotate | diff | comparison | revisions | |
embedding/components/windowwatcher/src/nsWWJSUtils.h | file | annotate | diff | comparison | revisions | |
js/src/jsarena.cpp | file | annotate | diff | comparison | revisions | |
js/src/jsbit.h | file | annotate | diff | comparison | revisions | |
js/src/jshashtable.h | file | annotate | diff | comparison | revisions | |
js/src/jstl.h | file | annotate | diff | comparison | revisions | |
js/src/jsvector.h | file | annotate | diff | comparison | revisions | |
js/src/mfbt/InlineMap.h | file | annotate | diff | comparison | revisions |
--- a/accessible/src/base/NotificationController.cpp +++ b/accessible/src/base/NotificationController.cpp @@ -311,16 +311,20 @@ NotificationController::WillRefresh(mozi // Process only currently queued events. nsTArray<nsRefPtr<AccEvent> > events; events.SwapElements(mEvents); PRUint32 eventCount = events.Length(); for (PRUint32 idx = 0; idx < eventCount; idx++) { AccEvent* accEvent = events[idx]; if (accEvent->mEventRule != AccEvent::eDoNotEmit) { + nsAccessible* target = accEvent->GetAccessible(); + if (!target || target->IsDefunct()) + continue; + // Dispatch the focus event if target is still focused. if (accEvent->mEventType == nsIAccessibleEvent::EVENT_FOCUS) { FocusMgr()->ProcessFocusEvent(accEvent); continue; } mDocument->ProcessPendingEvent(accEvent);
--- a/accessible/src/base/nsDocAccessible.cpp +++ b/accessible/src/base/nsDocAccessible.cpp @@ -1725,52 +1725,45 @@ nsDocAccessible::FireDelayedAccessibleEv mNotificationController->QueueEvent(aEvent); return NS_OK; } void nsDocAccessible::ProcessPendingEvent(AccEvent* aEvent) { - nsAccessible* accessible = aEvent->GetAccessible(); - if (!accessible) - return; - PRUint32 eventType = aEvent->GetEventType(); if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) { - nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryObject(accessible); + nsHyperTextAccessible* hyperText = aEvent->GetAccessible()->AsHyperText(); PRInt32 caretOffset; - if (accessibleText && - NS_SUCCEEDED(accessibleText->GetCaretOffset(&caretOffset))) { + if (hyperText && + NS_SUCCEEDED(hyperText->GetCaretOffset(&caretOffset))) { #ifdef DEBUG_A11Y PRUnichar chAtOffset; - accessibleText->GetCharacterAtOffset(caretOffset, &chAtOffset); + hyperText->GetCharacterAtOffset(caretOffset, &chAtOffset); printf("\nCaret moved to %d with char %c", caretOffset, chAtOffset); #endif nsRefPtr<AccEvent> caretMoveEvent = - new AccCaretMoveEvent(accessible, caretOffset); - if (!caretMoveEvent) - return; - + new AccCaretMoveEvent(hyperText, caretOffset); nsEventShell::FireEvent(caretMoveEvent); PRInt32 selectionCount; - accessibleText->GetSelectionCount(&selectionCount); + hyperText->GetSelectionCount(&selectionCount); if (selectionCount) { // There's a selection so fire selection change as well nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED, - accessible); + hyperText); } } } else { nsEventShell::FireEvent(aEvent); // Post event processing if (eventType == nsIAccessibleEvent::EVENT_HIDE) - ShutdownChildrenInSubtree(accessible); + ShutdownChildrenInSubtree(aEvent->GetAccessible()); } } void nsDocAccessible::ProcessContentInserted(nsAccessible* aContainer, const nsTArray<nsCOMPtr<nsIContent> >* aInsertedContent) { // Process the notification if the container accessible is still in tree.
--- a/accessible/src/msaa/nsAccessNodeWrap.cpp +++ b/accessible/src/msaa/nsAccessNodeWrap.cpp @@ -738,16 +738,20 @@ void nsAccessNodeWrap::DoATSpecificProce TurnOffNewTabSwitchingForJawsAndWE(); } nsRefPtrHashtable<nsVoidPtrHashKey, nsDocAccessible> nsAccessNodeWrap::sHWNDCache; LRESULT CALLBACK nsAccessNodeWrap::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { + // Note, this window's message handling should not invoke any call that + // may result in a cross-process ipc call. Doing so may violate RPC + // message semantics. + switch (msg) { case WM_GETOBJECT: { if (lParam == OBJID_CLIENT) { nsDocAccessible* document = sHWNDCache.GetWeak(static_cast<void*>(hWnd)); if (document) { IAccessible* msaaAccessible = NULL; document->GetNativeInterface((void**)&msaaAccessible); // does an addref
--- a/accessible/src/msaa/nsWinUtils.cpp +++ b/accessible/src/msaa/nsWinUtils.cpp @@ -41,16 +41,20 @@ #include "nsWinUtils.h" #include "nsIWinAccessNode.h" #include "nsRootAccessible.h" #include "nsArrayUtils.h" #include "nsIDocShellTreeItem.h" +// Window property used by ipc related code in identifying accessible +// tab windows. +const PRUnichar* kPropNameTabContent = L"AccessibleTabWindow"; + HRESULT nsWinUtils::ConvertToIA2Array(nsIArray *aGeckoArray, IUnknown ***aIA2Array, long *aIA2ArrayLen) { *aIA2Array = NULL; *aIA2ArrayLen = 0; if (!aGeckoArray) @@ -144,24 +148,29 @@ nsWinUtils::RegisterNativeWindow(LPCWSTR ::RegisterClassW(&wc); } HWND nsWinUtils::CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd, int aX, int aY, int aWidth, int aHeight, bool aIsActive) { - return ::CreateWindowExW(WS_EX_TRANSPARENT, aWindowClass, - L"NetscapeDispatchWnd", - WS_CHILD | (aIsActive ? WS_VISIBLE : 0), - aX, aY, aWidth, aHeight, - aParentWnd, - NULL, - GetModuleHandle(NULL), - NULL); + HWND hwnd = ::CreateWindowExW(WS_EX_TRANSPARENT, aWindowClass, + L"NetscapeDispatchWnd", + WS_CHILD | (aIsActive ? WS_VISIBLE : 0), + aX, aY, aWidth, aHeight, + aParentWnd, + NULL, + GetModuleHandle(NULL), + NULL); + if (hwnd) { + // Mark this window so that ipc related code can identify it. + ::SetPropW(hwnd, kPropNameTabContent, (HANDLE)1); + } + return hwnd; } void nsWinUtils::ShowNativeWindow(HWND aWnd) { ::ShowWindow(aWnd, SW_SHOW); }
--- a/accessible/tests/mochitest/treeview.js +++ b/accessible/tests/mochitest/treeview.js @@ -35,18 +35,18 @@ nsTreeView.prototype = }, setTree: function setTree(aTree) { this.mTree = aTree; }, getCellText: function getCellText(aRow, aCol) { var data = this.getDataForIndex(aRow); - if (aCol in data.colsText) - return data.colsText[aCol]; + if (aCol.id in data.colsText) + return data.colsText[aCol.id]; return data.text + aCol.id; }, getCellValue: function getCellValue(aRow, aCol) { var data = this.getDataForIndex(aRow); return data.value; }, @@ -115,17 +115,17 @@ nsTreeView.prototype = isEditable: function isEditable(aRow, aCol) { return true; }, isSelectable: function isSelectable(aRow, aCol) {}, setCellText: function setCellText(aRow, aCol, aValue) { var data = this.getDataForIndex(aRow); - data.colsText[aCol] = aValue; + data.colsText[aCol.id] = aValue; }, setCellValue: function setCellValue(aRow, aCol, aValue) { var data = this.getDataForIndex(aRow); data.value = aValue; this.mTree.invalidateCell(aRow, aCol); },
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -165,19 +165,18 @@ pref("app.update.silent", false); pref("app.update.url", "https://aus3.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml"); // app.update.url.manual is in branding section // app.update.url.details is in branding section // User-settable override to app.update.url for testing purposes. //pref("app.update.url.override", ""); // app.update.interval is in branding section +// app.update.promptWaitTime is in branding section -// Give the user x seconds to react before showing the big UI. default=12 hours -pref("app.update.promptWaitTime", 43200); // Show the Update Checking/Ready UI when the user was idle for x seconds pref("app.update.idletime", 60); // Whether or not we show a dialog box informing the user that the update was // successfully applied. This is off in Firefox by default since we show a // upgrade start page instead! Other apps may wish to show this UI, and supply // a whatsNewURL field in their brand.properties that contains a link to a page // which tells users what's new in this new update.
--- a/browser/base/content/highlighter.css +++ b/browser/base/content/highlighter.css @@ -37,16 +37,19 @@ } /* * Node Infobar */ #highlighter-nodeinfobar-container { position: absolute; +} + +#highlighter-nodeinfobar-container:not([locked]) { -moz-transition-property: top, left; -moz-transition-duration: 0.1s; -moz-transition-timing-function: linear; } #highlighter-nodeinfobar { display: block; white-space: nowrap;
--- a/browser/branding/aurora/pref/firefox-branding.js +++ b/browser/branding/aurora/pref/firefox-branding.js @@ -2,16 +2,18 @@ pref("startup.homepage_override_url",""); pref("startup.homepage_welcome_url",""); // The time interval between checks for a new version (in seconds) // nightly=8 hours, official=24 hours pref("app.update.interval", 28800); // The time interval between the downloading of mar file chunks in the // background (in seconds) pref("app.update.download.backgroundInterval", 60); +// Give the user x seconds to react before showing the big UI. default=24 hours +pref("app.update.promptWaitTime", 86400); // URL user can browse to manually if for some reason all update installation // attempts fail. pref("app.update.url.manual", "http://www.mozilla.com/firefox/channel/"); // A default value for the "More information about this update" link // supplied in the "An update is available" page of the update wizard. pref("app.update.url.details", "http://www.mozilla.org/projects/%APP%/"); // Release notes and vendor URLs
--- a/browser/branding/nightly/pref/firefox-branding.js +++ b/browser/branding/nightly/pref/firefox-branding.js @@ -1,15 +1,17 @@ pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/"); pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/"); // The time interval between checks for a new version (in seconds) pref("app.update.interval", 7200); // 2 hours // The time interval between the downloading of mar file chunks in the // background (in seconds) pref("app.update.download.backgroundInterval", 60); +// Give the user x seconds to react before showing the big UI. default=12 hours +pref("app.update.promptWaitTime", 43200); // URL user can browse to manually if for some reason all update installation // attempts fail. pref("app.update.url.manual", "http://nightly.mozilla.org/"); // A default value for the "More information about this update" link // supplied in the "An update is available" page of the update wizard. pref("app.update.url.details", "http://www.mozilla.org/projects/%APP%/"); // Release notes and vendor URLs
--- a/browser/branding/official/pref/firefox-branding.js +++ b/browser/branding/official/pref/firefox-branding.js @@ -2,16 +2,18 @@ pref("startup.homepage_override_url",""); pref("startup.homepage_welcome_url","http://www.mozilla.com/%LOCALE%/%APP%/%VERSION%/firstrun/"); // Interval: Time between checks for a new version (in seconds) // nightly=6 hours, official=24 hours pref("app.update.interval", 86400); // The time interval between the downloading of mar file chunks in the // background (in seconds) pref("app.update.download.backgroundInterval", 600); +// Give the user x seconds to react before showing the big UI. default=24 hours +pref("app.update.promptWaitTime", 86400); // URL user can browse to manually if for some reason all update installation // attempts fail. pref("app.update.url.manual", "http://www.firefox.com"); // A default value for the "More information about this update" link // supplied in the "An update is available" page of the update wizard. pref("app.update.url.details", "http://www.mozilla.com/%LOCALE%/%APP%/releases/"); // Release notes and vendor URLs
--- a/browser/branding/unofficial/pref/firefox-branding.js +++ b/browser/branding/unofficial/pref/firefox-branding.js @@ -1,15 +1,17 @@ pref("startup.homepage_override_url","http://www.mozilla.org/projects/%APP%/%VERSION%/whatsnew/"); pref("startup.homepage_welcome_url","http://www.mozilla.org/projects/%APP%/%VERSION%/firstrun/"); // The time interval between checks for a new version (in seconds) pref("app.update.interval", 86400); // 24 hours // The time interval between the downloading of mar file chunks in the // background (in seconds) pref("app.update.download.backgroundInterval", 60); +// Give the user x seconds to react before showing the big UI. default=24 hours +pref("app.update.promptWaitTime", 86400); // URL user can browse to manually if for some reason all update installation // attempts fail. pref("app.update.url.manual", "http://www.mozilla.org/products/%APP%/"); // A default value for the "More information about this update" link // supplied in the "An update is available" page of the update wizard. pref("app.update.url.details", "http://www.mozilla.org/projects/%APP%/"); // Release notes and vendor URLs
--- a/browser/config/mozconfigs/linux32/debug +++ b/browser/config/mozconfigs/linux32/debug @@ -1,11 +1,10 @@ ac_add_options --enable-application=browser -ac_add_options --disable-optimize ac_add_options --enable-debug ac_add_options --enable-libxul ac_add_options --enable-tests ac_add_options --enable-trace-malloc CC=/tools/gcc-4.5/bin/gcc CXX=/tools/gcc-4.5/bin/g++
--- a/browser/config/mozconfigs/linux64/debug +++ b/browser/config/mozconfigs/linux64/debug @@ -1,11 +1,10 @@ ac_add_options --enable-application=browser -ac_add_options --disable-optimize ac_add_options --enable-debug ac_add_options --enable-tests ac_add_options --enable-trace-malloc CC=/tools/gcc-4.5/bin/gcc CXX=/tools/gcc-4.5/bin/g++ # Avoid dependency on libstdc++ 4.5
--- a/browser/config/mozconfigs/macosx32/debug +++ b/browser/config/mozconfigs/macosx32/debug @@ -1,14 +1,13 @@ # Don't use the standard mozconfig. We don't want universal for a debug build. #. $topsrcdir/build/macosx/universal/mozconfig ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk -ac_add_options --disable-optimize ac_add_options --enable-debug ac_add_options --enable-libxul ac_add_options --enable-application=browser ac_add_options --enable-tests ac_add_options --enable-trace-malloc # For NSS symbols
--- a/browser/config/mozconfigs/macosx64/debug +++ b/browser/config/mozconfigs/macosx64/debug @@ -1,9 +1,8 @@ -ac_add_options --disable-optimize ac_add_options --enable-debug ac_add_options --enable-libxul ac_add_options --enable-application=browser ac_add_options --enable-tests ac_add_options --enable-trace-malloc ac_add_options --enable-accessibility
--- a/browser/config/mozconfigs/win32/debug +++ b/browser/config/mozconfigs/win32/debug @@ -1,11 +1,10 @@ ac_add_options --enable-application=browser ac_add_options --enable-jemalloc -ac_add_options --disable-optimize ac_add_options --enable-debug ac_add_options --enable-libxul ac_add_options --enable-trace-malloc ac_add_options --enable-tests # For NSS symbols export MOZ_DEBUG_SYMBOLS=1
--- a/browser/config/mozconfigs/win64/debug +++ b/browser/config/mozconfigs/win64/debug @@ -1,14 +1,13 @@ ac_add_options --target=x86_64-pc-mingw32 ac_add_options --host=x86_64-pc-mingw32 ac_add_options --enable-application=browser ac_add_options --enable-jemalloc -ac_add_options --disable-optimize ac_add_options --enable-debug ac_add_options --enable-libxul ac_add_options --enable-trace-malloc # Needed to enable breakpad in application.ini export MOZILLA_OFFICIAL=1 mk_add_options MOZ_MAKE_FLAGS=-j1
--- a/browser/devtools/highlighter/TreePanel.jsm +++ b/browser/devtools/highlighter/TreePanel.jsm @@ -1,10 +1,10 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * @@ -42,17 +42,17 @@ * ***** END LICENSE BLOCK ***** */ const Cu = Components.utils; Cu.import("resource:///modules/domplate.jsm"); Cu.import("resource:///modules/InsideOutBox.jsm"); Cu.import("resource:///modules/Services.jsm"); -var EXPORTED_SYMBOLS = ["TreePanel"]; +var EXPORTED_SYMBOLS = ["TreePanel", "DOMHelpers"]; const INSPECTOR_URI = "chrome://browser/content/inspector.html"; /** * TreePanel * A container for the Inspector's HTML Tree Panel widget constructor function. * @param aContext nsIDOMWindow (xulwindow) * @param aIUI global InspectorUI object @@ -91,16 +91,18 @@ TreePanel.prototype = { _init: function TP__init(aContext, aIUI) { this.IUI = aIUI; this.window = aContext; this.document = this.window.document; domplateUtils.setDOM(this.window); + this.DOMHelpers = new DOMHelpers(this.window); + let isOpen = this.isOpen.bind(this); this.registrationObject = { id: this.id, label: this.IUI.strings.GetStringFromName("htmlPanel.label"), tooltiptext: this.IUI.strings.GetStringFromName("htmlPanel.tooltiptext"), accesskey: this.IUI.strings.GetStringFromName("htmlPanel.accesskey"), context: this, @@ -134,16 +136,17 @@ TreePanel.prototype = { this.treePanelDiv = this.treeBrowserDocument.createElement("div"); this.treeBrowserDocument.body.appendChild(this.treePanelDiv); this.treePanelDiv.ownerPanel = this; this.ioBox = new InsideOutBox(this, this.treePanelDiv); this.ioBox.createObjectBox(this.IUI.win.document.documentElement); this.treeLoaded = true; this.treeIFrame.addEventListener("click", this.onTreeClick.bind(this), false); this.treeIFrame.addEventListener("dblclick", this.onTreeDblClick.bind(this), false); + this.treeIFrame.addEventListener("keypress", this.IUI, false); delete this.initializingTreePanel; Services.obs.notifyObservers(null, this.IUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, null); if (this.IUI.selection) this.select(this.IUI.selection, true); }, /** @@ -310,103 +313,33 @@ TreePanel.prototype = { { let tag = domplateUtils.getNodeTag(object); if (tag) return tag.replace({object: object}, this.treeBrowserDocument); }, getParentObject: function TP_getParentObject(node) { - let parentNode = node ? node.parentNode : null; - - if (!parentNode) { - // Documents have no parentNode; Attr, Document, DocumentFragment, Entity, - // and Notation. top level windows have no parentNode - if (node && node == this.window.Node.DOCUMENT_NODE) { - // document type - if (node.defaultView) { - let embeddingFrame = node.defaultView.frameElement; - if (embeddingFrame) - return embeddingFrame.parentNode; - } - } - // a Document object without a parentNode or window - return null; // top level has no parent - } - - if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) { - if (parentNode.defaultView) { - return parentNode.defaultView.frameElement; - } - // parent is document element, but no window at defaultView. - return null; - } - - if (!parentNode.localName) - return null; - - return parentNode; + return this.DOMHelpers.getParentObject(node); }, getChildObject: function TP_getChildObject(node, index, previousSibling) { - if (!node) - return null; - - if (node.contentDocument) { - // then the node is a frame - if (index == 0) { - return node.contentDocument.documentElement; // the node's HTMLElement - } - return null; - } - - if (node instanceof this.window.GetSVGDocument) { - let svgDocument = node.getSVGDocument(); - if (svgDocument) { - // then the node is a frame - if (index == 0) { - return svgDocument.documentElement; // the node's SVGElement - } - return null; - } - } - - let child = null; - if (previousSibling) // then we are walking - child = this.getNextSibling(previousSibling); - else - child = this.getFirstChild(node); - - if (this.showTextNodesWithWhitespace) - return child; - - for (; child; child = this.getNextSibling(child)) { - if (!domplateUtils.isWhitespaceText(child)) - return child; - } - - return null; // we have no children worth showing. + return this.DOMHelpers.getChildObject(node, index, previousSibling, + this.showTextNodesWithWhitespace); }, getFirstChild: function TP_getFirstChild(node) { - this.treeWalker = node.ownerDocument.createTreeWalker(node, - this.window.NodeFilter.SHOW_ALL, null, false); - return this.treeWalker.firstChild(); + return this.DOMHelpers.getFirstChild(node); }, getNextSibling: function TP_getNextSibling(node) { - let next = this.treeWalker.nextSibling(); - - if (!next) - delete this.treeWalker; - - return next; + return this.DOMHelpers.getNextSibling(node); }, ///////////////////////////////////////////////////////////////////// // Event Handling /** * Handle click events in the html tree panel. * @param aEvent @@ -742,27 +675,32 @@ TreePanel.prototype = { { if (this.isOpen()) { this.close(); } domplateUtils.setDOM(null); delete this.resizer; - delete this.treeWalker; + + if (this.DOMHelpers) { + this.DOMHelpers.destroy(); + delete this.DOMHelpers; + } if (this.treePanelDiv) { this.treePanelDiv.ownerPanel = null; let parent = this.treePanelDiv.parentNode; parent.removeChild(this.treePanelDiv); delete this.treePanelDiv; delete this.treeBrowserDocument; } if (this.treeIFrame) { + this.treeIFrame.removeEventListener("keypress", this.IUI, false); this.treeIFrame.removeEventListener("dblclick", this.onTreeDblClick, false); this.treeIFrame.removeEventListener("click", this.onTreeClick, false); let parent = this.treeIFrame.parentNode; parent.removeChild(this.treeIFrame); delete this.treeIFrame; } if (this.ioBox) { @@ -772,8 +710,127 @@ TreePanel.prototype = { if (!this.openInDock) { this.container.removeEventListener("popuphiding", this._boundClose, false); delete this._boundClose; } } }; + +/** + * DOMHelpers + * Makes DOM traversal easier. Goes through iframes. + * + * @constructor + * @param nsIDOMWindow aWindow + * The content window, owning the document to traverse. + */ +function DOMHelpers(aWindow) { + this.window = aWindow; +}; + +DOMHelpers.prototype = { + getParentObject: function Helpers_getParentObject(node) + { + let parentNode = node ? node.parentNode : null; + + if (!parentNode) { + // Documents have no parentNode; Attr, Document, DocumentFragment, Entity, + // and Notation. top level windows have no parentNode + if (node && node == this.window.Node.DOCUMENT_NODE) { + // document type + if (node.defaultView) { + let embeddingFrame = node.defaultView.frameElement; + if (embeddingFrame) + return embeddingFrame.parentNode; + } + } + // a Document object without a parentNode or window + return null; // top level has no parent + } + + if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) { + if (parentNode.defaultView) { + return parentNode.defaultView.frameElement; + } + // parent is document element, but no window at defaultView. + return null; + } + + if (!parentNode.localName) + return null; + + return parentNode; + }, + + getChildObject: function Helpers_getChildObject(node, index, previousSibling, + showTextNodesWithWhitespace) + { + if (!node) + return null; + + if (node.contentDocument) { + // then the node is a frame + if (index == 0) { + return node.contentDocument.documentElement; // the node's HTMLElement + } + return null; + } + + if (node instanceof this.window.GetSVGDocument) { + let svgDocument = node.getSVGDocument(); + if (svgDocument) { + // then the node is a frame + if (index == 0) { + return svgDocument.documentElement; // the node's SVGElement + } + return null; + } + } + + let child = null; + if (previousSibling) // then we are walking + child = this.getNextSibling(previousSibling); + else + child = this.getFirstChild(node); + + if (showTextNodesWithWhitespace) + return child; + + for (; child; child = this.getNextSibling(child)) { + if (!this.isWhitespaceText(child)) + return child; + } + + return null; // we have no children worth showing. + }, + + getFirstChild: function Helpers_getFirstChild(node) + { + let SHOW_ALL = Components.interfaces.nsIDOMNodeFilter.SHOW_ALL; + this.treeWalker = node.ownerDocument.createTreeWalker(node, + SHOW_ALL, null, false); + return this.treeWalker.firstChild(); + }, + + getNextSibling: function Helpers_getNextSibling(node) + { + let next = this.treeWalker.nextSibling(); + + if (!next) + delete this.treeWalker; + + return next; + }, + + isWhitespaceText: function Helpers_isWhitespaceText(node) + { + return node.nodeType == this.window.Node.TEXT_NODE && + !/[^\s]/.exec(node.nodeValue); + }, + + destroy: function Helpers_destroy() + { + delete this.window; + delete this.treeWalker; + } +};
--- a/browser/devtools/highlighter/inspector.jsm +++ b/browser/devtools/highlighter/inspector.jsm @@ -882,18 +882,17 @@ InspectorUI.prototype = { }, /** * Register and initialize any included tools. */ initTools: function IUI_initTools() { // Style inspector - // XXX bug 689164, remove /false &&/ from below when bug 689160 fixed. - if (false && Services.prefs.getBoolPref("devtools.styleinspector.enabled") && + if (Services.prefs.getBoolPref("devtools.styleinspector.enabled") && !this.toolRegistered("styleinspector")) { let stylePanel = StyleInspector.createPanel(true); this.registerTool({ id: "styleinspector", label: StyleInspector.l10n("style.highlighter.button.label"), tooltiptext: StyleInspector.l10n("style.highlighter.button.tooltip"), accesskey: StyleInspector.l10n("style.highlighter.accesskey"), context: stylePanel, @@ -985,23 +984,27 @@ InspectorUI.prototype = { this.store.setValue(this.winID, "isDirty", this.isDirty); } if (this.store.isEmpty()) { this.tabbrowser.tabContainer.removeEventListener("TabSelect", this, false); } this.stopInspecting(); + this.browser.removeEventListener("keypress", this, true); this.saveToolState(this.winID); this.toolsDo(function IUI_toolsHide(aTool) { this.unregisterTool(aTool); }.bind(this)); if (this.highlighter) { + this.highlighter.highlighterContainer.removeEventListener("keypress", + this, + true); this.highlighter.destroy(); this.highlighter = null; } this.inspectMenuitem.setAttribute("checked", false); this.browser = this.win = null; // null out references to browser and window this.winID = null; this.selection = null; @@ -1022,44 +1025,56 @@ InspectorUI.prototype = { startInspecting: function IUI_startInspecting() { // if currently editing an attribute value, starting // "live inspection" mode closes the editor if (this.treePanel && this.treePanel.editingContext) this.treePanel.closeEditor(); this.inspectToolbutton.checked = true; - this.attachPageListeners(); + // Attach event listeners to content window and child windows to enable + // highlighting and click to stop inspection. + this.browser.addEventListener("keypress", this, true); + this.highlighter.highlighterContainer.addEventListener("keypress", this, true); + this.highlighter.attachInspectListeners(); + this.inspecting = true; this.toolsDim(true); this.highlighter.veilContainer.removeAttribute("locked"); + this.highlighter.nodeInfo.container.removeAttribute("locked"); }, /** * Stop inspecting webpage, detach page listeners, disable highlighter * event listeners. * @param aPreventScroll * Prevent scroll in the HTML tree? */ stopInspecting: function IUI_stopInspecting(aPreventScroll) { if (!this.inspecting) { return; } this.inspectToolbutton.checked = false; - this.detachPageListeners(); + // Detach event listeners from content window and child windows to disable + // highlighting. We still want to be notified if the user presses "ESCAPE" + // to unlock the node, so we don't remove the "keypress" event until + // the highlighter is removed. + this.highlighter.detachInspectListeners(); + this.inspecting = false; this.toolsDim(false); if (this.highlighter.node) { this.select(this.highlighter.node, true, true, !aPreventScroll); } else { this.select(null, true, true); } this.highlighter.veilContainer.setAttribute("locked", true); + this.highlighter.nodeInfo.container.setAttribute("locked", true); }, /** * Select an object in the tree view. * @param aNode * node to inspect * @param forceUpdate * force an update? @@ -1160,21 +1175,19 @@ InspectorUI.prototype = { this.tabbrowser.tabContainer.removeEventListener("TabSelect", this, false); } break; case "keypress": switch (event.keyCode) { case this.chromeWin.KeyEvent.DOM_VK_RETURN: case this.chromeWin.KeyEvent.DOM_VK_ESCAPE: - if (this.inspecting) { - this.stopInspecting(); - event.preventDefault(); - event.stopPropagation(); - } + this.toggleInspection(); + event.preventDefault(); + event.stopPropagation(); break; case this.chromeWin.KeyEvent.DOM_VK_LEFT: let node; if (this.selection) { node = this.selection.parentNode; } else { node = this.defaultSelection; } @@ -1234,36 +1247,16 @@ InspectorUI.prototype = { event.preventDefault(); event.stopPropagation(); break; } break; } }, - /** - * Attach event listeners to content window and child windows to enable - * highlighting and click to stop inspection. - */ - attachPageListeners: function IUI_attachPageListeners() - { - this.browser.addEventListener("keypress", this, true); - this.highlighter.attachInspectListeners(); - }, - - /** - * Detach event listeners from content window and child windows - * to disable highlighting. - */ - detachPageListeners: function IUI_detachPageListeners() - { - this.browser.removeEventListener("keypress", this, true); - this.highlighter.detachInspectListeners(); - }, - ///////////////////////////////////////////////////////////////////////// //// Utility Methods /** * inspect the given node, highlighting it on the page and selecting the * correct row in the tree panel * * @param aNode
--- a/browser/devtools/highlighter/test/Makefile.in +++ b/browser/devtools/highlighter/test/Makefile.in @@ -57,15 +57,16 @@ include $(topsrcdir)/config/rules.mk browser_inspector_registertools.js \ browser_inspector_bug_665880.js \ browser_inspector_bug_674871.js \ browser_inspector_editor.js \ browser_inspector_bug_566084_location_changed.js \ browser_inspector_infobar.js \ browser_inspector_bug_690361.js \ browser_inspector_bug_672902_keyboard_shortcuts.js \ + browser_inspector_keybindings.js \ $(NULL) # Disabled due to constant failures # browser_inspector_treePanel_click.js \ libs:: $(_BROWSER_FILES) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
--- a/browser/devtools/highlighter/test/browser_inspector_initialization.js +++ b/browser/devtools/highlighter/test/browser_inspector_initialization.js @@ -72,32 +72,49 @@ function runInspectorTests() Services.obs.addObserver(treePanelTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, false); ok(InspectorUI.toolbar, "we have the toolbar."); ok(!InspectorUI.toolbar.hidden, "toolbar is visible"); ok(InspectorUI.inspecting, "Inspector is inspecting"); ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open"); ok(InspectorUI.highlighter, "Highlighter is up"); + InspectorUI.inspectNode(doc.body); + InspectorUI.stopInspecting(); InspectorUI.treePanel.open(); } function treePanelTests() { Services.obs.removeObserver(treePanelTests, InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY); - Services.obs.addObserver(runContextMenuTest, - InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false); + Services.obs.addObserver(stylePanelTests, + "StyleInspector-opened", false); ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open"); executeSoon(function() { + InspectorUI.stylePanel.showTool(doc.body); + }); +} + +function stylePanelTests() +{ + Services.obs.removeObserver(stylePanelTests, "StyleInspector-opened"); + Services.obs.addObserver(runContextMenuTest, + InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false); + + ok(InspectorUI.stylePanel.isOpen(), "Style Panel is Open"); + ok(InspectorUI.stylePanel.cssHtmlTree, "Style Panel has a cssHtmlTree"); + + executeSoon(function() { InspectorUI.closeInspectorUI(); }); + } function runContextMenuTest() { Services.obs.removeObserver(runContextMenuTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false); Services.obs.addObserver(inspectNodesFromContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false); salutation = doc.getElementById("salutation"); ok(salutation, "hello, context menu test!"); @@ -116,19 +133,18 @@ function runContextMenuTest() } function inspectNodesFromContextTest() { Services.obs.removeObserver(inspectNodesFromContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false); Services.obs.addObserver(openInspectorForContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false); ok(!InspectorUI.inspecting, "Inspector is not actively highlighting"); is(InspectorUI.selection, salutation, "Inspector is highlighting salutation"); - ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed"); - // TODO: These tests depend on the style inspector patches. - todo(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open"); + ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is closed"); + ok(!InspectorUI.stylePanel.isOpen(), "Inspector Style Panel is closed"); executeSoon(function() { InspectorUI.closeInspectorUI(true); }); } function openInspectorForContextTest() { Services.obs.removeObserver(openInspectorForContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
new file mode 100644 --- /dev/null +++ b/browser/devtools/highlighter/test/browser_inspector_keybindings.js @@ -0,0 +1,81 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + + +function test() +{ + waitForExplicitFinish(); + + let doc; + let node; + + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.selectedBrowser.addEventListener("load", function onload() { + gBrowser.selectedBrowser.removeEventListener("load", onload, true); + doc = content.document; + waitForFocus(setupKeyBindingsTest, content); + }, true); + + content.location = "data:text/html,<h1>foobar</h1>"; + + function setupKeyBindingsTest() + { + node = doc.querySelector("h1"); + Services.obs.addObserver(highlightNode, + InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false); + InspectorUI.toggleInspectorUI(); + } + + function highlightNode() + { + Services.obs.removeObserver(highlightNode, + InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED); + + executeSoon(function() { + Services.obs.addObserver(lockNode, + InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false); + + InspectorUI.inspectNode(node); + }); + } + + function lockNode() + { + Services.obs.removeObserver(lockNode, + InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING); + + EventUtils.synthesizeKey("VK_ESCAPE", { }); + + executeSoon(isTheNodeLocked); + } + + function isTheNodeLocked() + { + is(InspectorUI.selection, node, "selection matches node"); + ok(!InspectorUI.inspecting, "the node is locked"); + unlockNode(); + } + + function unlockNode() { + EventUtils.synthesizeKey("VK_ESCAPE", { }); + + executeSoon(isTheNodeUnlocked); + } + + function isTheNodeUnlocked() + { + ok(InspectorUI.inspecting, "the node is unlocked"); + + Services.obs.addObserver(finishUp, + InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false); + InspectorUI.closeInspectorUI(); + } + + function finishUp() { + Services.obs.removeObserver(finishUp, + InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED); + doc = node = null; + gBrowser.removeCurrentTab(); + finish(); + } +}
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm +++ b/browser/devtools/styleinspector/CssHtmlTree.jsm @@ -323,16 +323,44 @@ CssHtmlTree.prototype = { CssHtmlTree.propertyNames.push(prop); } } CssHtmlTree.propertyNames.sort(); CssHtmlTree.propertyNames.push.apply(CssHtmlTree.propertyNames, mozProps.sort()); }, + + /** + * Destructor for CssHtmlTree. + */ + destroy: function CssHtmlTree_destroy() + { + delete this.viewedElement; + + // Nodes used in templating + delete this.root; + delete this.path; + delete this.templateRoot; + delete this.templatePath; + delete this.propertyContainer; + delete this.templateProperty; + delete this.panel; + + // The document in which we display the results (csshtmltree.xhtml). + delete this.styleDocument; + + // The element that we're inspecting, and the document that it comes from. + delete this.propertyViews; + delete this.getRTLAttr; + delete this.styleWin; + delete this.cssLogic; + delete this.doc; + delete this.win; + }, }; /** * A container to give easy access to property data from the template engine. * * @constructor * @param {CssHtmlTree} aTree the CssHtmlTree instance we are working with. * @param {string} aName the CSS property name for which this PropertyView
--- a/browser/devtools/styleinspector/StyleInspector.jsm +++ b/browser/devtools/styleinspector/StyleInspector.jsm @@ -61,35 +61,34 @@ var StyleInspector = { * @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"); - let ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; - let panel = win.document.createElementNS(ns, "panel"); + let panel = win.document.createElement("panel"); panel.setAttribute("class", "styleInspector"); panel.setAttribute("orient", "vertical"); panel.setAttribute("ignorekeys", "true"); panel.setAttribute("noautofocus", "true"); panel.setAttribute("noautohide", "true"); panel.setAttribute("titlebar", "normal"); panel.setAttribute("close", "true"); panel.setAttribute("label", StyleInspector.l10n("panelTitle")); panel.setAttribute("width", 350); panel.setAttribute("height", win.screen.height / 2); let vbox = win.document.createElement("vbox"); vbox.setAttribute("flex", "1"); panel.appendChild(vbox); - let iframe = win.document.createElementNS(ns, "iframe"); + let iframe = win.document.createElement("iframe"); iframe.setAttribute("flex", "1"); iframe.setAttribute("tooltip", "aHTMLTooltip"); iframe.setAttribute("src", "chrome://browser/content/csshtmltree.xhtml"); iframe.addEventListener("load", SI_iframeOnload, true); vbox.appendChild(iframe); let hbox = win.document.createElement("hbox"); hbox.setAttribute("class", "resizerbox"); @@ -140,18 +139,18 @@ var StyleInspector = { 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.addEventListener("popupshown", SI_popupShown, false); + panel.addEventListener("popuphidden", SI_popupHidden, false); panel.preserveOnHide = !!aPreserveOnHide; /** * Check if the style inspector is open */ panel.isOpen = function SI_isOpen() { return this.state && this.state == "open"; @@ -171,25 +170,31 @@ var StyleInspector = { } }; /** * Destroy the style panel, remove listeners etc. */ panel.destroy = function SI_destroy() { - if (!this.cssLogic) - return; if (this.isOpen()) this.hideTool(); - this.cssLogic = null; - this.cssHtmlTree = null; - this.removeEventListener("popupshown", SI_popupShown); - this.removeEventListener("popuphidden", SI_popupHidden); - this.parentNode.removeChild(this); + if (panel.cssHtmlTree) + panel.cssHtmlTree.destroy(); + if (iframe) { + iframe.parentNode.removeChild(iframe); + iframe = null; + } + + delete panel.cssLogic; + delete panel.cssHtmlTree; + panel.removeEventListener("popupshown", SI_popupShown, false); + panel.removeEventListener("popuphidden", SI_popupHidden, false); + panel.parentNode.removeChild(panel); + panel = null; Services.obs.notifyObservers(null, "StyleInspector-closed", null); }; /** * Dim or undim a panel by setting or removing a dimmed attribute. * * @param aState * true = dim, false = undim
--- a/browser/devtools/styleinspector/test/browser/browser_bug683672.js +++ b/browser/devtools/styleinspector/test/browser/browser_bug683672.js @@ -15,16 +15,17 @@ function test() { waitForExplicitFinish(); addTab(TEST_URI); browser.addEventListener("load", tabLoaded, true); } function tabLoaded() { + browser.removeEventListener("load", tabLoaded, true); ok(window.StyleInspector, "StyleInspector exists"); ok(StyleInspector.isEnabled, "style inspector preference is enabled"); stylePanel = StyleInspector.createPanel(); Services.obs.addObserver(runTests, "StyleInspector-opened", false); stylePanel.openPopup(); } function runTests()
--- a/browser/locales/en-US/chrome/overrides/appstrings.properties +++ b/browser/locales/en-US/chrome/overrides/appstrings.properties @@ -42,16 +42,17 @@ connectionFailure=Firefox can't establis netInterrupt=The connection to %S was interrupted while the page was loading. netTimeout=The server at %S is taking too long to respond. redirectLoop=Firefox has detected that the server is redirecting the request for this address in a way that will never complete. ## LOCALIZATION NOTE (confirmRepostPrompt): In this item, don't translate "%S" confirmRepostPrompt=To display this page, %S must send information that will repeat any action (such as a search or order confirmation) that was performed earlier. resendButton.label=Resend unknownSocketType=Firefox doesn't know how to communicate with the server. netReset=The connection to the server was reset while the page was loading. +notCached=This document is no longer available. netOffline=Firefox is currently in offline mode and can't browse the Web. isprinting=The document cannot change while Printing or in Print Preview. deniedPortAccess=This address uses a network port which is normally used for purposes other than Web browsing. Firefox has canceled the request for your protection. proxyResolveFailure=Firefox is configured to use a proxy server that can't be found. proxyConnectFailure=Firefox is configured to use a proxy server that is refusing connections. contentEncodingError=The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression. unsafeContentType=The page you are trying to view cannot be shown because it is contained in a file type that may not be safe to open. Please contact the website owners to inform them of this problem. externalProtocolTitle=External Protocol Request
--- a/browser/locales/en-US/chrome/overrides/netError.dtd +++ b/browser/locales/en-US/chrome/overrides/netError.dtd @@ -47,16 +47,19 @@ <li>Make sure that you're using forward slashes (i.e. <strong>/</strong>).</li> </ul> "> <!ENTITY netInterrupt.title "The connection was interrupted"> <!ENTITY netInterrupt.longDesc "&sharedLongDesc;"> +<!ENTITY notCached.title "Document Expired"> +<!ENTITY notCached.longDesc "<p>The requested document is not available in Firefox's cache.</p><ul><li>As a security precuation, Firefox does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>"> + <!ENTITY netOffline.title "Offline mode"> <!ENTITY netOffline.longDesc2 " <ul> <li>Press "Try Again" to switch to online mode and reload the page.</li> </ul> "> <!ENTITY contentEncodingError.title "Content Encoding Error">
--- a/build/mobile/devicemanagerADB.py +++ b/build/mobile/devicemanagerADB.py @@ -280,18 +280,20 @@ class DeviceManagerADB(DeviceManager): return self.getFile(remoteFile) # copy file from device (remoteFile) to host (localFile) # external function # returns: # success: output of pullfile, string # failure: None def getFile(self, remoteFile, localFile = 'tmpfile_dm_adb'): + # TODO: add debug flags and allow for printing stdout + # self.runCmd(["pull", remoteFile, localFile]) try: - self.checkCmd(["pull", remoteFile, localFile]) + self.runCmd(["pull", remoteFile, localFile]).stdout.read() f = open(localFile) ret = f.read() f.close() return ret; except: return None # copy directory structure from device (remoteDir) to host (localDir)
--- a/configure.in +++ b/configure.in @@ -7122,27 +7122,16 @@ MOZ_ARG_ENABLE_BOOL(tracevis, [ --enable-tracevis Enable TraceVis tracing tool (default=no)], MOZ_TRACEVIS=1, MOZ_TRACEVIS= ) if test -n "$MOZ_TRACEVIS"; then AC_DEFINE(MOZ_TRACEVIS) fi dnl ======================================================== -dnl = Use GCTimer -dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(gctimer, -[ --enable-gctimer Enable GC timer (default=no)], - MOZ_GCTIMER=1, - MOZ_GCTIMER= ) -if test -n "$MOZ_GCTIMER"; then - AC_DEFINE(MOZ_GCTIMER) -fi - -dnl ======================================================== dnl ETW - Event Tracing for Windows dnl ======================================================== MOZ_ARG_ENABLE_BOOL(ETW, [ --enable-ETW Enable ETW (Event Tracing for Windows) event reporting (needs Windows Vista+ SDK)], MOZ_ETW=1, MOZ_ETW= ) if test -n "$MOZ_ETW"; then @@ -7400,16 +7389,33 @@ AC_SUBST(MOZ_DEMANGLE_SYMBOLS) dnl ======================================================== dnl = Support for gcc stack unwinding (from gcc 3.3) dnl ======================================================== if test -z "$SKIP_LIBRARY_CHECKS"; then MOZ_CHECK_HEADER(unwind.h, AC_CHECK_FUNCS(_Unwind_Backtrace)) fi dnl ======================================================== +dnl JIT observers +dnl ======================================================== + +MOZ_ARG_WITH_STRING(jitreport-granularity, +[ --jitreport-granularity=N + Default granularity at which to report JIT code + to external tools + 0 - no info + 1 - code ranges for whole functions only + 2 - per-line information + 3 - per-op information], + JITREPORT_GRANULARITY=$withval, + JITREPORT_GRANULARITY=3) + +AC_DEFINE_UNQUOTED(JS_DEFAULT_JITREPORT_GRANULARITY, $JITREPORT_GRANULARITY) + +dnl ======================================================== dnl = dnl = Misc. Options dnl = dnl ======================================================== MOZ_ARG_HEADER(Misc. Options) dnl ======================================================== dnl update xterm title
--- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -121,18 +121,18 @@ class Loader; namespace dom { class Link; class Element; } // namespace dom } // namespace mozilla #define NS_IDOCUMENT_IID \ -{ 0xd76bcf5f, 0xd02f, 0x459a, \ - { 0xb1, 0x23, 0x8e, 0x2c, 0x9a, 0x0d, 0x84, 0x68 } } +{ 0x448c396a, 0x013c, 0x47b8, \ + { 0x95, 0xf4, 0x56, 0x68, 0x0f, 0x5f, 0x12, 0xf8 } } // Flag for AddStyleSheet(). #define NS_STYLESHEET_FROM_CATALOG (1 << 0) // Document states // RTL locale: specific to the XUL localedir attribute #define NS_DOCUMENT_STATE_RTL_LOCALE NS_DEFINE_EVENT_STATE_MACRO(0) @@ -1316,27 +1316,27 @@ public: virtual void EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData) = 0; /** * Return whether the document is currently showing (in the sense of * OnPageShow() having been called already and OnPageHide() not having been * called yet. */ - bool IsShowing() { return mIsShowing; } + bool IsShowing() const { return mIsShowing; } /** * Return whether the document is currently visible (in the sense of * OnPageHide having been called and OnPageShow not yet having been called) */ - bool IsVisible() { return mVisible; } + bool IsVisible() const { return mVisible; } /** * Return true when this document is active, i.e., the active document * in a content viewer. */ - bool IsActive() { return mDocumentContainer && !mRemovedFromDocShell; } + bool IsActive() const { return mDocumentContainer && !mRemovedFromDocShell; } void RegisterFreezableElement(nsIContent* aContent); bool UnregisterFreezableElement(nsIContent* aContent); typedef void (* FreezableElementEnumerator)(nsIContent*, void*); void EnumerateFreezableElements(FreezableElementEnumerator aEnumerator, void* aData); #ifdef MOZ_SMIL @@ -1568,16 +1568,18 @@ public: #define DEPRECATED_OPERATION(_op) e##_op, enum DeprecatedOperations { #include "nsDeprecatedOperationList.h" eDeprecatedOperationCount }; #undef DEPRECATED_OPERATION void WarnOnceAbout(DeprecatedOperations aOperation); + virtual void PostVisibilityUpdateEvent() = 0; + private: PRUint64 mWarnedAbout; protected: ~nsIDocument() { // XXX The cleanup of mNodeInfoManager (calling DropDocumentReference and // releasing it) happens in the nsDocument destructor. We'd prefer to
--- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1521,16 +1521,17 @@ nsDOMImplementation::CreateHTMLDocument( // NOTE! nsDocument::operator new() zeroes out all members, so don't // bother initializing members to 0. nsDocument::nsDocument(const char* aContentType) : nsIDocument() , mAnimatingImages(PR_TRUE) , mIsFullScreen(PR_FALSE) + , mVisibilityState(eHidden) { SetContentTypeInternal(nsDependentCString(aContentType)); #ifdef PR_LOGGING if (!gDocumentLeakPRLog) gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak"); if (gDocumentLeakPRLog) @@ -3832,16 +3833,23 @@ nsDocument::SetScriptGlobalObject(nsIScr MaybeRescheduleAnimationFrameNotifications(); } // Remember the pointer to our window (or lack there of), to avoid // having to QI every time it's asked for. nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobalObject); mWindow = window; + + // Set our visibility state, but do not fire the event. This is correct + // because either we're coming out of bfcache (in which case IsVisible() will + // still test false at this point and no state change will happen) or we're + // doing the initial document load and don't want to fire the event for this + // change. + mVisibilityState = GetVisibilityState(); } nsIScriptGlobalObject* nsDocument::GetScriptHandlingObjectInternal() const { NS_ASSERTION(!mScriptGlobalObject, "Do not call this when mScriptGlobalObject is set!"); @@ -7317,16 +7325,18 @@ nsDocument::OnPageShow(bool aPersisted, mAnimationController->OnPageShow(); } #endif if (aPersisted) { SetImagesNeedAnimating(PR_TRUE); } + UpdateVisibilityState(); + nsCOMPtr<nsIDOMEventTarget> target = aDispatchStartTarget; if (!target) { target = do_QueryInterface(GetWindow()); } DispatchPageTransition(target, NS_LITERAL_STRING("pageshow"), aPersisted); } static bool @@ -7378,16 +7388,19 @@ nsDocument::OnPageHide(bool aPersisted, // Now send out a PageHide event. nsCOMPtr<nsIDOMEventTarget> target = aDispatchStartTarget; if (!target) { target = do_QueryInterface(GetWindow()); } DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted); mVisible = PR_FALSE; + + UpdateVisibilityState(); + EnumerateExternalResources(NotifyPageHide, &aPersisted); EnumerateFreezableElements(NotifyActivityChanged, nsnull); } void nsDocument::WillDispatchMutationEvent(nsINode* aTarget) { NS_ASSERTION(mSubtreeModifiedDepth != 0 || @@ -8653,8 +8666,66 @@ nsDocument::SizeOf() const return nsINode::SetOn##name_(cx, v); \ } #define TOUCH_EVENT EVENT #define DOCUMENT_ONLY_EVENT EVENT #include "nsEventNameList.h" #undef DOCUMENT_ONLY_EVENT #undef TOUCH_EVENT #undef EVENT + +void +nsDocument::UpdateVisibilityState() +{ + VisibilityState oldState = mVisibilityState; + mVisibilityState = GetVisibilityState(); + if (oldState != mVisibilityState) { + nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this), + NS_LITERAL_STRING("mozvisibilitychange"), + false, false); + } +} + +nsDocument::VisibilityState +nsDocument::GetVisibilityState() const +{ + // We have to check a few pieces of information here: + // 1) Are we in bfcache (!IsVisible())? If so, nothing else matters. + // 2) Do we have an outer window? If not, we're hidden. Note that we don't + // want to use GetWindow here because it does weird groveling for windows + // in some cases. + // 3) Is our outer window background? If so, we're hidden. + // Otherwise, we're visible. + if (!IsVisible() || !mWindow || !mWindow->GetOuterWindow() || + mWindow->GetOuterWindow()->IsBackground()) { + return eHidden; + } + + return eVisible; +} + +/* virtual */ void +nsDocument::PostVisibilityUpdateEvent() +{ + nsCOMPtr<nsIRunnable> event = + NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState); + NS_DispatchToMainThread(event); +} + +NS_IMETHODIMP +nsDocument::GetMozHidden(bool* aHidden) +{ + *aHidden = mVisibilityState != eVisible; + return NS_OK; +} + +NS_IMETHODIMP +nsDocument::GetMozVisibilityState(nsAString& aState) +{ + // This needs to stay in sync with the VisibilityState enum. + static const char states[][8] = { + "hidden", + "visible" + }; + PR_STATIC_ASSERT(NS_ARRAY_LENGTH(states) == eVisibilityStateCount); + aState.AssignASCII(states[mVisibilityState]); + return NS_OK; +}
--- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -943,16 +943,22 @@ public: virtual void ResetFullScreenElement(); virtual Element* GetFullScreenElement(); virtual void RequestFullScreen(Element* aElement); virtual void CancelFullScreen(); virtual void UpdateFullScreenStatus(bool aIsFullScreen); virtual bool IsFullScreenDoc(); + // This method may fire a DOM event; if it does so it will happen + // synchronously. + void UpdateVisibilityState(); + // Posts an event to call UpdateVisibilityState + virtual void PostVisibilityUpdateEvent(); + protected: friend class nsNodeUtils; /** * Check that aId is not empty and log a message to the console * service if it is. * @returns PR_TRUE if aId looks correct, PR_FALSE otherwise. */ @@ -1145,16 +1151,24 @@ protected: nsCOMPtr<nsIContent> mFirstBaseNodeWithHref; nsEventStates mDocumentState; nsEventStates mGotDocumentState; nsRefPtr<nsDOMNavigationTiming> mTiming; private: friend class nsUnblockOnloadEvent; + // This needs to stay in sync with the list in GetMozVisibilityState. + enum VisibilityState { + eHidden = 0, + eVisible, + eVisibilityStateCount + }; + // Recomputes the visibility state but doesn't set the new value. + VisibilityState GetVisibilityState() const; void PostUnblockOnloadEvent(); void DoUnblockOnload(); nsresult CheckFrameOptions(); nsresult InitCSP(); /** @@ -1225,16 +1239,18 @@ private: nsCString mScrollToRef; PRUint8 mScrolledToRefAlready : 1; PRUint8 mChangeScrollPosWhenScrollingToRef : 1; // Tracking for images in the document. nsDataHashtable< nsPtrHashKey<imgIRequest>, PRUint32> mImageTracker; + VisibilityState mVisibilityState; + #ifdef DEBUG protected: bool mWillReparent; #endif }; #define NS_DOCUMENT_INTERFACE_TABLE_BEGIN(_class) \ NS_NODE_OFFSET_AND_INTERFACE_TABLE_BEGIN(_class) \
--- a/content/base/test/Makefile.in +++ b/content/base/test/Makefile.in @@ -511,16 +511,17 @@ include $(topsrcdir)/config/rules.mk test_bug675166.html \ test_bug682554.html \ test_bug682592.html \ bug682592-subframe.html \ bug682592-subframe-ref.html \ test_bug684671.html \ test_bug685798.html \ test_bug686449.xhtml \ + test_bug690056.html \ test_bug692434.html \ file_bug692434.xml \ $(NULL) _CHROME_FILES = \ test_bug357450.js \ $(NULL)
new file mode 100644 --- /dev/null +++ b/content/base/test/test_bug690056.html @@ -0,0 +1,54 @@ +<!DOCTYPE HTML> +<html> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=690056 +--> +<head> + <title>Test for Bug 690056</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=690056">Mozilla Bug 690056</a> +<p id="display"> + <iframe id="x"></iframe> + <iframe style="display: none" id="y"></iframe> +</p> +<div id="content" style="display: none"> + +</div> +<pre id="test"> +<script type="application/javascript"> + +/** Test for Bug 690056 **/ +SimpleTest.waitForExplicitFinish(); +is(document.mozHidden, false, "Document should not be hidden during load"); +is(document.mozVisibilityState, "visible", + "Document should be visible during load"); + +addLoadEvent(function() { + var doc = document.implementation.createDocument("", "", null); + is(doc.mozHidden, true, "Data documents should be hidden"); + is(doc.mozVisibilityState, "hidden", "Data documents really should be hidden"); + + is(document.mozHidden, false, "Document should not be hidden onload"); + is(document.mozVisibilityState, "visible", + "Document should be visible onload"); + + is($("x").contentDocument.mozHidden, false, + "Subframe document should not be hidden onload"); + is($("x").contentDocument.mozVisibilityState, "visible", + "Subframe document should be visible onload"); + is($("y").contentDocument.mozHidden, false, + "display:none subframe document should not be hidden onload"); + is($("y").contentDocument.mozVisibilityState, "visible", + "display:none subframe document should be visible onload"); + + SimpleTest.finish(); +}); + + +</script> +</pre> +</body> +</html>
--- a/content/xslt/src/xslt/txStylesheetCompiler.h +++ b/content/xslt/src/xslt/txStylesheetCompiler.h @@ -72,18 +72,18 @@ public: nsRefPtr<txNamespaceMap> mMappings; nsTArray<PRInt32> mInstructionNamespaces; PRInt32 mDepth; }; class txACompileObserver { public: - virtual void AddRef() = 0; - virtual void Release() = 0; + NS_IMETHOD_(nsrefcnt) AddRef() = 0; + NS_IMETHOD_(nsrefcnt) Release() = 0; virtual nsresult loadURI(const nsAString& aUri, const nsAString& aReferrerUri, txStylesheetCompiler* aCompiler) = 0; virtual void onDoneCompiling(txStylesheetCompiler* aCompiler, nsresult aResult, const PRUnichar *aErrorText = nsnull, const PRUnichar *aParam = nsnull) = 0;
--- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -3969,20 +3969,22 @@ nsDocShell::DisplayLoadError(nsresult aE error.AssignLiteral("unknownSocketType"); break; case NS_ERROR_NET_RESET: // Doc failed to load because the server kept reseting the connection // before we could read any data from it error.AssignLiteral("netReset"); break; case NS_ERROR_DOCUMENT_NOT_CACHED: - // Doc failed to load because we are offline and the cache does not - // contain a copy of the document. + // Doc failed to load because the cache does not contain a copy of + // the document. + error.AssignLiteral("notCached"); + break; case NS_ERROR_OFFLINE: - // Doc failed to load because we are offline + // Doc failed to load because we are offline. error.AssignLiteral("netOffline"); break; case NS_ERROR_DOCUMENT_IS_PRINTMODE: // Doc navigation attempted while Printing or Print Preview error.AssignLiteral("isprinting"); break; case NS_ERROR_PORT_ACCESS_NOT_ALLOWED: // Port blocked for security reasons @@ -4877,16 +4879,20 @@ nsDocShell::SetIsActive(bool aIsActive) GetPresShell(getter_AddRefs(pshell)); if (pshell) pshell->SetIsActive(aIsActive); // Tell the window about it nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mScriptGlobal); if (win) { win->SetIsBackground(!aIsActive); + nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument()); + if (doc) { + doc->PostVisibilityUpdateEvent(); + } } // Recursively tell all of our children PRInt32 n = mChildList.Count(); for (PRInt32 i = 0; i < n; ++i) { nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(ChildAt(i)); if (docshell) docshell->SetIsActive(aIsActive); @@ -6361,119 +6367,27 @@ nsDocShell::EndPageLoad(nsIWebProgress * aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE || aStatus == NS_ERROR_NET_INTERRUPT || aStatus == NS_ERROR_NET_RESET || aStatus == NS_ERROR_OFFLINE || aStatus == NS_ERROR_MALWARE_URI || aStatus == NS_ERROR_PHISHING_URI || aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE || aStatus == NS_ERROR_REMOTE_XUL || + aStatus == NS_ERROR_OFFLINE || NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) { DisplayLoadError(aStatus, url, nsnull, aChannel); } else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) { - /* A document that was requested to be fetched *only* from - * the cache is not in cache. May be this is one of those - * postdata results. Throw a dialog to the user, - * saying that the page has expired from cache and ask if - * they wish to refetch the page from the net. Do this only - * if the request is a form post. - */ - nsCAutoString method; - if (httpChannel) - httpChannel->GetRequestMethod(method); - if (method.Equals("POST") && !NS_IsOffline()) { - bool repost; - rv = ConfirmRepost(&repost); - if (NS_FAILED(rv)) return rv; - // If the user pressed cancel in the dialog, return. Don't try - // to load the page without the post data. - if (!repost) - return NS_OK; - - // The user wants to repost the data to the server. - // If the page was loaded due to a back/forward/go - // operation, update the session history index. - // This is similar to the updating done in - // nsDocShell::OnNewURI() for regular pages - nsCOMPtr<nsISHistory> rootSH=mSessionHistory; - if (!mSessionHistory) { - nsCOMPtr<nsIDocShellTreeItem> root; - //Get the root docshell - GetSameTypeRootTreeItem(getter_AddRefs(root)); - if (root) { - // QI root to nsIWebNavigation - nsCOMPtr<nsIWebNavigation> rootAsWebnav = - do_QueryInterface(root); - if (rootAsWebnav) { - // Get the handle to SH from the root docshell - rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH)); - } - } - } // mSessionHistory - - if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) { - nsCOMPtr<nsISHistoryInternal> shInternal = - do_QueryInterface(rootSH); - if (shInternal) { - rootSH->GetIndex(&mPreviousTransIndex); - shInternal->UpdateIndex(); - rootSH->GetIndex(&mLoadedTransIndex); -#ifdef DEBUG_PAGE_CACHE - printf("Previous index: %d, Loaded index: %d\n\n", - mPreviousTransIndex, mLoadedTransIndex); -#endif - } - } - - // Make it look like we really did honestly finish loading the - // history page we were loading, since the "reload" load we're - // about to kick off will reload our current history entry. - // This is a bit of a hack, and if the force-load fails I think - // we'll end up being confused about what page we're on... but - // we would anyway, since we've updated the session history - // index above. - SetHistoryEntry(&mOSHE, loadingSHE); - - // The user does want to repost the data to the server. - // Initiate a new load again. - - // Get the postdata if any from the channel. - nsCOMPtr<nsIInputStream> inputStream; - nsCOMPtr<nsIURI> referrer; - if (httpChannel) { - httpChannel->GetReferrer(getter_AddRefs(referrer)); - nsCOMPtr<nsIUploadChannel> uploadChannel = - do_QueryInterface(aChannel); - if (uploadChannel) { - uploadChannel->GetUploadStream(getter_AddRefs(inputStream)); - } - } - nsCOMPtr<nsISeekableStream> postDataSeekable = - do_QueryInterface(inputStream); - if (postDataSeekable) { - postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); - } - InternalLoad(url, // URI - referrer, // Referring URI - nsnull, // Owner - INTERNAL_LOAD_FLAGS_INHERIT_OWNER, // Inherit owner - nsnull, // No window target - nsnull, // No type hint - inputStream, // Post data stream - nsnull, // No headers stream - LOAD_RELOAD_BYPASS_PROXY_AND_CACHE,// Load type - nsnull, // No SHEntry - PR_TRUE, // first party site - nsnull, // No nsIDocShell - nsnull); // No nsIRequest - } - else { - DisplayLoadError(aStatus, url, nsnull, aChannel); - } + // Non-caching channels will simply return NS_ERROR_OFFLINE. + // Caching channels would have to look at their flags to work + // out which error to return. Or we can fix up the error here. + if (!(mLoadType & LOAD_CMD_HISTORY)) + aStatus = NS_ERROR_OFFLINE; + DisplayLoadError(aStatus, url, nsnull, aChannel); } } // if we have a host return NS_OK; } //*****************************************************************************
--- a/docshell/resources/content/netError.xhtml +++ b/docshell/resources/content/netError.xhtml @@ -318,16 +318,17 @@ <h1 id="et_fileNotFound">&fileNotFound.title;</h1> <h1 id="et_malformedURI">&malformedURI.title;</h1> <h1 id="et_protocolNotFound">&protocolNotFound.title;</h1> <h1 id="et_connectionFailure">&connectionFailure.title;</h1> <h1 id="et_netTimeout">&netTimeout.title;</h1> <h1 id="et_redirectLoop">&redirectLoop.title;</h1> <h1 id="et_unknownSocketType">&unknownSocketType.title;</h1> <h1 id="et_netReset">&netReset.title;</h1> + <h1 id="et_notCached">¬Cached.title;</h1> <h1 id="et_netOffline">&netOffline.title;</h1> <h1 id="et_netInterrupt">&netInterrupt.title;</h1> <h1 id="et_deniedPortAccess">&deniedPortAccess.title;</h1> <h1 id="et_proxyResolveFailure">&proxyResolveFailure.title;</h1> <h1 id="et_proxyConnectFailure">&proxyConnectFailure.title;</h1> <h1 id="et_contentEncodingError">&contentEncodingError.title;</h1> <h1 id="et_unsafeContentType">&unsafeContentType.title;</h1> <h1 id="et_nssFailure2">&nssFailure2.title;</h1> @@ -343,16 +344,17 @@ <div id="ed_fileNotFound">&fileNotFound.longDesc;</div> <div id="ed_malformedURI">&malformedURI.longDesc;</div> <div id="ed_protocolNotFound">&protocolNotFound.longDesc;</div> <div id="ed_connectionFailure">&connectionFailure.longDesc;</div> <div id="ed_netTimeout">&netTimeout.longDesc;</div> <div id="ed_redirectLoop">&redirectLoop.longDesc;</div> <div id="ed_unknownSocketType">&unknownSocketType.longDesc;</div> <div id="ed_netReset">&netReset.longDesc;</div> + <div id="ed_notCached">¬Cached.longDesc;</div> <div id="ed_netOffline">&netOffline.longDesc2;</div> <div id="ed_netInterrupt">&netInterrupt.longDesc;</div> <div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div> <div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc;</div> <div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div> <div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div> <div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div> <div id="ed_nssFailure2">&nssFailure2.longDesc;</div>
--- a/docshell/test/chrome/Makefile.in +++ b/docshell/test/chrome/Makefile.in @@ -115,16 +115,18 @@ include $(topsrcdir)/config/rules.mk test_bug454235.xul \ bug454235-subframe.xul \ test_bug456980.xul \ test_bug662200.xul \ bug662200_window.xul \ 662200a.html \ 662200b.html \ 662200c.html \ + test_bug690056.xul \ + bug690056_window.xul \ $(NULL) _DOCSHELL_SUBHARNESS = \ docshell_helpers.js \ generic.html \ $(NULL) libs:: $(_HTTP_FILES)
new file mode 100644 --- /dev/null +++ b/docshell/test/chrome/bug690056_window.xul @@ -0,0 +1,176 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="chrome://global/skin" type="text/css"?> + +<window id="690056Test" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + width="600" + height="600" + onload="setTimeout(nextTest,0);" + title="bug 6500056 test"> + + <script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" /> + <script type="application/javascript" src="docshell_helpers.js" /> + <script type="application/javascript"><![CDATA[ + var tests = testIterator(); + + function nextTest() { + tests.next(); + } + + // Makes sure that we fire the visibilitychange events + function testIterator() { + // Enable bfcache + enableBFCache(8); + + // Load something for a start + doPageNavigation({ + uri: 'data:text/html,<title>initial load</title>', + onNavComplete: nextTest + }); + yield; + + // Now load a new page + doPageNavigation({ + uri: 'data:text/html,<title>new load</title>', + eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ], + expectedEvents: [ { type: "pagehide", + title: "initial load", + persisted: true }, + { type: "mozvisibilitychange", + title: "initial load", + visibilityState: "hidden", + hidden: true }, + // No visibilitychange events fired for initial pageload + { type: "pageshow", + title: "new load", + persisted: false }, // false on initial load + ], + onNavComplete: nextTest + }); + yield; + + // Now go back + doPageNavigation({ + back: true, + eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ], + expectedEvents: [ { type: "pagehide", + title: "new load", + persisted: true }, + { type: "mozvisibilitychange", + title: "new load", + visibilityState: "hidden", + hidden: true }, + { type: "mozvisibilitychange", + title: "initial load", + visibilityState: "visible", + hidden: false }, + { type: "pageshow", + title: "initial load", + persisted: true }, + ], + onNavComplete: nextTest + }); + yield; + + // And forward + doPageNavigation({ + forward: true, + eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ], + expectedEvents: [ { type: "pagehide", + title: "initial load", + persisted: true }, + { type: "mozvisibilitychange", + title: "initial load", + visibilityState: "hidden", + hidden: true }, + { type: "mozvisibilitychange", + title: "new load", + visibilityState: "visible", + hidden: false }, + { type: "pageshow", + title: "new load", + persisted: true }, + ], + onNavComplete: nextTest + }); + yield; + + function generateDetector(state, hidden, title, name) { + var detector = function (event) { + is(event.target.mozHidden, hidden, + name + " hidden value does not match"); + is(event.target.mozVisibilityState, state, + name + " state value does not match"); + is(event.target.title, title, + name + " title value does not match"); + document.getElementById("content") + .removeEventListener("mozvisibilitychange", + detector, + true); + nextTest(); + } + + document.getElementById("content") + .addEventListener("mozvisibilitychange", detector, true); + } + + generateDetector("hidden", true, "new load", "Going hidden"); + + // Now flip our docshell to not active + document.getElementById("content").docShellIsActive = false; + yield; + + // And navigate back; there should be no visibility state transitions + doPageNavigation({ + back: true, + eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ], + expectedEvents: [ { type: "pagehide", + title: "new load", + persisted: true }, + { type: "pageshow", + title: "initial load", + persisted: true }, + ], + unexpectedEvents: [ "mozvisibilitychange" ], + onNavComplete: nextTest + }); + yield; + + generateDetector("visible", false, "initial load", "Going visible"); + + // Now set the docshell active again + document.getElementById("content").docShellIsActive = true; + yield; + + // And forward + doPageNavigation({ + forward: true, + eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ], + expectedEvents: [ { type: "pagehide", + title: "initial load", + persisted: true }, + { type: "mozvisibilitychange", + title: "initial load", + visibilityState: "hidden", + hidden: true }, + { type: "mozvisibilitychange", + title: "new load", + visibilityState: "visible", + hidden: false }, + { type: "pageshow", + title: "new load", + persisted: true }, + ], + onNavComplete: nextTest + }); + yield; + + // Tell the framework the test is finished. Include the final 'yield' + // statement to prevent a StopIteration exception from being thrown. + finish(); + yield; + } + ]]></script> + + <browser type="content-primary" flex="1" id="content" src="about:blank"/> +</window> \ No newline at end of file
--- a/docshell/test/chrome/docshell_helpers.js +++ b/docshell/test/chrome/docshell_helpers.js @@ -13,16 +13,18 @@ for each (var name in imports) { const NAV_NONE = 0; const NAV_BACK = 1; const NAV_FORWARD = 2; const NAV_URI = 3; const NAV_RELOAD = 4; var gExpectedEvents; // an array of events which are expected to // be triggered by this navigation +var gUnexpectedEvents; // an array of event names which are NOT expected + // to be triggered by this navigation var gFinalEvent; // true if the last expected event has fired var gUrisNotInBFCache = []; // an array of uri's which shouldn't be stored // in the bfcache var gNavType = NAV_NONE; // defines the most recent navigation type // executed by doPageNavigation var gOrigMaxTotalViewers = // original value of max_total_viewers, undefined; // to be restored at end of test @@ -90,16 +92,18 @@ function doPageNavigation(params) { let back = params.back ? params.back : false; let forward = params.forward ? params.forward : false; let reload = params.reload ? params.reload : false; let uri = params.uri ? params.uri : false; let eventsToListenFor = typeof(params.eventsToListenFor) != "undefined" ? params.eventsToListenFor : ["pageshow"]; gExpectedEvents = typeof(params.eventsToListenFor) == "undefined" || eventsToListenFor.length == 0 ? undefined : params.expectedEvents; + gUnexpectedEvents = typeof(params.eventsToListenFor) == "undefined" || + eventsToListenFor.length == 0 ? undefined : params.unexpectedEvents; let preventBFCache = (typeof[params.preventBFCache] == "undefined") ? false : params.preventBFCache; let waitOnly = (typeof(params.waitForEventsOnly) == "boolean" && params.waitForEventsOnly); // Do some sanity checking on arguments. if (back && forward) throw "Can't specify both back and forward"; @@ -124,16 +128,20 @@ function doPageNavigation(params) { for each (let anEventType in eventsToListenFor) { let eventFound = false; if ( (anEventType == "pageshow") && (!gExpectedEvents) ) eventFound = true; for each (let anExpectedEvent in gExpectedEvents) { if (anExpectedEvent.type == anEventType) eventFound = true; } + for each (let anExpectedEventType in gUnexpectedEvents) { + if (anExpectedEventType == anEventType) + eventFound = true; + } if (!eventFound) throw "Event type " + anEventType + " is specified in " + "eventsToListenFor, but not in expectedEvents"; } // If the test explicitly sets .eventsToListenFor to [], don't wait for any // events. gFinalEvent = eventsToListenFor.length == 0 ? true : false; @@ -255,17 +263,22 @@ function pageEventListener(event) { if ( (event.type == "pageshow") && (gNavType == NAV_BACK || gNavType == NAV_FORWARD) ) { let uri = TestWindow.getBrowser().currentURI.spec; if (uri in gUrisNotInBFCache) { ok(!event.persisted, "pageshow event has .persisted = false, even " + "though it was loaded with .preventBFCache previously\n"); } } - + + if (typeof(gUnexpectedEvents) != "undefined") { + is(gUnexpectedEvents.indexOf(event.type), -1, + "Should not get unexpected event " + event.type); + } + // If no expected events were specified, mark the final event as having been // triggered when a pageshow event is fired; this will allow // doPageNavigation() to return. if ((typeof(gExpectedEvents) == "undefined") && event.type == "pageshow") { setTimeout(function() { gFinalEvent = true; }, 0); return; } @@ -296,16 +309,28 @@ function pageEventListener(event) { } if (typeof(expected.persisted) != "undefined") { is(event.persisted, expected.persisted, "The persisted property of the " + event.type + " event on page " + event.originalTarget.location + " had an unexpected value"); } + if ("visibilityState" in expected) { + is(event.originalTarget.mozVisibilityState, expected.visibilityState, + "The visibilityState property of the document on page " + + event.originalTarget.location + " had an unexpected value"); + } + + if ("hidden" in expected) { + is(event.originalTarget.mozHidden, expected.hidden, + "The hidden property of the document on page " + + event.originalTarget.location + " had an unexpected value"); + } + // If we're out of expected events, let doPageNavigation() return. if (gExpectedEvents.length == 0) setTimeout(function() { gFinalEvent = true; }, 0); } /** * End a test. */
new file mode 100644 --- /dev/null +++ b/docshell/test/chrome/test_bug690056.xul @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<?xml-stylesheet type="text/css" href="chrome://global/skin"?> +<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?> +<!-- +https://bugzilla.mozilla.org/show_bug.cgi?id=690056 +--> +<window title="Mozilla Bug 690056" + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> + <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> + + <!-- test results are displayed in the html:body --> + <body xmlns="http://www.w3.org/1999/xhtml"> + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=690056" + target="_blank">Mozilla Bug 690056</a> + </body> + + <!-- test code goes here --> + <script type="application/javascript"> + <![CDATA[ + /** Test for Bug 690056 **/ +SimpleTest.waitForExplicitFinish(); +window.open("bug690056_window.xul", "bug690056", + "chrome,width=600,height=600"); + ]]> + </script> +</window>
--- a/dom/base/ConsoleAPI.js +++ b/dom/base/ConsoleAPI.js @@ -202,17 +202,17 @@ ConsoleAPI.prototype = { let args = Array.prototype.slice.call(aArguments); let format = args.shift(); // Format specification regular expression. let pattern = /%(\d*).?(\d*)[a-zA-Z]/g; let processed = format.replace(pattern, function CA_PA_substitute(spec) { switch (spec[spec.length-1]) { case "o": case "s": - return args.shift().toString(); + return String(args.shift()); case "d": case "i": return parseInt(args.shift()); case "f": return parseFloat(args.shift()); default: return spec; };
--- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -92,31 +92,39 @@ public: virtual void ActivateOrDeactivate(bool aActivate) = 0; // this is called GetTopWindowRoot to avoid conflicts with nsIDOMWindow::GetWindowRoot virtual already_AddRefed<nsPIWindowRoot> GetTopWindowRoot() = 0; virtual void SetActive(bool aActive) { + NS_PRECONDITION(IsOuterWindow(), + "active state is only maintained on outer windows"); mIsActive = aActive; } bool IsActive() { + NS_PRECONDITION(IsOuterWindow(), + "active state is only maintained on outer windows"); return mIsActive; } virtual void SetIsBackground(bool aIsBackground) { + NS_PRECONDITION(IsOuterWindow(), + "background state is only maintained on outer windows"); mIsBackground = aIsBackground; } bool IsBackground() { + NS_PRECONDITION(IsOuterWindow(), + "background state is only maintained on outer windows"); return mIsBackground; } nsIDOMEventTarget* GetChromeEventHandler() const { return mChromeEventHandler; }
--- a/dom/interfaces/core/nsIDOMDocument.idl +++ b/dom/interfaces/core/nsIDOMDocument.idl @@ -61,17 +61,17 @@ interface nsIDOMLocation; * cannot exist outside the context of a Document, the nsIDOMDocument * interface also contains the factory methods needed to create these * objects. * * For more information on this interface please see * http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html */ -[scriptable, uuid(3f845f32-cb34-459c-8f79-2dfaa3088bbf)] +[scriptable, uuid(CD4CD7C3-C688-4E50-9A72-4A00EABE66AB)] interface nsIDOMDocument : nsIDOMNode { readonly attribute nsIDOMDocumentType doctype; readonly attribute nsIDOMDOMImplementation implementation; readonly attribute nsIDOMElement documentElement; nsIDOMElement createElement(in DOMString tagName) raises(DOMException); nsIDOMDocumentFragment createDocumentFragment(); @@ -406,9 +406,15 @@ interface nsIDOMDocument : nsIDOMNode /** * Inline event handler for readystatechange events. */ [implicit_jscontext] attribute jsval onreadystatechange; [implicit_jscontext] attribute jsval onmouseenter; [implicit_jscontext] attribute jsval onmouseleave; + + /** + * Visibility API implementation. + */ + readonly attribute boolean mozHidden; + readonly attribute DOMString mozVisibilityState; };
--- a/dom/interfaces/core/nsIDOMXMLDocument.idl +++ b/dom/interfaces/core/nsIDOMXMLDocument.idl @@ -33,17 +33,17 @@ * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsIDOMDocument.idl" -[scriptable, uuid(9f566fd8-8bd7-49eb-be8b-16fb50d00d32)] +[scriptable, uuid(BB4D4D76-3802-4191-88E2-933BA609C4E1)] interface nsIDOMXMLDocument : nsIDOMDocument { // DOM Level 3 Load & Save, DocumentLS // http://www.w3.org/TR/DOM-Level-3-LS/load-save.html#LS-DocumentLS /** * Whether to load synchronously or asynchronously. * The default is async==true. */
--- a/dom/interfaces/html/nsIDOMHTMLDocument.idl +++ b/dom/interfaces/html/nsIDOMHTMLDocument.idl @@ -42,17 +42,17 @@ /** * The nsIDOMHTMLDocument interface is the interface to a [X]HTML * document object. * * @see <http://www.whatwg.org/html/> */ interface nsISelection; -[scriptable, uuid(280857b8-c52c-455e-8b47-c56ad96614f7)] +[scriptable, uuid(C94A5F14-F79F-4054-A93C-E8FF35623460)] interface nsIDOMHTMLDocument : nsIDOMDocument { readonly attribute DOMString URL; attribute DOMString domain; attribute DOMString cookie; // returns "BackCompat" if we're in quirks mode, // or "CSS1Compat" if we're in strict mode readonly attribute DOMString compatMode;
--- a/dom/interfaces/svg/nsIDOMSVGDocument.idl +++ b/dom/interfaces/svg/nsIDOMSVGDocument.idl @@ -34,15 +34,15 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsIDOMDocument.idl" interface nsIDOMSVGSVGElement; -[scriptable, uuid(78ebe55f-631f-4b3b-9eba-c3689ff5ccbc)] +[scriptable, uuid(B3806DF6-7ED4-4426-84E6-545EEFE5AA9A)] interface nsIDOMSVGDocument : nsIDOMDocument { readonly attribute DOMString domain; readonly attribute DOMString URL; readonly attribute nsIDOMSVGSVGElement rootElement; };
--- a/dom/locales/en-US/chrome/appstrings.properties +++ b/dom/locales/en-US/chrome/appstrings.properties @@ -41,16 +41,17 @@ protocolNotFound=%S is not a registered connectionFailure=The connection was refused when attempting to contact %S. netInterrupt=The connection to %S has terminated unexpectedly. Some data may have been transferred. netTimeout=The operation timed out when attempting to contact %S. redirectLoop=Redirection limit for this URL exceeded. Unable to load the requested page. This may be caused by cookies that are blocked. confirmRepostPrompt=To display this page, the application must send information that will repeat any action (such as a search or order confirmation) that was performed earlier. resendButton.label=Resend unknownSocketType=This document cannot be displayed unless you install the Personal Security Manager (PSM). Download and install PSM and try again, or contact your system administrator. netReset=The document contains no data. +notCached=This document is no longer available. netOffline=This document cannot be displayed while offline. To go online, uncheck Work Offline from the File menu. isprinting=The document cannot change while Printing or in Print Preview. deniedPortAccess=Access to the port number given has been disabled for security reasons. proxyResolveFailure=The proxy server you have configured could not be found. Please check your proxy settings and try again. proxyConnectFailure=The connection was refused when attempting to contact the proxy server you have configured. Please check your proxy settings and try again. contentEncodingError=The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression. unsafeContentType=The page you are trying to view cannot be shown because it is contained in a file type that may not be safe to open. Please contact the website owners to inform them of this problem. externalProtocolTitle=External Protocol Request
--- a/dom/locales/en-US/chrome/netError.dtd +++ b/dom/locales/en-US/chrome/netError.dtd @@ -19,16 +19,19 @@ <!ENTITY generic.longDesc "<p>Additional information about this problem or error is currently unavailable.</p>"> <!ENTITY malformedURI.title "Invalid Address"> <!ENTITY malformedURI.longDesc "<p>The provided address is not in a recognized format. Please check the location bar for mistakes and try again.</p>"> <!ENTITY netInterrupt.title "Data Transfer Interrupted"> <!ENTITY netInterrupt.longDesc "<p>The browser connected successfully, but the connection was interrupted while transferring information. Please try again.</p><ul><li>Are you unable to browse other sites? Check the computer's network connection.</li><li>Still having trouble? Consult your network administrator or Internet provider for assistance.</li></ul>"> +<!ENTITY notCached.title "Document Expired"> +<!ENTITY notCached.longDesc "<p>The requested document is not available in the browser's cache.</p><ul><li>As a security precuation, the browser does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>"> + <!ENTITY netOffline.title "Offline Mode"> <!ENTITY netOffline.longDesc2 "<p>The browser is operating in its offline mode and cannot connect to the requested item.</p><ul><li>Is the computer connected to an active network?</li><li>Press "Try Again" to switch to online mode and reload the page.</li></ul>"> <!ENTITY contentEncodingError.title "Content Encoding Error"> <!ENTITY contentEncodingError.longDesc "<p>The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>"> <!ENTITY unsafeContentType.title "Unsafe File Type"> <!ENTITY unsafeContentType.longDesc "
--- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -155,19 +155,16 @@ NPObjWrapper_GetProperty(JSContext *cx, static JSBool NPObjWrapper_newEnumerate(JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp); static JSBool NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags, JSObject **objp); -static JSBool -NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp); - static void NPObjWrapper_Finalize(JSContext *cx, JSObject *obj); static JSBool NPObjWrapper_Call(JSContext *cx, uintN argc, jsval *vp); static JSBool NPObjWrapper_Construct(JSContext *cx, uintN argc, jsval *vp); @@ -178,17 +175,17 @@ CreateNPObjectMember(NPP npp, JSContext static JSClass sNPObjectJSWrapperClass = { NPRUNTIME_JSCLASS_NAME, JSCLASS_HAS_PRIVATE | JSCLASS_NEW_RESOLVE | JSCLASS_NEW_ENUMERATE, NPObjWrapper_AddProperty, NPObjWrapper_DelProperty, NPObjWrapper_GetProperty, NPObjWrapper_SetProperty, (JSEnumerateOp)NPObjWrapper_newEnumerate, - (JSResolveOp)NPObjWrapper_NewResolve, NPObjWrapper_Convert, + (JSResolveOp)NPObjWrapper_NewResolve, JS_ConvertStub, NPObjWrapper_Finalize, nsnull, nsnull, NPObjWrapper_Call, NPObjWrapper_Construct, nsnull, nsnull }; typedef struct NPObjectMemberPrivate { JSObject *npobjWrapper; jsval fieldValue; NPIdentifier methodName; @@ -1678,28 +1675,16 @@ NPObjWrapper_NewResolve(JSContext *cx, J return fnc != nsnull; } // no property or method return JS_TRUE; } -static JSBool -NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp) -{ - // The sole reason we implement this hook is to prevent the JS - // engine from calling valueOf() on NPObject's. Some NPObject's may - // actually implement a method named valueOf, but it's unlikely to - // behave as the JS engine expects it to. IOW, this is an empty hook - // that overrides what the default hook does. - - return JS_TRUE; -} - static void NPObjWrapper_Finalize(JSContext *cx, JSObject *obj) { NPObject *npobj = (NPObject *)::JS_GetPrivate(cx, obj); if (npobj) { if (sNPObjWrappers.ops) { PL_DHashTableOperate(&sNPObjWrappers, npobj, PL_DHASH_REMOVE); } @@ -2190,16 +2175,19 @@ NPObjectMember_Convert(JSContext *cx, JS switch (type) { case JSTYPE_VOID: case JSTYPE_STRING: case JSTYPE_NUMBER: case JSTYPE_BOOLEAN: case JSTYPE_OBJECT: *vp = memberPrivate->fieldValue; + if (!JSVAL_IS_PRIMITIVE(*vp)) { + return JS_ConvertStub(cx, JSVAL_TO_OBJECT(*vp), type, vp); + } return JS_TRUE; case JSTYPE_FUNCTION: // Leave this to NPObjectMember_Call. return JS_TRUE; default: NS_ERROR("illegal operation on JSObject prototype object"); return JS_FALSE; }
--- a/dom/plugins/test/mochitest/Makefile.in +++ b/dom/plugins/test/mochitest/Makefile.in @@ -41,16 +41,17 @@ srcdir = @srcdir@ VPATH = @srcdir@ relativesrcdir = dom/plugins/test include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _MOCHITEST_FILES = \ utils.js \ + test_defaultValue.html \ test_getauthenticationinfo.html \ test_npobject_getters.html \ test_npruntime_npnevaluate.html \ test_npruntime_npninvoke.html \ test_npruntime_npninvokedefault.html \ test_npruntime_identifiers.html \ npruntime_identifiers_subpage.html \ loremipsum.txt \
new file mode 100644 --- /dev/null +++ b/dom/plugins/test/mochitest/test_defaultValue.html @@ -0,0 +1,36 @@ +<html> + <head> + <title>NPObject [[DefaultValue]] implementation</title> + + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + </head> + + <body onload="run()"> + + <embed id="plugin" type="application/x-test" wmode="window"></embed> + + <script class="testbody" type="application/javascript"> + SimpleTest.waitForExplicitFinish(); + + function run() { + var plugin = document.getElementById("plugin"); + var pluginProto = Object.getPrototypeOf(plugin); + + plugin.propertyAndMethod = {}; + plugin.propertyAndMethod + "baz"; + ok(true, "|plugin.propertyAndMethod + \"baz\"| shouldn't assert"); + pluginProto.propertyAndMethod = {}; + pluginProto.propertyAndMethod + "quux"; + ok(true, "|pluginProto.propertyAndMethod + \"quux\"| shouldn't assert"); + + plugin + "foo"; + ok(true, "|plugin + \"foo\"| shouldn't assert"); + pluginProto + "bar"; + ok(true, "|pluginProto + \"bar\"| shouldn't assert"); + + SimpleTest.finish(); + } + </script> + </body> +</html>
--- a/dom/plugins/test/mochitest/test_npruntime_identifiers.html +++ b/dom/plugins/test/mochitest/test_npruntime_identifiers.html @@ -4,29 +4,25 @@ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> </head> <body> <p id="display"></p> - <iframe id="subframe" src="npruntime_identifiers_subpage.html"></iframe> - <script class="testbody" type="application/javascript"> //// // This test exercises NP identifiers by querying the reflector to make sure // that identifiers are translated to values correctly. SimpleTest.waitForExplicitFinish(); var testsRun = 0; - document.getElementById('subframe').addEventListener('load', doTest, false); - function doTest() { SpecialPowers.gc(); var reflector = document.getElementById("subframe").contentDocument.getElementById("plugin1").getReflector(); var i, prop, randomnumber; for (i = 0; i < 20; ++i) { @@ -51,10 +47,13 @@ if (testsRun == 3) { SimpleTest.finish(); } else { document.getElementById('subframe').contentWindow.location.reload(true); } } </script> + + <iframe id="subframe" src="npruntime_identifiers_subpage.html" onload="doTest()"></iframe> + </body> </html>
--- a/dom/tests/browser/browser_ConsoleAPITests.js +++ b/dom/tests/browser/browser_ConsoleAPITests.js @@ -215,16 +215,20 @@ function observeConsoleTest() { win.console.log("%d, %s, %l"); expect("log", "%a %b %c"); win.console.log("%a %b %c"); expect("log", "%a %b %c", "a", "b"); win.console.log("%a %b %c", "a", "b"); expect("log", "2, a, %l", 3); win.console.log("%d, %s, %l", 2, "a", 3); + // bug #692550 handle null and undefined + expect("log", "null, undefined"); + win.console.log("%s, %s", null, undefined); + expect("dir", win.toString()); win.console.dir(win); expect("error", "arg"); win.console.error("arg"); } function consoleAPISanityTest() {
--- a/dom/workers/ListenerManager.cpp +++ b/dom/workers/ListenerManager.cpp @@ -35,17 +35,17 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "ListenerManager.h" #include "jsapi.h" #include "jscntxt.h" -#include "jsvector.h" +#include "js/Vector.h" #include "Events.h" using mozilla::dom::workers::events::ListenerManager; namespace { struct Listener;
--- a/embedding/android/GeckoApp.java +++ b/embedding/android/GeckoApp.java @@ -74,16 +74,17 @@ abstract public class GeckoApp public static final String ACTION_ALERT_CLICK = "org.mozilla.gecko.ACTION_ALERT_CLICK"; public static final String ACTION_ALERT_CLEAR = "org.mozilla.gecko.ACTION_ALERT_CLEAR"; public static final String ACTION_WEBAPP = "org.mozilla.gecko.WEBAPP"; public static final String ACTION_DEBUG = "org.mozilla.gecko.DEBUG"; public static final String ACTION_BOOKMARK = "org.mozilla.gecko.BOOKMARK"; public static AbsoluteLayout mainLayout; public static GeckoSurfaceView surfaceView; + public static SurfaceView cameraView; public static GeckoApp mAppContext; public static boolean mFullscreen = false; public static File sGREDir = null; static Thread mLibLoadThread = null; public Handler mMainHandler; private IntentFilter mConnectivityFilter; private BroadcastReceiver mConnectivityReceiver; @@ -372,27 +373,36 @@ abstract public class GeckoApp if (sGREDir == null) sGREDir = new File(this.getApplicationInfo().dataDir); getWindow().setFlags(mFullscreen ? WindowManager.LayoutParams.FLAG_FULLSCREEN : 0, WindowManager.LayoutParams.FLAG_FULLSCREEN); + if (cameraView == null) { + cameraView = new SurfaceView(this); + cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); + } + if (surfaceView == null) surfaceView = new GeckoSurfaceView(this); else mainLayout.removeAllViews(); mainLayout = new AbsoluteLayout(this); mainLayout.addView(surfaceView, new AbsoluteLayout.LayoutParams(AbsoluteLayout.LayoutParams.MATCH_PARENT, // level 8 AbsoluteLayout.LayoutParams.MATCH_PARENT, 0, 0)); + + // Some phones (eg. nexus S) need at least a 8x16 preview size + mainLayout.addView(cameraView, new AbsoluteLayout.LayoutParams(8, 16, 0, 0)); + setContentView(mainLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); mConnectivityFilter = new IntentFilter(); mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); mConnectivityReceiver = new GeckoConnectivityReceiver();
--- a/embedding/android/GeckoAppShell.java +++ b/embedding/android/GeckoAppShell.java @@ -1526,17 +1526,17 @@ public class GeckoAppShell } public static android.hardware.Camera sCamera = null; static native void cameraCallbackBridge(byte[] data); static int kPreferedFps = 25; static byte[] sCameraBuffer = null; - + static int[] initCamera(String aContentType, int aCamera, int aWidth, int aHeight) { Log.i("GeckoAppJava", "initCamera(" + aContentType + ", " + aWidth + "x" + aHeight + ") on thread " + Thread.currentThread().getId()); // [0] = 0|1 (failure/success) // [1] = width // [2] = height // [3] = fps int[] result = new int[4]; @@ -1580,16 +1580,24 @@ public class GeckoAppShell android.hardware.Camera.Size size = sit.next(); if (Math.abs(size.width * size.height - aWidth * aHeight) < sizeDelta) { sizeDelta = Math.abs(size.width * size.height - aWidth * aHeight); params.setPreviewSize(size.width, size.height); bufferSize = size.width * size.height; } } + try { + sCamera.setPreviewDisplay(GeckoApp.cameraView.getHolder()); + } catch(IOException e) { + Log.e("GeckoAppJava", "Error setPreviewDisplay:", e); + } catch(RuntimeException e) { + Log.e("GeckoAppJava", "Error setPreviewDisplay:", e); + } + sCamera.setParameters(params); sCameraBuffer = new byte[(bufferSize * 12) / 8]; sCamera.addCallbackBuffer(sCameraBuffer); sCamera.setPreviewCallbackWithBuffer(new android.hardware.Camera.PreviewCallback() { public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { cameraCallbackBridge(data); if (sCamera != null) sCamera.addCallbackBuffer(sCameraBuffer);
--- a/embedding/components/windowwatcher/src/Makefile.in +++ b/embedding/components/windowwatcher/src/Makefile.in @@ -41,26 +41,26 @@ srcdir = @srcdir@ VPATH = @srcdir@ include $(DEPTH)/config/autoconf.mk MODULE = embedcomponents LIBRARY_NAME = windowwatcher_s LIBXUL_LIBRARY = 1 - CPPSRCS = \ - nsWWJSUtils.cpp \ nsWindowWatcher.cpp \ nsAutoWindowStateHelper.cpp \ $(NULL) ifdef MOZ_XUL CPPSRCS += nsDialogParamBlock.cpp \ $(NULL) endif # we don't want the shared lib, but we want to force the creation of a # static lib. FORCE_STATIC_LIB = 1 +# For nsJSUtils +LOCAL_INCLUDES += -I$(topsrcdir)/dom/base + include $(topsrcdir)/config/rules.mk -
deleted file mode 100644 --- a/embedding/components/windowwatcher/src/nsWWJSUtils.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2001 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* This file is a small subset of nsJSUtils utility functions, - from the dom directory. -*/ - -#include "nsCOMPtr.h" -#include "nsIScriptContext.h" -#include "nsIScriptGlobalObject.h" -#include "nsWWJSUtils.h" -#include "nsIXPConnect.h" -#include "nsDOMJSUtils.h" - -nsIScriptGlobalObject * -nsWWJSUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj) -{ - nsISupports* supports; - JSClass* clazz; - JSObject* parent; - JSObject* glob = aObj; // starting point for search - - if (!glob) - return nsnull; - - while (nsnull != (parent = JS_GetParent(aContext, glob))) - glob = parent; - - clazz = JS_GET_CLASS(aContext, glob); - - if (!clazz || - !(clazz->flags & JSCLASS_HAS_PRIVATE) || - !(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) || - !(supports = (nsISupports*) JS_GetPrivate(aContext, glob))) { - return nsnull; - } - - nsCOMPtr<nsIXPConnectWrappedNative> wrapper(do_QueryInterface(supports)); - NS_ENSURE_TRUE(wrapper, nsnull); - - nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper)); - - // This will return a pointer to something we're about to release, - // but that's ok here. - return sgo; -} - -nsIScriptContext * -nsWWJSUtils::GetDynamicScriptContext(JSContext *aContext) -{ - return GetScriptContextFromJSContext(aContext); -} - -nsIScriptGlobalObject * -nsWWJSUtils::GetDynamicScriptGlobal(JSContext* aContext) -{ - nsIScriptContext *scriptCX = GetDynamicScriptContext(aContext); - if (!scriptCX) - return nsnull; - return scriptCX->GetGlobalObject(); -} - -nsIScriptContext * -nsWWJSUtils::GetStaticScriptContext(JSContext* aContext, - JSObject* aObj) -{ - nsIScriptGlobalObject *nativeGlobal = GetStaticScriptGlobal(aContext, aObj); - if (!nativeGlobal) - return nsnull; - return nativeGlobal->GetContext(); -} -
deleted file mode 100644 --- a/embedding/components/windowwatcher/src/nsWWJSUtils.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2001 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef nsWWJSUtils_h__ -#define nsWWJSUtils_h__ - -/** - * Utility functions copied from nsJSUtils in dom/src/base. - */ - -#include "nsISupports.h" -#include "jsapi.h" - -class nsIScriptContext; -class nsIScriptGlobalObject; - -class nsWWJSUtils { -public: - static nsIScriptGlobalObject *GetStaticScriptGlobal(JSContext* aContext, - JSObject* aObj); - - static nsIScriptContext *GetStaticScriptContext(JSContext* aContext, - JSObject* aObj); - - static nsIScriptGlobalObject *GetDynamicScriptGlobal(JSContext *aContext); - - static nsIScriptContext *GetDynamicScriptContext(JSContext *aContext); -}; - -#endif /* nsWWJSUtils_h__ */
--- a/embedding/components/windowwatcher/src/nsWindowWatcher.cpp +++ b/embedding/components/windowwatcher/src/nsWindowWatcher.cpp @@ -39,17 +39,17 @@ //#define USEWEAKREFS // (haven't quite figured that out yet) #include "nsWindowWatcher.h" #include "nsAutoWindowStateHelper.h" #include "nsCRT.h" #include "nsNetUtil.h" -#include "nsWWJSUtils.h" +#include "nsJSUtils.h" #include "plstr.h" #include "nsIBaseWindow.h" #include "nsIDocShell.h" #include "nsIDocShellLoadInfo.h" #include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeOwner.h" #include "nsIDocumentLoader.h" @@ -311,17 +311,17 @@ nsresult JSContextAutoPopper::Push(JSCon // Get the safe context if we're not provided one. if (!cx && NS_FAILED(mService->GetSafeJSContext(&cx))) { cx = nsnull; } // Save cx in mContext to indicate need to pop. if (cx && NS_SUCCEEDED(mService->Push(cx))) { mContext = cx; - mContextKungFuDeathGrip = nsWWJSUtils::GetDynamicScriptContext(cx); + mContextKungFuDeathGrip = nsJSUtils::GetDynamicScriptContext(cx); } } return mContext ? NS_OK : NS_ERROR_FAILURE; } /**************************************************************** *********************** nsWindowWatcher ************************ ****************************************************************/ @@ -920,17 +920,17 @@ nsWindowWatcher::OpenWindowJSInternal(ns // get the calling context off the JS context stack nsCOMPtr<nsIJSContextStack> stack = do_GetService(sJSStackContractID); JSContext* ccx = nsnull; // get its document, if any if (stack && NS_SUCCEEDED(stack->Peek(&ccx)) && ccx) { - nsIScriptGlobalObject *sgo = nsWWJSUtils::GetDynamicScriptGlobal(ccx); + nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(ccx); nsCOMPtr<nsPIDOMWindow> w(do_QueryInterface(sgo)); if (w) { /* use the URL from the *extant* document, if any. The usual accessor GetDocument will synchronously create an about:blank document if it has no better answer, and we only care about a real document. Also using GetDocument to force document creation seems to screw up focus in the hidden window; see bug 36016. @@ -1369,17 +1369,17 @@ nsWindowWatcher::URIfromURL(const char * { nsCOMPtr<nsIDOMWindow> baseWindow; /* build the URI relative to the calling JS Context, if any. (note this is the same context used to make the security check in nsGlobalWindow.cpp.) */ JSContext *cx = GetJSContextFromCallStack(); if (cx) { - nsIScriptContext *scriptcx = nsWWJSUtils::GetDynamicScriptContext(cx); + nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx); if (scriptcx) { baseWindow = do_QueryInterface(scriptcx->GetGlobalObject()); } } // failing that, build it relative to the parent window, if possible if (!baseWindow) baseWindow = aParent; @@ -1712,17 +1712,17 @@ nsWindowWatcher::GetCallerTreeItem(nsIDo if (stack) { stack->Peek(&cx); } nsIDocShellTreeItem* callerItem = nsnull; if (cx) { nsCOMPtr<nsIWebNavigation> callerWebNav = - do_GetInterface(nsWWJSUtils::GetDynamicScriptGlobal(cx)); + do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx)); if (callerWebNav) { CallQueryInterface(callerWebNav, &callerItem); } } if (!callerItem) { NS_IF_ADDREF(callerItem = aParentItem);
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp +++ b/gfx/layers/opengl/ThebesLayerOGL.cpp @@ -142,18 +142,16 @@ ThebesLayerBufferOGL::RenderTo(const nsI } PRInt32 passes = mTexImageOnWhite ? 2 : 1; for (PRInt32 pass = 1; pass <= passes; ++pass) { LayerProgram *program; if (passes == 2) { ComponentAlphaTextureLayerProgram *alphaProgram; - NS_ASSERTION(!mTexImage->IsRGB() && !mTexImageOnWhite->IsRGB(), - "Only BGR image surported with component alpha (currently!)"); if (pass == 1) { alphaProgram = aManager->GetComponentAlphaPass1LayerProgram(); gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR, LOCAL_GL_ONE, LOCAL_GL_ONE); } else { alphaProgram = aManager->GetComponentAlphaPass2LayerProgram(); gl()->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ONE, LOCAL_GL_ONE, LOCAL_GL_ONE);
--- a/gfx/thebes/GLContext.cpp +++ b/gfx/thebes/GLContext.cpp @@ -770,17 +770,16 @@ TiledTextureImage::DirectUpdate(gfxASurf if (tileRegion.IsEmpty()) continue; tileRegion.MoveBy(-xPos, -yPos); // translate into tile local space result &= mImages[i]->DirectUpdate(aSurf, tileRegion, aFrom + nsIntPoint(xPos, yPos)); } mShaderType = mImages[0]->GetShaderProgramType(); - mIsRGBFormat = mImages[0]->IsRGB(); mTextureState = Valid; return result; } void TiledTextureImage::GetUpdateRegion(nsIntRegion& aForRegion) { if (mTextureState != Valid) { @@ -883,17 +882,16 @@ void TiledTextureImage::EndUpdate() { NS_ASSERTION(mInUpdate, "EndUpdate not in update"); if (!mUpdateSurface) { // update was to a single TextureImage mImages[mCurrentImage]->EndUpdate(); mInUpdate = PR_FALSE; mTextureState = Valid; mShaderType = mImages[mCurrentImage]->GetShaderProgramType(); - mIsRGBFormat = mImages[mCurrentImage]->IsRGB(); return; } // upload tiles from temp surface for (unsigned i = 0; i < mImages.Length(); i++) { int xPos = (i % mColumns) * mTileSize; int yPos = (i / mColumns) * mTileSize; nsIntRect imageRect = nsIntRect(nsIntPoint(xPos,yPos), mImages[i]->GetSize()); @@ -911,17 +909,16 @@ TiledTextureImage::EndUpdate() ctx->SetSource(mUpdateSurface, gfxPoint(-xPos, -yPos)); ctx->Paint(); mImages[i]->EndUpdate(); } mUpdateSurface = nsnull; mInUpdate = PR_FALSE; mShaderType = mImages[0]->GetShaderProgramType(); - mIsRGBFormat = mImages[0]->IsRGB(); mTextureState = Valid; } void TiledTextureImage::BeginTileIteration() { mCurrentImage = 0; }
--- a/gfx/thebes/GLContext.h +++ b/gfx/thebes/GLContext.h @@ -316,18 +316,16 @@ public: virtual already_AddRefed<gfxASurface> GetBackingSurface() { return NULL; } const nsIntSize& GetSize() const { return mSize; } ContentType GetContentType() const { return mContentType; } virtual bool InUpdate() const = 0; GLenum GetWrapMode() const { return mWrapMode; } - bool IsRGB() const { return mIsRGBFormat; } - void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; } protected: friend class GLContext; /** * After the ctor, the TextureImage is invalid. Implementations * must allocate resources successfully before returning the new @@ -335,29 +333,27 @@ protected: * clients must not be given partially-constructed TextureImages. */ TextureImage(const nsIntSize& aSize, GLenum aWrapMode, ContentType aContentType, bool aIsRGB = false) : mSize(aSize) , mWrapMode(aWrapMode) , mContentType(aContentType) - , mIsRGBFormat(aIsRGB) {} /** * Applies this TextureImage's filter, assuming that its texture is * the currently bound texture. */ virtual void ApplyFilter() = 0; nsIntSize mSize; GLenum mWrapMode; ContentType mContentType; - bool mIsRGBFormat; ShaderProgramType mShaderType; gfxPattern::GraphicsFilter mFilter; }; /** * BasicTextureImage is the baseline TextureImage implementation --- * it updates its texture by allocating a scratch buffer for the * client to draw into, then using glTexSubImage2D() to upload the new
--- a/gfx/thebes/GLContextProviderEGL.cpp +++ b/gfx/thebes/GLContextProviderEGL.cpp @@ -1202,17 +1202,17 @@ public: } Resize(aSize); } else { // Convert RGB24 to either ARGB32 on mobile. We can't // generate GL_RGB data, so we'll always have an alpha byte // for RGB24. No easy way to upload that to GL. // // Note that if we start using RGB565 here, we'll need to - // watch for a) setting mIsRGBFormat to TRUE; and b) getting + // watch for a) setting the correct format; and b) getting // the stride right. if (mUpdateFormat == gfxASurface::ImageFormatRGB24) { mUpdateFormat = gfxASurface::ImageFormatARGB32; } // We currently always use BGRA type textures mShaderType = BGRALayerProgramType; } } @@ -1270,19 +1270,16 @@ public: mUpdateSurface = GetLockSurface(); } else { mUpdateSurface = mBackingSurface; } return mUpdateSurface; } - // if we get this far, then we're using Cairo's byte order - mIsRGBFormat = PR_FALSE; - //printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat); mUpdateSurface = new gfxImageSurface(gfxIntSize(mUpdateRect.width, mUpdateRect.height), mUpdateFormat); mUpdateSurface->SetDeviceOffset(gfxPoint(-mUpdateRect.x, -mUpdateRect.y)); @@ -1641,17 +1638,16 @@ public: if (!BindTexImage()) { printf_stderr("ProviderEGL Failed to bind teximage: ERROR (0x%04x)\n", sEGLLibrary.fGetError()); return PR_FALSE; } } mBackingSurface = xsurface; - mIsRGBFormat = PR_TRUE; #endif return mBackingSurface != nsnull; } protected: typedef gfxASurface::gfxImageFormat ImageFormat;
--- a/gfx/thebes/gfx3DMatrix.cpp +++ b/gfx/thebes/gfx3DMatrix.cpp @@ -796,20 +796,31 @@ gfxRect gfx3DMatrix::ProjectRectBounds(c max_y = max(points[i].y, max_y); } return gfxRect(min_x, min_y, max_x - min_x, max_y - min_y); } gfxPoint3D gfx3DMatrix::GetNormalVector() const { - // Define a plane in transformed space as the transformations - // of 3 points on the z=0 screen plane. - gfxPoint3D a = Transform3D(gfxPoint3D(0, 0, 0)); - gfxPoint3D b = Transform3D(gfxPoint3D(0, 1, 0)); - gfxPoint3D c = Transform3D(gfxPoint3D(1, 0, 0)); + // Define a plane in transformed space as the transformations + // of 3 points on the z=0 screen plane. + gfxPoint3D a = Transform3D(gfxPoint3D(0, 0, 0)); + gfxPoint3D b = Transform3D(gfxPoint3D(0, 1, 0)); + gfxPoint3D c = Transform3D(gfxPoint3D(1, 0, 0)); + + // Convert to two vectors on the surface of the plane. + gfxPoint3D ab = b - a; + gfxPoint3D ac = c - a; - // Convert to two vectors on the surface of the plane. - gfxPoint3D ab = b - a; - gfxPoint3D ac = c - a; + return ac.CrossProduct(ab); +} - return ac.CrossProduct(ab); +bool gfx3DMatrix::IsBackfaceVisible() const +{ + // Inverse()._33 < 0; + gfxFloat det = Determinant(); + float _33 = _12*_24*_41 - _14*_22*_41 + + _14*_21*_42 - _11*_24*_42 - + _12*_21*_44 + _11*_22*_44; + return (_33 * det) < 0; } +
--- a/gfx/thebes/gfx3DMatrix.h +++ b/gfx/thebes/gfx3DMatrix.h @@ -302,16 +302,22 @@ public: /** * Returns a unit vector that is perpendicular to the plane formed * by transform the screen plane (z=0) by this matrix. */ gfxPoint3D GetNormalVector() const; /** + * Returns true if a plane transformed by this matrix will + * have it's back face visible. + */ + bool IsBackfaceVisible() const; + + /** * Check if matrix is singular (no inverse exists). */ bool IsSingular() const; /** * Create a translation matrix. * * \param aX Translation on X-axis.
--- a/ipc/glue/WindowsMessageLoop.cpp +++ b/ipc/glue/WindowsMessageLoop.cpp @@ -96,16 +96,20 @@ using namespace mozilla::ipc::windows; * modal UI related api calls block an RPC in-call in the child. To prevent * windows from freezing, and to allow concurrent processing of critical * events (such as painting), we spin a native event dispatch loop while * these in-calls are blocked. */ // pulled from widget's nsAppShell extern const PRUnichar* kAppShellEventId; +#if defined(ACCESSIBILITY) +// pulled from accessibility's win utils +extern const PRUnichar* kPropNameTabContent; +#endif namespace { const wchar_t kOldWndProcProp[] = L"MozillaIPCOldWndProc"; // This isn't defined before Windows XP. enum { WM_XP_THEMECHANGED = 0x031A }; @@ -374,16 +378,24 @@ WindowIsDeferredWindow(HWND hWnd) PRUnichar buffer[256] = { 0 }; int length = GetClassNameW(hWnd, (wchar_t*)buffer, sizeof(buffer) - 1); if (length <= 0) { NS_WARNING("Failed to get class name!"); return false; } +#if defined(ACCESSIBILITY) + // Tab content creates a window that responds to accessible WM_GETOBJECT + // calls. This window can safely be ignored. + if (::GetPropW(hWnd, kPropNameTabContent)) { + return false; + } +#endif + // Common mozilla windows we must defer messages to. nsDependentString className(buffer, length); if (StringBeginsWith(className, NS_LITERAL_STRING("Mozilla")) || StringBeginsWith(className, NS_LITERAL_STRING("Gecko")) || className.EqualsLiteral("nsToolkitClass") || className.EqualsLiteral("nsAppShell:EventWindowClass")) { return true; }
--- a/js/jetpack/JetpackActorCommon.cpp +++ b/js/jetpack/JetpackActorCommon.cpp @@ -32,20 +32,20 @@ * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "base/basictypes.h" -#include "jscntxt.h" #include "jsapi.h" -#include "jshashtable.h" +#include "jscntxt.h" +#include "js/HashTable.h" #include "mozilla/jetpack/JetpackActorCommon.h" #include "mozilla/jetpack/PJetpack.h" #include "mozilla/jetpack/PHandleParent.h" #include "mozilla/jetpack/PHandleChild.h" #include "mozilla/jetpack/Handle.h" #include "nsJSUtils.h"
rename from js/src/jshashtable.h rename to js/public/HashTable.h --- a/js/src/jshashtable.h +++ b/js/public/HashTable.h @@ -38,19 +38,18 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef jshashtable_h_ #define jshashtable_h_ -#include "jsalloc.h" -#include "jstl.h" -#include "jsutil.h" +#include "TemplateLib.h" +#include "Utility.h" namespace js { /* Integral types for all hash functions. */ typedef uint32 HashNumber; /*****************************************************************************/
new file mode 100644 --- /dev/null +++ b/js/public/TemplateLib.h @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Luke Wagner <luke@mozilla.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef js_template_lib_h__ +#define js_template_lib_h__ + +#include "mozilla/Types.h" +#include "jsstdint.h" + +/* + * Library of reusable template meta-functions (that is, functions on types and + * compile-time values). Meta-functions are placed inside the 'tl' namespace to + * avoid conflict with non-meta functions that logically have the same name + * (e.g., js::tl::Min vs. js::Min). + */ + +namespace js { +namespace tl { + +/* Compute min/max/clamp. */ +template <size_t i, size_t j> struct Min { + static const size_t result = i < j ? i : j; +}; +template <size_t i, size_t j> struct Max { + static const size_t result = i > j ? i : j; +}; +template <size_t i, size_t min, size_t max> struct Clamp { + static const size_t result = i < min ? min : (i > max ? max : i); +}; + +/* Compute x^y. */ +template <size_t x, size_t y> struct Pow { + static const size_t result = x * Pow<x, y - 1>::result; +}; +template <size_t x> struct Pow<x,0> { + static const size_t result = 1; +}; + +/* Compute floor(log2(i)). */ +template <size_t i> struct FloorLog2 { + static const size_t result = 1 + FloorLog2<i / 2>::result; +}; +template <> struct FloorLog2<0> { /* Error */ }; +template <> struct FloorLog2<1> { static const size_t result = 0; }; + +/* Compute ceiling(log2(i)). */ +template <size_t i> struct CeilingLog2 { + static const size_t result = FloorLog2<2 * i - 1>::result; +}; + +/* Round up to the nearest power of 2. */ +template <size_t i> struct RoundUpPow2 { + static const size_t result = 1u << CeilingLog2<i>::result; +}; +template <> struct RoundUpPow2<0> { + static const size_t result = 1; +}; + +/* Compute the number of bits in the given unsigned type. */ +template <class T> struct BitSize { + static const size_t result = sizeof(T) * JS_BITS_PER_BYTE; +}; + +/* Allow Assertions by only including the 'result' typedef if 'true'. */ +template <bool> struct StaticAssert {}; +template <> struct StaticAssert<true> { typedef int result; }; + +/* Boolean test for whether two types are the same. */ +template <class T, class U> struct IsSameType { + static const bool result = false; +}; +template <class T> struct IsSameType<T,T> { + static const bool result = true; +}; + +/* + * Produce an N-bit mask, where N <= BitSize<size_t>::result. Handle the + * language-undefined edge case when N = BitSize<size_t>::result. + */ +template <size_t N> struct NBitMask { + typedef typename StaticAssert<N < BitSize<size_t>::result>::result _; + static const size_t result = (size_t(1) << N) - 1; +}; +template <> struct NBitMask<BitSize<size_t>::result> { + static const size_t result = size_t(-1); +}; + +/* + * For the unsigned integral type size_t, compute a mask M for N such that + * for all X, !(X & M) implies X * N will not overflow (w.r.t size_t) + */ +template <size_t N> struct MulOverflowMask { + static const size_t result = + ~NBitMask<BitSize<size_t>::result - CeilingLog2<N>::result>::result; +}; +template <> struct MulOverflowMask<0> { /* Error */ }; +template <> struct MulOverflowMask<1> { static const size_t result = 0; }; + +/* + * Generate a mask for T such that if (X & sUnsafeRangeSizeMask), an X-sized + * array of T's is big enough to cause a ptrdiff_t overflow when subtracting + * a pointer to the end of the array from the beginning. + */ +template <class T> struct UnsafeRangeSizeMask { + /* + * The '2' factor means the top bit is clear, sizeof(T) converts from + * units of elements to bytes. + */ + static const size_t result = MulOverflowMask<2 * sizeof(T)>::result; +}; + +/* Return T stripped of any const-ness. */ +template <class T> struct StripConst { typedef T result; }; +template <class T> struct StripConst<const T> { typedef T result; }; + +/* + * Traits class for identifying POD types. Until C++0x, there is no automatic + * way to detect PODs, so for the moment it is done manually. + */ +template <class T> struct IsPodType { static const bool result = false; }; +template <> struct IsPodType<char> { static const bool result = true; }; +template <> struct IsPodType<signed char> { static const bool result = true; }; +template <> struct IsPodType<unsigned char> { static const bool result = true; }; +template <> struct IsPodType<short> { static const bool result = true; }; +template <> struct IsPodType<unsigned short> { static const bool result = true; }; +template <> struct IsPodType<int> { static const bool result = true; }; +template <> struct IsPodType<unsigned int> { static const bool result = true; }; +template <> struct IsPodType<long> { static const bool result = true; }; +template <> struct IsPodType<unsigned long> { static const bool result = true; }; +template <> struct IsPodType<long long> { static const bool result = true; }; +template <> struct IsPodType<unsigned long long> { static const bool result = true; }; +template <> struct IsPodType<float> { static const bool result = true; }; +template <> struct IsPodType<double> { static const bool result = true; }; +template <> struct IsPodType<wchar_t> { static const bool result = true; }; +template <typename T> struct IsPodType<T *> { static const bool result = true; }; + +/* Return the size/end of an array without using macros. */ +template <class T, size_t N> inline T *ArraySize(T (&)[N]) { return N; } +template <class T, size_t N> inline T *ArrayEnd(T (&arr)[N]) { return arr + N; } + +template <bool cond, typename T, T v1, T v2> struct If { static const T result = v1; }; +template <typename T, T v1, T v2> struct If<false, T, v1, v2> { static const T result = v2; }; + +} /* namespace tl */ +} /* namespace js */ + +#endif /* js_template_lib_h__ */
new file mode 100644 --- /dev/null +++ b/js/public/Utility.h @@ -0,0 +1,945 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=99 ft=cpp: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SpiderMonkey JavaScript code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef js_utility_h__ +#define js_utility_h__ + +#include <stdlib.h> +#include <string.h> + +#include "mozilla/Util.h" + +#ifdef __cplusplus + +/* The public JS engine namespace. */ +namespace JS {} + +/* The mozilla-shared reusable template/utility namespace. */ +namespace mozilla {} + +/* The private JS engine namespace. */ +namespace js { + +/* The private namespace is a superset of the public/shared namespaces. */ +using namespace JS; +using namespace mozilla; + +} /* namespace js */ +#endif /* __cplusplus */ + +JS_BEGIN_EXTERN_C + +/* + * Pattern used to overwrite freed memory. If you are accessing an object with + * this pattern, you probably have a dangling pointer. + */ +#define JS_FREE_PATTERN 0xDA + +/* JS_ASSERT */ +#ifdef DEBUG +# define JS_ASSERT(expr) \ + ((expr) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__)) +# define JS_ASSERT_IF(cond, expr) \ + ((!(cond) || (expr)) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__)) +# define JS_NOT_REACHED(reason) \ + JS_Assert(reason, __FILE__, __LINE__) +# define JS_ALWAYS_TRUE(expr) JS_ASSERT(expr) +# define JS_ALWAYS_FALSE(expr) JS_ASSERT(!(expr)) +# ifdef JS_THREADSAFE +# define JS_THREADSAFE_ASSERT(expr) JS_ASSERT(expr) +# else +# define JS_THREADSAFE_ASSERT(expr) ((void) 0) +# endif +#else +# define JS_ASSERT(expr) ((void) 0) +# define JS_ASSERT_IF(cond,expr) ((void) 0) +# define JS_NOT_REACHED(reason) +# define JS_ALWAYS_TRUE(expr) ((void) (expr)) +# define JS_ALWAYS_FALSE(expr) ((void) (expr)) +# define JS_THREADSAFE_ASSERT(expr) ((void) 0) +#endif + +/* + * JS_STATIC_ASSERT + * + * A compile-time assert. "cond" must be a constant expression. The macro can + * be used only in places where an "extern" declaration is allowed. + */ +#ifdef __SUNPRO_CC +/* + * Sun Studio C++ compiler has a bug + * "sizeof expression not accepted as size of array parameter" + * It happens when js_static_assert() function is declared inside functions. + * The bug number is 6688515. It is not public yet. + * Therefore, for Sun Studio, declare js_static_assert as an array instead. + */ +# define JS_STATIC_ASSERT(cond) extern char js_static_assert[(cond) ? 1 : -1] +#else +# ifdef __COUNTER__ +# define JS_STATIC_ASSERT_GLUE1(x,y) x##y +# define JS_STATIC_ASSERT_GLUE(x,y) JS_STATIC_ASSERT_GLUE1(x,y) +# define JS_STATIC_ASSERT(cond) \ + typedef int JS_STATIC_ASSERT_GLUE(js_static_assert, __COUNTER__)[(cond) ? 1 : -1] +# else +# define JS_STATIC_ASSERT(cond) extern void js_static_assert(int arg[(cond) ? 1 : -1]) +# endif +#endif + +#define JS_STATIC_ASSERT_IF(cond, expr) JS_STATIC_ASSERT(!(cond) || (expr)) + +/* + * Abort the process in a non-graceful manner. This will cause a core file, + * call to the debugger or other moral equivalent as well as causing the + * entire process to stop. + */ +extern JS_PUBLIC_API(void) JS_Abort(void); + +/* + * Custom allocator support for SpiderMonkey + */ +#if defined JS_USE_CUSTOM_ALLOCATOR +# include "jscustomallocator.h" +#else +# ifdef DEBUG +/* + * In order to test OOM conditions, when the shell command-line option + * |-A NUM| is passed, we fail continuously after the NUM'th allocation. + */ +extern JS_PUBLIC_DATA(JSUint32) OOM_maxAllocations; /* set from shell/js.cpp */ +extern JS_PUBLIC_DATA(JSUint32) OOM_counter; /* data race, who cares. */ +# define JS_OOM_POSSIBLY_FAIL() \ + do \ + { \ + if (OOM_counter++ >= OOM_maxAllocations) { \ + return NULL; \ + } \ + } while (0) + +# else +# define JS_OOM_POSSIBLY_FAIL() do {} while(0) +# endif + +/* + * SpiderMonkey code should not be calling these allocation functions directly. + * Instead, all calls should go through JSRuntime, JSContext or OffTheBooks. + * However, js_free() can be called directly. + */ +static JS_INLINE void* js_malloc(size_t bytes) +{ + JS_OOM_POSSIBLY_FAIL(); + return malloc(bytes); +} + +static JS_INLINE void* js_calloc(size_t bytes) +{ + JS_OOM_POSSIBLY_FAIL(); + return calloc(bytes, 1); +} + +static JS_INLINE void* js_realloc(void* p, size_t bytes) +{ + JS_OOM_POSSIBLY_FAIL(); + return realloc(p, bytes); +} + +static JS_INLINE void js_free(void* p) +{ + free(p); +} +#endif/* JS_USE_CUSTOM_ALLOCATOR */ + +/* + * Replace bit-scanning code sequences with CPU-specific instructions to + * speedup calculations of ceiling/floor log2. + * + * With GCC 3.4 or later we can use __builtin_clz for that, see bug 327129. + * + * SWS: Added MSVC intrinsic bitscan support. See bugs 349364 and 356856. + */ +#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) + +unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask); +unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask); +# pragma intrinsic(_BitScanForward,_BitScanReverse) + +__forceinline static int +__BitScanForward32(unsigned int val) +{ + unsigned long idx; + + _BitScanForward(&idx, (unsigned long)val); + return (int)idx; +} +__forceinline static int +__BitScanReverse32(unsigned int val) +{ + unsigned long idx; + + _BitScanReverse(&idx, (unsigned long)val); + return (int)(31-idx); +} +# define js_bitscan_ctz32(val) __BitScanForward32(val) +# define js_bitscan_clz32(val) __BitScanReverse32(val) +# define JS_HAS_BUILTIN_BITSCAN32 + +#if defined(_M_AMD64) || defined(_M_X64) +unsigned char _BitScanForward64(unsigned long * Index, unsigned __int64 Mask); +unsigned char _BitScanReverse64(unsigned long * Index, unsigned __int64 Mask); +# pragma intrinsic(_BitScanForward64,_BitScanReverse64) + +__forceinline static int +__BitScanForward64(unsigned __int64 val) +{ + unsigned long idx; + + _BitScanForward64(&idx, val); + return (int)idx; +} +__forceinline static int +__BitScanReverse64(unsigned __int64 val) +{ + unsigned long idx; + + _BitScanReverse64(&idx, val); + return (int)(63-idx); +} +# define js_bitscan_ctz64(val) __BitScanForward64(val) +# define js_bitscan_clz64(val) __BitScanReverse64(val) +# define JS_HAS_BUILTIN_BITSCAN64 +#endif +#elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + +# define js_bitscan_ctz32(val) __builtin_ctz(val) +# define js_bitscan_clz32(val) __builtin_clz(val) +# define JS_HAS_BUILTIN_BITSCAN32 +# if (JS_BYTES_PER_WORD == 8) +# define js_bitscan_ctz64(val) __builtin_ctzll(val) +# define js_bitscan_clz64(val) __builtin_clzll(val) +# define JS_HAS_BUILTIN_BITSCAN64 +# endif + +#endif + +/* +** Macro version of JS_CeilingLog2: Compute the log of the least power of +** 2 greater than or equal to _n. The result is returned in _log2. +*/ +#ifdef JS_HAS_BUILTIN_BITSCAN32 +/* + * Use intrinsic function or count-leading-zeros to calculate ceil(log2(_n)). + * The macro checks for "n <= 1" and not "n != 0" as js_bitscan_clz32(0) is + * undefined. + */ +# define JS_CEILING_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + unsigned int j_ = (unsigned int)(_n); \ + (_log2) = (j_ <= 1 ? 0 : 32 - js_bitscan_clz32(j_ - 1)); \ + JS_END_MACRO +#else +# define JS_CEILING_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + JSUint32 j_ = (JSUint32)(_n); \ + (_log2) = 0; \ + if ((j_) & ((j_)-1)) \ + (_log2) += 1; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + JS_END_MACRO +#endif + +/* +** Macro version of JS_FloorLog2: Compute the log of the greatest power of +** 2 less than or equal to _n. The result is returned in _log2. +** +** This is equivalent to finding the highest set bit in the word. +*/ +#ifdef JS_HAS_BUILTIN_BITSCAN32 +/* + * Use js_bitscan_clz32 or count-leading-zeros to calculate floor(log2(_n)). + * Since js_bitscan_clz32(0) is undefined, the macro set the loweset bit to 1 + * to ensure 0 result when _n == 0. + */ +# define JS_FLOOR_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + (_log2) = 31 - js_bitscan_clz32(((unsigned int)(_n)) | 1); \ + JS_END_MACRO +#else +# define JS_FLOOR_LOG2(_log2,_n) \ + JS_BEGIN_MACRO \ + JSUint32 j_ = (JSUint32)(_n); \ + (_log2) = 0; \ + if ((j_) >> 16) \ + (_log2) += 16, (j_) >>= 16; \ + if ((j_) >> 8) \ + (_log2) += 8, (j_) >>= 8; \ + if ((j_) >> 4) \ + (_log2) += 4, (j_) >>= 4; \ + if ((j_) >> 2) \ + (_log2) += 2, (j_) >>= 2; \ + if ((j_) >> 1) \ + (_log2) += 1; \ + JS_END_MACRO +#endif + +/* + * Internal function. + * Compute the log of the least power of 2 greater than or equal to n. This is + * a version of JS_CeilingLog2 that operates on unsigned integers with + * CPU-dependant size. + */ +#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1)) + +/* + * Internal function. + * Compute the log of the greatest power of 2 less than or equal to n. + * This is a version of JS_FloorLog2 that operates on unsigned integers with + * CPU-dependant size and requires that n != 0. + */ +#define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n)) + +#if JS_BYTES_PER_WORD == 4 +# ifdef JS_HAS_BUILTIN_BITSCAN32 +# define js_FloorLog2wImpl(n) \ + ((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n))) +# else +# define js_FloorLog2wImpl(n) ((size_t)JS_FloorLog2(n)) +# endif +#elif JS_BYTES_PER_WORD == 8 +# ifdef JS_HAS_BUILTIN_BITSCAN64 +# define js_FloorLog2wImpl(n) \ + ((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n))) +# else +extern size_t js_FloorLog2wImpl(size_t n); +# endif +#else +# error "NOT SUPPORTED" +#endif + +JS_END_EXTERN_C + +#ifdef __cplusplus +#include <new> + +/* + * User guide to memory management within SpiderMonkey: + * + * Quick tips: + * + * Allocation: + * - Prefer to allocate using JSContext: + * cx->{malloc_,realloc_,calloc_,new_,array_new} + * + * - If no JSContext is available, use a JSRuntime: + * rt->{malloc_,realloc_,calloc_,new_,array_new} + * + * - As a last resort, use unaccounted allocation ("OffTheBooks"): + * js::OffTheBooks::{malloc_,realloc_,calloc_,new_,array_new} + * + * Deallocation: + * - When the deallocation occurs on a slow path, use: + * Foreground::{free_,delete_,array_delete} + * + * - Otherwise deallocate on a background thread using a JSContext: + * cx->{free_,delete_,array_delete} + * + * - If no JSContext is available, use a JSRuntime: + * rt->{free_,delete_,array_delete} + * + * - As a last resort, use UnwantedForeground deallocation: + * js::UnwantedForeground::{free_,delete_,array_delete} + * + * General tips: + * + * - Mixing and matching these allocators is allowed (you may free memory + * allocated by any allocator, with any deallocator). + * + * - Never, ever use normal C/C++ memory management: + * malloc, free, new, new[], delete, operator new, etc. + * + * - Never, ever use low-level SpiderMonkey allocators: + * js_malloc(), js_free(), js_calloc(), js_realloc() + * Their use is reserved for the other memory managers. + * + * - Classes which have private constructors or destructors should have + * JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR added to their + * declaration. + * + * Details: + * + * Using vanilla new/new[] is unsafe in SpiderMonkey because they throw on + * failure instead of returning NULL, which is what SpiderMonkey expects. + * (Even overriding them is unsafe, as the system's C++ runtime library may + * throw, which we do not support. We also can't just use the 'nothrow' + * variant of new/new[], because we want to mediate *all* allocations + * within SpiderMonkey, to satisfy any embedders using + * JS_USE_CUSTOM_ALLOCATOR.) + * + * JSContexts and JSRuntimes keep track of memory allocated, and use this + * accounting to schedule GC. OffTheBooks does not. We'd like to remove + * OffTheBooks allocations as much as possible (bug 636558). + * + * On allocation failure, a JSContext correctly reports an error, which a + * JSRuntime and OffTheBooks does not. + * + * A JSContext deallocates in a background thread. A JSRuntime might + * deallocate in the background in the future, but does not now. Foreground + * deallocation is preferable on slow paths. UnwantedForeground deallocations + * occur where we have no JSContext or JSRuntime, and the deallocation is not + * on a slow path. We want to remove UnwantedForeground deallocations (bug + * 636561). + * + * JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR makes the allocation + * classes friends with your class, giving them access to private + * constructors and destructors. + * + * |make check| does a source level check on the number of uses OffTheBooks, + * UnwantedForeground, js_malloc, js_free etc, to prevent regressions. If you + * really must add one, update Makefile.in, and run |make check|. + * + * |make check| also statically prevents the use of vanilla new/new[]. + */ + +#define JS_NEW_BODY(allocator, t, parms) \ + void *memory = allocator(sizeof(t)); \ + return memory ? new(memory) t parms : NULL; + +/* + * Given a class which should provide new_() methods, add + * JS_DECLARE_NEW_METHODS (see JSContext for a usage example). This + * adds new_()s with up to 12 parameters. Add more versions of new_ below if + * you need more than 12 parameters. + * + * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS, + * or the build will break. + */ +#define JS_DECLARE_NEW_METHODS(ALLOCATOR, QUALIFIERS)\ + template <class T>\ + QUALIFIERS T *new_() {\ + JS_NEW_BODY(ALLOCATOR, T, ())\ + }\ +\ + template <class T, class P1>\ + QUALIFIERS T *new_(P1 p1) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1))\ + }\ +\ + template <class T, class P1, class P2>\ + QUALIFIERS T *new_(P1 p1, P2 p2) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2))\ + }\ +\ + template <class T, class P1, class P2, class P3>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3))\ + }\ +\ + template <class T, class P1, class P2, class P3, class P4>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4))\ + }\ +\ + template <class T, class P1, class P2, class P3, class P4, class P5>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5))\ + }\ +\ + template <class T, class P1, class P2, class P3, class P4, class P5, class P6>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6))\ + }\ +\ + template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7))\ + }\ +\ + template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8))\ + }\ +\ + template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9))\ + }\ +\ + template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))\ + }\ +\ + template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11))\ + }\ +\ + template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>\ + QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12) {\ + JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12))\ + }\ + static const int JSMinAlignment = 8;\ + template <class T>\ + QUALIFIERS T *array_new(size_t n) {\ + /* The length is stored just before the vector memory. */\ + uint64 numBytes64 = uint64(JSMinAlignment) + uint64(sizeof(T)) * uint64(n);\ + size_t numBytes = size_t(numBytes64);\ + if (numBytes64 != numBytes) {\ + JS_ASSERT(0); /* we want to know if this happens in debug builds */\ + return NULL;\ + }\ + void *memory = ALLOCATOR(numBytes);\ + if (!memory)\ + return NULL;\ + *(size_t *)memory = n;\ + memory = (void*)(uintptr_t(memory) + JSMinAlignment);\ + return new(memory) T[n];\ + }\ + + +#define JS_DECLARE_DELETE_METHODS(DEALLOCATOR, QUALIFIERS)\ + template <class T>\ + QUALIFIERS void delete_(T *p) {\ + if (p) {\ + p->~T();\ + DEALLOCATOR(p);\ + }\ + }\ +\ + template <class T>\ + QUALIFIERS void array_delete(T *p) {\ + if (p) {\ + void* p0 = (void *)(uintptr_t(p) - js::OffTheBooks::JSMinAlignment);\ + size_t n = *(size_t *)p0;\ + for (size_t i = 0; i < n; i++)\ + (p + i)->~T();\ + DEALLOCATOR(p0);\ + }\ + } + + +/* + * In general, all allocations should go through a JSContext or JSRuntime, so + * that the garbage collector knows how much memory has been allocated. In + * cases where it is difficult to use a JSContext or JSRuntime, OffTheBooks can + * be used, though this is undesirable. + */ +namespace js { + +class OffTheBooks { +public: + JS_DECLARE_NEW_METHODS(::js_malloc, JS_ALWAYS_INLINE static) + + static JS_INLINE void* malloc_(size_t bytes) { + return ::js_malloc(bytes); + } + + static JS_INLINE void* calloc_(size_t bytes) { + return ::js_calloc(bytes); + } + + static JS_INLINE void* realloc_(void* p, size_t bytes) { + return ::js_realloc(p, bytes); + } +}; + +/* + * We generally prefer deallocating using JSContext because it can happen in + * the background. On slow paths, we may prefer foreground allocation. + */ +class Foreground { +public: + /* See parentheses comment above. */ + static JS_ALWAYS_INLINE void free_(void* p) { + ::js_free(p); + } + + JS_DECLARE_DELETE_METHODS(::js_free, JS_ALWAYS_INLINE static) +}; + +class UnwantedForeground : public Foreground { +}; + +} /* namespace js */ + +/* + * Note lack of ; in JSRuntime below. This is intentional so "calling" this + * looks "normal". + */ +#define JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR \ + friend class js::OffTheBooks;\ + friend class js::Foreground;\ + friend class js::UnwantedForeground;\ + friend struct ::JSContext;\ + friend struct ::JSRuntime + +/* + * The following classes are designed to cause assertions to detect + * inadvertent use of guard objects as temporaries. In other words, + * when we have a guard object whose only purpose is its constructor and + * destructor (and is never otherwise referenced), the intended use + * might be: + * JSAutoTempValueRooter tvr(cx, 1, &val); + * but is is easy to accidentally write: + * JSAutoTempValueRooter(cx, 1, &val); + * which compiles just fine, but runs the destructor well before the + * intended time. + * + * They work by adding (#ifdef DEBUG) an additional parameter to the + * guard object's constructor, with a default value, so that users of + * the guard object's API do not need to do anything. The default value + * of this parameter is a temporary object. C++ (ISO/IEC 14882:1998), + * section 12.2 [class.temporary], clauses 4 and 5 seem to assume a + * guarantee that temporaries are destroyed in the reverse of their + * construction order, but I actually can't find a statement that that + * is true in the general case (beyond the two specific cases mentioned + * there). However, it seems to be true. + * + * These classes are intended to be used only via the macros immediately + * below them: + * JS_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member + * variable, and should be put where a declaration of a private + * member variable would be placed. + * JS_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the + * parameters to each constructor of the guard object; it declares + * (ifdef DEBUG) an additional parameter. + * JS_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each + * constructor. It uses the parameter declared by + * JS_GUARD_OBJECT_NOTIFIER_PARAM. + */ +#ifdef DEBUG +class JS_FRIEND_API(JSGuardObjectNotifier) +{ +private: + bool* mStatementDone; +public: + JSGuardObjectNotifier() : mStatementDone(NULL) {} + + ~JSGuardObjectNotifier() { + *mStatementDone = true; + } + + void setStatementDone(bool *aStatementDone) { + mStatementDone = aStatementDone; + } +}; + +class JS_FRIEND_API(JSGuardObjectNotificationReceiver) +{ +private: + bool mStatementDone; +public: + JSGuardObjectNotificationReceiver() : mStatementDone(false) {} + + ~JSGuardObjectNotificationReceiver() { + /* + * Assert that the guard object was not used as a temporary. + * (Note that this assert might also fire if Init is not called + * because the guard object's implementation is not using the + * above macros correctly.) + */ + JS_ASSERT(mStatementDone); + } + + void Init(const JSGuardObjectNotifier &aNotifier) { + /* + * aNotifier is passed as a const reference so that we can pass a + * temporary, but we really intend it as non-const + */ + const_cast<JSGuardObjectNotifier&>(aNotifier). + setStatementDone(&mStatementDone); + } +}; + +#define JS_DECL_USE_GUARD_OBJECT_NOTIFIER \ + JSGuardObjectNotificationReceiver _mCheckNotUsedAsTemporary; +#define JS_GUARD_OBJECT_NOTIFIER_PARAM \ + , const JSGuardObjectNotifier& _notifier = JSGuardObjectNotifier() +#define JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT \ + , const JSGuardObjectNotifier& _notifier +#define JS_GUARD_OBJECT_NOTIFIER_PARAM0 \ + const JSGuardObjectNotifier& _notifier = JSGuardObjectNotifier() +#define JS_GUARD_OBJECT_NOTIFIER_INIT \ + JS_BEGIN_MACRO _mCheckNotUsedAsTemporary.Init(_notifier); JS_END_MACRO + +#else /* defined(DEBUG) */ + +#define JS_DECL_USE_GUARD_OBJECT_NOTIFIER +#define JS_GUARD_OBJECT_NOTIFIER_PARAM +#define JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT +#define JS_GUARD_OBJECT_NOTIFIER_PARAM0 +#define JS_GUARD_OBJECT_NOTIFIER_INIT JS_BEGIN_MACRO JS_END_MACRO + +#endif /* !defined(DEBUG) */ + +namespace js { + +/* + * "Move" References + * + * Some types can be copied much more efficiently if we know the original's + * value need not be preserved --- that is, if we are doing a "move", not a + * "copy". For example, if we have: + * + * Vector<T> u; + * Vector<T> v(u); + * + * the constructor for v must apply a copy constructor to each element of u --- + * taking time linear in the length of u. However, if we know we will not need u + * any more once v has been initialized, then we could initialize v very + * efficiently simply by stealing u's dynamically allocated buffer and giving it + * to v --- a constant-time operation, regardless of the size of u. + * + * Moves often appear in container implementations. For example, when we append + * to a vector, we may need to resize its buffer. This entails moving each of + * its extant elements from the old, smaller buffer to the new, larger buffer. + * But once the elements have been migrated, we're just going to throw away the + * old buffer; we don't care if they still have their values. So if the vector's + * element type can implement "move" more efficiently than "copy", the vector + * resizing should by all means use a "move" operation. Hash tables also need to + * be resized. + * + * The details of the optimization, and whether it's worth applying, vary from + * one type to the next. And while some constructor calls are moves, many really + * are copies, and can't be optimized this way. So we need: + * + * 1) a way for a particular invocation of a copy constructor to say that it's + * really a move, and that the value of the original isn't important + * afterwards (althought it must still be safe to destroy); and + * + * 2) a way for a type (like Vector) to announce that it can be moved more + * efficiently than it can be copied, and provide an implementation of that + * move operation. + * + * The Move(T &) function takes a reference to a T, and returns an MoveRef<T> + * referring to the same value; that's 1). An MoveRef<T> is simply a reference + * to a T, annotated to say that a copy constructor applied to it may move that + * T, instead of copying it. Finally, a constructor that accepts an MoveRef<T> + * should perform a more efficient move, instead of a copy, providing 2). + * + * So, where we might define a copy constructor for a class C like this: + * + * C(const C &rhs) { ... copy rhs to this ... } + * + * we would declare a move constructor like this: + * + * C(MoveRef<C> rhs) { ... move rhs to this ... } + * + * And where we might perform a copy like this: + * + * C c2(c1); + * + * we would perform a move like this: + * + * C c2(Move(c1)) + * + * Note that MoveRef<T> implicitly converts to T &, so you can pass an + * MoveRef<T> to an ordinary copy constructor for a type that doesn't support a + * special move constructor, and you'll just get a copy. This means that + * templates can use Move whenever they know they won't use the original value + * any more, even if they're not sure whether the type at hand has a specialized + * move constructor. If it doesn't, the MoveRef<T> will just convert to a T &, + * and the ordinary copy constructor will apply. + * + * A class with a move constructor can also provide a move assignment operator, + * which runs this's destructor, and then applies the move constructor to + * *this's memory. A typical definition: + * + * C &operator=(MoveRef<C> rhs) { + * this->~C(); + * new(this) C(rhs); + * return *this; + * } + * + * With that in place, one can write move assignments like this: + * + * c2 = Move(c1); + * + * This destroys c1, moves c1's value to c2, and leaves c1 in an undefined but + * destructible state. + * + * This header file defines MoveRef and Move in the js namespace. It's up to + * individual containers to annotate moves as such, by calling Move; and it's up + * to individual types to define move constructors. + * + * One hint: if you're writing a move constructor where the type has members + * that should be moved themselves, it's much nicer to write this: + * + * C(MoveRef<C> c) : x(c->x), y(c->y) { } + * + * than the equivalent: + * + * C(MoveRef<C> c) { new(&x) X(c->x); new(&y) Y(c->y); } + * + * especially since GNU C++ fails to notice that this does indeed initialize x + * and y, which may matter if they're const. + */ +template<typename T> +class MoveRef { + public: + typedef T Referent; + explicit MoveRef(T &t) : pointer(&t) { } + T &operator*() const { return *pointer; } + T *operator->() const { return pointer; } +#ifdef __GXX_EXPERIMENTAL_CXX0X__ + /* + * If MoveRef is used in a rvalue position (which is expected), we can + * end up in a situation where, without this ifdef, we would try to pass + * a T& to a move constructor, which fails. It is not clear if the compiler + * should instead use the copy constructor, but for now this lets us build + * with clang. See bug 689066 and llvm.org/pr11003 for the details. + * Note: We can probably remove MoveRef completely once we are comfortable + * using c++11. + */ + operator T&& () const { return static_cast<T&&>(*pointer); } +#else + operator T& () const { return *pointer; } +#endif + private: + T *pointer; +}; + +template<typename T> +MoveRef<T> Move(T &t) { return MoveRef<T>(t); } + +template<typename T> +MoveRef<T> Move(const T &t) { return MoveRef<T>(const_cast<T &>(t)); } + +/* Useful for implementing containers that assert non-reentrancy */ +class ReentrancyGuard +{ + /* ReentrancyGuard is not copyable. */ + ReentrancyGuard(const ReentrancyGuard &); + void operator=(const ReentrancyGuard &); + +#ifdef DEBUG + bool &entered; +#endif + public: + template <class T> +#ifdef DEBUG + ReentrancyGuard(T &obj) + : entered(obj.entered) +#else + ReentrancyGuard(T &/*obj*/) +#endif + { +#ifdef DEBUG + JS_ASSERT(!entered); + entered = true; +#endif + } + ~ReentrancyGuard() + { +#ifdef DEBUG + entered = false; +#endif + } +}; + +/* + * Round x up to the nearest power of 2. This function assumes that the most + * significant bit of x is not set, which would lead to overflow. + */ +JS_ALWAYS_INLINE size_t +RoundUpPow2(size_t x) +{ + return size_t(1) << JS_CEILING_LOG2W(x); +} + +} /* namespace js */ + +#endif /* defined(__cplusplus) */ + +/* + * This signature is for malloc_usable_size-like functions used to measure + * memory usage. A return value of zero indicates that the size is unknown, + * and so a fall-back computation should be done for the size. + */ +typedef size_t(*JSUsableSizeFun)(void *p); + +/* sixgill annotation defines */ +#ifndef HAVE_STATIC_ANNOTATIONS +# define HAVE_STATIC_ANNOTATIONS +# ifdef XGILL_PLUGIN +# define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) +# define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND))) +# define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) +# define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND))) +# define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) +# define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) +# define STATIC_PASTE2(X,Y) X ## Y +# define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y) +# define STATIC_ASSERT(COND) \ + JS_BEGIN_MACRO \ + __attribute__((assert_static(#COND), unused)) \ + int STATIC_PASTE1(assert_static_, __COUNTER__); \ + JS_END_MACRO +# define STATIC_ASSUME(COND) \ + JS_BEGIN_MACRO \ + __attribute__((assume_static(#COND), unused)) \ + int STATIC_PASTE1(assume_static_, __COUNTER__); \ + JS_END_MACRO +# define STATIC_ASSERT_RUNTIME(COND) \ + JS_BEGIN_MACRO \ + __attribute__((assert_static_runtime(#COND), unused)) \ + int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \ + JS_END_MACRO +# else /* XGILL_PLUGIN */ +# define STATIC_PRECONDITION(COND) /* nothing */ +# define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ +# define STATIC_POSTCONDITION(COND) /* nothing */ +# define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ +# define STATIC_INVARIANT(COND) /* nothing */ +# define STATIC_INVARIANT_ASSUME(COND) /* nothing */ +# define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO +# define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO +# define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO +# endif /* XGILL_PLUGIN */ +# define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) +#endif /* HAVE_STATIC_ANNOTATIONS */ + +#endif /* js_utility_h__ */
rename from js/src/jsvector.h rename to js/public/Vector.h --- a/js/src/jsvector.h +++ b/js/public/Vector.h @@ -36,29 +36,30 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef jsvector_h_ #define jsvector_h_ -#include "jsalloc.h" -#include "jstl.h" -#include "jsprvtd.h" -#include "jsutil.h" +#include "TemplateLib.h" +#include "Utility.h" /* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */ #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4345) #endif namespace js { +template <class T, size_t N, class AllocPolicy> +class Vector; + /* * This template class provides a default implementation for vector operations * when the element type is not known to be a POD, as judged by IsPodType. */ template <class T, size_t N, class AP, bool IsPod> struct VectorImpl { /* Destroys constructed objects in the range [begin, end). */
--- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -90,17 +90,24 @@ endif # JS shell would like to link to the static library. ifdef JS_SHARED_LIBRARY FORCE_SHARED_LIB = 1 endif FORCE_STATIC_LIB = 1 DIST_INSTALL = 1 -VPATH = $(srcdir) +VPATH = \ + $(srcdir) \ + $(srcdir)/builtin \ + $(srcdir)/ds \ + $(srcdir)/frontend \ + $(srcdir)/gc \ + $(srcdir)/vm \ + $(NULL) CPPSRCS = \ jsalloc.cpp \ jsanalyze.cpp \ jsapi.cpp \ jsarray.cpp \ jsatom.cpp \ jsbool.cpp \ @@ -158,31 +165,31 @@ CPPSRCS = \ GlobalObject.cpp \ Stack.cpp \ String.cpp \ ParseMaps.cpp \ LifoAlloc.cpp \ RegExpObject.cpp \ RegExpStatics.cpp \ RegExp.cpp \ + Statistics.cpp \ Unicode.cpp \ $(NULL) # Changes to internal header files, used externally, massively slow down # browser builds. Don't add new files here unless you know what you're # doing! INSTALLED_HEADERS = \ js-config.h \ jsautocfg.h \ $(CURDIR)/jsautokw.h \ js.msg \ jsalloc.h \ jsapi.h \ jsatom.h \ - jsbit.h \ jsclass.h \ jsclist.h \ jsclone.h \ jscntxt.h \ jscompat.h \ jscrashreport.h \ jsdate.h \ jsdbgapi.h \ @@ -197,76 +204,91 @@ INSTALLED_HEADERS = \ jsinttypes.h \ jslock.h \ json.h \ jsopcode.tbl \ jsopcode.h \ jsotypes.h \ jsproxy.h \ jsprf.h \ - jsprobes.h \ jspropertycache.h \ jspropertytree.h \ jsproto.tbl \ jsprvtd.h \ jspubtd.h \ jsreflect.h \ jsscan.h \ jsstaticcheck.h \ jsstdint.h \ jsstr.h \ jstracer.h \ jstypedarray.h \ jstypes.h \ jsutil.h \ - jsvector.h \ - jstl.h \ - jshashtable.h \ jsversion.h \ jswrapper.h \ jsxdrapi.h \ jsval.h \ prmjtime.h \ $(NULL) ###################################################### -# BEGIN include sources for the engine subdirectories +# BEGIN exported headers that are only exported +# because of inclusion by an INSTALLED_HEADER # -VPATH += \ - $(srcdir)/builtin \ - $(srcdir)/ds \ - $(srcdir)/frontend \ - $(srcdir)/vm \ - $(NULL) - -EXPORTS_NAMESPACES = vm ds +EXPORTS_NAMESPACES += vm ds gc EXPORTS_vm = \ String.h \ StackSpace.h \ Unicode.h \ $(NULL) EXPORTS_ds = \ - LifoAlloc.h + LifoAlloc.h \ + $(NULL) + +EXPORTS_gc = \ + Statistics.h \ + $(NULL) + +###################################################### +# BEGIN include exported headers from the JS engine +# +# Ultimately, after cleansing INSTALLED_HEADERS, +# these will be the ONLY headers exported by +# the js engine +# +VPATH += \ + $(srcdir)/../public \ + $(NULL) + +EXPORTS_NAMESPACES += js + +EXPORTS_js = \ + HashTable.h \ + TemplateLib.h \ + Utility.h \ + Vector.h \ + $(NULL) ############################################### # BEGIN include sources for low-level code shared with Gecko # VPATH += \ $(srcdir)/../../mfbt \ $(NULL) EXPORTS_NAMESPACES += mozilla EXPORTS_mozilla = \ RangedPtr.h \ - RefPtr.h \ - Types.h \ - Util.h \ + RefPtr.h \ + Types.h \ + Util.h \ $(NULL) ifdef ENABLE_TRACEJIT VPATH += \ $(srcdir)/tracejit \ $(srcdir)/nanojit \ INSTALLED_HEADERS += \
--- a/js/src/assembler/assembler/X86Assembler.h +++ b/js/src/assembler/assembler/X86Assembler.h @@ -32,17 +32,17 @@ #include "assembler/wtf/Platform.h" #if ENABLE_ASSEMBLER && (WTF_CPU_X86 || WTF_CPU_X86_64) #include "AssemblerBuffer.h" #include "jsstdint.h" #include "assembler/wtf/Assertions.h" -#include "jsvector.h" +#include "js/Vector.h" #include "methodjit/Logging.h" #define IPFX " %s" #define ISPFX " " #ifdef JS_METHODJIT_SPEW # define MAYBE_PAD (isOOLPath ? "> " : "") # define PRETTY_PRINT_OFFSET(os) (((os)<0)?"-":""), (((os)<0)?-(os):(os)) # define FIXME_INSN_PRINTING \
--- a/js/src/assembler/jit/ExecutableAllocator.h +++ b/js/src/assembler/jit/ExecutableAllocator.h @@ -23,23 +23,24 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ExecutableAllocator_h #define ExecutableAllocator_h #include <stddef.h> // for ptrdiff_t #include <limits> -#include "assembler/wtf/Assertions.h" +#include "jsalloc.h" #include "jsapi.h" -#include "jshashtable.h" #include "jsprvtd.h" -#include "jsvector.h" -#include "jslock.h" + +#include "assembler/wtf/Assertions.h" +#include "js/HashTable.h" +#include "js/Vector.h" #if WTF_CPU_SPARC #ifdef linux // bugzilla 502369 static void sync_instruction_memory(caddr_t v, u_int len) { caddr_t end = v + len; caddr_t p = v; while (p < end) { @@ -160,20 +161,22 @@ private: size_t available() const { JS_ASSERT(m_end >= m_freePtr); return m_end - m_freePtr; } }; class ExecutableAllocator { + typedef void (*DestroyCallback)(void* addr, size_t size); enum ProtectionSetting { Writable, Executable }; + DestroyCallback destroyCallback; public: - ExecutableAllocator() + ExecutableAllocator() : destroyCallback(NULL) { if (!pageSize) { pageSize = determinePageSize(); /* * On Windows, VirtualAlloc effectively allocates in 64K chunks. * (Technically, it allocates in page chunks, but the starting * address is always a multiple of 64K, so each allocation uses up * 64K of address space.) So a size less than that would be @@ -216,22 +219,28 @@ public: // (found, or created if necessary) a pool that had enough space. void *result = (*poolp)->alloc(n, type); JS_ASSERT(result); return result; } void releasePoolPages(ExecutablePool *pool) { JS_ASSERT(pool->m_allocation.pages); + if (destroyCallback) + destroyCallback(pool->m_allocation.pages, pool->m_allocation.size); systemRelease(pool->m_allocation); m_pools.remove(m_pools.lookup(pool)); // this asserts if |pool| is not in m_pools } void getCodeStats(size_t& method, size_t& regexp, size_t& unused) const; + void setDestroyCallback(DestroyCallback destroyCallback) { + this->destroyCallback = destroyCallback; + } + private: static size_t pageSize; static size_t largeAllocSize; static const size_t OVERSIZE_ALLOCATION = size_t(-1); static size_t roundUpAllocationSize(size_t request, size_t granularity) {
--- a/js/src/assembler/wtf/SegmentedVector.h +++ b/js/src/assembler/wtf/SegmentedVector.h @@ -25,17 +25,17 @@ * (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 SegmentedVector_h #define SegmentedVector_h #include "jsprvtd.h" -#include "jsvector.h" +#include "js/Vector.h" namespace WTF { // An iterator for SegmentedVector. It supports only the pre ++ operator template <typename T, size_t SegmentSize> class SegmentedVector; template <typename T, size_t SegmentSize> class SegmentedVectorIterator { private: friend class SegmentedVector<T, SegmentSize>;
--- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -34,17 +34,16 @@ * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "jsinfer.h" -#include "jstl.h" #include "builtin/RegExp.h" #include "vm/RegExpObject-inl.h" #include "vm/RegExpStatics-inl.h" using namespace js; using namespace js::types;
--- a/js/src/configure.in +++ b/js/src/configure.in @@ -4416,38 +4416,16 @@ MOZ_ARG_ENABLE_BOOL(tracevis, if test -n "$MOZ_TRACEVIS"; then AC_DEFINE(MOZ_TRACEVIS) if test -z "$ENABLE_TRACEJIT"; then AC_MSG_ERROR([--enable-tracevis is incompatible with --disable-tracejit]) fi fi dnl ======================================================== -dnl = Use GCTimer -dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(gctimer, -[ --enable-gctimer Enable GC timer (default=no)], - MOZ_GCTIMER=1, - MOZ_GCTIMER= ) -if test -n "$MOZ_GCTIMER"; then - AC_DEFINE(MOZ_GCTIMER) -fi - -dnl ======================================================== -dnl = Don't enable GC-TestPilot plumbing -dnl ======================================================== -JSGC_TESTPILOT=1 -MOZ_ARG_DISABLE_BOOL(gctestpilot, -[ --disable-gctestpilot Disable GC TestPilot study hooks], - JSGC_TESTPILOT= ) -if test -n "$JSGC_TESTPILOT"; then - AC_DEFINE(JSGC_TESTPILOT) -fi - -dnl ======================================================== dnl = Use Valgrind dnl ======================================================== MOZ_ARG_ENABLE_BOOL(valgrind, [ --enable-valgrind Enable Valgrind integration hooks (default=no)], MOZ_VALGRIND=1, MOZ_VALGRIND= ) if test -n "$MOZ_VALGRIND"; then AC_CHECK_HEADER([valgrind/valgrind.h], [], @@ -4654,16 +4632,33 @@ AC_SUBST(MOZ_DEMANGLE_SYMBOLS) dnl ======================================================== dnl = Support for gcc stack unwinding (from gcc 3.3) dnl ======================================================== if test -z "$SKIP_LIBRARY_CHECKS"; then AC_CHECK_HEADER(unwind.h, AC_CHECK_FUNCS(_Unwind_Backtrace)) fi dnl ======================================================== +dnl JIT observers +dnl ======================================================== + +MOZ_ARG_WITH_STRING(jitreport-granularity, +[ --jitreport-granularity=N + Default granularity at which to report JIT code + to external tools + 0 - no info + 1 - code ranges for whole functions only + 2 - per-line information + 3 - per-op information], + JITREPORT_GRANULARITY=$withval, + JITREPORT_GRANULARITY=3) + +AC_DEFINE_UNQUOTED(JS_DEFAULT_JITREPORT_GRANULARITY, $JITREPORT_GRANULARITY) + +dnl ======================================================== dnl = dnl = Misc. Options dnl = dnl ======================================================== MOZ_ARG_HEADER(Misc. Options) dnl ======================================================== dnl update xterm title
--- a/js/src/ctypes/CTypes.h +++ b/js/src/ctypes/CTypes.h @@ -36,20 +36,21 @@ * * ***** END LICENSE BLOCK ***** */ #ifndef CTYPES_H #define CTYPES_H #include "jscntxt.h" #include "jsapi.h" -#include "jshashtable.h" #include "prlink.h" #include "ffi.h" +#include "js/HashTable.h" + namespace js { namespace ctypes { /******************************************************************************* ** Utility classes *******************************************************************************/ template<class T>
rename from js/src/mfbt/InlineMap.h rename to js/src/ds/InlineMap.h --- a/js/src/mfbt/InlineMap.h +++ b/js/src/ds/InlineMap.h @@ -36,17 +36,17 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef InlineMap_h__ #define InlineMap_h__ -#include "jshashtable.h" +#include "js/HashTable.h" namespace js { /* * A type can only be used as an InlineMap key if zero is an invalid key value * (and thus may be used as a tombstone value by InlineMap). */ template <typename T> struct ZeroIsReserved { static const bool result = false; };
--- a/js/src/ds/LifoAlloc.cpp +++ b/js/src/ds/LifoAlloc.cpp @@ -60,24 +60,49 @@ BumpChunk::new_(size_t chunkSize) * We assume that the alignment of sAlign is less than that of * the underlying memory allocator -- creating a new BumpChunk should * always satisfy the sAlign alignment constraint. */ JS_ASSERT(AlignPtr(result->bump) == result->bump); return result; } +void +BumpChunk::delete_(BumpChunk *chunk) +{ +#ifdef DEBUG + memset(chunk, 0xcd, sizeof(*chunk) + chunk->bumpSpaceSize); +#endif + js_free(chunk); +} + +bool +BumpChunk::canAlloc(size_t n) +{ + char *aligned = AlignPtr(bump); + char *bumped = aligned + n; + return bumped <= limit && bumped > headerBase(); +} + +bool +BumpChunk::canAllocUnaligned(size_t n) +{ + char *bumped = bump + n; + return bumped <= limit && bumped > headerBase(); +} + void * BumpChunk::tryAllocUnaligned(size_t n) { char *oldBump = bump; char *newBump = bump + n; if (newBump > limit) return NULL; + JS_ASSERT(canAllocUnaligned(n)); setBump(newBump); return oldBump; } } /* namespace detail */ } /* namespace js */ void @@ -131,19 +156,30 @@ LifoAlloc::getOrCreateChunk(size_t n) latest = latest->next(); latest->resetBump(); /* This was an unused BumpChunk on the chain. */ if (latest->canAlloc(n)) return latest; } } size_t defaultChunkFreeSpace = defaultChunkSize_ - sizeof(BumpChunk); - size_t chunkSize = n > defaultChunkFreeSpace - ? RoundUpPow2(n + sizeof(BumpChunk)) - : defaultChunkSize_; + size_t chunkSize; + if (n > defaultChunkFreeSpace) { + size_t allocSizeWithHeader = n + sizeof(BumpChunk); + + /* Guard for overflow. */ + if (allocSizeWithHeader < n || + (allocSizeWithHeader & (size_t(1) << (tl::BitSize<size_t>::result - 1)))) { + return NULL; + } + + chunkSize = RoundUpPow2(allocSizeWithHeader); + } else { + chunkSize = defaultChunkSize_; + } /* If we get here, we couldn't find an existing BumpChunk to fill the request. */ BumpChunk *newChunk = BumpChunk::new_(chunkSize); if (!newChunk) return NULL; if (!first) { latest = first = newChunk; } else {
--- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -44,17 +44,18 @@ /* * This data structure supports stacky LIFO allocation (mark/release and * LifoAllocScope). It does not maintain one contiguous segment; instead, it * maintains a bunch of linked memory segments. In order to prevent malloc/free * thrashing, unused segments are deallocated when garbage collection occurs. */ #include "jsutil.h" -#include "jstl.h" + +#include "js/TemplateLib.h" namespace js { namespace detail { static const size_t LIFO_ALLOC_ALIGN = 8; JS_ALWAYS_INLINE @@ -73,17 +74,18 @@ AlignPtr(void *orig) /* Header for a chunk of memory wrangled by the LifoAlloc. */ class BumpChunk { char *bump; char *limit; BumpChunk *next_; size_t bumpSpaceSize; - char *base() const { return limit - bumpSpaceSize; } + char *headerBase() { return reinterpret_cast<char *>(this); } + char *bumpBase() const { return limit - bumpSpaceSize; } BumpChunk *thisDuringConstruction() { return this; } explicit BumpChunk(size_t bumpSpaceSize) : bump(reinterpret_cast<char *>(thisDuringConstruction()) + sizeof(BumpChunk)), limit(bump + bumpSpaceSize), next_(NULL), bumpSpaceSize(bumpSpaceSize) { @@ -92,82 +94,77 @@ class BumpChunk void clobberUnused() { #ifdef DEBUG memset(bump, 0xcd, limit - bump); #endif } void setBump(void *ptr) { - JS_ASSERT(base() <= ptr); + JS_ASSERT(bumpBase() <= ptr); JS_ASSERT(ptr <= limit); DebugOnly<char *> prevBump = bump; bump = static_cast<char *>(ptr); if (prevBump < bump) clobberUnused(); } public: BumpChunk *next() const { return next_; } void setNext(BumpChunk *succ) { next_ = succ; } - size_t used() const { return bump - base(); } + size_t used() const { return bump - bumpBase(); } void resetBump() { - setBump(reinterpret_cast<char *>(this) + sizeof(BumpChunk)); + setBump(headerBase() + sizeof(BumpChunk)); } void *mark() const { return bump; } void release(void *mark) { JS_ASSERT(contains(mark)); JS_ASSERT(mark <= bump); setBump(mark); } bool contains(void *mark) const { - return base() <= mark && mark <= limit; + return bumpBase() <= mark && mark <= limit; } - bool canAlloc(size_t n) { - return AlignPtr(bump) + n <= limit; - } - - bool canAllocUnaligned(size_t n) { - return bump + n <= limit; - } + bool canAlloc(size_t n); + bool canAllocUnaligned(size_t n); /* Try to perform an allocation of size |n|, return null if not possible. */ JS_ALWAYS_INLINE void *tryAlloc(size_t n) { char *aligned = AlignPtr(bump); char *newBump = aligned + n; + if (newBump > limit) return NULL; + /* Check for overflow. */ + if (JS_UNLIKELY(newBump < bump)) + return NULL; + + JS_ASSERT(canAlloc(n)); /* Ensure consistency between "can" and "try". */ setBump(newBump); return aligned; } void *tryAllocUnaligned(size_t n); void *allocInfallible(size_t n) { void *result = tryAlloc(n); JS_ASSERT(result); return result; } static BumpChunk *new_(size_t chunkSize); - - static void delete_(BumpChunk *chunk) { -#ifdef DEBUG - memset(chunk, 0xcd, sizeof(*chunk) + chunk->bumpSpaceSize); -#endif - js_free(chunk); - } + static void delete_(BumpChunk *chunk); }; } /* namespace detail */ /* * LIFO bump allocator: used for phase-oriented and fast LIFO allocations. * * Note: |latest| is not necessary "last". We leave BumpChunks latent in the
--- a/js/src/frontend/ParseMaps.h +++ b/js/src/frontend/ParseMaps.h @@ -36,19 +36,18 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef ParseMaps_h__ #define ParseMaps_h__ -#include "jsvector.h" - -#include "mfbt/InlineMap.h" +#include "ds/InlineMap.h" +#include "js/HashTable.h" namespace js { /* * A pool that permits the reuse of the backing storage for the defn, index, or * defn-or-header (multi) maps. * * The pool owns all the maps that are given out, and is responsible for
new file mode 100644 --- /dev/null +++ b/js/src/gc/Statistics.cpp @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey JavaScript engine. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <stdio.h> + +#include "jscntxt.h" +#include "jsprobes.h" +#include "jsutil.h" +#include "jscrashformat.h" +#include "jscrashreport.h" +#include "prmjtime.h" + +#include "gc/Statistics.h" + +namespace js { +namespace gcstats { + +Statistics::Statistics(JSRuntime *rt) + : runtime(rt) +{ + char *env = getenv("MOZ_GCTIMER"); + if (!env || strcmp(env, "none") == 0) { + fp = NULL; + return; + } + + if (strcmp(env, "stdout") == 0) { + fullFormat = false; + fp = stdout; + } else if (strcmp(env, "stderr") == 0) { + fullFormat = false; + fp = stderr; + } else { + fullFormat = true; + + fp = fopen(env, "a"); + JS_ASSERT(fp); + + fprintf(fp, " AppTime, Total, Wait, Mark, Sweep, FinObj," + " FinStr, FinScr, FinShp, Destry, End, +Chu, -Chu, T, Reason\n"); + } + + PodArrayZero(counts); + + startupTime = PRMJ_Now(); +} + +Statistics::~Statistics() +{ + if (fp && fp != stdout && fp != stderr) + fclose(fp); +} + +struct GCCrashData +{ + int isRegen; + int isCompartment; +}; + +void +Statistics::beginGC(JSCompartment *comp, Reason reason) +{ + compartment = comp; + + PodArrayZero(phaseStarts); + PodArrayZero(phaseEnds); + PodArrayZero(phaseTimes); + + triggerReason = reason; + + beginPhase(PHASE_GC); + Probes::GCStart(compartment); + + GCCrashData crashData; + crashData.isRegen = runtime->shapeGen & SHAPE_OVERFLOW_BIT; + crashData.isCompartment = !!compartment; + crash::SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData)); +} + +double +Statistics::t(Phase phase) +{ + return double(phaseTimes[phase]) / PRMJ_USEC_PER_MSEC; +} + +double +Statistics::beginDelay(Phase phase1, Phase phase2) +{ + return double(phaseStarts[phase1] - phaseStarts[phase2]) / PRMJ_USEC_PER_MSEC; +} + +double +Statistics::endDelay(Phase phase1, Phase phase2) +{ + return double(phaseEnds[phase1] - phaseEnds[phase2]) / PRMJ_USEC_PER_MSEC; +} + +void +Statistics::printStats() +{ + if (fullFormat) { + /* App , Total, Wait , Mark , Sweep, FinOb, FinSt, FinSc, FinSh, Destry, End */ + fprintf(fp, + "%12.0f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, ", + double(phaseStarts[PHASE_GC] - startupTime) / PRMJ_USEC_PER_MSEC, + t(PHASE_GC), + beginDelay(PHASE_MARK, PHASE_GC), + t(PHASE_MARK), t(PHASE_SWEEP), + t(PHASE_SWEEP_OBJECT), t(PHASE_SWEEP_STRING), + t(PHASE_SWEEP_SCRIPT), t(PHASE_SWEEP_SHAPE), + t(PHASE_DESTROY), + endDelay(PHASE_GC, PHASE_DESTROY)); + + fprintf(fp, "%4d, %4d,", counts[STAT_NEW_CHUNK], counts[STAT_DESTROY_CHUNK]); + fprintf(fp, " %s, %s\n", compartment ? "C" : "G", ExplainReason(triggerReason)); + } else { + fprintf(fp, "%f %f %f\n", + t(PHASE_GC), t(PHASE_MARK), t(PHASE_SWEEP)); + } + fflush(fp); +} + +void +Statistics::endGC() +{ + Probes::GCEnd(compartment); + endPhase(PHASE_GC); + crash::SnapshotGCStack(); + + if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) { + (*cb)(JS_TELEMETRY_GC_REASON, triggerReason); + (*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, compartment ? 1 : 0); + (*cb)(JS_TELEMETRY_GC_IS_SHAPE_REGEN, + runtime->shapeGen & SHAPE_OVERFLOW_BIT ? 1 : 0); + (*cb)(JS_TELEMETRY_GC_MS, t(PHASE_GC)); + (*cb)(JS_TELEMETRY_GC_MARK_MS, t(PHASE_MARK)); + (*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(PHASE_SWEEP)); + } + + if (fp) + printStats(); + + PodArrayZero(counts); +} + +void +Statistics::beginPhase(Phase phase) +{ + phaseStarts[phase] = PRMJ_Now(); + + if (phase == gcstats::PHASE_SWEEP) { + Probes::GCStartSweepPhase(NULL); + if (!compartment) { + for (JSCompartment **c = runtime->compartments.begin(); + c != runtime->compartments.end(); ++c) + { + Probes::GCStartSweepPhase(*c); + } + } + } +} + +void +Statistics::endPhase(Phase phase) +{ + phaseEnds[phase] = PRMJ_Now(); + phaseTimes[phase] += phaseEnds[phase] - phaseStarts[phase]; + + if (phase == gcstats::PHASE_SWEEP) { + if (!compartment) { + for (JSCompartment **c = runtime->compartments.begin(); + c != runtime->compartments.end(); ++c) + { + Probes::GCEndSweepPhase(*c); + } + } + Probes::GCEndSweepPhase(NULL); + } +} + +} /* namespace gcstats */ +} /* namespace js */
new file mode 100644 --- /dev/null +++ b/js/src/gc/Statistics.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is SpiderMonkey JavaScript engine. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef jsgc_statistics_h___ +#define jsgc_statistics_h___ + +#include <string.h> + +#include "jspubtd.h" +#include "jsutil.h" + +struct JSCompartment; + +namespace js { +namespace gcstats { + +enum Reason { + PUBLIC_API, + MAYBEGC, + LASTCONTEXT, + DESTROYCONTEXT, + LASTDITCH, + TOOMUCHMALLOC, + ALLOCTRIGGER, + CHUNK, + SHAPE, + REFILL +}; +static const int NUM_REASONS = REFILL + 1; + +static inline const char * +ExplainReason(Reason r) +{ + static const char *strs[] = {" API", "Maybe", "LastC", "DestC", "LastD", + "Mallc", "Alloc", "Chunk", "Shape", "Refil"}; + + JS_ASSERT(strcmp(strs[SHAPE], "Shape") == 0 && + sizeof(strs) / sizeof(strs[0]) == NUM_REASONS); + + return strs[r]; +} + +enum Phase { + PHASE_GC, + PHASE_MARK, + PHASE_SWEEP, + PHASE_SWEEP_OBJECT, + PHASE_SWEEP_STRING, + PHASE_SWEEP_SCRIPT, + PHASE_SWEEP_SHAPE, + PHASE_DESTROY, + + PHASE_LIMIT +}; + +enum Stat { + STAT_NEW_CHUNK, + STAT_DESTROY_CHUNK, + + STAT_LIMIT +}; + +struct Statistics { + Statistics(JSRuntime *rt); + ~Statistics(); + + void beginGC(JSCompartment *comp, Reason reason); + void endGC(); + + void beginPhase(Phase phase); + void endPhase(Phase phase); + + void count(Stat s) { + JS_ASSERT(s < STAT_LIMIT); + counts[s]++; + } + + private: + JSRuntime *runtime; + + uint64 startupTime; + + FILE *fp; + bool fullFormat; + + Reason triggerReason; + JSCompartment *compartment; + + uint64 phaseStarts[PHASE_LIMIT]; + uint64 phaseEnds[PHASE_LIMIT]; + uint64 phaseTimes[PHASE_LIMIT]; + unsigned int counts[STAT_LIMIT]; + + double t(Phase phase); + double beginDelay(Phase phase1, Phase phase2); + double endDelay(Phase phase1, Phase phase2); + void printStats(); +}; + +struct AutoGC { + AutoGC(Statistics &stats, JSCompartment *comp, Reason reason JS_GUARD_OBJECT_NOTIFIER_PARAM) + : stats(stats) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginGC(comp, reason); } + ~AutoGC() { stats.endGC(); } + + Statistics &stats; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +struct AutoPhase { + AutoPhase(Statistics &stats, Phase phase JS_GUARD_OBJECT_NOTIFIER_PARAM) + : stats(stats), phase(phase) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginPhase(phase); } + ~AutoPhase() { stats.endPhase(phase); } + + Statistics &stats; + Phase phase; + JS_DECL_USE_GUARD_OBJECT_NOTIFIER +}; + +} /* namespace gcstats */ +} /* namespace js */ + +#endif /* jsgc_statistics_h___ */
--- a/js/src/jsanalyze.h +++ b/js/src/jsanalyze.h @@ -40,19 +40,19 @@ #ifndef jsanalyze_h___ #define jsanalyze_h___ #include "jscompartment.h" #include "jscntxt.h" #include "jsinfer.h" #include "jsscript.h" -#include "jstl.h" #include "ds/LifoAlloc.h" +#include "js/TemplateLib.h" struct JSScript; /* Forward declaration of downstream register allocations computed for join points. */ namespace js { namespace mjit { struct RegisterAllocation; } } namespace js { namespace analyze {
--- a/js/src/jsapi-tests/testThreadGC.cpp +++ b/js/src/jsapi-tests/testThreadGC.cpp @@ -159,17 +159,17 @@ BEGIN_TEST(testThreadGC_bug590533) if (setGCIsNeeded) { /* * Use JS internal API to set the GC trigger flag after we know * that the child is in a request and is about to run an infinite * loop. Then run the GC with JSRuntime->gcIsNeeded flag set. */ js::AutoLockGC lock(rt); - js::TriggerGC(rt); + js::TriggerGC(rt, js::gcstats::PUBLIC_API); } JS_GC(cx); PR_Lock(shared->lock); shared->childShouldStop = true; while (shared->childState == SharedData::CHILD_RUNNING) { JS_TriggerOperationCallback(shared->childContext);
--- a/js/src/jsapi-tests/tests.h +++ b/js/src/jsapi-tests/tests.h @@ -35,17 +35,20 @@ * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "jsapi.h" #include "jsprvtd.h" -#include "jsvector.h" +#include "jsalloc.h" + +#include "js/Vector.h" + #include <errno.h> #include <string.h> #include <stdio.h> #include <stdlib.h> class jsvalRoot { public:
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -78,30 +78,28 @@ #include "jsprobes.h" #include "jsproxy.h" #include "jsscope.h" #include "jsscript.h" #include "jsstr.h" #include "jstracer.h" #include "prmjtime.h" #include "jsstaticcheck.h" -#include "jsvector.h" #include "jsweakmap.h" #include "jswrapper.h" #include "jstypedarray.h" #include "ds/LifoAlloc.h" #include "builtin/RegExp.h" #include "jsatominlines.h" #include "jsinferinlines.h" #include "jsobjinlines.h" #include "jsscopeinlines.h" #include "jsscriptinlines.h" -#include "assembler/wtf/Platform.h" #include "vm/RegExpObject-inl.h" #include "vm/Stack-inl.h" #include "vm/String-inl.h" #if ENABLE_YARR_JIT #include "assembler/jit/ExecutableAllocator.h" #include "methodjit/Logging.h" @@ -659,16 +657,17 @@ JSRuntime::JSRuntime() gcNumber(0), gcMarkingTracer(NULL), gcChunkAllocationSinceLastGC(false), gcNextFullGCTime(0), gcJitReleaseTime(0), gcMode(JSGC_MODE_GLOBAL), gcIsNeeded(0), gcWeakMapList(NULL), + gcStats(thisFromCtor()), gcTriggerCompartment(NULL), gcCurrentCompartment(NULL), gcCheckCompartment(NULL), gcPoke(false), gcMarkAndSweep(false), gcRunning(false), gcRegenShapes(false), #ifdef JS_GC_ZEAL @@ -691,26 +690,27 @@ JSRuntime::JSRuntime() hadOutOfMemory(false), data(NULL), #ifdef JS_THREADSAFE gcLock(NULL), gcDone(NULL), requestDone(NULL), requestCount(0), gcThread(NULL), - gcHelperThread(this), + gcHelperThread(thisFromCtor()), rtLock(NULL), # ifdef DEBUG rtLockOwner(0), # endif stateChange(NULL), #endif debuggerMutations(0), securityCallbacks(NULL), structuredCloneCallbacks(NULL), + telemetryCallback(NULL), propertyRemovals(0), scriptFilenameTable(NULL), #ifdef JS_THREADSAFE scriptFilenameTableLock(NULL), #endif thousandsSeparator(0), decimalSeparator(0), numGrouping(0), @@ -2701,24 +2701,22 @@ JS_IsGCMarkingTracer(JSTracer *trc) JS_PUBLIC_API(void) JS_CompartmentGC(JSContext *cx, JSCompartment *comp) { /* We cannot GC the atoms compartment alone; use a full GC instead. */ JS_ASSERT(comp != cx->runtime->atomsCompartment); LeaveTrace(cx); - GCREASON(PUBLIC_API); - js_GC(cx, comp, GC_NORMAL); + js_GC(cx, comp, GC_NORMAL, gcstats::PUBLIC_API); } JS_PUBLIC_API(void) JS_GC(JSContext *cx) { - GCREASON(PUBLIC_API); JS_CompartmentGC(cx, NULL); } JS_PUBLIC_API(void) JS_MaybeGC(JSContext *cx) { LeaveTrace(cx);
--- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -42,19 +42,20 @@ #define jsapi_h___ /* * JavaScript API. */ #include <stddef.h> #include <stdio.h> #include "js-config.h" #include "jspubtd.h" -#include "jsutil.h" #include "jsval.h" +#include "js/Utility.h" + /************************************************************************/ /* JS::Value can store a full int32. */ #define JSVAL_INT_BITS 32 #define JSVAL_INT_MIN ((jsint)0x80000000) #define JSVAL_INT_MAX ((jsint)0x7fffffff) /************************************************************************/ @@ -1692,16 +1693,27 @@ extern JS_PUBLIC_DATA(jsid) JSID_EMPTY; * If you set this flag in a JSFunctionSpec struct's flags initializer, then * that struct must live at least as long as the native static method object * created due to this flag by JS_DefineFunctions or JS_InitClass. Typically * JSFunctionSpec structs are allocated in static arrays. */ #define JSFUN_GENERIC_NATIVE JSFUN_LAMBDA /* + * The first call to JS_CallOnce by any thread in a process will call 'func'. + * Later calls to JS_CallOnce with the same JSCallOnceType object will be + * suppressed. + * + * Equivalently: each distinct JSCallOnceType object will allow one JS_CallOnce + * to invoke its JSInitCallback. + */ +extern JS_PUBLIC_API(JSBool) +JS_CallOnce(JSCallOnceType *once, JSInitCallback func); + +/* * Microseconds since the epoch, midnight, January 1, 1970 UTC. See the * comment in jstypes.h regarding safe int64 usage. */ extern JS_PUBLIC_API(int64) JS_Now(void); /* Don't want to export data, so provide accessors for non-inline jsvals. */ extern JS_PUBLIC_API(jsval)
deleted file mode 100644 --- a/js/src/jsarena.cpp +++ /dev/null @@ -1,258 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/* - * Lifetime-based fast allocation, inspired by much prior art, including - * "Fast Allocation and Deallocation of Memory Based on Object Lifetimes" - * David R. Hanson, Software -- Practice and Experience, Vol. 20(1). - */ -#include <stdlib.h> -#include <string.h> -#include "jsalloc.h" -#include "jstypes.h" -#include "jsstdint.h" -#include "jsbit.h" -#include "jsarena.h" -#include "jsprvtd.h" - -using namespace js; - -/* If JSArena's length is a multiple of 8, that ensures its payload is 8-aligned. */ -JS_STATIC_ASSERT(sizeof(JSArena) % 8 == 0); - -JS_PUBLIC_API(void) -JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size, size_t align) -{ - /* Restricting ourselves to some simple alignments keeps things simple. */ - if (align == 1 || align == 2 || align == 4 || align == 8) { - pool->mask = align - 1; - } else { - /* This shouldn't happen, but set pool->mask reasonably if it does. */ - JS_NOT_REACHED("JS_InitArenaPool: bad align"); - pool->mask = 7; - } - pool->first.next = NULL; - /* pool->first is a zero-sized dummy arena that's never allocated from. */ - pool->first.base = pool->first.avail = pool->first.limit = - JS_ARENA_ALIGN(pool, &pool->first + 1); - pool->current = &pool->first; - pool->arenasize = size; -} - -JS_PUBLIC_API(void *) -JS_ArenaAllocate(JSArenaPool *pool, size_t nb) -{ - /* - * Search pool from current forward till we find or make enough space. - * - * NB: subtract nb from a->limit in the loop condition, instead of adding - * nb to a->avail, to avoid overflow (possible when running a 32-bit - * program on a 64-bit system where the kernel maps the heap up against the - * top of the 32-bit address space, see bug 279273). Note that this - * necessitates a comparison between nb and a->limit that looks like a - * (conceptual) type error but isn't. - */ - JS_ASSERT((nb & pool->mask) == 0); - JSArena *a; - /* - * Comparing nb to a->limit looks like a (conceptual) type error, but it's - * necessary to avoid wrap-around. Yuk. - */ - for (a = pool->current; nb > a->limit || a->avail > a->limit - nb; pool->current = a) { - JSArena **ap = &a->next; - if (!*ap) { - /* Not enough space in pool, so we must malloc. */ - size_t gross = sizeof(JSArena) + JS_MAX(nb, pool->arenasize); - a = (JSArena *) OffTheBooks::malloc_(gross); - if (!a) - return NULL; - - a->next = NULL; - a->base = a->avail = jsuword(a) + sizeof(JSArena); - /* - * Because malloc returns 8-aligned pointers and sizeof(JSArena) is - * a multiple of 8, a->base will always be 8-aligned, which should - * suffice for any valid pool. - */ - JS_ASSERT(a->base == JS_ARENA_ALIGN(pool, a->base)); - a->limit = (jsuword)a + gross; - - *ap = a; - continue; - } - a = *ap; /* move to next arena */ - } - - void* p = (void *)a->avail; - a->avail += nb; - JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); - return p; -} - -JS_PUBLIC_API(void *) -JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr) -{ - /* If we've called JS_ArenaRealloc, the new size must be bigger than pool->arenasize. */ - JS_ASSERT(size + incr > pool->arenasize); - - /* Find the arena containing |p|. */ - JSArena *a; - JSArena **ap = &pool->first.next; - while (true) { - a = *ap; - if (JS_IS_IN_ARENA(a, p)) - break; - JS_ASSERT(a != pool->current); - ap = &a->next; - } - /* If we've called JS_ArenaRealloc, p must be at the start of an arena. */ - JS_ASSERT(a->base == jsuword(p)); - - size_t gross = sizeof(JSArena) + JS_ARENA_ALIGN(pool, size + incr); - a = (JSArena *) OffTheBooks::realloc_(a, gross); - if (!a) - return NULL; - - a->base = jsuword(a) + sizeof(JSArena); - a->avail = a->limit = jsuword(a) + gross; - /* - * Because realloc returns 8-aligned pointers and sizeof(JSArena) is a - * multiple of 8, a->base will always be 8-aligned, which should suffice - * for any valid pool. - */ - JS_ASSERT(a->base == JS_ARENA_ALIGN(pool, a->base)); - - if (a != *ap) { - /* realloc moved the allocation: update other pointers to a. */ - if (pool->current == *ap) - pool->current = a; - *ap = a; - } - - return (void *)a->base; -} - -JS_PUBLIC_API(void *) -JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr) -{ - void *newp; - - /* - * If p points to an oversized allocation, it owns an entire arena, so we - * can simply realloc the arena. - */ - if (size > pool->arenasize) - return JS_ArenaRealloc(pool, p, size, incr); - - JS_ARENA_ALLOCATE(newp, pool, size + incr); - if (newp) - memcpy(newp, p, size); - return newp; -} - -/* - * Free tail arenas linked after head, which may not be the true list head. - * Reset pool->current to point to head in case it pointed at a tail arena. - */ -static void -FreeArenaList(JSArenaPool *pool, JSArena *head) -{ - JSArena **ap, *a; - - ap = &head->next; - a = *ap; - if (!a) - return; - -#ifdef DEBUG - do { - JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); - a->avail = a->base; - JS_CLEAR_UNUSED(a); - } while ((a = a->next) != NULL); - a = *ap; -#endif - - do { - *ap = a->next; - JS_CLEAR_ARENA(a); - UnwantedForeground::free_(a); - } while ((a = *ap) != NULL); - - pool->current = head; -} - -JS_PUBLIC_API(void) -JS_ArenaRelease(JSArenaPool *pool, char *mark) -{ - JSArena *a; - - for (a = &pool->first; a; a = a->next) { - JS_ASSERT(a->base <= a->avail && a->avail <= a->limit); - - if (JS_IS_IN_ARENA(a, mark)) { - a->avail = JS_ARENA_ALIGN(pool, mark); - JS_ASSERT(a->avail <= a->limit); - FreeArenaList(pool, a); - return; - } - } -} - -JS_PUBLIC_API(void) -JS_FreeArenaPool(JSArenaPool *pool) -{ - FreeArenaList(pool, &pool->first); -} - -JS_PUBLIC_API(void) -JS_FinishArenaPool(JSArenaPool *pool) -{ - FreeArenaList(pool, &pool->first); -} - -JS_PUBLIC_API(void) -JS_ArenaFinish() -{ -} - -JS_PUBLIC_API(void) -JS_ArenaShutDown(void) -{ -}
--- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -104,34 +104,32 @@ #include "jstypes.h" #include "jsstdint.h" #include "jsutil.h" #include "jsapi.h" #include "jsarray.h" #include "jsatom.h" -#include "jsbit.h" #include "jsbool.h" #include "jsbuiltins.h" #include "jscntxt.h" #include "jsversion.h" #include "jsfun.h" #include "jsgc.h" #include "jsgcmark.h" #include "jsinterp.h" #include "jsiter.h" #include "jslock.h" #include "jsnum.h" #include "jsobj.h" #include "jsscope.h" #include "jsstr.h" #include "jsstaticcheck.h" #include "jstracer.h" -#include "jsvector.h" #include "jswrapper.h" #include "methodjit/MethodJIT.h" #include "methodjit/StubCalls.h" #include "methodjit/StubCalls-inl.h" #include "vm/ArgumentsObject.h" #include "jsarrayinlines.h"
--- a/js/src/jsatom.cpp +++ b/js/src/jsatom.cpp @@ -47,17 +47,16 @@ #include "jstypes.h" #include "jsstdint.h" #include "jsutil.h" #include "jshash.h" #include "jsprf.h" #include "jsapi.h" #include "jsatom.h" -#include "jsbit.h" #include "jscntxt.h" #include "jsgc.h" #include "jsgcmark.h" #include "jslock.h" #include "jsnum.h" #include "jsparse.h" #include "jsstr.h" #include "jsversion.h"
--- a/js/src/jsatom.h +++ b/js/src/jsatom.h @@ -37,23 +37,24 @@ * * ***** END LICENSE BLOCK ***** */ #ifndef jsatom_h___ #define jsatom_h___ #include <stddef.h> #include "jsversion.h" +#include "jsalloc.h" #include "jsapi.h" #include "jsprvtd.h" #include "jshash.h" -#include "jshashtable.h" #include "jspubtd.h" #include "jslock.h" +#include "js/HashTable.h" #include "vm/String.h" /* Engine-internal extensions of jsid */ static JS_ALWAYS_INLINE jsid JSID_FROM_BITS(size_t bits) { jsid id;
deleted file mode 100644 --- a/js/src/jsbit.h +++ /dev/null @@ -1,305 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Communicator client code, released - * March 31, 1998. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef jsbit_h___ -#define jsbit_h___ - -#include "jstypes.h" -#include "jscompat.h" -#include "jsutil.h" - -JS_BEGIN_EXTERN_C - -/* -** A jsbitmap_t is a long integer that can be used for bitmaps -*/ -typedef jsuword jsbitmap_t; /* NSPR name, a la Unix system types */ -typedef jsbitmap_t jsbitmap; /* JS-style scalar typedef name */ - -#define JS_BITMAP_SIZE(bits) (JS_HOWMANY(bits, JS_BITS_PER_WORD) * \ - sizeof(jsbitmap)) - -#define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] & \ - ((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) -#define JS_SET_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] |= \ - ((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) -#define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= \ - ~((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1)))) - -/* -** Compute the log of the least power of 2 greater than or equal to n -*/ -extern JS_PUBLIC_API(JSIntn) JS_CeilingLog2(JSUint32 i); - -/* -** Compute the log of the greatest power of 2 less than or equal to n -*/ -extern JS_PUBLIC_API(JSIntn) JS_FloorLog2(JSUint32 i); - -/* - * Replace bit-scanning code sequences with CPU-specific instructions to - * speedup calculations of ceiling/floor log2. - * - * With GCC 3.4 or later we can use __builtin_clz for that, see bug 327129. - * - * SWS: Added MSVC intrinsic bitscan support. See bugs 349364 and 356856. - */ -#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) - -unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask); -unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask); -# pragma intrinsic(_BitScanForward,_BitScanReverse) - -__forceinline static int -__BitScanForward32(unsigned int val) -{ - unsigned long idx; - - _BitScanForward(&idx, (unsigned long)val); - return (int)idx; -} -__forceinline static int -__BitScanReverse32(unsigned int val) -{ - unsigned long idx; - - _BitScanReverse(&idx, (unsigned long)val); - return (int)(31-idx); -} -# define js_bitscan_ctz32(val) __BitScanForward32(val) -# define js_bitscan_clz32(val) __BitScanReverse32(val) -# define JS_HAS_BUILTIN_BITSCAN32 - -#if defined(_M_AMD64) || defined(_M_X64) -unsigned char _BitScanForward64(unsigned long * Index, unsigned __int64 Mask); -unsigned char _BitScanReverse64(unsigned long * Index, unsigned __int64 Mask); -# pragma intrinsic(_BitScanForward64,_BitScanReverse64) - -__forceinline static int -__BitScanForward64(unsigned __int64 val) -{ - unsigned long idx; - - _BitScanForward64(&idx, val); - return (int)idx; -} -__forceinline static int -__BitScanReverse64(unsigned __int64 val) -{ - unsigned long idx; - - _BitScanReverse64(&idx, val); - return (int)(63-idx); -} -# define js_bitscan_ctz64(val) __BitScanForward64(val) -# define js_bitscan_clz64(val) __BitScanReverse64(val) -# define JS_HAS_BUILTIN_BITSCAN64 -#endif -#elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) - -# define js_bitscan_ctz32(val) __builtin_ctz(val) -# define js_bitscan_clz32(val) __builtin_clz(val) -# define JS_HAS_BUILTIN_BITSCAN32 -# if (JS_BYTES_PER_WORD == 8) -# define js_bitscan_ctz64(val) __builtin_ctzll(val) -# define js_bitscan_clz64(val) __builtin_clzll(val) -# define JS_HAS_BUILTIN_BITSCAN64 -# endif - -#endif - -/* -** Macro version of JS_CeilingLog2: Compute the log of the least power of -** 2 greater than or equal to _n. The result is returned in _log2. -*/ -#ifdef JS_HAS_BUILTIN_BITSCAN32 -/* - * Use intrinsic function or count-leading-zeros to calculate ceil(log2(_n)). - * The macro checks for "n <= 1" and not "n != 0" as js_bitscan_clz32(0) is - * undefined. - */ -# define JS_CEILING_LOG2(_log2,_n) \ - JS_BEGIN_MACRO \ - unsigned int j_ = (unsigned int)(_n); \ - (_log2) = (j_ <= 1 ? 0 : 32 - js_bitscan_clz32(j_ - 1)); \ - JS_END_MACRO -#else -# define JS_CEILING_LOG2(_log2,_n) \ - JS_BEGIN_MACRO \ - JSUint32 j_ = (JSUint32)(_n); \ - (_log2) = 0; \ - if ((j_) & ((j_)-1)) \ - (_log2) += 1; \ - if ((j_) >> 16) \ - (_log2) += 16, (j_) >>= 16; \ - if ((j_) >> 8) \ - (_log2) += 8, (j_) >>= 8; \ - if ((j_) >> 4) \ - (_log2) += 4, (j_) >>= 4; \ - if ((j_) >> 2) \ - (_log2) += 2, (j_) >>= 2; \ - if ((j_) >> 1) \ - (_log2) += 1; \ - JS_END_MACRO -#endif - -/* -** Macro version of JS_FloorLog2: Compute the log of the greatest power of -** 2 less than or equal to _n. The result is returned in _log2. -** -** This is equivalent to finding the highest set bit in the word. -*/ -#ifdef JS_HAS_BUILTIN_BITSCAN32 -/* - * Use js_bitscan_clz32 or count-leading-zeros to calculate floor(log2(_n)). - * Since js_bitscan_clz32(0) is undefined, the macro set the loweset bit to 1 - * to ensure 0 result when _n == 0. - */ -# define JS_FLOOR_LOG2(_log2,_n) \ - JS_BEGIN_MACRO \ - (_log2) = 31 - js_bitscan_clz32(((unsigned int)(_n)) | 1); \ - JS_END_MACRO -#else -# define JS_FLOOR_LOG2(_log2,_n) \ - JS_BEGIN_MACRO \ - JSUint32 j_ = (JSUint32)(_n); \ - (_log2) = 0; \ - if ((j_) >> 16) \ - (_log2) += 16, (j_) >>= 16; \ - if ((j_) >> 8) \ - (_log2) += 8, (j_) >>= 8; \ - if ((j_) >> 4) \ - (_log2) += 4, (j_) >>= 4; \ - if ((j_) >> 2) \ - (_log2) += 2, (j_) >>= 2; \ - if ((j_) >> 1) \ - (_log2) += 1; \ - JS_END_MACRO -#endif - -/* - * Internal function. - * Compute the log of the least power of 2 greater than or equal to n. This is - * a version of JS_CeilingLog2 that operates on unsigned integers with - * CPU-dependant size. - */ -#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1)) - -/* - * Internal function. - * Compute the log of the greatest power of 2 less than or equal to n. - * This is a version of JS_FloorLog2 that operates on unsigned integers with - * CPU-dependant size and requires that n != 0. - */ -#define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n)) - -#if JS_BYTES_PER_WORD == 4 - -# ifdef JS_HAS_BUILTIN_BITSCAN32 -# define js_FloorLog2wImpl(n) \ - ((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n))) -# else -# define js_FloorLog2wImpl(n) ((size_t)JS_FloorLog2(n)) -#endif - -#elif JS_BYTES_PER_WORD == 8 - -# ifdef JS_HAS_BUILTIN_BITSCAN64 -# define js_FloorLog2wImpl(n) \ - ((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n))) -# else -extern size_t js_FloorLog2wImpl(size_t n); -# endif - -#else - -# error "NOT SUPPORTED" - -#endif - -namespace js { - -inline size_t -CountTrailingZeros(size_t n) -{ - JS_ASSERT(n != 0); -#if JS_BYTES_PER_WORD != 4 && JS_BYTES_PER_WORD != 8 -# error "NOT SUPPORTED" -#endif - -#if JS_BYTES_PER_WORD == 4 && defined JS_HAS_BUILTIN_BITSCAN32 - return js_bitscan_ctz32(n); -#elif JS_BYTES_PER_WORD == 8 && defined JS_HAS_BUILTIN_BITSCAN64 - return js_bitscan_ctz64(n); -#else - size_t count = 0; -# if JS_BYTES_PER_WORD == 8 - if (!(n & size_t(0xFFFFFFFFU))) { count += 32; n >>= 32; } -# endif - if (!(n & 0xFFFF)) { count += 16; n >>= 16; } - if (!(n & 0xFF)) { count += 8; n >>= 8; } - if (!(n & 0xF)) { count += 4; n >>= 4; } - if (!(n & 0x3)) { count += 2; n >>= 2; } - if (!(n & 0x1)) { count += 1; n >>= 1; } - return count + 1 - (n & 0x1); -#endif -} - -} - -/* - * Macros for rotate left. There is no rotate operation in the C Language so - * the construct (a << 4) | (a >> 28) is used instead. Most compilers convert - * this to a rotate instruction but some versions of MSVC don't without a - * little help. To get MSVC to generate a rotate instruction, we have to use - * the _rotl intrinsic and use a pragma to make _rotl inline. - * - * MSVC in VS2005 will do an inline rotate instruction on the above construct. - */ - -#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \ - defined(_M_X64)) -#include <stdlib.h> -#pragma intrinsic(_rotl) -#define JS_ROTATE_LEFT32(a, bits) _rotl(a, bits) -#else -#define JS_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits)))) -#endif - -JS_END_EXTERN_C -#endif /* jsbit_h___ */
--- a/js/src/jsbool.cpp +++ b/js/src/jsbool.cpp @@ -48,17 +48,16 @@ #include "jsbool.h" #include "jscntxt.h" #include "jsinfer.h" #include "jsversion.h" #include "jslock.h" #include "jsnum.h" #include "jsobj.h" #include "jsstr.h" -#include "jsvector.h" #include "vm/GlobalObject.h" #include "jsinferinlines.h" #include "jsobjinlines.h" #include "jsstrinlines.h" using namespace js;
--- a/js/src/jsbuiltins.cpp +++ b/js/src/jsbuiltins.cpp @@ -53,17 +53,16 @@ #include "jsmath.h" #include "jsnum.h" #include "prmjtime.h" #include "jsdate.h" #include "jsscope.h" #include "jsstr.h" #include "jsbuiltins.h" #include "jstracer.h" -#include "jsvector.h" #include "jsatominlines.h" #include "jscntxtinlines.h" #include "jsnuminlines.h" #include "jsobjinlines.h" #include "jsscopeinlines.h" using namespace avmplus;
--- a/js/src/jsclone.h +++ b/js/src/jsclone.h @@ -36,19 +36,20 @@ * * ***** END LICENSE BLOCK ***** */ #ifndef jsclone_h___ #define jsclone_h___ #include "jsapi.h" #include "jscntxt.h" -#include "jshashtable.h" #include "jsstdint.h" -#include "jsvector.h" + +#include "js/HashTable.h" +#include "js/Vector.h" JS_FRIEND_API(uint64_t) js_GetSCOffset(JSStructuredCloneWriter* writer); namespace js { bool WriteStructuredClone(JSContext *cx, const Value &v, uint64_t **bufp, size_t *nbytesp,
--- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -528,31 +528,28 @@ js_DestroyContext(JSContext *cx, JSDestr * request to end. We'll let it run below, just before we do the truly * final GC and then free atom state. */ while (cx->outstandingRequests != 0) JS_EndRequest(cx); #endif if (last) { - GCREASON(LASTCONTEXT); - js_GC(cx, NULL, GC_LAST_CONTEXT); + js_GC(cx, NULL, GC_LAST_CONTEXT, gcstats::LASTCONTEXT); /* Take the runtime down, now that it has no contexts or atoms. */ JS_LOCK_GC(rt); rt->state = JSRTS_DOWN; JS_NOTIFY_ALL_CONDVAR(rt->stateChange); } else { - if (mode == JSDCM_FORCE_GC) { - GCREASON(DESTROYCONTEXT); - js_GC(cx, NULL, GC_NORMAL); - } else if (mode == JSDCM_MAYBE_GC) { - GCREASON(DESTROYCONTEXT); + if (mode == JSDCM_FORCE_GC) + js_GC(cx, NULL, GC_NORMAL, gcstats::DESTROYCONTEXT); + else if (mode == JSDCM_MAYBE_GC) JS_MaybeGC(cx); - } + JS_LOCK_GC(rt); js_WaitForGC(rt); } } #ifdef JS_THREADSAFE #ifdef DEBUG JSThread *t = cx->thread(); #endif @@ -1160,17 +1157,17 @@ js_InvokeOperationCallback(JSContext *cx JS_LOCK_GC(rt); td->interruptFlags = 0; #ifdef JS_THREADSAFE JS_ATOMIC_DECREMENT(&rt->interruptCounter); #endif JS_UNLOCK_GC(rt); if (rt->gcIsNeeded) { - js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL); + js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL, rt->gcTriggerReason); /* * On trace we can exceed the GC quota, see comments in NewGCArena. So * we check the quota and report OOM here when we are off trace. */ if (checkOutOfMemory(rt)) { #ifdef JS_THREADSAFE /* @@ -1337,16 +1334,17 @@ DSTOffsetCache::DSTOffsetCache() } JSContext::JSContext(JSRuntime *rt) : defaultVersion(JSVERSION_DEFAULT), hasVersionOverride(false), throwing(false), exception(UndefinedValue()), runOptions(0), + reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY), localeCallbacks(NULL), resolvingList(NULL), generatingError(false), #if JS_STACK_GROWTH_DIRECTION > 0 stackLimit((jsuword)-1), #else stackLimit(0), #endif @@ -1509,18 +1507,17 @@ JSRuntime::onTooMuchMalloc() AutoLockGC lock(this); /* * We can be called outside a request and can race against a GC that * mutates the JSThread set during the sweeping phase. */ js_WaitForGC(this); #endif - GCREASON(TOOMUCHMALLOC); - TriggerGC(this); + TriggerGC(this, gcstats::TOOMUCHMALLOC); } JS_FRIEND_API(void *) JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx) { /* * Retry when we are done with the background sweeping and have stopped * all the allocations and released the empty GC chunks.
--- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -40,31 +40,33 @@ #ifndef jscntxt_h___ #define jscntxt_h___ /* * JS execution context. */ #include <string.h> +#include "jsfriendapi.h" #include "jsprvtd.h" #include "jsatom.h" #include "jsclist.h" #include "jsdhash.h" #include "jsgc.h" #include "jsgcchunk.h" -#include "jshashtable.h" #include "jspropertycache.h" #include "jspropertytree.h" #include "jsstaticcheck.h" #include "jsutil.h" -#include "jsvector.h" #include "prmjtime.h" #include "ds/LifoAlloc.h" +#include "gc/Statistics.h" +#include "js/HashTable.h" +#include "js/Vector.h" #include "vm/StackSpace.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */ #pragma warning(push) #pragma warning(disable:4355) /* Silence warning about "this" used in base member initializer list */ #endif @@ -425,16 +427,20 @@ struct JSRuntime { uint32 gcNumber; js::GCMarker *gcMarkingTracer; bool gcChunkAllocationSinceLastGC; int64 gcNextFullGCTime; int64 gcJitReleaseTime; JSGCMode gcMode; volatile jsuword gcIsNeeded; js::WeakMapBase *gcWeakMapList; + js::gcstats::Statistics gcStats; + + /* The reason that an interrupt-triggered GC should be called. */ + js::gcstats::Reason gcTriggerReason; /* Pre-allocated space for the GC mark stacks. Pointer type ensures alignment. */ void *gcMarkStackObjs[js::OBJECT_MARK_STACK_SIZE / sizeof(void *)]; void *gcMarkStackRopes[js::ROPES_MARK_STACK_SIZE / sizeof(void *)]; void *gcMarkStackTypes[js::TYPE_MARK_STACK_SIZE / sizeof(void *)]; void *gcMarkStackXMLs[js::XML_MARK_STACK_SIZE / sizeof(void *)]; void *gcMarkStackLarges[js::LARGE_MARK_STACK_SIZE / sizeof(void *)]; @@ -594,16 +600,19 @@ struct JSRuntime { * Security callbacks set on the runtime are used by each context unless * an override is set on the context. */ JSSecurityCallbacks *securityCallbacks; /* Structured data callbacks are runtime-wide. */ const JSStructuredCloneCallbacks *structuredCloneCallbacks; + /* Call this to accumulate telemetry data. */ + JSAccumulateTelemetryDataCallback telemetryCallback; + /* * The propertyRemovals counter is incremented for every JSObject::clear, * and for each JSObject::remove method call that frees a slot in the given * object. See js_NativeGet and js_NativeSet in jsobj.cpp. */ int32 propertyRemovals; /* Script filename table. */ @@ -668,69 +677,23 @@ struct JSRuntime { /* * To ensure that cx->malloc does not cause a GC, we set this flag during * OOM reporting (in js_ReportOutOfMemory). If a GC is requested while * reporting the OOM, we ignore it. */ int32 inOOMReport; -#if defined(MOZ_GCTIMER) || defined(JSGC_TESTPILOT) - struct GCData { - GCData() - : firstEnter(0), - firstEnterValid(false) -#ifdef JSGC_TESTPILOT - , infoEnabled(false), - start(0), - count(0) -#endif - { } - - /* - * Timestamp of the first GCTimer -- application runtime is determined - * relative to this value. - */ - uint64 firstEnter; - bool firstEnterValid; - - void setFirstEnter(uint64 v) { - JS_ASSERT(!firstEnterValid); - firstEnter = v; - firstEnterValid = true; - } - -#ifdef JSGC_TESTPILOT - bool infoEnabled; - - bool isTimerEnabled() { - return infoEnabled; - } - - /* - * Circular buffer with GC data. - * count may grow >= INFO_LIMIT, which would indicate data loss. - */ - static const size_t INFO_LIMIT = 64; - JSGCInfo info[INFO_LIMIT]; - size_t start; - size_t count; -#else /* defined(MOZ_GCTIMER) */ - bool isTimerEnabled() { - return true; - } -#endif - } gcData; -#endif - JSRuntime(); ~JSRuntime(); bool init(uint32 maxbytes); + JSRuntime *thisFromCtor() { return this; } + void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind); void reduceGCTriggerBytes(uint32 amount); /* * Call the system malloc while checking for GC memory pressure and * reporting OOM error when cx is not null. We will not GC from here. */ void* malloc_(size_t bytes, JSContext *cx = NULL) { @@ -965,16 +928,18 @@ struct JSContext /* Exception state -- the exception member is a GC root by definition. */ JSBool throwing; /* is there a pending exception? */ js::Value exception; /* most-recently-thrown exception */ /* Per-context run options. */ uintN runOptions; /* see jsapi.h for JSOPTION_* */ public: + int32 reportGranularity; /* see jsprobes.h */ + /* Locale specific callbacks for string conversion. */ JSLocaleCallbacks *localeCallbacks; js::AutoResolving *resolvingList; /* * True if generating an error, to prevent runaway recursion. * NB: generatingError packs with throwing below.
--- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -842,17 +842,22 @@ date_parseISOString(JSLinearString *str, if (PEEK('Z')) { ++i; } else if (PEEK('+') || PEEK('-')) { if (PEEK('-')) tzMul = -1; ++i; NEED_NDIGITS(2, tzHour); - NEED(':'); + /* + * Non-standard extension to the ISO date format (permitted by ES5): + * allow "-0700" as a time zone offset, not just "-07:00". + */ + if (PEEK(':')) + ++i; NEED_NDIGITS(2, tzMin); } else { isLocalTime = JS_TRUE; } done: if (year > 275943 // ceil(1e8/365) + 1970 || (month == 0 || month > 12)
--- a/js/src/jsdbgapi.cpp +++ b/js/src/jsdbgapi.cpp @@ -44,17 +44,16 @@ */ #include <string.h> #include <stdarg.h> #include "jsprvtd.h" #include "jstypes.h" #include "jsstdint.h" #include "jsutil.h" #include "jsclist.h" -#include "jshashtable.h" #include "jsapi.h" #include "jscntxt.h" #include "jsversion.h" #include "jsdbgapi.h" #include "jsemit.h" #include "jsfun.h" #include "jsgc.h" #include "jsgcmark.h" @@ -64,16 +63,17 @@ #include "jsopcode.h" #include "jsparse.h" #include "jsscope.h" #include "jsscript.h" #include "jsstaticcheck.h" #include "jsstr.h" #include "jswatchpoint.h" #include "jswrapper.h" + #include "vm/Debugger.h" #include "jsatominlines.h" #include "jsinferinlines.h" #include "jsobjinlines.h" #include "jsinterpinlines.h" #include "jsscopeinlines.h" #include "jsscriptinlines.h"
--- a/js/src/jsdhash.cpp +++ b/js/src/jsdhash.cpp @@ -40,17 +40,16 @@ /* * Double hashing implementation. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "jsstdint.h" -#include "jsbit.h" #include "jsdhash.h" #include "jsutil.h" using namespace js; #ifdef JS_DHASHMETER # if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan # include "nsTraceMalloc.h"
--- a/js/src/jsdtoa.cpp +++ b/js/src/jsdtoa.cpp @@ -42,17 +42,16 @@ */ #include "jstypes.h" #include "jsstdint.h" #include "jsdtoa.h" #include "jsprf.h" #include "jsapi.h" #include "jsprvtd.h" #include "jsnum.h" -#include "jsbit.h" #include "jslibmath.h" #include "jscntxt.h" #include "jsobjinlines.h" using namespace js; #ifdef IS_LITTLE_ENDIAN
--- a/js/src/jsemit.cpp +++ b/js/src/jsemit.cpp @@ -44,17 +44,16 @@ #ifdef HAVE_MEMORY_H #include <memory.h> #endif #include <new> #include <string.h> #include "jstypes.h" #include "jsstdint.h" #include "jsutil.h" -#include "jsbit.h" #include "jsprf.h" #include "jsapi.h" #include "jsatom.h" #include "jsbool.h" #include "jscntxt.h" #include "jsversion.h" #include "jsemit.h" #include "jsfun.h" @@ -7770,23 +7769,16 @@ js_FinishTakingSrcNotes(JSContext *cx, J mainCount = cg->main.noteCount; totalCount = prologCount + mainCount; if (prologCount) memcpy(notes, cg->prolog.notes, SRCNOTE_SIZE(prologCount)); memcpy(notes + prologCount, cg->main.notes, SRCNOTE_SIZE(mainCount)); SN_MAKE_TERMINATOR(¬es[totalCount]); -#ifdef DEBUG_notme - { int bin = JS_CeilingLog2(totalCount); - if (bin >= NBINS) - bin = NBINS - 1; - ++hist[bin]; - } -#endif return JS_TRUE; } static JSBool NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, uintN stackDepth, size_t start, size_t end) { JS_ASSERT((uintN)(uint16)stackDepth == stackDepth);
--- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -40,17 +40,16 @@ /* * JS standard exception implementation. */ #include <stdlib.h> #include <string.h> #include "jstypes.h" #include "jsstdint.h" -#include "jsbit.h" #include "jsutil.h" #include "jsprf.h" #include "jsapi.h" #include "jscntxt.h" #include "jsversion.h" #include "jsexn.h" #include "jsfun.h" #include "jsgc.h" @@ -613,18 +612,18 @@ StackTraceToString(JSContext *cx, JSExnP goto bad; \ \ if (length_ > stackmax - stacklen) { \ void *ptr_; \ if (stackmax >= STACK_LENGTH_LIMIT || \ length_ >= STACK_LENGTH_LIMIT - stacklen) { \ goto done; \ } \ - stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \ - ptr_ = cx->realloc_(stackbuf, (stackmax+1) * sizeof(jschar)); \ + stackmax = RoundUpPow2(stacklen + length_); \ + ptr_ = cx->realloc_(stackbuf, (stackmax+1) * sizeof(jschar)); \ if (!ptr_) \ goto bad; \ stackbuf = (jschar *) ptr_; \ } \ js_strncpy(stackbuf + stacklen, chars_, length_); \ stacklen += length_; \ JS_END_MACRO
--- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -217,8 +217,14 @@ JS_SetProtoCalled(JSContext *) extern size_t sCustomIteratorCount; JS_FRIEND_API(size_t) JS_GetCustomIteratorCount(JSContext *cx) { return sCustomIteratorCount; } + +JS_FRIEND_API(void) +JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback) +{ + rt->telemetryCallback = callback; +}
--- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -74,16 +74,31 @@ extern JS_FRIEND_API(size_t) JS_GetE4XObjectsCreated(JSContext *cx); extern JS_FRIEND_API(size_t) JS_SetProtoCalled(JSContext *cx); extern JS_FRIEND_API(size_t) JS_GetCustomIteratorCount(JSContext *cx); +enum { + JS_TELEMETRY_GC_REASON, + JS_TELEMETRY_GC_IS_COMPARTMENTAL, + JS_TELEMETRY_GC_IS_SHAPE_REGEN, + JS_TELEMETRY_GC_MS, + JS_TELEMETRY_GC_MARK_MS, + JS_TELEMETRY_GC_SWEEP_MS +}; + +typedef void +(* JSAccumulateTelemetryDataCallback)(int id, JSUint32 sample); + +extern JS_FRIEND_API(void) +JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback); + /* Data for tracking analysis/inference memory usage. */ typedef struct TypeInferenceMemoryStats { int64 scripts; int64 objects; int64 tables; int64 temporary; int64 emptyShapes;
--- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -39,17 +39,16 @@ * ***** END LICENSE BLOCK ***** */ /* * JS function support. */ #include <string.h> #include "jstypes.h" #include "jsstdint.h" -#include "jsbit.h" #include "jsutil.h" #include "jsapi.h" #include "jsarray.h" #include "jsatom.h" #include "jsbool.h" #include "jsbuiltins.h" #include "jscntxt.h" #include "jsversion.h"
--- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -49,33 +49,31 @@ * XXX swizzle page to freelist for better locality of reference */ #include <math.h> #include <string.h> /* for memset used when DEBUG */ #include "jstypes.h" #include "jsstdint.h" #include "jsutil.h" #include "jshash.h" -#include "jsbit.h" #include "jsclist.h" #include "jsprf.h" #include "jsapi.h" #include "jsatom.h" #include "jscompartment.h" #include "jscrashreport.h" #include "jscrashformat.h" #include "jscntxt.h" #include "jsversion.h" #include "jsdbgapi.h" #include "jsexn.h" #include "jsfun.h" #include "jsgc.h" #include "jsgcchunk.h" #include "jsgcmark.h" -#include "jshashtable.h" #include "jsinterp.h" #include "jsiter.h" #include "jslock.h" #include "jsnum.h" #include "jsobj.h" #include "jsparse.h" #include "jsprobes.h" #include "jsproxy.h" @@ -84,23 +82,23 @@ #include "jsstaticcheck.h" #include "jswatchpoint.h" #include "jsweakmap.h" #if JS_HAS_XML_SUPPORT #include "jsxml.h" #endif #include "methodjit/MethodJIT.h" +#include "vm/Debugger.h" #include "vm/String.h" -#include "vm/Debugger.h" #include "jsobjinlines.h" +#include "vm/CallObject-inl.h" #include "vm/String-inl.h" -#include "vm/CallObject-inl.h" #ifdef MOZ_VALGRIND # define JS_VALGRIND #endif #ifdef JS_VALGRIND # include <valgrind/memcheck.h> #endif @@ -437,17 +435,17 @@ ChunkPool::get(JSRuntime *rt) Chunk *chunk = emptyChunkListHead; if (chunk) { JS_ASSERT(emptyCount); emptyChunkListHead = chunk->info.next; --emptyCount; } else { JS_ASSERT(!emptyCount); - chunk = Chunk::allocate(); + chunk = Chunk::allocate(rt); if (!chunk) return NULL; } JS_ASSERT(chunk->unused()); JS_ASSERT(!rt->gcChunkSet.has(chunk)); #ifdef JS_THREADSAFE if (wantBackgroundAllocation(rt)) @@ -470,17 +468,17 @@ ChunkPool::put(JSRuntime *rt, Chunk *chu * empty chunks until we are done with all the sweeping and finalization * that cannot be done in the background even if shouldShrink() is true. * This way we can safely call IsAboutToBeFinalized and Cell::isMarked for * finalized GC things in empty chunks. So we only release the chunk if we * are called from the background thread. */ if (rt->gcHelperThread.sweeping()) { if (rt->gcHelperThread.shouldShrink()) { - Chunk::release(chunk); + Chunk::release(rt, chunk); return; } /* * Set the age to one as we expire chunks early during the background * sweep so this chunk already survived one GC cycle. */ initialAge = 1; @@ -509,46 +507,42 @@ ChunkPool::expire(JSRuntime *rt, bool re JS_ASSERT(emptyCount); Chunk *chunk = *chunkp; JS_ASSERT(chunk->unused()); JS_ASSERT(!rt->gcChunkSet.has(chunk)); JS_ASSERT(chunk->info.age <= MAX_EMPTY_CHUNK_AGE); if (releaseAll || chunk->info.age == MAX_EMPTY_CHUNK_AGE) { *chunkp = chunk->info.next; --emptyCount; - Chunk::release(chunk); + Chunk::release(rt, chunk); } else { /* Keep the chunk but increase its age. */ ++chunk->info.age; chunkp = &chunk->info.next; } } JS_ASSERT_IF(releaseAll, !emptyCount); } /* static */ Chunk * -Chunk::allocate() +Chunk::allocate(JSRuntime *rt) { Chunk *chunk = static_cast<Chunk *>(AllocGCChunk()); if (!chunk) return NULL; chunk->init(); -#ifdef MOZ_GCTIMER - JS_ATOMIC_INCREMENT(&newChunkCount); -#endif + rt->gcStats.count(gcstats::STAT_NEW_CHUNK); return chunk; } /* static */ inline void -Chunk::release(Chunk *chunk) +Chunk::release(JSRuntime *rt, Chunk *chunk) { JS_ASSERT(chunk); -#ifdef MOZ_GCTIMER - JS_ATOMIC_INCREMENT(&destroyChunkCount); -#endif + rt->gcStats.count(gcstats::STAT_DESTROY_CHUNK); FreeGCChunk(chunk); } void Chunk::init() { JS_POISON(this, JS_FREE_PATTERN, GC_CHUNK_SIZE); @@ -622,17 +616,17 @@ Chunk::allocateArena(JSCompartment *comp if (!hasAvailableArenas()) removeFromAvailableList(); JSRuntime *rt = comp->rt; Probes::resizeHeap(comp, rt->gcBytes, rt->gcBytes + ArenaSize); JS_ATOMIC_ADD(&rt->gcBytes, ArenaSize); JS_ATOMIC_ADD(&comp->gcBytes, ArenaSize); if (comp->gcBytes >= comp->gcTriggerBytes) - TriggerCompartmentGC(comp); + TriggerCompartmentGC(comp, gcstats::ALLOCTRIGGER); return aheader; } void Chunk::releaseArena(ArenaHeader *aheader) { JS_ASSERT(aheader->allocated()); @@ -695,17 +689,17 @@ PickChunk(JSCompartment *comp) /* * FIXME bug 583732 - chunk is newly allocated and cannot be present in * the table so using ordinary lookupForAdd is suboptimal here. */ GCChunkSet::AddPtr p = rt->gcChunkSet.lookupForAdd(chunk); JS_ASSERT(!p); if (!rt->gcChunkSet.add(p, chunk)) { - Chunk::release(chunk); + Chunk::release(rt, chunk); return NULL; } chunk->info.prevp = NULL; chunk->info.next = NULL; chunk->addToAvailableList(comp); return chunk; @@ -1054,17 +1048,17 @@ js_FinishGC(JSRuntime *rt) for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) Foreground::delete_(*c); rt->compartments.clear(); rt->atomsCompartment = NULL; rt->gcSystemAvailableChunkListHead = NULL; rt->gcUserAvailableChunkListHead = NULL; for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) - Chunk::release(r.front()); + Chunk::release(rt, r.front()); rt->gcChunkSet.clear(); #ifdef JS_THREADSAFE rt->gcHelperThread.finish(); #endif /* * Finish the pool after the background thread stops in case it was doing @@ -1522,18 +1516,17 @@ RunLastDitchGC(JSContext *cx) JSRuntime *rt = cx->runtime; #ifdef JS_THREADSAFE Maybe<AutoUnlockAtomsCompartment> maybeUnlockAtomsCompartment; if (cx->compartment == rt->atomsCompartment && rt->atomsCompartmentIsLocked) maybeUnlockAtomsCompartment.construct(cx); #endif /* The last ditch GC preserves all atoms. */ AutoKeepAtoms keep(rt); - GCREASON(LASTDITCH); - js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL); + js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL, gcstats::LASTDITCH); #ifdef JS_THREADSAFE if (rt->gcBytes >= rt->gcMaxBytes) { AutoLockGC lock(rt); cx->runtime->gcHelperThread.waitBackgroundSweepEnd(); } #endif } @@ -1576,18 +1569,17 @@ ArenaLists::refillFreeList(JSContext *cx return thing; /* * 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 (runGC || !IsGCAllowed(cx)) { AutoLockGC lock(rt); - GCREASON(REFILL); - TriggerGC(rt); + TriggerGC(rt, gcstats::REFILL); break; } runGC = true; } js_ReportOutOfMemory(cx); return NULL; } @@ -1977,107 +1969,103 @@ MarkRuntime(JSTracer *trc) if (!IS_GC_MARKING_TRACER(trc)) { /* We don't want to miss these when called from TraceRuntime. */ if (JSTraceDataOp op = rt->gcGrayRootsTraceOp) (*op)(trc, rt->gcGrayRootsData); } } void -TriggerGC(JSRuntime *rt) +TriggerGC(JSRuntime *rt, gcstats::Reason reason) { JS_ASSERT(!rt->gcRunning); if (rt->gcIsNeeded) return; /* * Trigger the GC when it is safe to call an operation callback on any * thread. */ rt->gcIsNeeded = true; rt->gcTriggerCompartment = NULL; + rt->gcTriggerReason = reason; TriggerAllOperationCallbacks(rt); } void -TriggerCompartmentGC(JSCompartment *comp) +TriggerCompartmentGC(JSCompartment *comp, gcstats::Reason reason) { JSRuntime *rt = comp->rt; JS_ASSERT(!rt->gcRunning); - GCREASON(COMPARTMENT); if (rt->gcZeal()) { - TriggerGC(rt); + TriggerGC(rt, reason); return; } if (rt->gcMode != JSGC_MODE_COMPARTMENT || comp == rt->atomsCompartment) { /* We can't do a compartmental GC of the default compartment. */ - TriggerGC(rt); + TriggerGC(rt, reason); return; } if (rt->gcIsNeeded) { /* If we need to GC more than one compartment, run a full GC. */ if (rt->gcTriggerCompartment != comp) rt->gcTriggerCompartment = NULL; return; } if (rt->gcBytes > 8192 && rt->gcBytes >= 3 * (rt->gcTriggerBytes / 2)) { /* If we're using significantly more than our quota, do a full GC. */ - TriggerGC(rt); + TriggerGC(rt, reason); return; } /* * Trigger the GC when it is safe to call an operation callback on any * thread. */ rt->gcIsNeeded = true; rt->gcTriggerCompartment = comp; + rt->gcTriggerReason = reason; TriggerAllOperationCallbacks(comp->rt); } void MaybeGC(JSContext *cx) { JSRuntime *rt = cx->runtime; if (rt->gcZeal()) { - GCREASON(MAYBEGC); - js_GC(cx, NULL, GC_NORMAL); + js_GC(cx, NULL, GC_NORMAL, gcstats::MAYBEGC); return; } JSCompartment *comp = cx->compartment; if (rt->gcIsNeeded) { - GCREASON(MAYBEGC); - js_GC(cx, (comp == rt->gcTriggerCompartment) ? comp : NULL, GC_NORMAL); + js_GC(cx, (comp == rt->gcTriggerCompartment) ? comp : NULL, GC_NORMAL, gcstats::MAYBEGC); return; } if (comp->gcBytes > 8192 && comp->gcBytes >= 3 * (comp->gcTriggerBytes / 4)) { - GCREASON(MAYBEGC); - js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL); + js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL, gcstats::MAYBEGC); return; } /* * On 32 bit setting gcNextFullGCTime below is not atomic and a race condition * could trigger an GC. We tolerate this. */ int64 now = PRMJ_Now(); if (rt->gcNextFullGCTime && rt->gcNextFullGCTime <= now) { - if (rt->gcChunkAllocationSinceLastGC) { - GCREASON(MAYBEGC); - js_GC(cx, NULL, GC_SHRINK); - } else { + if (rt->gcChunkAllocationSinceLastGC) + js_GC(cx, NULL, GC_SHRINK, gcstats::MAYBEGC); + else rt->gcNextFullGCTime = now + GC_IDLE_FULL_SPAN; - } } } } /* namespace js */ #ifdef JS_THREADSAFE namespace js { @@ -2154,17 +2142,17 @@ GCHelperThread::threadLoop() state = IDLE; PR_NotifyAllCondVar(done); break; case ALLOCATING: do { Chunk *chunk; { AutoUnlockGC unlock(rt); - chunk = Chunk::allocate(); + chunk = Chunk::allocate(rt); } /* OOM stops the background allocation. */ if (!chunk) break; rt->gcChunkPool.put(rt, chunk); } while (state == ALLOCATING && rt->gcChunkPool.wantBackgroundAllocation(rt)); if (state == ALLOCATING) @@ -2281,17 +2269,17 @@ GCHelperThread::doSweep() } for (void ***iter = freeVector.begin(); iter != freeVector.end(); ++iter) { void **array = *iter; freeElementsAndArray(array, array + FREE_ARRAY_LENGTH); } freeVector.resize(0); } -} +} /* namespace js */ #endif /* JS_THREADSAFE */ static uint32 ComputeJitReleaseInterval(JSContext *cx) { JSRuntime *rt = cx->runtime; /* @@ -2341,17 +2329,17 @@ SweepCompartments(JSContext *cx, JSGCInv continue; } *write++ = compartment; } rt->compartments.resize(write - rt->compartments.begin()); } static void -BeginMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_PARAM) +BeginMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind) { JSRuntime *rt = cx->runtime; /* * Reset the property cache's type id generator so we can compress ids. * Same for the protoHazardShape proxy-shape standing in for all object * prototypes having readonly or setter properties. */ @@ -2371,32 +2359,32 @@ BeginMarkPhase(JSContext *cx, GCMarker * JSContext *iter = NULL; while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter)) acx->purge(); } /* * Mark phase. */ - GCTIMESTAMP(startMark); + rt->gcStats.beginPhase(gcstats::PHASE_MARK); for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) r.front()->bitmap.clear(); if (rt->gcCurrentCompartment) { for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) (*c)->markCrossCompartmentWrappers(gcmarker); Debugger::markCrossCompartmentDebuggerObjectReferents(gcmarker); } MarkRuntime(gcmarker); } static void -EndMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_PARAM) +EndMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind) { JSRuntime *rt = cx->runtime; gcmarker->setMarkColor(GRAY); if (JSTraceDataOp op = rt->gcGrayRootsTraceOp) (*op)(gcmarker, rt->gcGrayRootsData); gcmarker->drainMarkStack(); gcmarker->setMarkColor(BLACK); @@ -2408,32 +2396,34 @@ EndMarkPhase(JSContext *cx, GCMarker *gc WeakMapBase::markAllIteratively(gcmarker) || Debugger::markAllIteratively(gcmarker)) { gcmarker->drainMarkStack(); } rt->gcMarkingTracer = NULL; + rt->gcStats.endPhase(gcstats::PHASE_MARK); + if (rt->gcCallback) (void) rt->gcCallback(cx, JSGC_MARK_END); #ifdef DEBUG /* Make sure that we didn't mark an object in another compartment */ if (rt->gcCurrentCompartment) { for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) { JS_ASSERT_IF(*c != rt->gcCurrentCompartment && *c != rt->atomsCompartment, (*c)->arenas.checkArenaListAllUnmarked()); } } #endif } static void -SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_PARAM) +SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind) { JSRuntime *rt = cx->runtime; /* * Sweep phase. * * Finalize as we sweep, outside of rt->gcLock but with rt->gcRunning set * so that any attempt to allocate a GC-thing from a finalizer will fail, @@ -2441,108 +2431,108 @@ SweepPhase(JSContext *cx, GCMarker *gcma * * We first sweep atom state so we can use IsAboutToBeFinalized on * JSString held in a hashtable to check if the hashtable entry can be * freed. Note that even after the entry is freed, JSObject finalizers can * continue to access the corresponding JSString* assuming that they are * unique. This works since the atomization API must not be called during * the GC. */ - GCTIMESTAMP(startSweep); + gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP); /* Finalize unreachable (key,value) pairs in all weak maps. */ WeakMapBase::sweepAll(gcmarker); js_SweepAtomState(cx); /* Collect watch points associated with unreachable objects. */ WatchpointMap::sweepAll(cx); - Probes::GCStartSweepPhase(NULL); - for (GCCompartmentsIter c(rt); !c.done(); c.next()) - Probes::GCStartSweepPhase(c); - if (!rt->gcCurrentCompartment) Debugger::sweepAll(cx); uint32 releaseInterval = rt->gcCurrentCompartment ? 0 : ComputeJitReleaseInterval(cx); for (GCCompartmentsIter c(rt); !c.done(); c.next()) c->sweep(cx, releaseInterval); - /* - * We finalize objects before other GC things to ensure that the object's - * finalizer can access the other things even if they will be freed. - */ - for (GCCompartmentsIter c(rt); !c.done(); c.next()) - c->arenas.finalizeObjects(cx); - - GCTIMESTAMP(sweepObjectEnd); - - for (GCCompartmentsIter c(rt); !c.done(); c.next()) - c->arenas.finalizeStrings(cx); - - GCTIMESTAMP(sweepStringEnd); - - for (GCCompartmentsIter c(rt); !c.done(); c.next()) - c->arenas.finalizeScripts(cx); - - GCTIMESTAMP(sweepScriptEnd); - - for (GCCompartmentsIter c(rt); !c.done(); c.next()) - c->arenas.finalizeShapes(cx); - - GCTIMESTAMP(sweepShapeEnd); - - for (GCCompartmentsIter c(rt); !c.done(); c.next()) - Probes::GCEndSweepPhase(c); - Probes::GCEndSweepPhase(NULL); + { + gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_OBJECT); + + /* + * We finalize objects before other GC things to ensure that the object's + * finalizer can access the other things even if they will be freed. + */ + for (GCCompartmentsIter c(rt); !c.done(); c.next()) + c->arenas.finalizeObjects(cx); + } + + { + gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_STRING); + for (GCCompartmentsIter c(rt); !c.done(); c.next()) + c->arenas.finalizeStrings(cx); + } + + { + gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_SCRIPT); + for (GCCompartmentsIter c(rt); !c.done(); c.next()) + c->arenas.finalizeScripts(cx); + } + + { + gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_SHAPE); + for (GCCompartmentsIter c(rt); !c.done(); c.next()) + c->arenas.finalizeShapes(cx); + } #ifdef DEBUG PropertyTree::dumpShapes(cx); #endif - /* - * Sweep script filenames after sweeping functions in the generic loop - * above. In this way when a scripted function's finalizer destroys the - * script and calls rt->destroyScriptHook, the hook can still access the - * script's filename. See bug 323267. - */ - for (GCCompartmentsIter c(rt); !c.done(); c.next()) - js_SweepScriptFilenames(c); - - /* - * This removes compartments from rt->compartment, so we do it last to make - * sure we don't miss sweeping any compartments. - */ - if (!rt->gcCurrentCompartment) - SweepCompartments(cx, gckind); + { + gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DESTROY); + + /* + * Sweep script filenames after sweeping functions in the generic loop + * above. In this way when a scripted function's finalizer destroys the + * script and calls rt->destroyScriptHook, the hook can still access the + * script's filename. See bug 323267. + */ + for (GCCompartmentsIter c(rt); !c.done(); c.next()) + js_SweepScriptFilenames(c); + + /* + * This removes compartments from rt->compartment, so we do it last to make + * sure we don't miss sweeping any compartments. + */ + if (!rt->gcCurrentCompartment) + SweepCompartments(cx, gckind); #ifndef JS_THREADSAFE - /* - * Destroy arenas after we finished the sweeping so finalizers can safely - * use IsAboutToBeFinalized(). - * This is done on the GCHelperThread if JS_THREADSAFE is defined. - */ - rt->gcChunkPool.expire(rt, gckind == GC_SHRINK); + /* + * Destroy arenas after we finished the sweeping so finalizers can safely + * use IsAboutToBeFinalized(). + * This is done on the GCHelperThread if JS_THREADSAFE is defined. + */ + rt->gcChunkPool.expire(rt, gckind == GC_SHRINK); #endif - GCTIMESTAMP(sweepDestroyEnd); + } if (rt->gcCallback) (void) rt->gcCallback(cx, JSGC_FINALIZE_END); } /* * Perform mark-and-sweep GC. * * In a JS_THREADSAFE build, the calling thread must be rt->gcThread and each * other thread must be either outside all requests or blocked waiting for GC * to finish. The caller must hold rt->gcLock. */ static void -MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM) +MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind) { JSRuntime *rt = cx->runtime; rt->gcNumber++; /* Clear gcIsNeeded now, when we are about to start a normal GC cycle. */ rt->gcIsNeeded = false; rt->gcTriggerCompartment = NULL; @@ -2551,20 +2541,20 @@ MarkAndSweep(JSContext *cx, JSGCInvocati AutoUnlockGC unlock(rt); GCMarker gcmarker(cx); JS_ASSERT(IS_GC_MARKING_TRACER(&gcmarker)); JS_ASSERT(gcmarker.getMarkColor() == BLACK); rt->gcMarkingTracer = &gcmarker; - BeginMarkPhase(cx, &gcmarker, gckind GCTIMER_ARG); + BeginMarkPhase(cx, &gcmarker, gckind); gcmarker.drainMarkStack(); - EndMarkPhase(cx, &gcmarker, gckind GCTIMER_ARG); - SweepPhase(cx, &gcmarker, gckind GCTIMER_ARG); + EndMarkPhase(cx, &gcmarker, gckind); + SweepPhase(cx, &gcmarker, gckind); } #ifdef JS_THREADSAFE /* * If the GC is running and we're called on another thread, wait for this GC * activation to finish. We can safely wait here without fear of deadlock (in * the case where we are called within a request on another thread's context) @@ -2736,17 +2726,17 @@ AutoGCSession::~AutoGCSession() /* * GC, repeatedly if necessary, until we think we have not created any new * garbage and no other threads are demanding more GC. We disable inlining * to ensure that the bottom of the stack with possible GC roots recorded in * js_GC excludes any pointers we use during the marking implementation. */ static JS_NEVER_INLINE void -GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_PARAM) +GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind) { JSRuntime *rt = cx->runtime; JS_ASSERT_IF(comp, gckind != GC_LAST_CONTEXT); JS_ASSERT_IF(comp, comp != rt->atomsCompartment); JS_ASSERT_IF(comp, rt->gcMode == JSGC_MODE_COMPARTMENT); /* @@ -2798,17 +2788,17 @@ GCCycle(JSContext *cx, JSCompartment *co JS_ASSERT(!cx->gcBackgroundFree); rt->gcHelperThread.waitBackgroundSweepOrAllocEnd(); if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) { if (rt->gcHelperThread.prepareForBackgroundSweep(cx)) cx->gcBackgroundFree = &rt->gcHelperThread; } #endif - MarkAndSweep(cx, gckind GCTIMER_ARG); + MarkAndSweep(cx, gckind); #ifdef JS_THREADSAFE if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) { JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread); cx->gcBackgroundFree = NULL; rt->gcHelperThread.startBackgroundSweep(gckind == GC_SHRINK); } else { JS_ASSERT(!cx->gcBackgroundFree); @@ -2820,24 +2810,18 @@ GCCycle(JSContext *cx, JSCompartment *co rt->setGCLastBytes(rt->gcBytes, gckind); rt->gcCurrentCompartment = NULL; rt->gcWeakMapList = NULL; for (JSCompartment **c = rt->compartments.begin(); c != rt->compartments.end(); ++c) (*c)->setGCLastBytes((*c)->gcBytes, gckind); } -struct GCCrashData -{ - int isRegen; - int isCompartment; -}; - void -js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind) +js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Reason reason) { JSRuntime *rt = cx->runtime; /* * Don't collect garbage if the runtime isn't up, and cx is not the last * context in the runtime. The last context must force a GC, and nothing * should suppress that final collection or there may be shutdown leaks, * or runtime bloat until the next context is created. @@ -2847,32 +2831,17 @@ js_GC(JSContext *cx, JSCompartment *comp if (JS_ON_TRACE(cx)) { JS_ASSERT(gckind != GC_LAST_CONTEXT); return; } RecordNativeStackTopForGC(cx); - GCCrashData crashData; - crashData.isRegen = rt->shapeGen & SHAPE_OVERFLOW_BIT; - crashData.isCompartment = !!comp; - crash::SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData)); - - GCTIMER_BEGIN(rt, comp); - - struct AutoGCProbe { - JSCompartment *comp; - AutoGCProbe(JSCompartment *comp) : comp(comp) { - Probes::GCStart(comp); - } - ~AutoGCProbe() { - Probes::GCEnd(comp); /* background thread may still be sweeping */ - } - } autoGCProbe(comp); + gcstats::AutoGC agc(rt->gcStats, comp, reason); do { /* * Let the API user decide to defer a GC if it wants to (unless this * is the last context). Invoke the callback regardless. Sample the * callback in case we are freely racing with a JS_SetGCCallback{,RT} * on another thread. */ @@ -2880,35 +2849,32 @@ js_GC(JSContext *cx, JSCompartment *comp if (!callback(cx, JSGC_BEGIN) && gckind != GC_LAST_CONTEXT) return; } { /* Lock out other GC allocator and collector invocations. */ AutoLockGC lock(rt); rt->gcPoke = false; - GCCycle(cx, comp, gckind GCTIMER_ARG); + GCCycle(cx, comp, gckind); } /* We re-sample the callback again as the finalizers can change it. */ if (JSGCCallback callback = rt->gcCallback) (void) callback(cx, JSGC_END); /* * On shutdown, iterate until finalizers or the JSGC_END callback * stop creating garbage. */ } while (gckind == GC_LAST_CONTEXT && rt->gcPoke); rt->gcNextFullGCTime = PRMJ_Now() + GC_IDLE_FULL_SPAN; rt->gcChunkAllocationSinceLastGC = false; - GCTIMER_END(gckind == GC_LAST_CONTEXT); - - crash::SnapshotGCStack(); } namespace js { class AutoCopyFreeListToArenas { JSRuntime *rt; public:
--- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -40,30 +40,32 @@ #ifndef jsgc_h___ #define jsgc_h___ /* * JS Garbage Collector. */ #include <setjmp.h> +#include "jsalloc.h" #include "jstypes.h" #include "jsprvtd.h" #include "jspubtd.h" #include "jsdhash.h" -#include "jsbit.h" #include "jsgcchunk.h" -#include "jshashtable.h" #include "jslock.h" #include "jsutil.h" -#include "jsvector.h" #include "jsversion.h" #include "jsgcstats.h" #include "jscell.h" +#include "gc/Statistics.h" +#include "js/HashTable.h" +#include "js/Vector.h" + struct JSCompartment; extern "C" void js_TraceXML(JSTracer *trc, JSXML* thing); #if JS_STACK_GROWTH_DIRECTION > 0 # define JS_CHECK_STACK_SIZE(limit, lval) ((jsuword)(lval) < limit) #else @@ -651,18 +653,18 @@ struct Chunk { inline void addToAvailableList(JSCompartment *compartment); inline void removeFromAvailableList(); ArenaHeader *allocateArena(JSCompartment *comp, AllocKind kind); void releaseArena(ArenaHeader *aheader); - static Chunk *allocate(); - static inline void release(Chunk *chunk); + static Chunk *allocate(JSRuntime *rt); + static inline void release(JSRuntime *rt, Chunk *chunk); private: inline void init(); }; JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE); JS_STATIC_ASSERT(sizeof(Chunk) + BytesPerArena > GC_CHUNK_SIZE); @@ -1260,21 +1262,21 @@ MarkRuntime(JSTracer *trc); extern void TraceRuntime(JSTracer *trc); extern JS_REQUIRES_STACK JS_FRIEND_API(void) MarkContext(JSTracer *trc, JSContext *acx); /* Must be called with GC lock taken. */ extern void -TriggerGC(JSRuntime *rt); +TriggerGC(JSRuntime *rt, js::gcstats::Reason reason); /* Must be called with GC lock taken. */ extern void -TriggerCompartmentGC(JSCompartment *comp); +TriggerCompartmentGC(JSCompartment *comp, js::gcstats::Reason reason); extern void MaybeGC(JSContext *cx); } /* namespace js */ /* * Kinds of js_GC invocation. @@ -1290,17 +1292,17 @@ typedef enum JSGCInvocationKind { GC_LAST_CONTEXT = 1, /* Minimize GC triggers and release empty GC chunks right away. */ GC_SHRINK = 2 } JSGCInvocationKind; /* Pass NULL for |comp| to get a full GC. */ extern void -js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind); +js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, js::gcstats::Reason r); #ifdef JS_THREADSAFE /* * This is a helper for code at can potentially run outside JS request to * ensure that the GC is not running when the function returns. * * This function must be called with the GC lock held. */
--- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -38,21 +38,21 @@ * ***** END LICENSE BLOCK ***** */ #ifndef jsgcinlines_h___ #define jsgcinlines_h___ #include "jsgc.h" #include "jscntxt.h" #include "jscompartment.h" +#include "jslock.h" #include "jsscope.h" #include "jsxml.h" -#include "jslock.h" -#include "jstl.h" +#include "js/TemplateLib.h" namespace js { struct Shape; namespace gc { inline JSGCTraceKind
--- a/js/src/jsgcmark.h +++ b/js/src/jsgcmark.h @@ -38,19 +38,20 @@ * ***** END LICENSE BLOCK ***** */ #ifndef jsgcmark_h___ #define jsgcmark_h___ #include "jsgc.h" #include "jscntxt.h" #include "jscompartment.h" +#include "jslock.h" -#include "jslock.h" -#include "jstl.h" + +#include "js/TemplateLib.h" namespace js { namespace gc { void MarkString(JSTracer *trc, JSString *str); void
--- a/js/src/jsgcstats.cpp +++ b/js/src/jsgcstats.cpp @@ -75,64 +75,16 @@ ConservativeGCStats::dump(FILE *fp) 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)); #undef ULSTAT } #endif } //gc -} //js - -#ifdef JSGC_TESTPILOT -typedef JSRuntime::GCData GCData; - -JS_PUBLIC_API(bool) -JS_GetGCInfoEnabled(JSRuntime *rt) -{ - return rt->gcData.infoEnabled; -} - -JS_PUBLIC_API(void) -JS_SetGCInfoEnabled(JSRuntime *rt, bool enabled) -{ - rt->gcData.infoEnabled = enabled; -} - -JS_PUBLIC_API(JSGCInfo *) -JS_GCInfoFront(JSRuntime *rt) -{ - GCData &data = rt->gcData; - JS_ASSERT(data.infoEnabled); - if (!data.count) - return NULL; - - return &data.info[data.start]; -} - -JS_PUBLIC_API(bool) -JS_GCInfoPopFront(JSRuntime *rt) -{ - GCData &data = rt->gcData; - JS_ASSERT(data.infoEnabled); - JS_ASSERT(data.count); - - if (data.count >= GCData::INFO_LIMIT) { - data.count = data.start = 0; - return true; - } - - data.start = (data.start + 1) % GCData::INFO_LIMIT; - data.count -= 1; - return false; -} -#endif - - -namespace js { #ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS void GCMarker::dumpConservativeRoots() { if (!conservativeDumpFileName) return; @@ -148,17 +100,17 @@ GCMarker::dumpConservativeRoots() return; } conservativeStats.dump(fp); for (void **thingp = conservativeRoots.begin(); thingp != conservativeRoots.end(); ++thingp) { void *thing = thingp; fprintf(fp, " %p: ", thing); - + switch (GetGCThingTraceKind(thing)) { case JSTRACE_OBJECT: { JSObject *obj = (JSObject *) thing; fprintf(fp, "object %s", obj->getClass()->name); break; } case JSTRACE_STRING: { JSString *str = (JSString *) thing; @@ -195,148 +147,9 @@ GCMarker::dumpConservativeRoots() } fputc('\n', fp); if (fp != stdout && fp != stderr) fclose(fp); } #endif /* JS_DUMP_CONSERVATIVE_GC_ROOTS */ -#if defined(MOZ_GCTIMER) || defined(JSGC_TESTPILOT) - -volatile GCTimer::JSGCReason gcReason = GCTimer::NOREASON; -const char *gcReasons[] = {" API", "Maybe", "LastC", "DestC", "Compa", "LastD", - "Malloc", "Refill", "Chunk", "Shape", " None"}; - -jsrefcount newChunkCount = 0; -jsrefcount destroyChunkCount = 0; - -#ifdef MOZ_GCTIMER -static const char *gcTimerStatPath = NULL; -#endif - -GCTimer::GCTimer(JSRuntime *rt, JSCompartment *comp) - : rt(rt), isCompartmental(comp), - enabled(rt->gcData.isTimerEnabled()) -{ -#ifdef MOZ_GCTIMER - if (!gcTimerStatPath) { - gcTimerStatPath = getenv("MOZ_GCTIMER"); - if (!gcTimerStatPath || !gcTimerStatPath[0]) - gcTimerStatPath = "gcTimer.dat"; - } - if (!strcmp(gcTimerStatPath, "none")) - enabled = false; -#endif - clearTimestamps(); - getFirstEnter(); - enter = PRMJ_Now(); -} - -uint64 -GCTimer::getFirstEnter() -{ - JSRuntime::GCData &data = rt->gcData; - if (enabled && !data.firstEnterValid) - data.setFirstEnter(PRMJ_Now()); - - return data.firstEnter; -} - -#define TIMEDIFF(start, end) ((double)(end - start) / PRMJ_USEC_PER_MSEC) - -void -GCTimer::finish(bool lastGC) -{ -#if defined(JSGC_TESTPILOT) - if (!enabled) { - newChunkCount = 0; - destroyChunkCount = 0; - return; - } -#endif - end = PRMJ_Now(); - - if (startMark > 0) { - double appTime = TIMEDIFF(getFirstEnter(), enter); - double gcTime = TIMEDIFF(enter, end); - double waitTime = TIMEDIFF(enter, startMark); - double markTime = TIMEDIFF(startMark, startSweep); - double sweepTime = TIMEDIFF(startSweep, sweepDestroyEnd); - double sweepObjTime = TIMEDIFF(startSweep, sweepObjectEnd); - double sweepStringTime = TIMEDIFF(sweepObjectEnd, sweepStringEnd); - double sweepScriptTime = TIMEDIFF(sweepStringEnd, sweepScriptEnd); - double sweepShapeTime = TIMEDIFF(sweepScriptEnd, sweepShapeEnd); - double destroyTime = TIMEDIFF(sweepShapeEnd, sweepDestroyEnd); - double endTime = TIMEDIFF(sweepDestroyEnd, end); - -#if defined(JSGC_TESTPILOT) - GCData &data = rt->gcData; - size_t oldLimit = (data.start + data.count) % GCData::INFO_LIMIT; - data.count += 1; - - JSGCInfo &info = data.info[oldLimit]; - info.appTime = appTime; - info.gcTime = gcTime; - info.waitTime = waitTime; - info.markTime = markTime; - info.sweepTime = sweepTime; - info.sweepObjTime = sweepObjTime; - info.sweepStringTime = sweepStringTime; - info.sweepScriptTime = sweepScriptTime; - info.sweepShapeTime = sweepShapeTime; - info.destroyTime = destroyTime; - info.endTime = endTime; - info.isCompartmental = isCompartmental; -#endif - -#if defined(MOZ_GCTIMER) - static FILE *gcFile; - static bool fullFormat; - - if (!gcFile) { - if (!strcmp(gcTimerStatPath, "stdout")) { - gcFile = stdout; - fullFormat = false; - } else if (!strcmp(gcTimerStatPath, "stderr")) { - gcFile = stderr; - fullFormat = false; - } else { - gcFile = fopen(gcTimerStatPath, "a"); - JS_ASSERT(gcFile); - fullFormat = true; - fprintf(gcFile, " AppTime, Total, Wait, Mark, Sweep, FinObj," - " FinStr, SwScripts, SwShapes, Destroy, End, +Chu, -Chu, T, Reason\n"); - } - } - - if (!fullFormat) { - fprintf(stderr, "%f %f %f\n", - TIMEDIFF(enter, end), - TIMEDIFF(startMark, startSweep), - TIMEDIFF(startSweep, sweepDestroyEnd)); - } else { - /* App , Tot , Wai , Mar , Swe , FiO , FiS , SwScr , SwS , Des , End */ - fprintf(gcFile, "%12.0f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %8.1f, %6.1f, %6.1f, ", - appTime, gcTime, waitTime, markTime, sweepTime, sweepObjTime, sweepStringTime, - sweepScriptTime, sweepShapeTime, destroyTime, endTime); - fprintf(gcFile, "%4d, %4d,", newChunkCount, destroyChunkCount); - fprintf(gcFile, " %s, %s\n", isCompartmental ? "C" : "G", gcReasons[gcReason]); - } - fflush(gcFile); - - if (lastGC && gcFile != stdout && gcFile != stderr) - fclose(gcFile); -#endif - } - newChunkCount = 0; - destroyChunkCount = 0; - gcReason = NOREASON; -} - -#undef TIMEDIFF - -#endif - -} //js - -#undef UL -#undef PERCENT +} /* namespace js */
--- a/js/src/jsgcstats.h +++ b/js/src/jsgcstats.h @@ -38,59 +38,16 @@ #ifndef jsgcstats_h___ #define jsgcstats_h___ #if !defined JS_DUMP_CONSERVATIVE_GC_ROOTS && defined DEBUG # define JS_DUMP_CONSERVATIVE_GC_ROOTS 1 #endif -#ifdef JSGC_TESTPILOT -JS_BEGIN_EXTERN_C - -struct JSGCInfo -{ - double appTime, gcTime, waitTime, markTime, sweepTime; - double sweepObjTime, sweepStringTime, sweepScriptTime, sweepShapeTime; - double destroyTime, endTime; - bool isCompartmental; -}; - -extern JS_PUBLIC_API(void) -JS_SetGCInfoEnabled(JSRuntime *rt, bool enabled); - -extern JS_PUBLIC_API(bool) -JS_GetGCInfoEnabled(JSRuntime *rt); - -/* - * Data in the circular buffer may end up clobbered before the API client - * consumes it. Because of this we have a multi-part API. The client uses code - * like the following: - * - * - Call GetInfo, which provides an info pointer. - * - Read data out of the info pointer to a location the client owns. - * - Call PopInfo, which provides a "did info get dropped?" value. If that - * value is true, the data read out of the info pointer may be tainted, and - * must be thrown out. Otherwise, the data was definitely safe to read, and - * may be committed to a database or some such. - * - * When PopInfo indicates that data has been dropped, all of the information in - * the circular buffer is reset. - */ - -extern JS_PUBLIC_API(JSGCInfo *) -JS_GCInfoFront(JSRuntime *rt); - -/* Return whether info has dropped. See comment above. */ -extern JS_PUBLIC_API(bool) -JS_GCInfoPopFront(JSRuntime *rt); - -JS_END_EXTERN_C -#endif - namespace js { namespace gc { /* * The conservative GC test for a word shows that it is either a valid GC * thing or is not for one of the following reasons. */ enum ConservativeGCTest { @@ -116,84 +73,11 @@ struct ConservativeGCStats counter[i] += another.counter[i]; } void dump(FILE *fp); }; } //gc -#if defined(MOZ_GCTIMER) || defined(JSGC_TESTPILOT) - -extern jsrefcount newChunkCount; -extern jsrefcount destroyChunkCount; - -struct GCTimer -{ - JSRuntime *rt; - - uint64 enter; - uint64 startMark; - uint64 startSweep; - uint64 sweepObjectEnd; - uint64 sweepStringEnd; - uint64 sweepScriptEnd; - uint64 sweepShapeEnd; - uint64 sweepDestroyEnd; - uint64 end; - - bool isCompartmental; - bool enabled; /* Disabled timers should cause no PRMJ calls. */ - - GCTimer(JSRuntime *rt, JSCompartment *comp); - - uint64 getFirstEnter(); - - void clearTimestamps() { - memset(&enter, 0, &end - &enter + sizeof(end)); - } - - void finish(bool lastGC); - - enum JSGCReason { - PUBLIC_API, - MAYBEGC, - LASTCONTEXT, - DESTROYCONTEXT, - COMPARTMENT, - LASTDITCH, - TOOMUCHMALLOC, - ALLOCTRIGGER, - REFILL, - SHAPE, - NOREASON - }; -}; - -/* We accept the possiblility of races for this variable. */ -extern volatile GCTimer::JSGCReason gcReason; - -#define GCREASON(x) ((gcReason == GCTimer::NOREASON) ? gcReason = GCTimer::x : gcReason = gcReason) - -# define GCTIMER_PARAM , GCTimer &gcTimer -# define GCTIMER_ARG , gcTimer -# define GCTIMESTAMP(stamp_name_) \ - JS_BEGIN_MACRO \ - if (gcTimer.enabled) \ - gcTimer.stamp_name_ = PRMJ_Now(); \ - JS_END_MACRO -# define GCTIMER_BEGIN(rt, comp) GCTimer gcTimer(rt, comp) -# define GCTIMER_END(last) (gcTimer.finish(last)) -#else -# define GCREASON(x) ((void) 0) -# define GCTIMER_PARAM -# define GCTIMER_ARG -# define GCTIMESTAMP(x) ((void) 0) -# define GCTIMER_BEGIN(rt, comp) ((void) 0) -# define GCTIMER_END(last) ((void) 0) -#endif - } //js -extern JS_FRIEND_API(void) -js_DumpGCStats(JSRuntime *rt, FILE *fp); - #endif /* jsgcstats_h__ */
--- a/js/src/jshash.cpp +++ b/js/src/jshash.cpp @@ -39,17 +39,16 @@ /* * PR hash table package. */ #include <stdlib.h> #include <string.h> #include "jstypes.h" #include "jsstdint.h" -#include "jsbit.h" #include "jsutil.h" #include "jshash.h" using namespace js; /* Compute the number of buckets in ht */ #define NBUCKETS(ht) JS_BIT(JS_HASH_BITS - (ht)->shift) @@ -102,17 +101,17 @@ JS_NewHashTable(uint32 n, JSHashFunction JSHashAllocOps *allocOps, void *allocPriv) { JSHashTable *ht; size_t nb; if (n <= MINBUCKETS) { n = MINBUCKETSLOG2; } else { - n = JS_CeilingLog2(n); + n = JS_CEILING_LOG2W(n); if ((int32)n < 0) return NULL; } if (!allocOps) allocOps = &defaultHashAllocOps; ht = (JSHashTable*) allocOps->allocTable(allocPriv, sizeof *ht); if (!ht) @@ -382,17 +381,17 @@ JS_HashTableEnumerateEntries(JSHashTable } out: /* Shrink table if removal of entries made it underloaded */ if (ht->nentries != nlimit) { JS_ASSERT(ht->nentries < nlimit); nbuckets = NBUCKETS(ht); if (MINBUCKETS < nbuckets && ht->nentries < UNDERLOADED(nbuckets)) { - newlog2 = JS_CeilingLog2(ht->nentries); + newlog2 = JS_CEILING_LOG2W(ht->nentries); if (newlog2 < MINBUCKETSLOG2) newlog2 = MINBUCKETSLOG2; /* Check that we really shrink the table. */ JS_ASSERT(JS_HASH_BITS - ht->shift > newlog2); Resize(ht, JS_HASH_BITS - newlog2); } }
--- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -34,33 +34,31 @@ * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "jsapi.h" #include "jsautooplen.h" -#include "jsbit.h" #include "jsbool.h" #include "jsdate.h" #include "jsexn.h" #include "jsfriendapi.h" #include "jsgc.h" #include "jsgcmark.h" #include "jsinfer.h" #include "jsmath.h" #include "jsnum.h" #include "jsobj.h" #include "jsscript.h" #include "jscntxt.h" #include "jsscan.h" #include "jsscope.h" #include "jsstr.h" -#include "jstl.h" #include "jsiter.h" #include "methodjit/MethodJIT.h" #include "methodjit/Retcon.h" #include "jsatominlines.h" #include "jsgcinlines.h" #include "jsinferinlines.h"
--- a/js/src/jsinfer.h +++ b/js/src/jsinfer.h @@ -40,21 +40,20 @@ /* Definitions related to javascript type inference. */ #ifndef jsinfer_h___ #define jsinfer_h___ #include "jsalloc.h" #include "jscell.h" #include "jsfriendapi.h" -#include "jstl.h" #include "jsprvtd.h" -#include "jshashtable.h" #include "ds/LifoAlloc.h" +#include "js/HashTable.h" namespace js { namespace types { /* Type set entry for either a JSObject with singleton type or a non-singleton TypeObject. */ struct TypeObjectKey { static intptr_t keyBits(TypeObjectKey *obj) { return (intptr_t) obj; } static TypeObjectKey *getKey(TypeObjectKey *obj) { return obj; }
--- a/js/src/jsinterp.cpp +++ b/js/src/jsinterp.cpp @@ -68,17 +68,17 @@ #include "jspropertycache.h" #include "jsemit.h" #include "jsscope.h" #include "jsscript.h" #include "jsstr.h" #include "jsstaticcheck.h" #include "jstracer.h" #include "jslibmath.h" -#include "jsvector.h" + #ifdef JS_METHODJIT #include "methodjit/MethodJIT.h" #include "methodjit/MethodJIT-inl.h" #include "methodjit/Logging.h" #endif #include "vm/Debugger.h" #include "jsatominlines.h" @@ -2725,17 +2725,17 @@ BEGIN_CASE(JSOP_BINDNAME) if (!obj) goto error; } while (0); PUSH_OBJECT(*obj); } END_CASE(JSOP_BINDNAME) BEGIN_CASE(JSOP_IMACOP) - JS_ASSERT(JS_UPTRDIFF(regs.fp()->imacropc(), script->code) < script->length); + JS_ASSERT(UnsignedPtrDiff(regs.fp()->imacropc(), script->code) < script->length); op = JSOp(*regs.fp()->imacropc()); DO_OP(); #define BITWISE_OP(OP) \ JS_BEGIN_MACRO \ int32_t i, j; \ if (!ValueToECMAInt32(cx, regs.sp[-2], &i)) \ goto error; \
--- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -51,29 +51,27 @@ #include "jsbool.h" #include "jsbuiltins.h" #include "jscntxt.h" #include "jsversion.h" #include "jsexn.h" #include "jsfun.h" #include "jsgc.h" #include "jsgcmark.h" -#include "jshashtable.h" #include "jsinterp.h" #include "jsiter.h" #include "jslock.h" #include "jsnum.h" #include "jsobj.h" #include "jsopcode.h" #include "jsproxy.h" #include "jsscan.h" #include "jsscope.h" #include "jsscript.h" #include "jsstaticcheck.h" -#include "jsvector.h" #if JS_HAS_XML_SUPPORT #include "jsxml.h" #endif #include "vm/GlobalObject.h" #include "jsinferinlines.h"
--- a/js/src/jslock.cpp +++ b/js/src/jslock.cpp @@ -32,35 +32,36 @@ * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ +#include "jsapi.h" +#include "jspubtd.h" +#include "jstypes.h" + #ifdef JS_THREADSAFE /* * JS locking stubs. */ #include <stdlib.h> #include <string.h> #ifdef XP_WIN # include "jswin.h" #else # include <unistd.h> #endif -#include "jspubtd.h" #include "jsutil.h" -#include "jstypes.h" #include "jsstdint.h" -#include "jsbit.h" #include "jscntxt.h" #include "jsgc.h" #include "jslock.h" #include "jsscope.h" #include "jsstr.h" using namespace js; @@ -499,17 +500,17 @@ js_SetupLocks(int listc, int globc) if (global_locks) return JS_TRUE; #ifdef DEBUG if (listc > 10000 || listc < 0) /* listc == fat lock list chunk length */ printf("Bad number %d in js_SetupLocks()!\n", listc); if (globc > 100 || globc < 0) /* globc == number of global locks */ printf("Bad number %d in js_SetupLocks()!\n", listc); #endif - global_locks_log2 = JS_CeilingLog2(globc); + global_locks_log2 = JS_CEILING_LOG2W(globc); global_locks_mask = JS_BITMASK(global_locks_log2); global_lock_count = JS_BIT(global_locks_log2); global_locks = (PRLock **) OffTheBooks::malloc_(global_lock_count * sizeof(PRLock*)); if (!global_locks) return JS_FALSE; for (i = 0; i < global_lock_count; i++) { global_locks[i] = PR_NewLock(); if (!global_locks[i]) { @@ -758,9 +759,33 @@ js_UnlockRuntime(JSRuntime *rt) #ifdef DEBUG JSBool js_IsRuntimeLocked(JSRuntime *rt) { return js_CurrentThreadId() == rt->rtLockOwner; } #endif /* DEBUG */ + +static PRStatus +CallOnce(void *func) +{ + JSInitCallback init = JS_DATA_TO_FUNC_PTR(JSInitCallback, func); + return init() ? PR_FAILURE : PR_SUCCESS; +} + +JS_PUBLIC_API(JSBool) +JS_CallOnce(JSCallOnceType *once, JSInitCallback func) +{ + return PR_CallOnceWithArg(once, CallOnce, JS_FUNC_TO_DATA_PTR(void *, func)) == PR_SUCCESS; +} +#else /* JS_THREADSAFE */ +JS_PUBLIC_API(JSBool) +JS_CallOnce(JSCallOnceType *once, JSInitCallback func) +{ + if (!*once) { + *once = true; + return func(); + } else { + return JS_TRUE; + } +} #endif /* JS_THREADSAFE */
--- a/js/src/jslock.h +++ b/js/src/jslock.h @@ -43,16 +43,17 @@ #include "jsapi.h" #include "jsprvtd.h" #ifdef JS_THREADSAFE # include "pratom.h" # include "prlock.h" # include "prcvar.h" # include "prthread.h" +# include "prinit.h" #endif #ifdef JS_THREADSAFE #if (defined(_WIN32) && defined(_M_IX86)) || \ (defined(_WIN64) && (defined(_M_AMD64) || defined(_M_X64))) || \ (defined(__i386) && (defined(__GNUC__) || defined(__SUNPRO_CC))) || \ (defined(__x86_64) && (defined(__GNUC__) || defined(__SUNPRO_CC))) || \
--- a/js/src/jslog2.cpp +++ b/js/src/jslog2.cpp @@ -32,17 +32,16 @@ * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "jsstdint.h" -#include "jsbit.h" #include "jsutil.h" /* * Check that we can use js_bitscan_clz32 to implement JS_FLOOR_LOG2 and * JS_FLOOR_LOG2W and js_bitscan_clz64 to implement JS_FLOOR_LOG2W on 64-bit * systems. */ #ifdef JS_HAS_BUILTIN_BITSCAN32 @@ -51,41 +50,16 @@ JS_STATIC_ASSERT_IF(JS_BYTES_PER_WORD == sizeof(unsigned int) == sizeof(JSUword)); #endif #ifdef JS_HAS_BUILTIN_BITSCAN64 JS_STATIC_ASSERT_IF(JS_BYTES_PER_WORD == 8, sizeof(unsigned long long) == sizeof(JSUword)); #endif /* - * Compute the log of the least power of 2 greater than or equal to n - */ -JS_PUBLIC_API(JSIntn) -JS_CeilingLog2(JSUint32 n) -{ - JSIntn log2; - - JS_CEILING_LOG2(log2, n); - return log2; -} - -/* - * Compute the log of the greatest power of 2 less than or equal to n. - * This really just finds the highest set bit in the word. - */ -JS_PUBLIC_API(JSIntn) -JS_FloorLog2(JSUint32 n) -{ - JSIntn log2; - - JS_FLOOR_LOG2(log2, n); - return log2; -} - -/* * js_FloorLog2wImpl has to be defined only for 64-bit non-GCC case. */ #if !defined(JS_HAS_BUILTIN_BITSCAN64) && JS_BYTES_PER_WORD == 8 size_t js_FloorLog2wImpl(size_t n) { size_t log2, m;
--- a/js/src/jsnum.cpp +++ b/js/src/jsnum.cpp @@ -67,17 +67,16 @@ #include "jsinterp.h" #include "jsnum.h" #include "jsobj.h" #include "jsopcode.h" #include "jsprf.h" #include "jsscope.h" #include "jsstr.h" #include "jstracer.h" -#include "jsvector.h" #include "jslibmath.h" #include "vm/GlobalObject.h" #include "jsatominlines.h" #include "jsinferinlines.h" #include "jsnuminlines.h" #include "jsobjinlines.h"
--- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -40,17 +40,16 @@ /* * JS object implementation. */ #include <stdlib.h> #include <string.h> #include "jstypes.h" #include "jsstdint.h" -#include "jsbit.h" #include "jsutil.h" #include "jshash.h" #include "jsdhash.h" #include "jsprf.h" #include "jsapi.h" #include "jsarray.h" #include "jsatom.h" #include "jsbool.h"
--- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -52,17 +52,16 @@ #include "jsapi.h" #include "jsclass.h" #include "jsfriendapi.h" #include "jsinfer.h" #include "jshash.h" #include "jspubtd.h" #include "jsprvtd.h" #include "jslock.h" -#include "jsvector.h" #include "jscell.h" #include "vm/String.h" namespace nanojit { class ValidateWriter; } namespace js {
--- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -66,17 +66,16 @@ #include "jsscriptinlines.h" #include "jsstr.h" #include "vm/GlobalObject.h" #include "jsatominlines.h" #include "jsfuninlines.h" #include "jsgcinlines.h" -#include "jsprobes.h" #include "jsscopeinlines.h" inline bool JSObject::preventExtensions(JSContext *cx, js::AutoIdVector *props) { JS_ASSERT(isExtensible()); if (js::FixOp fix = getOps()->fix) {
--- a/js/src/json.cpp +++ b/js/src/json.cpp @@ -45,27 +45,25 @@ #include "jsatom.h" #include "jsbool.h" #include "jscntxt.h" #include "jsfun.h" #include "jsinterp.h" #include "jsiter.h" #include "jsnum.h" #include "jsobj.h" +#include "json.h" #include "jsonparser.h" #include "jsprf.h" #include "jsscan.h" #include "jsstr.h" #include "jstypes.h" #include "jsstdint.h" #include "jsutil.h" #include "jsxml.h" -#include "jsvector.h" - -#include "json.h" #include "jsatominlines.h" #include "jsinferinlines.h" #include "jsobjinlines.h" #include "jsstrinlines.h" #include "vm/Stack-inl.h"
--- a/js/src/json.h +++ b/js/src/json.h @@ -35,17 +35,18 @@ * * ***** END LICENSE BLOCK ***** */ #ifndef json_h___ #define json_h___ #include "jsprvtd.h" #include "jspubtd.h" -#include "jsvector.h" + +#include "js/Vector.h" #define JSON_MAX_DEPTH 2048 #define JSON_PARSER_BUFSIZE 1024 extern JSObject * js_InitJSONClass(JSContext *cx, JSObject *obj); extern JSBool
--- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -63,17 +63,16 @@ #include "jsnum.h" #include "jsobj.h" #include "jsopcode.h" #include "jsscan.h" #include "jsscope.h" #include "jsscript.h" #include "jsstr.h" #include "jsstaticcheck.h" -#include "jsvector.h" #include "vm/Debugger.h" #include "jscntxtinlines.h" #include "jsobjinlines.h" #include "jsopcodeinlines.h" #include "jsscriptinlines.h" @@ -4095,17 +4094,17 @@ Decompile(SprintStack *ss, jsbytecode *p * un-parenthesized generator expression. The ss->inGenExp * special case of JSOP_YIELD shares array comprehension * decompilation code that leaves the result as the single * string pushed on ss2. */ outer = jp->script; outerfun = jp->fun; outerLocalNames = jp->localNames; - LOCAL_ASSERT(JS_UPTRDIFF(pc, outer->code) <= outer->length); + LOCAL_ASSERT(UnsignedPtrDiff(pc, outer->code) <= outer->length); jp->script = inner; jp->fun = fun; jp->localNames = innerLocalNames; /* * Decompile only the main bytecode, to avoid tripping over * new prolog ops that have stack effects. */
--- a/js/src/jsotypes.h +++ b/js/src/jsotypes.h @@ -90,14 +90,9 @@ typedef JSInt64 int64; /* /usr/include/model.h on HP-UX defines int8, int16, and int32 */ typedef JSInt32 int32; typedef JSInt16 int16; typedef JSInt8 int8; #endif /* AIX && HAVE_SYS_INTTYPES_H */ typedef JSFloat64 float64; -/* Re: jsbit.h */ -#define TEST_BIT JS_TEST_BIT -#define SET_BIT JS_SET_BIT -#define CLEAR_BIT JS_CLEAR_BIT - #endif /* !defined(PROTYPES_H) */
--- a/js/src/jsparse.cpp +++ b/js/src/jsparse.cpp @@ -75,17 +75,16 @@ #include "jsparse.h" #include "jsprobes.h" #include "jsscan.h" #include "jsscope.h" #include "jsscript.h" #include "jsstr.h" #include "jsstaticcheck.h" #include "jslibmath.h" -#include "jsvector.h" #if JS_HAS_XML_SUPPORT #include "jsxml.h" #endif #if JS_HAS_DESTRUCTURING #include "jsdhash.h" #endif
--- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -1072,17 +1072,17 @@ struct JSFunctionBoxQueue { size_t count() { return head - tail; } size_t length() { return lengthMask + 1; } JSFunctionBoxQueue() : vector(NULL), head(0), tail(0), lengthMask(0) { } bool init(uint32 count) { - lengthMask = JS_BITMASK(JS_CeilingLog2(count)); + lengthMask = JS_BITMASK(JS_CEILING_LOG2W(count)); vector = (JSFunctionBox **) js::OffTheBooks::malloc_(sizeof(JSFunctionBox) * length()); return !!vector; } ~JSFunctionBoxQueue() { js::UnwantedForeground::free_(vector); } void push(JSFunctionBox *funbox) { if (!funbox->queued) {
--- a/js/src/jsprobes.cpp +++ b/js/src/jsprobes.cpp @@ -60,16 +60,158 @@ using namespace js; const char Probes::nullName[] = "(null)"; const char Probes::anonymousName[] = "(anonymous)"; bool Probes::ProfilingActive = true; +static Vector<Probes::JITWatcher*, 4, SystemAllocPolicy> jitWatchers; + +bool +Probes::addJITWatcher(JITWatcher *watcher) +{ + return jitWatchers.append(watcher); +} + +bool +Probes::removeJITWatcher(JSRuntime *rt, JITWatcher *watcher) +{ + JITWatcher **place = Find(jitWatchers, watcher); + if (!place) + return false; + if (rt) + rt->delete_(*place); + else + Foreground::delete_(*place); + jitWatchers.erase(place); + return true; +} + +void +Probes::removeAllJITWatchers(JSRuntime *rt) +{ + if (rt) { + for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) + rt->delete_(*p); + } else { + for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) + Foreground::delete_(*p); + } + jitWatchers.clear(); +} + +Probes::JITReportGranularity +Probes::JITGranularityRequested() +{ + JITReportGranularity want = JITREPORT_GRANULARITY_NONE; + for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) { + JITReportGranularity request = (*p)->granularityRequested(); + if (request > want) + want = request; + } + + return want; +} + +#ifdef JS_METHODJIT +void +Probes::registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr, + JSScript *script, JSFunction *fun, + js::mjit::Compiler_ActiveFrame **inlineFrames, + void *mainCodeAddress, size_t mainCodeSize, + void *stubCodeAddress, size_t stubCodeSize) +{ + for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) + (*p)->registerMJITCode(cx, jscr, script, fun, + inlineFrames, + mainCodeAddress, mainCodeSize, + stubCodeAddress, stubCodeSize); +} + +void +Probes::discardMJITCode(JSContext *cx, mjit::JITScript *jscr, JSScript *script, void* address) +{ + for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) + (*p)->discardMJITCode(cx, jscr, script, address); +} + +void +Probes::registerICCode(JSContext *cx, + mjit::JITScript *jscr, JSScript *script, jsbytecode* pc, + void *start, size_t size) +{ + for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) + (*p)->registerICCode(cx, jscr, script, pc, start, size); +} +#endif + +/* ICs are unregistered in a batch */ +void +Probes::discardExecutableRegion(void *start, size_t size) +{ + for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p) + (*p)->discardExecutableRegion(start, size); +} + +static JSRuntime *initRuntime; + +JSBool +Probes::startEngine() +{ + bool ok = true; + + return ok; +} + +bool +Probes::createRuntime(JSRuntime *rt) +{ + bool ok = true; + + static JSCallOnceType once = { 0 }; + initRuntime = rt; + if (!JS_CallOnce(&once, Probes::startEngine)) + ok = false; + +#ifdef MOZ_ETW + if (!ETWCreateRuntime(rt)) + ok = false; +#endif + + return ok; +} + +bool +Probes::destroyRuntime(JSRuntime *rt) +{ + bool ok = true; +#ifdef MOZ_ETW + if (!ETWDestroyRuntime(rt)) + ok = false; +#endif + + return ok; +} + +bool +Probes::shutdown() +{ + bool ok = true; +#ifdef MOZ_ETW + if (!ETWShutdown()) + ok = false; +#endif + + Probes::removeAllJITWatchers(NULL); + + return ok; +} + #ifdef INCLUDE_MOZILLA_DTRACE static const char * ScriptFilename(const JSScript *script) { if (!script) return Probes::nullName; if (!script->filename) return Probes::anonymousName;
--- a/js/src/jsprobes.h +++ b/js/src/jsprobes.h @@ -40,19 +40,26 @@ #ifndef _JSPROBES_H #define _JSPROBES_H #ifdef INCLUDE_MOZILLA_DTRACE #include "javascript-trace.h" #endif #include "jspubtd.h" #include "jsprvtd.h" +#include "jsscript.h" +#include "jsobj.h" namespace js { +namespace mjit { +struct NativeAddressInfo; +struct Compiler_ActiveFrame; +} + namespace Probes { /* * Static probes * * The probe points defined in this file are scattered around the SpiderMonkey * source tree. The presence of Probes::someEvent() means that someEvent is * about to happen or has happened. To the extent possible, probes should be @@ -80,32 +87,41 @@ namespace Probes { * Internal use only: remember whether "profiling", whatever that means, is * currently active. Used for state management. */ extern bool ProfilingActive; extern const char nullName[]; extern const char anonymousName[]; +/* Called when first runtime is created for this process */ +JSBool startEngine(); + /* JSRuntime created, with currently valid fields */ bool createRuntime(JSRuntime *rt); /* JSRuntime about to be destroyed */ bool destroyRuntime(JSRuntime *rt); /* Total JS engine shutdown */ bool shutdown(); /* * Test whether we are tracking JS function call enter/exit. The JITs use this * to decide whether they can optimize in a way that would prevent probes from * firing. */ bool callTrackingActive(JSContext *); +/* + * Test whether anything is looking for JIT native code registration events. + * This information will not be collected otherwise. + */ +bool wantNativeAddressInfo(JSContext *); + /* Entering a JS function */ bool enterJSFun(JSContext *, JSFunction *, JSScript *, int counter = 1); /* About to leave a JS function */ bool exitJSFun(JSContext *, JSFunction *, JSScript *, int counter = 0); /* Executing a script */ bool startExecution(JSContext *cx, JSScript *script); @@ -190,16 +206,111 @@ bool GCEndSweepPhase(JSCompartment *comp * application-meaningful events and phases of execution. * * Not all backends support these. */ bool CustomMark(JSString *string); bool CustomMark(const char *string); bool CustomMark(int marker); +/* JIT code observation */ + +enum JITReportGranularity { + JITREPORT_GRANULARITY_NONE = 0, + JITREPORT_GRANULARITY_FUNCTION = 1, + JITREPORT_GRANULARITY_LINE = 2, + JITREPORT_GRANULARITY_OP = 3 +}; + +/* + * Observer class for JIT code allocation/deallocation. Currently, this only + * handles the method JIT, and does not get notifications when JIT code is + * changed (patched) with no new allocation. + */ +class JITWatcher { +public: + virtual JITReportGranularity granularityRequested() = 0; + +#ifdef JS_METHODJIT + virtual void registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr, + JSScript *script, JSFunction *fun, + mjit::Compiler_ActiveFrame** inlineFrames, + void *mainCodeAddress, size_t mainCodeSize, + void *stubCodeAddress, size_t stubCodeSize) = 0; + + virtual void discardMJITCode(JSContext *cx, mjit::JITScript *jscr, JSScript *script, + void* address) = 0; + + virtual void registerICCode(JSContext *cx, + js::mjit::JITScript *jscr, JSScript *script, jsbytecode* pc, + void *start, size_t size) = 0; +#endif + + virtual void discardExecutableRegion(void *start, size_t size) = 0; +}; + +/* + * Register a JITWatcher subclass to be informed of JIT code + * allocation/deallocation. + */ +bool +addJITWatcher(JITWatcher *watcher); + +/* + * Remove (and destroy) a registered JITWatcher. rt may be NULL. Returns false + * if the watcher is not found. + */ +bool +removeJITWatcher(JSRuntime *rt, JITWatcher *watcher); + +/* + * Remove (and destroy) all registered JITWatchers. rt may be NULL. + */ +void +removeAllJITWatchers(JSRuntime *rt); + +/* + * Finest granularity of JIT information desired by all watchers. + */ +JITReportGranularity +JITGranularityRequested(); + +#ifdef JS_METHODJIT +/* + * New method JIT code has been created + */ +void +registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr, + JSScript *script, JSFunction *fun, + mjit::Compiler_ActiveFrame** inlineFrames, + void *mainCodeAddress, size_t mainCodeSize, + void *stubCodeAddress, size_t stubCodeSize); + +/* + * Method JIT code is about to be discarded + */ +void +discardMJITCode(JSContext *cx, mjit::JITScript *jscr, JSScript *script, void* address); + +/* + * IC code has been allocated within the given JITScript + */ +void +registerICCode(JSContext *cx, + mjit::JITScript *jscr, JSScript *script, jsbytecode* pc, + void *start, size_t size); +#endif /* JS_METHODJIT */ + +/* + * A whole region of code has been deallocated, containing any number of ICs. + * (ICs are unregistered in a batch, so individual ICs are not registered.) + */ +void +discardExecutableRegion(void *start, size_t size); + /* * Internal: DTrace-specific functions to be called during Probes::enterJSFun * and Probes::exitJSFun. These will not be inlined, but the argument * marshalling required for these probe points is expensive enough that it * shouldn't really matter. */ void DTraceEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script); void DTraceExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script); @@ -238,54 +349,21 @@ bool ETWCustomMark(int marker); bool ETWStartExecution(JSContext *cx, JSScript *script); bool ETWStopExecution(JSContext *cx, JSScript *script); bool ETWResizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize); #endif } /* namespace Probes */ /* - * Probe handlers are implemented inline for minimal performance impact, + * Many probe handlers are implemented inline for minimal performance impact, * especially important when no backends are enabled. */ inline bool -Probes::createRuntime(JSRuntime *rt) -{ - bool ok = true; -#ifdef MOZ_ETW - if (!ETWCreateRuntime(rt)) - ok = false; -#endif - return ok; -} - -inline bool -Probes::destroyRuntime(JSRuntime *rt) -{ - bool ok = true; -#ifdef MOZ_ETW - if (!ETWDestroyRuntime(rt)) - ok = false; -#endif - return ok; -} - -inline bool -Probes::shutdown() -{ - bool ok = true; -#ifdef MOZ_ETW - if (!ETWShutdown()) - ok = false; -#endif - return ok; -} - -inline bool Probes::callTrackingActive(JSContext *cx) { #ifdef INCLUDE_MOZILLA_DTRACE if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED() || JAVASCRIPT_FUNCTION_RETURN_ENABLED()) return true; #endif #ifdef MOZ_TRACE_JSCALLS if (cx->functionCallback) @@ -294,16 +372,23 @@ Probes::callTrackingActive(JSContext *cx #ifdef MOZ_ETW if (ProfilingActive && ETWCallTrackingActive(cx)) return true; #endif return false; } inline bool +Probes::wantNativeAddressInfo(JSContext *cx) +{ + return (cx->reportGranularity >= JITREPORT_GRANULARITY_FUNCTION && + JITGranularityRequested() >= JITREPORT_GRANULARITY_FUNCTION); +} + +inline bool Probes::enterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter) { bool ok = true; #ifdef INCLUDE_MOZILLA_DTRACE if (JAVASCRIPT_FUNCTION_ENTRY_ENABLED()) DTraceEnterJSFun(cx, fun, script); #endif #ifdef MOZ_TRACE_JSCALLS
--- a/js/src/jspropertycache.cpp +++ b/js/src/jspropertycache.cpp @@ -493,17 +493,17 @@ PropertyCache::purge(JSContext *cx) } void PropertyCache::purgeForScript(JSContext *cx, JSScript *script) { JS_ASSERT(!cx->runtime->gcRunning); for (PropertyCacheEntry *entry = table; entry < table + SIZE; entry++) { - if (JS_UPTRDIFF(entry->kpc, script->code) < script->length) { + if (UnsignedPtrDiff(entry->kpc, script->code) < script->length) { entry->kpc = NULL; #ifdef DEBUG entry->kshape = entry->vcap = 0; entry->vword.setNull(); #endif } } }
--- a/js/src/jspropertytree.h +++ b/js/src/jspropertytree.h @@ -35,19 +35,20 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef jspropertytree_h___ #define jspropertytree_h___ -#include "jshashtable.h" #include "jsprvtd.h" +#include "js/HashTable.h" + namespace js { struct ShapeHasher { typedef js::Shape *Key; typedef const js::Shape *Lookup; static inline HashNumber hash(const Lookup l); static inline bool match(Key k, Lookup l);
--- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -872,17 +872,16 @@ Proxy::typeOf(JSContext *cx, JSObject *p JS_CHECK_RECURSION(cx, return JSTYPE_OBJECT); AutoPendingProxyOperation pending(cx, proxy); return GetProxyHandler(proxy)->typeOf(cx, proxy); } bool Proxy::objectClassIs(JSObject *proxy, ESClassValue classValue, JSContext *cx) { - JS_CHECK_RECURSION(cx, JS_NOT_REACHED("cannot reenter")); AutoPendingProxyOperation pending(cx, proxy); return GetProxyHandler(proxy)->objectClassIs(proxy, classValue, cx); } JSString * Proxy::obj_toString(JSContext *cx, JSObject *proxy) { JS_CHECK_RECURSION(cx, return NULL);
--- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -236,11 +236,18 @@ typedef struct JSXDRState #ifdef __cplusplus class JSFlatString; class JSString; #else typedef struct JSFlatString JSFlatString; typedef struct JSString JSString; #endif +#ifdef JS_THREADSAFE +typedef struct PRCallOnceType JSCallOnceType; +#else +typedef JSBool JSCallOnceType; +#endif +typedef JSBool (*JSInitCallback)(void); + JS_END_EXTERN_C #endif /* jspubtd_h___ */
--- a/js/src/jsreflect.cpp +++ b/js/src/jsreflect.cpp @@ -42,21 +42,19 @@ */ #include <stdlib.h> #include <string.h> /* for jsparse.h */ #include "jspubtd.h" #include "jsatom.h" #include "jsobj.h" #include "jsreflect.h" #include "jscntxt.h" /* for jsparse.h */ -#include "jsbit.h" /* for jsparse.h */ #include "jsscript.h" /* for jsparse.h */ #include "jsinterp.h" /* for jsparse.h */ #include "jsparse.h" -#include "jsvector.h" #include "jsemit.h" #include "jsscan.h" #include "jsprf.h" #include "jsiter.h" #include "jsbool.h" #include "jsval.h" #include "jsinferinlines.h" #include "jsobjinlines.h"
--- a/js/src/jsscan.cpp +++ b/js/src/jsscan.cpp @@ -49,32 +49,30 @@ #ifdef HAVE_MEMORY_H #include <memory.h> #endif #include <stdarg.h> #include <stdlib.h> #include <string.h> #include "jstypes.h" #include "jsstdint.h" -#include "jsbit.h" #include "jsutil.h" #include "jsprf.h" #include "jsapi.h" #include "jsatom.h" #include "jscntxt.h" #include "jsversion.h" #include "jsemit.h" #include "jsexn.h" #include "jsnum.h" #include "jsopcode.h" #include "jsparse.h" #include "jsscan.h" #include "jsscript.h" #include "jsstaticcheck.h" -#include "jsvector.h" #include "vm/RegExpObject.h" #include "jsscriptinlines.h" #if JS_HAS_XML_SUPPORT #include "jsxml.h" #endif
--- a/js/src/jsscan.h +++ b/js/src/jsscan.h @@ -46,17 +46,18 @@ #include <stddef.h> #include <stdio.h> #include <stdarg.h> #include "jscntxt.h" #include "jsversion.h" #include "jsopcode.h" #include "jsprvtd.h" #include "jspubtd.h" -#include "jsvector.h" + +#include "js/Vector.h" #define JS_KEYWORD(keyword, type, op, version) \ extern const char js_##keyword##_str[]; #include "jskeyword.tbl" #undef JS_KEYWORD namespace js {
--- a/js/src/jsscope.cpp +++ b/js/src/jsscope.cpp @@ -41,17 +41,16 @@ /* * JS symbol tables. */ #include <new> #include <stdlib.h> #include <string.h> #include "jstypes.h" #include "jsstdint.h" -#include "jsbit.h" #include "jsclist.h" #include "jsdhash.h" #include "jsutil.h" #include "jsapi.h" #include "jsatom.h" #include "jscntxt.h" #include "jsdbgapi.h" #include "jslock.h" @@ -83,18 +82,17 @@ js_GenerateShape(JSRuntime *rt) * have a chance to wrap around shapeGen to zero. */ rt->shapeGen = SHAPE_OVERFLOW_BIT; shape = SHAPE_OVERFLOW_BIT; #ifdef JS_THREADSAFE AutoLockGC lockIf(rt); #endif - GCREASON(SHAPE); - TriggerGC(rt); + TriggerGC(rt, gcstats::SHAPE); } return shape; } uint32 js_GenerateShape(JSContext *cx) { return js_GenerateShape(cx->runtime); @@ -136,17 +134,17 @@ PropertyTable::init(JSRuntime *rt, Shape { /* * Either we're creating a table for a large scope that was populated * via property cache hit logic under JSOP_INITPROP, JSOP_SETNAME, or * JSOP_SETPROP; or else calloc failed at least once already. In any * event, let's try to grow, overallocating to hold at least twice the * current population. */ - uint32 sizeLog2 = JS_CeilingLog2(2 * entryCount); + uint32 sizeLog2 = JS_CEILING_LOG2W(2 * entryCount); if (sizeLog2 < MIN_SIZE_LOG2) sizeLog2 = MIN_SIZE_LOG2; /* * Use rt->calloc_ for memory accounting and overpressure handling * without OOM reporting. See PropertyTable::change. */ entries = (Shape **) rt->calloc_(sizeOfEntries(JS_BIT(sizeLog2)));
--- a/js/src/jsscope.h +++ b/js/src/jsscope.h @@ -47,22 +47,23 @@ #ifdef DEBUG #include <stdio.h> #endif #include "jstypes.h" #include "jscntxt.h" #include "jscompartment.h" -#include "jshashtable.h" #include "jsobj.h" #include "jsprvtd.h" #include "jspubtd.h" #include "jspropertytree.h" +#include "js/HashTable.h" + #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4800) #pragma warning(push) #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */ #endif /*
--- a/js/src/jsstaticcheck.h +++ b/js/src/jsstaticcheck.h @@ -35,91 +35,9 @@ * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef jsstaticcheck_h___ #define jsstaticcheck_h___ -#ifdef NS_STATIC_CHECKING -/* - * Trigger a control flow check to make sure that code flows through label - */ -inline __attribute__ ((unused)) void MUST_FLOW_THROUGH(const char *label) { -} - -/* avoid unused goto-label warnings */ -#define MUST_FLOW_LABEL(label) goto label; label: - -inline JS_FORCES_STACK void VOUCH_DOES_NOT_REQUIRE_STACK() {} - -inline JS_FORCES_STACK void -JS_ASSERT_NOT_ON_TRACE(JSContext *cx) -{ - JS_ASSERT(!JS_ON_TRACE(cx)); -} - -#else -#define MUST_FLOW_THROUGH(label) ((void) 0) -#define MUST_FLOW_LABEL(label) -#define VOUCH_DOES_NOT_REQUIRE_STACK() ((void) 0) -#define JS_ASSERT_NOT_ON_TRACE(cx) JS_ASSERT(!JS_ON_TRACE(cx)) -#endif -#define VOUCH_HAVE_STACK VOUCH_DOES_NOT_REQUIRE_STACK - -/* sixgill annotation defines */ - -/* Avoid name collision if included with other headers defining annotations. */ -#ifndef HAVE_STATIC_ANNOTATIONS -#define HAVE_STATIC_ANNOTATIONS - -#ifdef XGILL_PLUGIN - -#define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) -#define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND))) -#define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) -#define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND))) -#define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) -#define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) - -/* Used to make identifiers for assert/assume annotations in a function. */ -#define STATIC_PASTE2(X,Y) X ## Y -#define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y) - -#define STATIC_ASSERT(COND) \ - JS_BEGIN_MACRO \ - __attribute__((assert_static(#COND), unused)) \ - int STATIC_PASTE1(assert_static_, __COUNTER__); \ - JS_END_MACRO - -#define STATIC_ASSUME(COND) \ - JS_BEGIN_MACRO \ - __attribute__((assume_static(#COND), unused)) \ - int STATIC_PASTE1(assume_static_, __COUNTER__); \ - JS_END_MACRO - -#define STATIC_ASSERT_RUNTIME(COND) \ - JS_BEGIN_MACRO \ - __attribute__((assert_static_runtime(#COND), unused)) \ - int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \ - JS_END_MACRO - -#else /* XGILL_PLUGIN */ - -#define STATIC_PRECONDITION(COND) /* nothing */ -#define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ -#define STATIC_POSTCONDITION(COND) /* nothing */ -#define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ -#define STATIC_INVARIANT(COND) /* nothing */ -#define STATIC_INVARIANT_ASSUME(COND) /* nothing */ - -#define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO -#define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO -#define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO - -#endif /* XGILL_PLUGIN */ - -#define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) - -#endif /* HAVE_STATIC_ANNOTATIONS */ - #endif /* jsstaticcheck_h___ */
--- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -66,18 +66,16 @@ #include "jslock.h" #include "jsnum.h" #include "jsobj.h" #include "jsopcode.h" #include "jsprobes.h" #include "jsscope.h" #include "jsstaticcheck.h" #include "jsstr.h" -#include "jsbit.h" -#include "jsvector.h" #include "jsversion.h" #include "vm/GlobalObject.h" #include "vm/RegExpObject.h" #include "jsinferinlines.h" #include "jsobjinlines.h" #include "jsautooplen.h" // generated headers last
--- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -39,20 +39,20 @@ #ifndef jsstr_h___ #define jsstr_h___ #include <ctype.h> #include "jsapi.h" #include "jsatom.h" #include "jsprvtd.h" -#include "jshashtable.h" #include "jslock.h" #include "jscell.h" +#include "js/HashTable.h" #include "vm/Unicode.h" namespace js { /* Implemented in jsstrinlines.h */ class StringBuffer; /*
deleted file mode 100644 --- a/js/src/jstl.h +++ /dev/null @@ -1,447 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * vim: set ts=8 sw=4 et tw=99 ft=cpp: - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released - * July 16, 2009. - * - * The Initial Developer of the Original Code is - * the Mozilla Corporation. - * - * Contributor(s): - * Luke Wagner <lw@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef jstl_h_ -#define jstl_h_ - -#include "jsprvtd.h" -#include "jsbit.h" -#include "jsstaticcheck.h" -#include "jsstdint.h" - -#include <new> -#include <string.h> - -namespace js { - -/* JavaScript Template Library. */ -namespace tl { - -/* Compute min/max/clamp. */ -template <size_t i, size_t j> struct Min { - static const size_t result = i < j ? i : j; -}; -template <size_t i, size_t j> struct Max { - static const size_t result = i > j ? i : j; -}; -template <size_t i, size_t min, size_t max> struct Clamp { - static const size_t result = i < min ? min : (i > max ? max : i); -}; - -/* Compute x^y. */ -template <size_t x, size_t y> struct Pow { - static const size_t result = x * Pow<x, y - 1>::result; -}; -template <size_t x> struct Pow<x,0> { - static const size_t result = 1; -}; - -/* Compute floor(log2(i)). */ -template <size_t i> struct FloorLog2 { - static const size_t result = 1 + FloorLog2<i / 2>::result; -}; -template <> struct FloorLog2<0> { /* Error */ }; -template <> struct FloorLog2<1> { static const size_t result = 0; }; - -/* Compute ceiling(log2(i)). */ -template <size_t i> struct CeilingLog2 { - static const size_t result = FloorLog2<2 * i - 1>::result; -}; - -/* Round up to the nearest power of 2. */ -template <size_t i> struct RoundUpPow2 { - static const size_t result = 1u << CeilingLog2<i>::result; -}; -template <> struct RoundUpPow2<0> { - static const size_t result = 1; -}; - -/* Compute the number of bits in the given unsigned type. */ -template <class T> struct BitSize { - static const size_t result = sizeof(T) * JS_BITS_PER_BYTE; -}; - -/* Allow Assertions by only including the 'result' typedef if 'true'. */ -template <bool> struct StaticAssert {}; -template <> struct StaticAssert<true> { typedef int result; }; - -/* Boolean test for whether two types are the same. */ -template <class T, class U> struct IsSameType { - static const bool result = false; -}; -template <class T> struct IsSameType<T,T> { - static const bool result = true; -}; - -/* - * Produce an N-bit mask, where N <= BitSize<size_t>::result. Handle the - * language-undefined edge case when N = BitSize<size_t>::result. - */ -template <size_t N> struct NBitMask { - typedef typename StaticAssert<N < BitSize<size_t>::result>::result _; - static const size_t result = (size_t(1) << N) - 1; -}; -template <> struct NBitMask<BitSize<size_t>::result> { - static const size_t result = size_t(-1); -}; - -/* - * For the unsigned integral type size_t, compute a mask M for N such that - * for all X, !(X & M) implies X * N will not overflow (w.r.t size_t) - */ -template <size_t N> struct MulOverflowMask { - static const size_t result = - ~NBitMask<BitSize<size_t>::result - CeilingLog2<N>::result>::result; -}; -template <> struct MulOverflowMask<0> { /* Error */ }; -template <> struct MulOverflowMask<1> { static const size_t result = 0; }; - -/* - * Generate a mask for T such that if (X & sUnsafeRangeSizeMask), an X-sized - * array of T's is big enough to cause a ptrdiff_t overflow when subtracting - * a pointer to the end of the array from the beginning. - */ -template <class T> struct UnsafeRangeSizeMask { - /* - * The '2' factor means the top bit is clear, sizeof(T) converts from - * units of elements to bytes. - */ - static const size_t result = MulOverflowMask<2 * sizeof(T)>::result; -}; - -/* Return T stripped of any const-ness. */ -template <class T> struct StripConst { typedef T result; }; -template <class T> struct StripConst<const T> { typedef T result; }; - -/* - * Traits class for identifying POD types. Until C++0x, there is no automatic - * way to detect PODs, so for the moment it is done manually. - */ -template <class T> struct IsPodType { static const bool result = false; }; -template <> struct IsPodType<char> { static const bool result = true; }; -template <> struct IsPodType<signed char> { static const bool result = true; }; -template <> struct IsPodType<unsigned char> { static const bool result = true; }; -template <> struct IsPodType<short> { static const bool result = true; }; -template <> struct IsPodType<unsigned short> { static const bool result = true; }; -template <> struct IsPodType<int> { static const bool result = true; }; -template <> struct IsPodType<unsigned int> { static const bool result = true; }; -template <> struct IsPodType<long> { static const bool result = true; }; -template <> struct IsPodType<unsigned long> { static const bool result = true; }; -template <> struct IsPodType<long long> { static const bool result = true; }; -template <> struct IsPodType<unsigned long long> { static const bool result = true; }; -template <> struct IsPodType<float> { static const bool result = true; }; -template <> struct IsPodType<double> { static const bool result = true; }; -template <> struct IsPodType<wchar_t> { static const bool result = true; }; -template <typename T> struct IsPodType<T *> { static const bool result = true; }; - -/* Return the size/end of an array without using macros. */ -template <class T, size_t N> inline T *ArraySize(T (&)[N]) { return N; } -template <class T, size_t N> inline T *ArrayEnd(T (&arr)[N]) { return arr + N; } - -template <bool cond, typename T, T v1, T v2> struct If { static const T result = v1; }; -template <typename T, T v1, T v2> struct If<false, T, v1, v2> { static const T result = v2; }; - -} /* namespace tl */ - -/* Useful for implementing containers that assert non-reentrancy */ -class ReentrancyGuard -{ - /* ReentrancyGuard is not copyable. */ - ReentrancyGuard(const ReentrancyGuard &); - void operator=(const ReentrancyGuard &); - -#ifdef DEBUG - bool &entered; -#endif - public: - template <class T> -#ifdef DEBUG - ReentrancyGuard(T &obj) - : entered(obj.entered) -#else - ReentrancyGuard(T &/*obj*/) -#endif - { -#ifdef DEBUG - JS_ASSERT(!entered); - entered = true; -#endif - } - ~ReentrancyGuard() - { -#ifdef DEBUG - entered = false; -#endif - } -}; - -/* - * Round x up to the nearest power of 2. This function assumes that the most - * significant bit of x is not set, which would lead to overflow. - */ -STATIC_POSTCONDITION_ASSUME(return >= x) -JS_ALWAYS_INLINE size_t -RoundUpPow2(size_t x) -{ - size_t log2 = JS_CEILING_LOG2W(x); - JS_ASSERT(log2 < tl::BitSize<size_t>::result); - size_t result = size_t(1) << log2; - return result; -} - -template <class T> -class AlignedPtrAndFlag -{ - uintptr_t bits; - - public: - AlignedPtrAndFlag(T *t, bool flag) { - JS_ASSERT((uintptr_t(t) & 1) == 0); - bits = uintptr_t(t) | uintptr_t(flag); - } - - T *ptr() const { - return (T *)(bits & ~uintptr_t(1)); - } - - bool flag() const { - return (bits & 1) != 0; - } - - void setPtr(T *t) { - JS_ASSERT((uintptr_t(t) & 1) == 0); - bits = uintptr_t(t) | uintptr_t(flag()); - } - - void setFlag() { - bits |= 1; - } - - void unsetFlag() { - bits &= ~uintptr_t(1); - } - - void set(T *t, bool flag) { - JS_ASSERT((uintptr_t(t) & 1) == 0); - bits = uintptr_t(t) | flag; - } -}; - -template <class T> -static inline void -Reverse(T *beg, T *end) -{ - while (beg != end) { - if (--end == beg) - return; - T tmp = *beg; - *beg = *end; - *end = tmp; - ++beg; - } -} - -template <class T> -static inline T * -Find(T *beg, T *end, const T &v) -{ - for (T *p = beg; p != end; ++p) { - if (*p == v) - return p; - } - return end; -} - -template <class Container> -static inline typename Container::ElementType * -Find(Container &c, const typename Container::ElementType &v) -{ - return Find(c.begin(), c.end(), v); -} - -template <typename InputIterT, typename CallableT> -void -ForEach(InputIterT begin, InputIterT end, CallableT f) -{ - for (; begin != end; ++begin) - f(*begin); -} - -template <class T> -static inline T -Min(T t1, T t2) -{ - return t1 < t2 ? t1 : t2; -} - -template <class T> -static inline T -Max(T t1, T t2) -{ - return t1 > t2 ? t1 : t2; -} - -/* Allows a const variable to be initialized after its declaration. */ -template <class T> -static T& -InitConst(const T &t) -{ - return const_cast<T &>(t); -} - -template <class T, class U> -JS_ALWAYS_INLINE T & -ImplicitCast(U &u) -{ - T &t = u; - return t; -} - -template<typename T> -class AutoScopedAssign -{ - private: - JS_DECL_USE_GUARD_OBJECT_NOTIFIER - T *addr; - T old; - - public: - AutoScopedAssign(T *addr, const T &value JS_GUARD_OBJECT_NOTIFIER_PARAM) - : addr(addr), old(*addr) - { - JS_GUARD_OBJECT_NOTIFIER_INIT; - *addr = value; - } - - ~AutoScopedAssign() { *addr = old; } -}; - -template <class RefCountable> -class AlreadyIncRefed -{ - typedef RefCountable *****ConvertibleToBool; - - RefCountable *obj; - - public: - explicit AlreadyIncRefed(RefCountable *obj) : obj(obj) {} - - bool null() const { return obj == NULL; } - operator ConvertibleToBool() const { return (ConvertibleToBool)obj; } - - RefCountable *operator->() const { JS_ASSERT(!null()); return obj; } - RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; } - RefCountable *get() const { return obj; } -}; - -template <class RefCountable> -class NeedsIncRef -{ - typedef RefCountable *****ConvertibleToBool; - - RefCountable *obj; - - public: - explicit NeedsIncRef(RefCountable *obj) : obj(obj) {} - - bool null() const { return obj == NULL; } - operator ConvertibleToBool() const { return (ConvertibleToBool)obj; } - - RefCountable *operator->() const { JS_ASSERT(!null()); return obj; } - RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; } - RefCountable *get() const { return obj; } -}; - -template <class RefCountable> -class AutoRefCount -{ - typedef RefCountable *****ConvertibleToBool; - - JSContext *const cx; - RefCountable *obj; - - AutoRefCount(const AutoRefCount &); - void operator=(const AutoRefCount &); - - public: - explicit AutoRefCount(JSContext *cx) - : cx(cx), obj(NULL) - {} - - AutoRefCount(JSContext *cx, NeedsIncRef<RefCountable> aobj) - : cx(cx), obj(aobj.get()) - { - if (obj) - obj->incref(cx); - } - - AutoRefCount(JSContext *cx, AlreadyIncRefed<RefCountable> aobj) - : cx(cx), obj(aobj.get()) - {} - - ~AutoRefCount() { - if (obj) - obj->decref(cx); - } - - void reset(NeedsIncRef<RefCountable> aobj) { - if (obj) - obj->decref(cx); - obj = aobj.get(); - if (obj) - obj->incref(cx); - } - - void reset(AlreadyIncRefed<RefCountable> aobj) { - if (obj) - obj->decref(cx); - obj = aobj.get(); - } - - bool null() const { return obj == NULL; } - operator ConvertibleToBool() const { return (ConvertibleToBool)obj; } - - RefCountable *operator->() const { JS_ASSERT(!null()); return obj; } - RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; } - RefCountable *get() const { return obj; } -}; - -} /* namespace js */ - -#endif /* jstl_h_ */
--- a/js/src/jstracer.cpp +++ b/js/src/jstracer.cpp @@ -35,17 +35,16 @@ * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "jsstdint.h" -#include "jsbit.h" // low-level (NSPR-based) headers next #include "jsprf.h" #include <math.h> // standard headers next #if defined(_MSC_VER) || defined(__MINGW32__) #include <malloc.h> #ifdef _MSC_VER #define alloca _alloca #endif @@ -70,17 +69,16 @@ #include "jsinterp.h" #include "jsiter.h" #include "jsmath.h" #include "jsobj.h" #include "jsopcode.h" #include "jsscope.h" #include "jsscript.h" #include "jsstaticcheck.h" -#include "jstl.h" #include "jstracer.h" #include "jsxml.h" #include "jstypedarray.h" #include "builtin/RegExp.h" #include "jsatominlines.h" #include "jscntxtinlines.h" @@ -7934,32 +7932,32 @@ FinishJIT() JS_REQUIRES_STACK void PurgeScriptFragments(TraceMonitor* tm, JSScript* script) { debug_only_printf(LC_TMTracer, "Purging fragments for JSScript %p.\n", (void*)script); /* A recorder script is being evaluated and can not be destroyed or GC-ed. */ JS_ASSERT_IF(tm->recorder, - JS_UPTRDIFF(tm->recorder->getTree()->ip, script->code) >= script->length); + UnsignedPtrDiff(tm->recorder->getTree()->ip, script->code) >= script->length); for (LoopProfileMap::Enum e(*tm->loopProfiles); !e.empty(); e.popFront()) { - if (JS_UPTRDIFF(e.front().key, script->code) < script->length) + if (UnsignedPtrDiff(e.front().key, script->code) < script->length) e.removeFront(); } TracedScriptSet::Ptr found = tm->tracedScripts.lookup(script); if (!found) return; tm->tracedScripts.remove(found); for (size_t i = 0; i < FRAGMENT_TABLE_SIZE; ++i) { TreeFragment** fragp = &tm->vmfragments[i]; while (TreeFragment* frag = *fragp) { - if (JS_UPTRDIFF(frag->ip, script->code) < script->length) { + if (UnsignedPtrDiff(frag->ip, script->code) < script->length) { /* This fragment is associated with the script. */ debug_only_printf(LC_TMTracer, "Disconnecting TreeFragment %p " "with ip %p, in range [%p,%p).\n", (void*)frag, frag->ip, script->code, script->code + script->length); JS_ASSERT(frag->root == frag); @@ -7971,17 +7969,17 @@ PurgeScriptFragments(TraceMonitor* tm, J continue; } fragp = &frag->next; } } RecordAttemptMap &table = *tm->recordAttempts; for (RecordAttemptMap::Enum e(table); !e.empty(); e.popFront()) { - if (JS_UPTRDIFF(e.front().key, script->code) < script->length) + if (UnsignedPtrDiff(e.front().key, script->code) < script->length) e.removeFront(); } } bool OverfullJITCache(JSContext *cx, TraceMonitor* tm) { /*
--- a/js/src/jstracer.h +++ b/js/src/jstracer.h @@ -46,17 +46,16 @@ #include "jstypes.h" #include "jsbuiltins.h" #include "jscntxt.h" #include "jsdhash.h" #include "jsinterp.h" #include "jslock.h" #include "jsnum.h" -#include "jsvector.h" #include "jscompartment.h" #include "Writer.h" namespace js { template <typename T> class Queue { T* _data;
--- a/js/src/jstypedarray.cpp +++ b/js/src/jstypedarray.cpp @@ -53,18 +53,16 @@ #include "jsversion.h" #include "jsgc.h" #include "jsgcmark.h" #include "jsinterp.h" #include "jslock.h" #include "jsnum.h" #include "jsobj.h" #include "jsstaticcheck.h" -#include "jsbit.h" -#include "jsvector.h" #include "jstypedarray.h" #include "jsutil.h" #include "vm/GlobalObject.h" #include "jsatominlines.h" #include "jsinferinlines.h" #include "jsobjinlines.h"
--- a/js/src/jsutil.cpp +++ b/js/src/jsutil.cpp @@ -103,17 +103,16 @@ JS_PUBLIC_API(void) JS_Assert(const char CrashInJS(); } #ifdef JS_BASIC_STATS #include <math.h> #include <string.h> #include "jscompat.h" -#include "jsbit.h" /* * Histogram bins count occurrences of values <= the bin label, as follows: * * linear: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or more * 2**x: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or more * 10**x: 0, 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 or more * @@ -137,17 +136,17 @@ ValToBin(uintN logscale, uint32 val) { uintN bin; if (val <= 1) return val; bin = (logscale == 10) ? (uintN) ceil(log10((double) val)) : (logscale == 2) - ? (uintN) JS_CeilingLog2(val) + ? (uintN) JS_CEILING_LOG2W(val) : val; return JS_MIN(bin, 10); } void JS_BasicStatsAccum(JSBasicStats *bs, uint32 val) { uintN oldscale, newscale, bin; @@ -238,161 +237,17 @@ JS_DumpHistogram(JSBasicStats *bs, FILE fprintf(fp, "[%6u, %6u]", val, end - 1); else fprintf(fp, "[%6u, +inf]", val); fprintf(fp, ": %8u ", cnt); if (cnt != 0) { if (max > 1e6 && mean > 1e3) cnt = (uint32) ceil(log10((double) cnt)); else if (max > 16 && mean > 8) - cnt = JS_CeilingLog2(cnt); + cnt = JS_CEILING_LOG2W(cnt); for (uintN i = 0; i < cnt; i++) putc('*', fp); } putc('\n', fp); } } #endif /* JS_BASIC_STATS */ - -#if defined(DEBUG_notme) && defined(XP_UNIX) - -#define __USE_GNU 1 -#include <dlfcn.h> -#include <string.h> -#include "jshash.h" -#include "jsprf.h" - -JSCallsite js_calltree_root = {0, NULL, NULL, 0, NULL, NULL, NULL, NULL}; - -static JSCallsite * -CallTree(void **bp) -{ - void **bpup, **bpdown, *pc; - JSCallsite *parent, *site, **csp; - Dl_info info; - int ok, offset; - const char *symbol; - char *method; - - /* Reverse the stack frame list to avoid recursion. */ - bpup = NULL; - for (;;) { - bpdown = (void**) bp[0]; - bp[0] = (void*) bpup; - if ((void**) bpdown[0] < bpdown) - break; - bpup = bp; - bp = bpdown; - } - - /* Reverse the stack again, finding and building a path in the tree. */ - parent = &js_calltree_root; - do { - bpup = (void**) bp[0]; - bp[0] = (void*) bpdown; - pc = bp[1]; - - csp = &parent->kids; - while ((site = *csp) != NULL) { - if (site->pc == (uint32)pc) { - /* Put the most recently used site at the front of siblings. */ - *csp = site->siblings; - site->siblings = parent->kids; - parent->kids = site; - - /* Site already built -- go up the stack. */ - goto upward; - } - csp = &site->siblings; - } - - /* Check for recursion: see if pc is on our ancestor line. */ - for (site = parent; site; site = site->parent) { - if (site->pc == (uint32)pc) - goto upward; - } - - /* - * Not in tree at all: let's find our symbolic callsite info. - * XXX static syms are masked by nearest lower global - */ - info.dli_fname = info.dli_sname = NULL; - ok = dladdr(pc, &info); - if (ok < 0) { - fprintf(stderr, "dladdr failed!\n"); - return NULL; - } - -/* XXXbe sub 0x08040000? or something, see dbaron bug with tenthumbs comment */ - symbol = info.dli_sname; - offset = (char*)pc - (char*)info.dli_fbase; - method = symbol - ? strdup(symbol) - : JS_smprintf("%s+%X", - info.dli_fname ? info.dli_fname : "main", - offset); - if (!method) - return NULL; - - /* Create a new callsite record. */ - site = (JSCallsite *) OffTheBooks::malloc(sizeof(JSCallsite)); - if (!site) - return NULL; - - /* Insert the new site into the tree. */ - site->pc = (uint32)pc; - site->name = method; - site->library = info.dli_fname; - site->offset = offset; - site->parent = parent; - site->siblings = parent->kids; - parent->kids = site; - site->kids = NULL; -