diff --git a/CLOBBER b/CLOBBER index ab9b2f944106..032a934f2f9f 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,4 +22,4 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 958889 moves files into the new mobile/android/base/tabspanel/ package. +Bug 1003702 - ICU is unhappy. diff --git a/accessible/src/jsat/OutputGenerator.jsm b/accessible/src/jsat/OutputGenerator.jsm index 0fd7fd74b68b..f606aebf8e88 100644 --- a/accessible/src/jsat/OutputGenerator.jsm +++ b/accessible/src/jsat/OutputGenerator.jsm @@ -597,6 +597,14 @@ this.UtteranceGenerator = { rowheader: function rowheader() { return this.objectOutputFunctions.cell.apply(this, arguments); + }, + + statictext: function statictext(aAccessible) { + if (Utils.isListItemDecorator(aAccessible, true)) { + return []; + } + + return this.objectOutputFunctions.defaultFunc.apply(this, arguments); } }, @@ -778,7 +786,7 @@ this.BrailleGenerator = { statictext: function statictext(aAccessible, aRoleStr, aState, aFlags) { // Since we customize the list bullet's output, we add the static // text from the first node in each listitem, so skip it here. - if (aAccessible.parent.role == Roles.LISTITEM) { + if (Utils.isListItemDecorator(aAccessible)) { return []; } diff --git a/accessible/src/jsat/TraversalRules.jsm b/accessible/src/jsat/TraversalRules.jsm index 529ebe569894..95cca9b3e93a 100644 --- a/accessible/src/jsat/TraversalRules.jsm +++ b/accessible/src/jsat/TraversalRules.jsm @@ -2,6 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* global PrefCache, Roles, Prefilters, States, Filters, Utils, + TraversalRules */ +/* exported TraversalRules */ + 'use strict'; const Cc = Components.classes; @@ -9,17 +13,17 @@ const Ci = Components.interfaces; const Cu = Components.utils; const Cr = Components.results; -this.EXPORTED_SYMBOLS = ['TraversalRules']; +this.EXPORTED_SYMBOLS = ['TraversalRules']; // jshint ignore:line Cu.import('resource://gre/modules/accessibility/Utils.jsm'); Cu.import('resource://gre/modules/XPCOMUtils.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, 'Roles', +XPCOMUtils.defineLazyModuleGetter(this, 'Roles', // jshint ignore:line 'resource://gre/modules/accessibility/Constants.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, 'Filters', +XPCOMUtils.defineLazyModuleGetter(this, 'Filters', // jshint ignore:line 'resource://gre/modules/accessibility/Constants.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, 'States', +XPCOMUtils.defineLazyModuleGetter(this, 'States', // jshint ignore:line 'resource://gre/modules/accessibility/Constants.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, 'Prefilters', +XPCOMUtils.defineLazyModuleGetter(this, 'Prefilters', // jshint ignore:line 'resource://gre/modules/accessibility/Constants.jsm'); let gSkipEmptyImages = new PrefCache('accessibility.accessfu.skip_empty_images'); @@ -30,7 +34,7 @@ function BaseTraversalRule(aRoles, aMatchFunc, aPreFilter) { if (aRoles.indexOf(Roles.LABEL) < 0) { this._matchRoles.push(Roles.LABEL); } - this._matchFunc = aMatchFunc || function (acc) { return Filters.MATCH; }; + this._matchFunc = aMatchFunc || function() { return Filters.MATCH; }; this.preFilter = aPreFilter || gSimplePreFilter; } @@ -91,17 +95,28 @@ var gSimpleTraversalRoles = Roles.SLIDER, Roles.SPINBUTTON, Roles.OPTION, + Roles.LISTITEM, // Used for traversing in to child OOP frames. Roles.INTERNAL_FRAME]; var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) { - function hasZeroOrSingleChildDescendants () { - for (let acc = aAccessible; acc.childCount > 0; acc = acc.firstChild) { - if (acc.childCount > 1) { + // An object is simple, if it either has a single child lineage, + // or has a flat subtree. + function isSingleLineage(acc) { + for (let child = acc; child; child = child.firstChild) { + if (child.childCount > 1) { return false; } } + return true; + } + function isFlatSubtree(acc) { + for (let child = acc.firstChild; child; child = child.nextSibling) { + if (child.childCount > 0) { + return false; + } + } return true; } @@ -114,30 +129,28 @@ var gSimpleMatchFunc = function gSimpleMatchFunc(aAccessible) { { // Nameless text leaves are boring, skip them. let name = aAccessible.name; - if (name && name.trim()) - return Filters.MATCH; - else - return Filters.IGNORE; + return (name && name.trim()) ? Filters.MATCH : Filters.IGNORE; } case Roles.STATICTEXT: - { - let parent = aAccessible.parent; - // Ignore prefix static text in list items. They are typically bullets or numbers. - if (parent.childCount > 1 && aAccessible.indexInParent == 0 && - parent.role == Roles.LISTITEM) - return Filters.IGNORE; - - return Filters.MATCH; - } + // Ignore prefix static text in list items. They are typically bullets or numbers. + return Utils.isListItemDecorator(aAccessible) ? + Filters.IGNORE : Filters.MATCH; case Roles.GRAPHIC: return TraversalRules._shouldSkipImage(aAccessible); case Roles.HEADER: case Roles.HEADING: if ((aAccessible.childCount > 0 || aAccessible.name) && - hasZeroOrSingleChildDescendants()) { + (isSingleLineage(aAccessible) || isFlatSubtree(aAccessible))) { return Filters.MATCH | Filters.IGNORE_SUBTREE; - } else { - return Filters.IGNORE; + } + return Filters.IGNORE; + case Roles.LISTITEM: + { + let item = aAccessible.childCount === 2 && + aAccessible.firstChild.role === Roles.STATICTEXT ? + aAccessible.lastChild : aAccessible; + return isSingleLineage(item) || isFlatSubtree(item) ? + Filters.MATCH | Filters.IGNORE_SUBTREE : Filters.IGNORE; } default: // Ignore the subtree, if there is one. So that we don't land on @@ -152,7 +165,7 @@ var gSimplePreFilter = Prefilters.DEFUNCT | Prefilters.ARIA_HIDDEN | Prefilters.TRANSPARENT; -this.TraversalRules = { +this.TraversalRules = { // jshint ignore:line Simple: new BaseTraversalRule(gSimpleTraversalRoles, gSimpleMatchFunc), SimpleOnScreen: new BaseTraversalRule( diff --git a/accessible/src/jsat/Utils.jsm b/accessible/src/jsat/Utils.jsm index ea61d5dbe01e..e273dc141f7a 100644 --- a/accessible/src/jsat/Utils.jsm +++ b/accessible/src/jsat/Utils.jsm @@ -343,6 +343,17 @@ this.Utils = { } return null; + }, + + isListItemDecorator: function isListItemDecorator(aStaticText, + aExcludeOrdered) { + let parent = aStaticText.parent; + if (aExcludeOrdered && parent.parent.DOMNode.nodeName === 'OL') { + return false; + } + + return parent.role === Roles.LISTITEM && parent.childCount > 1 && + aStaticText.indexInParent === 0; } }; diff --git a/accessible/tests/mochitest/jsat/test_output.html b/accessible/tests/mochitest/jsat/test_output.html index 9ae0cbf35946..f9cc5aa126e3 100644 --- a/accessible/tests/mochitest/jsat/test_output.html +++ b/accessible/tests/mochitest/jsat/test_output.html @@ -92,6 +92,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984 ["1.", "list one"], ["1.", "list one"] ] + }, + { + accOrElmOrID: "li_two", + expectedUtterance: [ + ["list 1 item", "First item", "list two"], + ["list two", "First item", "list 1 item"] + ], + expectedBraille: [ + ["*", "list two"], + ["*", "list two"] + ] }, { accOrElmOrID: "cell", expectedUtterance: [[ @@ -339,8 +350,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984 ["I am pressed!", "pressed toggle button"]], expectedBraille: [["(x)", "I am pressed!"], ["I am pressed!", "(x)"]] - } - ]; + }, { + accOrElmOrID: "listbox-option", + expectedUtterance: [["list box", "option", "Search suggestion"], + ["Search suggestion", "option", "list box"]], + expectedBraille: [["option", "Search suggestion"], + ["Search suggestion", "option"]] + }]; // Test all possible utterance order preference values. tests.forEach(function run(test) { @@ -402,6 +418,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
  1. list one
+
dd one @@ -454,6 +473,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=753984
I ain't pressed
I am pressed!
+ diff --git a/accessible/tests/mochitest/jsat/test_traversal.html b/accessible/tests/mochitest/jsat/test_traversal.html index f1685b556731..fd6f6b9abeb0 100644 --- a/accessible/tests/mochitest/jsat/test_traversal.html +++ b/accessible/tests/mochitest/jsat/test_traversal.html @@ -111,8 +111,8 @@ 'A esoteric weapon wielded by only the most ' + 'formidable warriors, for its unrelenting strict' + ' power is unfathomable.', - 'Lists of Programming Languages', 'Lisp ', - 'Scheme', 'Racket', 'Clojure', 'JavaScript', 'heading-5', + '• Lists of Programming Languages', 'Lisp ', + '1. Scheme', '2. Racket', '3. Clojure', '• JavaScript', 'heading-5', 'image-2', 'image-3', 'Not actually an image', 'link-1', 'anchor-1', 'link-2', 'anchor-2', 'link-3', '3', '1', '4', '1', 'Just an innocuous separator', diff --git a/browser/components/customizableui/content/panelUI.js b/browser/components/customizableui/content/panelUI.js index f69ce5751f1a..11740856761e 100644 --- a/browser/components/customizableui/content/panelUI.js +++ b/browser/components/customizableui/content/panelUI.js @@ -363,17 +363,6 @@ const PanelUI = { } }, - /** - * Open a dialog window that allow the user to customize listed character sets. - */ - onCharsetCustomizeCommand: function() { - this.hide(); - window.openDialog("chrome://global/content/customizeCharset.xul", - "PrefWindow", - "chrome,modal=yes,resizable=yes", - "browser"); - }, - onWidgetAfterDOMChange: function(aNode, aNextNode, aContainer, aWasRemoval) { if (aContainer != this.contents) { return; diff --git a/build/autoconf/config.status.m4 b/build/autoconf/config.status.m4 index 06114364b69c..5ae1dc5e6a1b 100644 --- a/build/autoconf/config.status.m4 +++ b/build/autoconf/config.status.m4 @@ -181,11 +181,12 @@ EOF fi changequote([, ]) + +chmod +x $CONFIG_STATUS ]) define([MOZ_RUN_CONFIG_STATUS], [ -chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files dnl Execute config.status, unless --no-create was passed to configure. if test "$no_create" != yes && ! ${PYTHON} $CONFIG_STATUS; then diff --git a/build/autoconf/icu.m4 b/build/autoconf/icu.m4 index de6e34585f1b..12f3b431f7a3 100644 --- a/build/autoconf/icu.m4 +++ b/build/autoconf/icu.m4 @@ -147,6 +147,9 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_TRANSLITERATION" ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_REGULAR_EXPRESSIONS" ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_BREAK_ITERATION" + ICU_CPPFLAGS="$ICU_CPPFLAGS -DUCONFIG_NO_IDNA" + # we don't need to pass data to and from legacy char* APIs + ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_CHARSET_IS_UTF8" # make sure to not accidentally pick up system-icu headers ICU_CPPFLAGS="$ICU_CPPFLAGS -I$icudir/common -I$icudir/i18n" diff --git a/caps/src/nsSecurityManagerFactory.cpp b/caps/src/nsSecurityManagerFactory.cpp index a57ea3b7a594..711c60aba8e7 100644 --- a/caps/src/nsSecurityManagerFactory.cpp +++ b/caps/src/nsSecurityManagerFactory.cpp @@ -99,11 +99,10 @@ nsSecurityNameSet::InitializeNameSet(nsIScriptContext* aScriptContext) securityObj = &v.toObject(); } else { /* define netscape.security object */ - obj = JS_DefineObject(cx, global, "netscape", objectClass, nullptr, 0); + obj = JS_DefineObject(cx, global, "netscape", objectClass); if (obj == nullptr) return NS_ERROR_FAILURE; - securityObj = JS_DefineObject(cx, obj, "security", objectClass, - nullptr, 0); + securityObj = JS_DefineObject(cx, obj, "security", objectClass); if (securityObj == nullptr) return NS_ERROR_FAILURE; } @@ -118,8 +117,7 @@ nsSecurityNameSet::InitializeNameSet(nsIScriptContext* aScriptContext) return NS_OK; /* Define PrivilegeManager object with the necessary "static" methods. */ - obj = JS_DefineObject(cx, securityObj, "PrivilegeManager", objectClass, - nullptr, 0); + obj = JS_DefineObject(cx, securityObj, "PrivilegeManager", objectClass); if (obj == nullptr) return NS_ERROR_FAILURE; diff --git a/configure.in b/configure.in index 9be1c6900840..e8862e9b9078 100644 --- a/configure.in +++ b/configure.in @@ -2548,114 +2548,17 @@ dnl Check for .hidden assembler directive and visibility attribute. dnl Borrowed from glibc configure.in dnl =============================================================== if test "$GNU_CC"; then - AC_CACHE_CHECK(for visibility(hidden) attribute, - ac_cv_visibility_hidden, - [cat > conftest.c </dev/null 2>&1; then - if egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then - ac_cv_visibility_hidden=yes - fi - fi - rm -f conftest.[cs] - ]) - if test "$ac_cv_visibility_hidden" = "yes"; then - AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE) - - AC_CACHE_CHECK(for visibility(default) attribute, - ac_cv_visibility_default, - [cat > conftest.c </dev/null 2>&1; then - if ! egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then - ac_cv_visibility_default=yes - fi - fi - rm -f conftest.[cs] - ]) - if test "$ac_cv_visibility_default" = "yes"; then - AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE) - - AC_CACHE_CHECK(for visibility pragma support, - ac_cv_visibility_pragma, - [cat > conftest.c </dev/null 2>&1; then - if egrep '\.(hidden|private_extern).*foo_hidden' conftest.s >/dev/null; then - if ! egrep '\.(hidden|private_extern).*foo_default' conftest.s > /dev/null; then - ac_cv_visibility_pragma=yes - fi - fi - fi - rm -f conftest.[cs] - ]) - if test "$ac_cv_visibility_pragma" = "yes"; then - AC_CACHE_CHECK(For gcc visibility bug with class-level attributes (GCC bug 26905), - ac_cv_have_visibility_class_bug, - [cat > conftest.c < /dev/null 2>&1 ; then - ac_cv_have_visibility_class_bug=yes - else - if test `egrep -c '@PLT|\\$stub' conftest.S` = 0; then - ac_cv_have_visibility_class_bug=yes - fi - fi - rm -rf conftest.{c,S} - ]) - - AC_CACHE_CHECK(For x86_64 gcc visibility bug with builtins (GCC bug 20297), - ac_cv_have_visibility_builtin_bug, - [cat > conftest.c < -#pragma GCC visibility pop - -__attribute__ ((visibility ("default"))) void Func() { - char c[[100]]; - memset(c, 0, sizeof(c)); -} -EOF - ac_cv_have_visibility_builtin_bug=no - if ! ${CC-cc} ${CFLAGS} ${DSO_PIC_CFLAGS} ${DSO_LDOPTS} -O2 -S -o conftest.S conftest.c > /dev/null 2>&1 ; then - ac_cv_have_visibility_builtin_bug=yes - else - if test `grep -c "@PLT" conftest.S` = 0; then - ac_cv_visibility_builtin_bug=yes - fi - fi - rm -f conftest.{c,S} - ]) - if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \ - "$ac_cv_have_visibility_class_bug" = "no"; then - VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h' - WRAP_SYSTEM_INCLUDES=1 - STL_FLAGS='-I$(DIST)/stl_wrappers' - WRAP_STL_INCLUDES=1 - else - VISIBILITY_FLAGS='-fvisibility=hidden' - fi # have visibility pragma bug - fi # have visibility pragma - fi # have visibility(default) attribute - fi # have visibility(hidden) attribute + AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE) + AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE) + case "${OS_TARGET}" in + Darwin|Android) + VISIBILITY_FLAGS='-fvisibility=hidden' + ;; + *) + VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h' + WRAP_SYSTEM_INCLUDES=1 + ;; + esac fi # GNU_CC # visibility hidden flag for Sun Studio on Solaris @@ -2663,6 +2566,15 @@ if test "$SOLARIS_SUNPRO_CC"; then VISIBILITY_FLAGS='-xldscope=hidden' fi # Sun Studio on Solaris +case "${OS_TARGET}" in +WINNT|Darwin|Android) + ;; +*) + STL_FLAGS='-I$(DIST)/stl_wrappers' + WRAP_STL_INCLUDES=1 + ;; +esac + AC_SUBST(WRAP_SYSTEM_INCLUDES) AC_SUBST(VISIBILITY_FLAGS) @@ -5955,6 +5867,11 @@ case "$OS_TARGET" in Darwin|WINNT|Linux) MOZ_GAMEPAD=1 ;; + Android) + if test "$MOZ_WIDGET_TOOLKIT" != "gonk"; then + MOZ_GAMEPAD=1 + fi + ;; *) ;; esac @@ -5979,6 +5896,9 @@ if test "$MOZ_GAMEPAD"; then fi MOZ_GAMEPAD_BACKEND=linux ;; + Android) + MOZ_GAMEPAD_BACKEND=android + ;; *) ;; esac diff --git a/content/base/src/DOMImplementation.cpp b/content/base/src/DOMImplementation.cpp index e8e2bbc3b6b0..ad9a2c47e861 100644 --- a/content/base/src/DOMImplementation.cpp +++ b/content/base/src/DOMImplementation.cpp @@ -23,7 +23,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMImplementation) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMImplementation, mOwner) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMImplementation, mOwner) NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMImplementation) NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMImplementation) diff --git a/content/base/src/DOMParser.cpp b/content/base/src/DOMParser.cpp index 65762036c45d..98908733dddb 100644 --- a/content/base/src/DOMParser.cpp +++ b/content/base/src/DOMParser.cpp @@ -38,7 +38,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMParser) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMParser, mOwner) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMParser, mOwner) NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMParser) NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMParser) diff --git a/content/base/src/DOMPoint.cpp b/content/base/src/DOMPoint.cpp index 777be174d2ce..b5cd255403b9 100644 --- a/content/base/src/DOMPoint.cpp +++ b/content/base/src/DOMPoint.cpp @@ -12,7 +12,7 @@ using namespace mozilla; using namespace mozilla::dom; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMPoint, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMPoint, mParent) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMPoint, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMPoint, Release) diff --git a/content/base/src/DOMQuad.cpp b/content/base/src/DOMQuad.cpp index 2cfceee703c5..6d1b1b6d4eaa 100644 --- a/content/base/src/DOMQuad.cpp +++ b/content/base/src/DOMQuad.cpp @@ -14,8 +14,8 @@ using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::gfx; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_6(DOMQuad, mParent, mBounds, mPoints[0], - mPoints[1], mPoints[2], mPoints[3]) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMQuad, mParent, mBounds, mPoints[0], + mPoints[1], mPoints[2], mPoints[3]) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMQuad, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMQuad, Release) diff --git a/content/base/src/DOMRect.cpp b/content/base/src/DOMRect.cpp index b26414b6e291..7541fbb75db3 100644 --- a/content/base/src/DOMRect.cpp +++ b/content/base/src/DOMRect.cpp @@ -12,7 +12,7 @@ using namespace mozilla; using namespace mozilla::dom; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMRectReadOnly, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMRectReadOnly, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMRectReadOnly) NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMRectReadOnly) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMRectReadOnly) @@ -72,7 +72,7 @@ DOMRect::Constructor(const GlobalObject& aGlobal, double aX, double aY, // ----------------------------------------------------------------------------- -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(DOMRectList, mParent, mArray) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMRectList, mParent, mArray) NS_INTERFACE_TABLE_HEAD(DOMRectList) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index f4ce2a798318..6f04aea5439d 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -2874,8 +2874,7 @@ TestSitePerm(nsIPrincipal* aPrincipal, const char* aType, uint32_t aPerm, bool a return aPerm != nsIPermissionManager::ALLOW_ACTION; } - nsCOMPtr permMgr = - do_GetService("@mozilla.org/permissionmanager;1"); + nsCOMPtr permMgr = services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, false); uint32_t perm; diff --git a/content/base/src/nsDOMCaretPosition.cpp b/content/base/src/nsDOMCaretPosition.cpp index 8ea6b0007ea0..24bbac837460 100644 --- a/content/base/src/nsDOMCaretPosition.cpp +++ b/content/base/src/nsDOMCaretPosition.cpp @@ -62,8 +62,8 @@ nsDOMCaretPosition::WrapObject(JSContext *aCx) return mozilla::dom::CaretPositionBinding::Wrap(aCx, this); } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsDOMCaretPosition, - mOffsetNode, mAnonymousContentNode) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCaretPosition, + mOffsetNode, mAnonymousContentNode) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCaretPosition) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCaretPosition) diff --git a/content/base/src/nsDOMMutationObserver.cpp b/content/base/src/nsDOMMutationObserver.cpp index 50d89554f7dd..53443aba146a 100644 --- a/content/base/src/nsDOMMutationObserver.cpp +++ b/content/base/src/nsDOMMutationObserver.cpp @@ -52,11 +52,11 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMMutationRecord) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMMutationRecord) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_7(nsDOMMutationRecord, - mTarget, - mPreviousSibling, mNextSibling, - mAddedNodes, mRemovedNodes, - mNext, mOwner) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMMutationRecord, + mTarget, + mPreviousSibling, mNextSibling, + mAddedNodes, mRemovedNodes, + mNext, mOwner) // Observer diff --git a/content/base/src/nsDOMSerializer.cpp b/content/base/src/nsDOMSerializer.cpp index ce8825215dec..8998a8347a73 100644 --- a/content/base/src/nsDOMSerializer.cpp +++ b/content/base/src/nsDOMSerializer.cpp @@ -32,7 +32,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMSerializer) NS_INTERFACE_MAP_ENTRY(nsIDOMSerializer) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMSerializer, mOwner) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMSerializer, mOwner) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMSerializer) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMSerializer) diff --git a/content/base/src/nsDOMTokenList.cpp b/content/base/src/nsDOMTokenList.cpp index c242a83486ef..80254fe09475 100644 --- a/content/base/src/nsDOMTokenList.cpp +++ b/content/base/src/nsDOMTokenList.cpp @@ -29,7 +29,7 @@ nsDOMTokenList::nsDOMTokenList(Element* aElement, nsIAtom* aAttrAtom) nsDOMTokenList::~nsDOMTokenList() { } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMTokenList, mElement) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMTokenList, mElement) NS_INTERFACE_MAP_BEGIN(nsDOMTokenList) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index cece6ef2baaf..f6ce3d57d9f3 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -12155,10 +12155,11 @@ nsIDocument::WrapObject(JSContext *aCx) NS_NAMED_LITERAL_STRING(doc_str, "document"); - if (!JS_DefineUCProperty(aCx, winVal.toObjectOrNull(), doc_str.get(), - doc_str.Length(), JS::ObjectValue(*obj), - JS_PropertyStub, JS_StrictPropertyStub, - JSPROP_READONLY | JSPROP_ENUMERATE)) { + JS::Rooted winObj(aCx, &winVal.toObject()); + if (!JS_DefineUCProperty(aCx, winObj, doc_str.get(), + doc_str.Length(), obj, + JSPROP_READONLY | JSPROP_ENUMERATE, + JS_PropertyStub, JS_StrictPropertyStub)) { return nullptr; } diff --git a/content/base/src/nsFormData.cpp b/content/base/src/nsFormData.cpp index 41fa252f8aca..c5bd9edba32d 100644 --- a/content/base/src/nsFormData.cpp +++ b/content/base/src/nsFormData.cpp @@ -22,7 +22,7 @@ nsFormData::nsFormData(nsISupports* aOwner) // ------------------------------------------------------------------------- // nsISupports -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsFormData, mOwner) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsFormData, mOwner) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsFormData) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormData) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsFormData) diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index 7a87073c5c71..c9e1972ea904 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -2616,7 +2616,7 @@ nsFrameLoader::ResetPermissionManagerStatus() return; } - nsCOMPtr permMgr = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + nsCOMPtr permMgr = services::GetPermissionManager(); if (!permMgr) { NS_ERROR("No PermissionManager available!"); return; diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index b398301e471f..80b82c02fa7d 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -24,6 +24,7 @@ #include "nsPluginHost.h" #include "nsPluginInstanceOwner.h" #include "nsJSNPRuntime.h" +#include "nsINestedURI.h" #include "nsIPresShell.h" #include "nsIScriptGlobalObject.h" #include "nsScriptSecurityManager.h" @@ -2025,6 +2026,31 @@ nsObjectLoadingContent::LoadObject(bool aNotify, } } + // Don't allow view-source scheme. + // view-source is the only scheme to which this applies at the moment due to + // potential timing attacks to read data from cross-origin documents. If this + // widens we should add a protocol flag for whether the scheme is only allowed + // in top and use something like nsNetUtil::NS_URIChainHasFlags. + if (mType != eType_Null) { + nsCOMPtr tempURI = mURI; + nsCOMPtr nestedURI = do_QueryInterface(tempURI); + while (nestedURI) { + // view-source should always be an nsINestedURI, loop and check the + // scheme on this and all inner URIs that are also nested URIs. + bool isViewSource = false; + rv = tempURI->SchemeIs("view-source", &isViewSource); + if (NS_FAILED(rv) || isViewSource) { + LOG(("OBJLC [%p]: Blocking as effective URI has view-source scheme", + this)); + mType = eType_Null; + break; + } + + nestedURI->GetInnerURI(getter_AddRefs(tempURI)); + nestedURI = do_QueryInterface(tempURI); + } + } + // If we're a plugin but shouldn't start yet, load fallback with // reason click-to-play instead. Items resolved as Image/Document // will not be checked for previews, as well as invalid plugins @@ -3095,8 +3121,8 @@ nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentTyp NS_ENSURE_SUCCESS(rv, false); nsCOMPtr topDoc = do_QueryInterface(topDocument); - nsCOMPtr permissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, false); + nsCOMPtr permissionManager = services::GetPermissionManager(); + NS_ENSURE_TRUE(permissionManager, false); // For now we always say that the system principal uses click-to-play since // that maintains current behavior and we have tests that expect this. diff --git a/content/base/src/nsXMLHttpRequest.cpp b/content/base/src/nsXMLHttpRequest.cpp index 3dcf83476dea..781bae778191 100644 --- a/content/base/src/nsXMLHttpRequest.cpp +++ b/content/base/src/nsXMLHttpRequest.cpp @@ -396,7 +396,7 @@ nsXMLHttpRequest::InitParameters(bool aAnon, bool aSystem) nsCOMPtr principal = doc->NodePrincipal(); nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (!permMgr) return; diff --git a/content/base/test/file_general_document.html b/content/base/test/file_general_document.html new file mode 100644 index 000000000000..2539669de9fc --- /dev/null +++ b/content/base/test/file_general_document.html @@ -0,0 +1,10 @@ + + + + +General document for testing + + +

Hello mochitest!

+ + diff --git a/content/base/test/mochitest.ini b/content/base/test/mochitest.ini index e5e67acb9c18..7c9270779a17 100644 --- a/content/base/test/mochitest.ini +++ b/content/base/test/mochitest.ini @@ -135,6 +135,7 @@ support-files = file_bug902350.html file_bug902350_frame.html file_bug907892.html + file_general_document.html file_html_in_xhr.html file_html_in_xhr.sjs file_html_in_xhr2.html @@ -604,6 +605,7 @@ skip-if = toolkit == 'android' || e10s #RANDOM [test_title.html] [test_treewalker_nextsibling.xml] [test_viewport_scroll.html] +[test_viewsource_forbidden_in_object.html] [test_w3element_traversal.html] [test_w3element_traversal.xhtml] [test_w3element_traversal_svg.html] diff --git a/content/base/test/test_bug682592.html b/content/base/test/test_bug682592.html index bba919e7f31d..0e698e09b5ad 100644 --- a/content/base/test/test_bug682592.html +++ b/content/base/test/test_bug682592.html @@ -39,8 +39,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=682592 */ SimpleTest.waitForExplicitFinish(); -if (navigator.platform.startsWith("Linux arm")) { - SimpleTest.expectAssertions(0, 2); +if (navigator.platform.startsWith("Linux arm")) { /* bugs 982875, 999429 */ + SimpleTest.expectAssertions(0, 4); } var refFrame = document.getElementById("iframe-ref") diff --git a/content/base/test/test_viewsource_forbidden_in_object.html b/content/base/test/test_viewsource_forbidden_in_object.html new file mode 100644 index 000000000000..67ad367efd48 --- /dev/null +++ b/content/base/test/test_viewsource_forbidden_in_object.html @@ -0,0 +1,74 @@ + + + + + +Tests for Bug 973837 + + + + + + + +Mozilla Bug 973837 +

+ + + + + diff --git a/content/canvas/src/CanvasRenderingContext2D.cpp b/content/canvas/src/CanvasRenderingContext2D.cpp index d4fe0636263b..ac466e72e546 100755 --- a/content/canvas/src/CanvasRenderingContext2D.cpp +++ b/content/canvas/src/CanvasRenderingContext2D.cpp @@ -415,12 +415,12 @@ CanvasGradient::AddColorStop(float offset, const nsAString& colorstr, ErrorResul NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasGradient, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasGradient, Release) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(CanvasGradient, mContext) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasGradient, mContext) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPattern, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPattern, Release) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(CanvasPattern, mContext) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CanvasPattern, mContext) class CanvasRenderingContext2DUserData : public LayerUserData { public: diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index 459d4c0ffa4f..e64e20ebfa1e 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -956,7 +956,7 @@ WebGLContext::MozGetUnderlyingParamString(uint32_t pname, nsAString& retval) void WebGLContext::ClearScreen() { - bool colorAttachmentsMask[WebGLContext::sMaxColorAttachments] = {false}; + bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = {false}; MakeContextCurrent(); ScopedBindFramebuffer autoFB(gl, 0); @@ -986,7 +986,7 @@ static bool IsShadowCorrect(float shadow, float actual) { #endif void -WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[sMaxColorAttachments]) +WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[kMaxColorAttachments]) { MakeContextCurrent(); @@ -995,7 +995,7 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool bool initializeStencilBuffer = 0 != (mask & LOCAL_GL_STENCIL_BUFFER_BIT); bool drawBuffersIsEnabled = IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers); - GLenum currentDrawBuffers[WebGLContext::sMaxColorAttachments]; + GLenum currentDrawBuffers[WebGLContext::kMaxColorAttachments]; // Fun GL fact: No need to worry about the viewport here, glViewport is just // setting up a coordinates transformation, it doesn't affect glClear at all. @@ -1068,7 +1068,7 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool if (drawBuffersIsEnabled) { - GLenum drawBuffersCommand[WebGLContext::sMaxColorAttachments] = { LOCAL_GL_NONE }; + GLenum drawBuffersCommand[WebGLContext::kMaxColorAttachments] = { LOCAL_GL_NONE }; for(int32_t i = 0; i < mGLMaxDrawBuffers; i++) { GLint temp; @@ -1396,7 +1396,7 @@ WebGLContext::GetSurfaceSnapshot(bool* aPremultAlpha) NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext) NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_13(WebGLContext, +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext, mCanvasElement, mExtensions, mBound2DTextures, diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 7b6478ff88aa..11172ea49b43 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -230,13 +230,13 @@ public: // Returns null if the current bound FB is not likely complete. const WebGLRectangleObject* CurValidFBRectObject() const; - static const size_t sMaxColorAttachments = 16; + static const size_t kMaxColorAttachments = 16; // This is similar to GLContext::ClearSafely, but tries to minimize the // amount of work it does. // It only clears the buffers we specify, and can reset its state without // first having to query anything, as WebGL knows its state at all times. - void ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[sMaxColorAttachments]); + void ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool colorAttachmentsMask[kMaxColorAttachments]); // Calls ForceClearFramebufferWithDefaultValues() for the Context's 'screen'. void ClearScreen(); diff --git a/content/canvas/src/WebGLExtensionDrawBuffers.cpp b/content/canvas/src/WebGLExtensionDrawBuffers.cpp index ae3fb052901a..e26a34a25ac0 100644 --- a/content/canvas/src/WebGLExtensionDrawBuffers.cpp +++ b/content/canvas/src/WebGLExtensionDrawBuffers.cpp @@ -30,7 +30,7 @@ WebGLExtensionDrawBuffers::WebGLExtensionDrawBuffers(WebGLContext* context) gl->fGetIntegerv(LOCAL_GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); // WEBGL_draw_buffers specifications don't give a maximal value reachable by MAX_COLOR_ATTACHMENTS. - maxColorAttachments = std::min(maxColorAttachments, GLint(WebGLContext::sMaxColorAttachments)); + maxColorAttachments = std::min(maxColorAttachments, GLint(WebGLContext::kMaxColorAttachments)); if (context->MinCapabilityMode()) { diff --git a/content/canvas/src/WebGLFramebuffer.cpp b/content/canvas/src/WebGLFramebuffer.cpp index 396028f5fd6b..52669f508ca8 100644 --- a/content/canvas/src/WebGLFramebuffer.cpp +++ b/content/canvas/src/WebGLFramebuffer.cpp @@ -292,7 +292,7 @@ WebGLFramebuffer::Attachment::IsComplete() const if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 && mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + - WebGLContext::sMaxColorAttachments)) + WebGLContext::kMaxColorAttachments)) { return IsValidFBOTextureColorFormat(internalFormat); } @@ -314,7 +314,7 @@ WebGLFramebuffer::Attachment::IsComplete() const if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 && mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + - WebGLContext::sMaxColorAttachments)) + WebGLContext::kMaxColorAttachments)) { return IsValidFBORenderbufferColorFormat(internalFormat); } @@ -785,8 +785,8 @@ WebGLFramebuffer::CheckAndInitializeAttachments() // Get buffer-bit-mask and color-attachment-mask-list uint32_t mask = 0; - bool colorAttachmentsMask[WebGLContext::sMaxColorAttachments] = { false }; - MOZ_ASSERT(colorAttachmentCount <= WebGLContext::sMaxColorAttachments); + bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = { false }; + MOZ_ASSERT(colorAttachmentCount <= WebGLContext::kMaxColorAttachments); for (size_t i = 0; i < colorAttachmentCount; i++) { if (mColorAttachments[i].HasUninitializedImageData()) { @@ -855,7 +855,7 @@ bool WebGLFramebuffer::CheckColorAttachmentNumber(GLenum attachment, const char* void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId) { - MOZ_ASSERT(colorAttachmentId < WebGLContext::sMaxColorAttachments); + MOZ_ASSERT(colorAttachmentId < WebGLContext::kMaxColorAttachments); size_t currentAttachmentCount = mColorAttachments.Length(); if (colorAttachmentId < currentAttachmentCount) @@ -940,7 +940,7 @@ ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback, aName, aFlags); } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(WebGLFramebuffer, +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer, mColorAttachments, mDepthAttachment, mStencilAttachment, diff --git a/content/canvas/src/WebGLProgram.cpp b/content/canvas/src/WebGLProgram.cpp index 6457f37a88e3..b44b1676c477 100644 --- a/content/canvas/src/WebGLProgram.cpp +++ b/content/canvas/src/WebGLProgram.cpp @@ -237,7 +237,7 @@ WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name) { return info; } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(WebGLProgram, mAttachedShaders) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mAttachedShaders) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release) diff --git a/content/canvas/src/WebGLTexture.cpp b/content/canvas/src/WebGLTexture.cpp index 67eaac256605..129dc9c5d255 100644 --- a/content/canvas/src/WebGLTexture.cpp +++ b/content/canvas/src/WebGLTexture.cpp @@ -3,12 +3,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "WebGLContext.h" #include "WebGLTexture.h" + #include "GLContext.h" -#include "ScopedGLHelpers.h" -#include "WebGLTexelConversions.h" #include "mozilla/dom/WebGLRenderingContextBinding.h" +#include "mozilla/Scoped.h" +#include "ScopedGLHelpers.h" +#include "WebGLContext.h" +#include "WebGLTexelConversions.h" + #include using namespace mozilla; @@ -433,6 +436,104 @@ WebGLTexture::ResolvedFakeBlackStatus() { return mFakeBlackStatus; } + +static bool +ClearByMask(WebGLContext* context, GLbitfield mask) +{ + gl::GLContext* gl = context->GL(); + MOZ_ASSERT(gl->IsCurrent()); + + GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER); + if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) + return false; + + bool colorAttachmentsMask[WebGLContext::kMaxColorAttachments] = {false}; + if (mask & LOCAL_GL_COLOR_BUFFER_BIT) { + colorAttachmentsMask[0] = true; + } + + context->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask); + return true; +} + +// `mask` from glClear. +static bool +ClearWithTempFB(WebGLContext* context, GLuint tex, + GLenum texImageTarget, GLint level, + GLenum baseInternalFormat, + GLsizei width, GLsizei height) +{ + if (texImageTarget != LOCAL_GL_TEXTURE_2D) + return false; + + gl::GLContext* gl = context->GL(); + MOZ_ASSERT(gl->IsCurrent()); + + gl::ScopedFramebuffer fb(gl); + gl::ScopedBindFramebuffer autoFB(gl, fb.FB()); + GLbitfield mask = 0; + + switch (baseInternalFormat) { + case LOCAL_GL_LUMINANCE: + case LOCAL_GL_LUMINANCE_ALPHA: + case LOCAL_GL_ALPHA: + case LOCAL_GL_RGB: + case LOCAL_GL_RGBA: + case LOCAL_GL_BGR: + case LOCAL_GL_BGRA: + mask = LOCAL_GL_COLOR_BUFFER_BIT; + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + texImageTarget, tex, level); + break; + + case LOCAL_GL_DEPTH_COMPONENT: + mask = LOCAL_GL_DEPTH_BUFFER_BIT; + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, + texImageTarget, tex, level); + break; + + case LOCAL_GL_DEPTH_STENCIL: + mask = LOCAL_GL_DEPTH_BUFFER_BIT | + LOCAL_GL_STENCIL_BUFFER_BIT; + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, + texImageTarget, tex, level); + gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, + texImageTarget, tex, level); + break; + + default: + return false; + } + MOZ_ASSERT(mask); + + if (ClearByMask(context, mask)) + return true; + + // Failed to simply build an FB from the tex, but maybe it needs a + // color buffer to be complete. + + if (mask & LOCAL_GL_COLOR_BUFFER_BIT) { + // Nope, it already had one. + return false; + } + + gl::ScopedRenderbuffer rb(gl); + { + gl::ScopedBindRenderbuffer(gl, rb.RB()); + gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, + LOCAL_GL_RGBA4, + width, height); + } + + gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, + LOCAL_GL_RENDERBUFFER, rb.RB()); + mask |= LOCAL_GL_COLOR_BUFFER_BIT; + + // Last chance! + return ClearByMask(context, mask); +} + + void WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level) { @@ -440,9 +541,22 @@ WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level) MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData); mContext->MakeContextCurrent(); + + // Try to clear with glCLear. + WebGLTexelFormat texelformat = GetWebGLTexelFormat(imageInfo.mInternalFormat, imageInfo.mType); + GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat); + + bool cleared = ClearWithTempFB(mContext, GLName(), + imageTarget, level, + format, imageInfo.mHeight, imageInfo.mWidth); + if (cleared) { + SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData); + return; + } + + // That didn't work. Try uploading zeros then. gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget); - WebGLTexelFormat texelformat = GetWebGLTexelFormat(imageInfo.mInternalFormat, imageInfo.mType); uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat); CheckedUint32 checked_byteLength = WebGLContext::GetImageSize( @@ -451,24 +565,29 @@ WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level) texelsize, mContext->mPixelStoreUnpackAlignment); MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier - void *zeros = calloc(1, checked_byteLength.value()); + ScopedFreePtr zeros; + zeros = calloc(1, checked_byteLength.value()); - GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat); mContext->GetAndFlushUnderlyingGLErrors(); mContext->gl->fTexImage2D(imageTarget, level, imageInfo.mInternalFormat, imageInfo.mWidth, imageInfo.mHeight, 0, format, imageInfo.mType, zeros); GLenum error = mContext->GetAndFlushUnderlyingGLErrors(); - - free(zeros); - SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData); - if (error) { - // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here. - MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past. - return; + // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here. + printf_stderr("Error: 0x%4x\n", error); + MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past. } + + SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData); +} + +void +WebGLTexture::SetFakeBlackStatus(WebGLTextureFakeBlackStatus x) +{ + mFakeBlackStatus = x; + mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown); } NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture) diff --git a/content/canvas/src/WebGLTexture.h b/content/canvas/src/WebGLTexture.h index 870953c3722b..ec81a01aa228 100644 --- a/content/canvas/src/WebGLTexture.h +++ b/content/canvas/src/WebGLTexture.h @@ -11,6 +11,7 @@ #include "nsWrapperCache.h" +#include "mozilla/CheckedInt.h" #include "mozilla/LinkedList.h" #include @@ -273,10 +274,8 @@ public: bool IsMipmapCubeComplete() const; - void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x) { - mFakeBlackStatus = x; - mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown); - } + void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x); + // Returns the current fake-black-status, except if it was Unknown, // in which case this function resolves it first, so it never returns Unknown. WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus(); diff --git a/content/canvas/src/WebGLVertexArray.cpp b/content/canvas/src/WebGLVertexArray.cpp index 0081b8b8d5fd..a9e27432da58 100644 --- a/content/canvas/src/WebGLVertexArray.cpp +++ b/content/canvas/src/WebGLVertexArray.cpp @@ -56,7 +56,7 @@ bool WebGLVertexArray::EnsureAttrib(GLuint index, const char *info) return true; } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(WebGLVertexArray, +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLVertexArray, mAttribs, mBoundElementArrayBuffer) diff --git a/content/html/content/src/HTMLCanvasElement.cpp b/content/html/content/src/HTMLCanvasElement.cpp index c89416787e38..289837060e5b 100644 --- a/content/html/content/src/HTMLCanvasElement.cpp +++ b/content/html/content/src/HTMLCanvasElement.cpp @@ -52,8 +52,8 @@ HTMLImageOrCanvasOrVideoElement; namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(HTMLCanvasPrintState, mCanvas, - mContext, mCallback) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLCanvasPrintState, mCanvas, + mContext, mCallback) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(HTMLCanvasPrintState, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(HTMLCanvasPrintState, Release) diff --git a/content/html/content/src/HTMLMediaElement.cpp b/content/html/content/src/HTMLMediaElement.cpp index 1a0880dd7222..ba43334724ed 100644 --- a/content/html/content/src/HTMLMediaElement.cpp +++ b/content/html/content/src/HTMLMediaElement.cpp @@ -2338,7 +2338,7 @@ bool HTMLMediaElement::CheckAudioChannelPermissions(const nsAString& aString) } nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (!permissionManager) { return false; } diff --git a/content/html/content/src/HTMLOptionsCollection.cpp b/content/html/content/src/HTMLOptionsCollection.cpp index 66d1468aa304..15292cc41eec 100644 --- a/content/html/content/src/HTMLOptionsCollection.cpp +++ b/content/html/content/src/HTMLOptionsCollection.cpp @@ -89,7 +89,7 @@ HTMLOptionsCollection::GetOptionIndex(Element* aOption, } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(HTMLOptionsCollection, mElements) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLOptionsCollection, mElements) // nsISupports diff --git a/content/html/content/src/HTMLTableElement.cpp b/content/html/content/src/HTMLTableElement.cpp index f9804145be1a..5a789e98a19f 100644 --- a/content/html/content/src/HTMLTableElement.cpp +++ b/content/html/content/src/HTMLTableElement.cpp @@ -89,7 +89,7 @@ TableRowsCollection::WrapObject(JSContext* aCx) return HTMLCollectionBinding::Wrap(aCx, this); } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TableRowsCollection, mOrphanRows) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TableRowsCollection, mOrphanRows) NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection) NS_IMPL_CYCLE_COLLECTING_RELEASE(TableRowsCollection) diff --git a/content/html/content/src/MediaError.cpp b/content/html/content/src/MediaError.cpp index 16c559a0bf8e..6b82ace4bd16 100644 --- a/content/html/content/src/MediaError.cpp +++ b/content/html/content/src/MediaError.cpp @@ -11,7 +11,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(MediaError, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaError, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaError) NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaError) diff --git a/content/html/content/src/UndoManager.cpp b/content/html/content/src/UndoManager.cpp index b28d5acf80a1..8ca1f4af52b5 100644 --- a/content/html/content/src/UndoManager.cpp +++ b/content/html/content/src/UndoManager.cpp @@ -820,7 +820,7 @@ protected: // UndoManager ///////////////////////////////////////////////// -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(UndoManager, mTxnManager, mHostNode) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(UndoManager, mTxnManager, mHostNode) NS_IMPL_CYCLE_COLLECTING_ADDREF(UndoManager) NS_IMPL_CYCLE_COLLECTING_RELEASE(UndoManager) diff --git a/content/html/content/src/ValidityState.cpp b/content/html/content/src/ValidityState.cpp index 2c85208aab0d..ed9304d1786d 100644 --- a/content/html/content/src/ValidityState.cpp +++ b/content/html/content/src/ValidityState.cpp @@ -11,7 +11,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(ValidityState, mConstraintValidation) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ValidityState, mConstraintValidation) NS_IMPL_CYCLE_COLLECTING_ADDREF(ValidityState) NS_IMPL_CYCLE_COLLECTING_RELEASE(ValidityState) diff --git a/content/html/content/src/nsGenericHTMLFrameElement.cpp b/content/html/content/src/nsGenericHTMLFrameElement.cpp index 0989b476685c..3029c5860741 100644 --- a/content/html/content/src/nsGenericHTMLFrameElement.cpp +++ b/content/html/content/src/nsGenericHTMLFrameElement.cpp @@ -418,7 +418,7 @@ nsGenericHTMLFrameElement::GetReallyIsBrowserOrApp(bool *aOut) // Fail if the node principal isn't trusted. nsIPrincipal *principal = NodePrincipal(); nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, NS_OK); uint32_t permission = nsIPermissionManager::DENY_ACTION; @@ -464,7 +464,7 @@ nsGenericHTMLFrameElement::GetAppManifestURL(nsAString& aOut) // Check permission. nsIPrincipal *principal = NodePrincipal(); nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, NS_OK); uint32_t permission = nsIPermissionManager::DENY_ACTION; diff --git a/content/html/document/src/HTMLAllCollection.cpp b/content/html/document/src/HTMLAllCollection.cpp index 73f260009973..bcc052b1f5fb 100644 --- a/content/html/document/src/HTMLAllCollection.cpp +++ b/content/html/document/src/HTMLAllCollection.cpp @@ -322,7 +322,7 @@ nsHTMLDocumentSH::DocumentAllNewResolve(JSContext *cx, JS::Handle obj bool ok = true; if (v.get() != JSVAL_VOID) { - ok = ::JS_DefinePropertyById(cx, obj, id, v, nullptr, nullptr, 0); + ok = ::JS_DefinePropertyById(cx, obj, id, v, 0); objp.set(obj); } diff --git a/content/media/AudioSegment.h b/content/media/AudioSegment.h index 8c54e5e947a0..9d6d57f08b47 100644 --- a/content/media/AudioSegment.h +++ b/content/media/AudioSegment.h @@ -187,6 +187,7 @@ public: if (c.IsNull()) { c.mDuration *= aOutRate / aInRate; mDuration += c.mDuration; + continue; } uint32_t channels = c.mChannelData.Length(); output.SetLength(channels); @@ -265,7 +266,14 @@ public: int ChannelCount() { NS_WARN_IF_FALSE(!mChunks.IsEmpty(), "Cannot query channel count on a AudioSegment with no chunks."); - return mChunks.IsEmpty() ? 0 : mChunks[0].mChannelData.Length(); + // Find the first chunk that has non-zero channels. A chunk that hs zero + // channels is just silence and we can simply discard it. + for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) { + if (ci->ChannelCount()) { + return ci->ChannelCount(); + } + } + return 0; } static Type StaticType() { return AUDIO; } diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index e7c7031c38fa..c87009d3e957 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -2277,12 +2277,17 @@ SourceMediaStream::ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSe AudioSegment* segment = static_cast(aSegment); if (!aTrackData->mResampler) { int channels = segment->ChannelCount(); - SpeexResamplerState* state = speex_resampler_init(channels, - aTrackData->mInputRate, - GraphImpl()->AudioSampleRate(), - SPEEX_RESAMPLER_QUALITY_DEFAULT, - nullptr); - if (state) { + + // If this segment is just silence, we delay instanciating the resampler. + if (channels) { + SpeexResamplerState* state = speex_resampler_init(channels, + aTrackData->mInputRate, + GraphImpl()->AudioSampleRate(), + SPEEX_RESAMPLER_QUALITY_DEFAULT, + nullptr); + if (!state) { + return; + } aTrackData->mResampler.own(state); } } diff --git a/content/media/TextTrackCueList.cpp b/content/media/TextTrackCueList.cpp index 3fe293a9de17..3fc5eac56983 100644 --- a/content/media/TextTrackCueList.cpp +++ b/content/media/TextTrackCueList.cpp @@ -24,7 +24,7 @@ public: } }; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(TextTrackCueList, mParent, mList) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TextTrackCueList, mParent, mList) NS_IMPL_CYCLE_COLLECTING_ADDREF(TextTrackCueList) NS_IMPL_CYCLE_COLLECTING_RELEASE(TextTrackCueList) diff --git a/content/media/TextTrackRegion.cpp b/content/media/TextTrackRegion.cpp index 7a40ecf00090..6b3b4487600a 100644 --- a/content/media/TextTrackRegion.cpp +++ b/content/media/TextTrackRegion.cpp @@ -10,7 +10,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TextTrackRegion, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TextTrackRegion, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(TextTrackRegion) NS_IMPL_CYCLE_COLLECTING_RELEASE(TextTrackRegion) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TextTrackRegion) diff --git a/content/media/VideoPlaybackQuality.cpp b/content/media/VideoPlaybackQuality.cpp index 2547e6b0ed4d..1601ec188328 100644 --- a/content/media/VideoPlaybackQuality.cpp +++ b/content/media/VideoPlaybackQuality.cpp @@ -43,7 +43,7 @@ VideoPlaybackQuality::WrapObject(JSContext *aCx) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VideoPlaybackQuality, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VideoPlaybackQuality, Release) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(VideoPlaybackQuality, mElement) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VideoPlaybackQuality, mElement) } // namespace dom } // namespace mozilla diff --git a/content/media/encoder/OmxTrackEncoder.cpp b/content/media/encoder/OmxTrackEncoder.cpp index 1359679e3b91..5cc06205582c 100644 --- a/content/media/encoder/OmxTrackEncoder.cpp +++ b/content/media/encoder/OmxTrackEncoder.cpp @@ -184,7 +184,7 @@ OmxAudioTrackEncoder::AppendEncodedFrames(EncodedFrameContainer& aContainer) audiodata->SetFrameType(isCSD ? EncodedFrame::AMR_AUDIO_CSD : EncodedFrame::AMR_AUDIO_FRAME); } else { - MOZ_ASSERT("audio codec not supported"); + MOZ_ASSERT(false, "audio codec not supported"); } audiodata->SetTimeStamp(outTimeUs); rv = audiodata->SwapInFrameData(frameData); diff --git a/content/media/webaudio/AudioBuffer.cpp b/content/media/webaudio/AudioBuffer.cpp index c926b082f818..4a83161ab622 100644 --- a/content/media/webaudio/AudioBuffer.cpp +++ b/content/media/webaudio/AudioBuffer.cpp @@ -196,8 +196,9 @@ StealJSArrayDataIntoThreadSharedFloatArrayBufferList(JSContext* aJSContext, nsRefPtr result = new ThreadSharedFloatArrayBufferList(aJSArrays.Length()); for (uint32_t i = 0; i < aJSArrays.Length(); ++i) { + JS::Rooted arrayBufferView(aJSContext, aJSArrays[i]); JS::Rooted arrayBuffer(aJSContext, - JS_GetArrayBufferViewBuffer(aJSContext, aJSArrays[i])); + JS_GetArrayBufferViewBuffer(aJSContext, arrayBufferView)); uint8_t* stolenData = arrayBuffer ? (uint8_t*) JS_StealArrayBufferContents(aJSContext, arrayBuffer) : nullptr; diff --git a/content/media/webaudio/AudioDestinationNode.cpp b/content/media/webaudio/AudioDestinationNode.cpp index d4375c5b5029..480fa8a3ab3f 100644 --- a/content/media/webaudio/AudioDestinationNode.cpp +++ b/content/media/webaudio/AudioDestinationNode.cpp @@ -7,6 +7,7 @@ #include "AudioDestinationNode.h" #include "mozilla/dom/AudioDestinationNodeBinding.h" #include "mozilla/Preferences.h" +#include "mozilla/Services.h" #include "AudioChannelAgent.h" #include "AudioChannelService.h" #include "AudioNodeEngine.h" @@ -482,7 +483,7 @@ AudioDestinationNode::CheckAudioChannelPermissions(AudioChannel aValue) } nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (!permissionManager) { return false; } diff --git a/content/media/webaudio/AudioListener.cpp b/content/media/webaudio/AudioListener.cpp index d9e02a34ced6..a297f61b4ac7 100644 --- a/content/media/webaudio/AudioListener.cpp +++ b/content/media/webaudio/AudioListener.cpp @@ -11,7 +11,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(AudioListener, mContext) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AudioListener, mContext) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(AudioListener, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(AudioListener, Release) diff --git a/content/media/webaudio/PeriodicWave.cpp b/content/media/webaudio/PeriodicWave.cpp index 045d53a2f65a..abbeda395a0f 100644 --- a/content/media/webaudio/PeriodicWave.cpp +++ b/content/media/webaudio/PeriodicWave.cpp @@ -11,7 +11,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PeriodicWave, mContext) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PeriodicWave, mContext) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PeriodicWave, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PeriodicWave, Release) diff --git a/content/media/webrtc/MediaEngine.h b/content/media/webrtc/MediaEngine.h index 91ae08a908cd..c7500cdc47a5 100644 --- a/content/media/webrtc/MediaEngine.h +++ b/content/media/webrtc/MediaEngine.h @@ -154,13 +154,23 @@ public: } private: static int32_t GetDefWidth(bool aHD = false) { - return aHD ? MediaEngine::DEFAULT_169_VIDEO_WIDTH : - MediaEngine::DEFAULT_43_VIDEO_WIDTH; + // It'd be nice if we could use the ternary operator here, but we can't + // because of bug 1002729. + if (aHD) { + return MediaEngine::DEFAULT_169_VIDEO_WIDTH; + } + + return MediaEngine::DEFAULT_43_VIDEO_WIDTH; } static int32_t GetDefHeight(bool aHD = false) { - return aHD ? MediaEngine::DEFAULT_169_VIDEO_HEIGHT : - MediaEngine::DEFAULT_43_VIDEO_HEIGHT; + // It'd be nice if we could use the ternary operator here, but we can't + // because of bug 1002729. + if (aHD) { + return MediaEngine::DEFAULT_169_VIDEO_HEIGHT; + } + + return MediaEngine::DEFAULT_43_VIDEO_HEIGHT; } }; diff --git a/content/media/webrtc/MediaEngineDefault.cpp b/content/media/webrtc/MediaEngineDefault.cpp index 7acbe153469a..ab7f3f2d5939 100644 --- a/content/media/webrtc/MediaEngineDefault.cpp +++ b/content/media/webrtc/MediaEngineDefault.cpp @@ -22,7 +22,9 @@ #include "nsISupportsUtils.h" #endif +#ifdef MOZ_WEBRTC #include "YuvStamper.h" +#endif #define VIDEO_RATE USECS_PER_S #define AUDIO_RATE 16000 @@ -245,11 +247,13 @@ MediaEngineDefaultVideoSource::Notify(nsITimer* aTimer) layers::PlanarYCbCrData data; AllocateSolidColorFrame(data, mOpts.mWidth, mOpts.mHeight, 0x80, mCb, mCr); +#ifdef MOZ_WEBRTC uint64_t timestamp = PR_Now(); YuvStamper::Encode(mOpts.mWidth, mOpts.mHeight, mOpts.mWidth, data.mYChannel, reinterpret_cast(×tamp), sizeof(timestamp), 0, 0); +#endif ycbcr_image->SetData(data); // SetData copies data, so we can free the frame diff --git a/content/media/webspeech/recognition/SpeechGrammar.cpp b/content/media/webspeech/recognition/SpeechGrammar.cpp index 69a42a1fedce..bf6fca538881 100644 --- a/content/media/webspeech/recognition/SpeechGrammar.cpp +++ b/content/media/webspeech/recognition/SpeechGrammar.cpp @@ -12,7 +12,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechGrammar, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammar, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechGrammar) NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechGrammar) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechGrammar) diff --git a/content/media/webspeech/recognition/SpeechGrammarList.cpp b/content/media/webspeech/recognition/SpeechGrammarList.cpp index e2d9b74ebbd5..6d89846daaaf 100644 --- a/content/media/webspeech/recognition/SpeechGrammarList.cpp +++ b/content/media/webspeech/recognition/SpeechGrammarList.cpp @@ -12,7 +12,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechGrammarList, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammarList, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechGrammarList) NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechGrammarList) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechGrammarList) diff --git a/content/media/webspeech/recognition/SpeechRecognitionAlternative.cpp b/content/media/webspeech/recognition/SpeechRecognitionAlternative.cpp index 0f4345de3074..55c64a53398d 100644 --- a/content/media/webspeech/recognition/SpeechRecognitionAlternative.cpp +++ b/content/media/webspeech/recognition/SpeechRecognitionAlternative.cpp @@ -13,7 +13,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechRecognitionAlternative, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechRecognitionAlternative, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechRecognitionAlternative) NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechRecognitionAlternative) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionAlternative) diff --git a/content/media/webspeech/recognition/SpeechRecognitionResult.cpp b/content/media/webspeech/recognition/SpeechRecognitionResult.cpp index d3a70a119544..7bcc2328a4f0 100644 --- a/content/media/webspeech/recognition/SpeechRecognitionResult.cpp +++ b/content/media/webspeech/recognition/SpeechRecognitionResult.cpp @@ -12,7 +12,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechRecognitionResult, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechRecognitionResult, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechRecognitionResult) NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechRecognitionResult) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionResult) diff --git a/content/media/webspeech/recognition/SpeechRecognitionResultList.cpp b/content/media/webspeech/recognition/SpeechRecognitionResultList.cpp index 8e3928048270..4a72ddff765f 100644 --- a/content/media/webspeech/recognition/SpeechRecognitionResultList.cpp +++ b/content/media/webspeech/recognition/SpeechRecognitionResultList.cpp @@ -13,7 +13,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(SpeechRecognitionResultList, mParent, mItems) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechRecognitionResultList, mParent, mItems) NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechRecognitionResultList) NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechRecognitionResultList) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionResultList) diff --git a/content/media/webspeech/synth/SpeechSynthesisVoice.cpp b/content/media/webspeech/synth/SpeechSynthesisVoice.cpp index 16bd05a6b5a0..6b2437eda9cb 100644 --- a/content/media/webspeech/synth/SpeechSynthesisVoice.cpp +++ b/content/media/webspeech/synth/SpeechSynthesisVoice.cpp @@ -11,7 +11,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SpeechSynthesisVoice, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechSynthesisVoice, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechSynthesisVoice) NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechSynthesisVoice) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechSynthesisVoice) diff --git a/content/svg/content/src/SVGMatrix.cpp b/content/svg/content/src/SVGMatrix.cpp index d44b6dc98437..4a3c6337cbe0 100644 --- a/content/svg/content/src/SVGMatrix.cpp +++ b/content/svg/content/src/SVGMatrix.cpp @@ -14,7 +14,7 @@ const double radPerDegree = 2.0 * M_PI / 360.0; namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SVGMatrix, mTransform) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGMatrix, mTransform) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SVGMatrix, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SVGMatrix, Release) diff --git a/content/svg/content/src/SVGRect.cpp b/content/svg/content/src/SVGRect.cpp index 0f0d579137e2..31977b4638da 100644 --- a/content/svg/content/src/SVGRect.cpp +++ b/content/svg/content/src/SVGRect.cpp @@ -22,7 +22,7 @@ SVGRect::SVGRect(nsIContent* aParent, float x, float y, float w, float h) //---------------------------------------------------------------------- // nsISupports methods: -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(SVGRect, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SVGRect, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGRect) NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGRect) diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp index d86e4652d14e..143214a8c16a 100644 --- a/dom/asmjscache/AsmJSCache.cpp +++ b/dom/asmjscache/AsmJSCache.cpp @@ -36,6 +36,7 @@ #include "nsXULAppAPI.h" #include "prio.h" #include "private/pprio.h" +#include "mozilla/Services.h" #define ASMJSCACHE_METADATA_FILE_NAME "metadata" #define ASMJSCACHE_ENTRY_FILE_NAME_BASE "module" @@ -688,7 +689,7 @@ MainProcessRunnable::InitOnMainThread() MOZ_ASSERT(isApp); nsCOMPtr pm = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(pm, NS_ERROR_UNEXPECTED); uint32_t permission; diff --git a/dom/base/BarProps.cpp b/dom/base/BarProps.cpp index 229976ad8e4f..bcb893bdff64 100644 --- a/dom/base/BarProps.cpp +++ b/dom/base/BarProps.cpp @@ -40,7 +40,7 @@ BarProp::WrapObject(JSContext* aCx) return BarPropBinding::Wrap(aCx, this); } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(BarProp, mDOMWindow) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BarProp, mDOMWindow) NS_IMPL_CYCLE_COLLECTING_ADDREF(BarProp) NS_IMPL_CYCLE_COLLECTING_RELEASE(BarProp) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BarProp) diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index 63dc12cdca7e..53545689c9a2 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -295,9 +295,10 @@ private: return false; } + JS::Rooted arg(aCx); for (uint32_t i = 0; i < mCallData->mArguments.Length(); ++i) { - if (!JS_DefineElement(aCx, arguments, i, mCallData->mArguments[i], - nullptr, nullptr, JSPROP_ENUMERATE)) { + arg = mCallData->mArguments[i]; + if (!JS_DefineElement(aCx, arguments, i, arg, JSPROP_ENUMERATE)) { return false; } } @@ -405,9 +406,10 @@ private: return false; } + JS::Rooted arg(aCx); for (uint32_t i = 0; i < mArguments.Length(); ++i) { - if (!JS_DefineElement(aCx, arguments, i, mArguments[i], nullptr, nullptr, - JSPROP_ENUMERATE)) { + arg = mArguments[i]; + if (!JS_DefineElement(aCx, arguments, i, arg, JSPROP_ENUMERATE)) { return false; } } diff --git a/dom/base/Crypto.cpp b/dom/base/Crypto.cpp index 53524c32f83e..549cf7b554b0 100644 --- a/dom/base/Crypto.cpp +++ b/dom/base/Crypto.cpp @@ -29,7 +29,7 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(Crypto) NS_IMPL_CYCLE_COLLECTING_RELEASE(Crypto) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Crypto, mWindow) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Crypto, mWindow) Crypto::Crypto() { diff --git a/dom/base/DOMError.cpp b/dom/base/DOMError.cpp index 40d40a554c64..e214ab6a5ec6 100644 --- a/dom/base/DOMError.cpp +++ b/dom/base/DOMError.cpp @@ -12,7 +12,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMError, mWindow) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMError, mWindow) NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMError) NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMError) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMError) diff --git a/dom/base/MessageChannel.cpp b/dom/base/MessageChannel.cpp index a959645222c6..a8763b7faa5a 100644 --- a/dom/base/MessageChannel.cpp +++ b/dom/base/MessageChannel.cpp @@ -13,7 +13,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(MessageChannel, mWindow, mPort1, mPort2) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mWindow, mPort1, mPort2) NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel) NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel) diff --git a/dom/base/MessagePortList.cpp b/dom/base/MessagePortList.cpp index 9b45f282b674..dc7b3c038f33 100644 --- a/dom/base/MessagePortList.cpp +++ b/dom/base/MessagePortList.cpp @@ -11,7 +11,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(MessagePortList, mOwner, mPorts) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessagePortList, mOwner, mPorts) NS_IMPL_CYCLE_COLLECTING_ADDREF(MessagePortList) NS_IMPL_CYCLE_COLLECTING_RELEASE(MessagePortList) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessagePortList) diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index f802eb20c728..89812f00db25 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -94,6 +94,9 @@ #include "nsIPrivateBrowsingChannel.h" #include "nsIDocShell.h" +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" + namespace mozilla { namespace dom { @@ -1410,10 +1413,12 @@ Navigator::GetBattery(ErrorResult& aRv) return mBatteryManager; } -already_AddRefed -Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv) +/* static */ already_AddRefed +Navigator::GetDataStores(nsPIDOMWindow* aWindow, + const nsAString& aName, + ErrorResult& aRv) { - if (!mWindow || !mWindow->GetDocShell()) { + if (!aWindow || !aWindow->GetDocShell()) { aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr; } @@ -1426,12 +1431,18 @@ Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv) } nsCOMPtr promise; - aRv = service->GetDataStores(mWindow, aName, getter_AddRefs(promise)); + aRv = service->GetDataStores(aWindow, aName, getter_AddRefs(promise)); nsRefPtr p = static_cast(promise.get()); return p.forget(); } +already_AddRefed +Navigator::GetDataStores(const nsAString& aName, ErrorResult& aRv) +{ + return GetDataStores(mWindow, aName, aRv); +} + PowerManager* Navigator::GetMozPower(ErrorResult& aRv) { @@ -1782,7 +1793,7 @@ Navigator::CheckPermission(nsPIDOMWindow* aWindow, const char* aType) } nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, false); uint32_t permission = nsIPermissionManager::DENY_ACTION; @@ -2178,7 +2189,7 @@ Navigator::HasWifiManagerSupport(JSContext* /* unused */, nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal); nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, false); uint32_t permission = nsIPermissionManager::DENY_ACTION; @@ -2291,9 +2302,9 @@ Navigator::HasInputMethodSupport(JSContext* /* unused */, /* static */ bool -Navigator::HasDataStoreSupport(JSContext* cx, JSObject* aGlobal) +Navigator::HasDataStoreSupport(nsIPrincipal* aPrincipal) { - JS::Rooted global(cx, aGlobal); + workers::AssertIsOnMainThread(); // First of all, the general pref has to be turned on. bool enabled = false; @@ -2307,6 +2318,64 @@ Navigator::HasDataStoreSupport(JSContext* cx, JSObject* aGlobal) return true; } + uint16_t status; + if (NS_FAILED(aPrincipal->GetAppStatus(&status))) { + return false; + } + + // Only support DataStore API for certified apps for now. + return status == nsIPrincipal::APP_STATUS_CERTIFIED; +} + +// A WorkerMainThreadRunnable to synchronously dispatch the call of +// HasDataStoreSupport() from the worker thread to the main thread. +class HasDataStoreSupportRunnable MOZ_FINAL + : public workers::WorkerMainThreadRunnable +{ +public: + bool mResult; + + HasDataStoreSupportRunnable(workers::WorkerPrivate* aWorkerPrivate) + : workers::WorkerMainThreadRunnable(aWorkerPrivate) + , mResult(false) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + workers::AssertIsOnMainThread(); + + mResult = Navigator::HasDataStoreSupport(mWorkerPrivate->GetPrincipal()); + + return true; + } +}; + +/* static */ +bool +Navigator::HasDataStoreSupport(JSContext* aCx, JSObject* aGlobal) +{ + // If the caller is on the worker thread, dispatch this to the main thread. + if (!NS_IsMainThread()) { + workers::WorkerPrivate* workerPrivate = + workers::GetWorkerPrivateFromContext(aCx); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr runnable = + new HasDataStoreSupportRunnable(workerPrivate); + runnable->Dispatch(aCx); + + return runnable->mResult; + } + + workers::AssertIsOnMainThread(); + + JS::Rooted global(aCx, aGlobal); + nsCOMPtr win = GetWindowFromGlobal(global); if (!win) { return false; @@ -2317,12 +2386,7 @@ Navigator::HasDataStoreSupport(JSContext* cx, JSObject* aGlobal) return false; } - uint16_t status; - if (NS_FAILED(doc->NodePrincipal()->GetAppStatus(&status))) { - return false; - } - - return status == nsIPrincipal::APP_STATUS_CERTIFIED; + return HasDataStoreSupport(doc->NodePrincipal()); } /* static */ diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index b257bae39717..3de2c1c461f8 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -27,6 +27,7 @@ class nsIDOMNavigatorSystemMessages; class nsDOMCameraManager; class nsDOMDeviceStorage; class nsIDOMBlob; +class nsIPrincipal; namespace mozilla { namespace dom { @@ -156,6 +157,11 @@ public: // The XPCOM GetDoNotTrack is ok Geolocation* GetGeolocation(ErrorResult& aRv); battery::BatteryManager* GetBattery(ErrorResult& aRv); + + static already_AddRefed GetDataStores(nsPIDOMWindow* aWindow, + const nsAString& aName, + ErrorResult& aRv); + already_AddRefed GetDataStores(const nsAString &aName, ErrorResult& aRv); bool Vibrate(uint32_t aDuration); @@ -299,6 +305,8 @@ public: static bool HasInputMethodSupport(JSContext* /* unused */, JSObject* aGlobal); + static bool HasDataStoreSupport(nsIPrincipal* aPrincipal); + static bool HasDataStoreSupport(JSContext* cx, JSObject* aGlobal); static bool HasDownloadsSupport(JSContext* aCx, JSObject* aGlobal); diff --git a/dom/base/PerformanceEntry.cpp b/dom/base/PerformanceEntry.cpp index 6c3688da5522..9607e9cee011 100644 --- a/dom/base/PerformanceEntry.cpp +++ b/dom/base/PerformanceEntry.cpp @@ -9,7 +9,7 @@ using namespace mozilla::dom; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PerformanceEntry, mPerformance) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceEntry, mPerformance) NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceEntry) NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceEntry) diff --git a/dom/base/URLSearchParams.cpp b/dom/base/URLSearchParams.cpp index 50e710a77ae3..9707476a780c 100644 --- a/dom/base/URLSearchParams.cpp +++ b/dom/base/URLSearchParams.cpp @@ -9,7 +9,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(URLSearchParams, mObservers) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(URLSearchParams, mObservers) NS_IMPL_CYCLE_COLLECTING_ADDREF(URLSearchParams) NS_IMPL_CYCLE_COLLECTING_RELEASE(URLSearchParams) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index c11c0d27c881..c2c5e53effe3 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -1434,8 +1434,9 @@ nsDOMClassInfo::ResolveConstructor(JSContext *cx, JSObject *aObj, // window.classname, just fall through and let the JS engine // return the Object constructor. - if (!::JS_DefinePropertyById(cx, obj, sConstructor_id, val, JS_PropertyStub, - JS_StrictPropertyStub, JSPROP_ENUMERATE)) { + JS::Rooted id(cx, sConstructor_id); + if (!::JS_DefinePropertyById(cx, obj, id, val, JSPROP_ENUMERATE, + JS_PropertyStub, JS_StrictPropertyStub)) { return NS_ERROR_UNEXPECTED; } @@ -1670,8 +1671,8 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto) if (!contentDefinedProperty && desc.object() && !desc.value().isUndefined() && !JS_DefineUCProperty(cx, global, mData->mNameUTF16, NS_strlen(mData->mNameUTF16), - desc.value(), desc.getter(), desc.setter(), - desc.attributes())) { + desc.value(), desc.attributes(), + desc.getter(), desc.setter())) { return NS_ERROR_UNEXPECTED; } @@ -3263,9 +3264,9 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, rv = WrapNative(cx, location, &NS_GET_IID(nsIDOMLocation), true, &v); NS_ENSURE_SUCCESS(rv, rv); - bool ok = JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub, - LocationSetterUnwrapper, - JSPROP_PERMANENT | JSPROP_ENUMERATE); + bool ok = JS_DefinePropertyById(cx, obj, id, v, + JSPROP_PERMANENT | JSPROP_ENUMERATE, + JS_PropertyStub, LocationSetterUnwrapper); if (!ok) { return NS_ERROR_FAILURE; @@ -3291,9 +3292,10 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // Hold on to the top window object as a global property so we // don't need to worry about losing expando properties etc. - if (!JS_DefinePropertyById(cx, obj, id, v, JS_PropertyStub, JS_StrictPropertyStub, + if (!JS_DefinePropertyById(cx, obj, id, v, JSPROP_READONLY | JSPROP_PERMANENT | - JSPROP_ENUMERATE)) { + JSPROP_ENUMERATE, + JS_PropertyStub, JS_StrictPropertyStub)) { return NS_ERROR_FAILURE; } *objp = obj; @@ -3322,8 +3324,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // also already defined it, so we don't have to. if (desc.object() && !desc.value().isUndefined() && !JS_DefinePropertyById(cx, global, id, desc.value(), - desc.getter(), desc.setter(), - desc.attributes())) { + desc.attributes(), + desc.getter(), desc.setter())) { return NS_ERROR_FAILURE; } } @@ -3340,8 +3342,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, MOZ_ASSERT_IF(isXray, !desc.value().isUndefined()); if (!desc.value().isUndefined() && !JS_DefinePropertyById(cx, obj, id, desc.value(), - desc.getter(), desc.setter(), - desc.attributes())) { + desc.attributes(), + desc.getter(), desc.setter())) { return NS_ERROR_FAILURE; } @@ -3527,7 +3529,7 @@ nsGenericArraySH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, uint32_t index = uint32_t(n); if (index < length) { - *_retval = ::JS_DefineElement(cx, obj, index, JSVAL_VOID, nullptr, nullptr, + *_retval = ::JS_DefineElement(cx, obj, index, JS::UndefinedHandleValue, JSPROP_ENUMERATE | JSPROP_SHARED); *objp = obj; } @@ -3588,7 +3590,7 @@ nsGenericArraySH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, int32_t length = len_val.toInt32(); for (int32_t i = 0; ok && i < length; ++i) { - ok = ::JS_DefineElement(cx, obj, i, JSVAL_VOID, nullptr, nullptr, + ok = ::JS_DefineElement(cx, obj, i, JS::UndefinedHandleValue, JSPROP_ENUMERATE | JSPROP_SHARED); } } @@ -3719,8 +3721,8 @@ nsStorage2SH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, NS_ENSURE_SUCCESS(rv, rv); if (!DOMStringIsNull(data)) { - if (!::JS_DefinePropertyById(cx, realObj, id, JSVAL_VOID, nullptr, - nullptr, JSPROP_ENUMERATE)) { + if (!::JS_DefinePropertyById(cx, realObj, id, JS::UndefinedHandleValue, + JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index aee6f7fe4115..a9e1f502a880 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -13653,7 +13653,7 @@ nsGlobalWindow::EnableNetworkEvent(uint32_t aType) MOZ_ASSERT(IsInnerWindow()); nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (!permMgr) { NS_ERROR("No PermissionManager available!"); return; diff --git a/dom/base/nsMimeTypeArray.cpp b/dom/base/nsMimeTypeArray.cpp index d04a1785d88b..faef9a0135e0 100644 --- a/dom/base/nsMimeTypeArray.cpp +++ b/dom/base/nsMimeTypeArray.cpp @@ -25,10 +25,10 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMimeTypeArray) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsMimeTypeArray, - mWindow, - mMimeTypes, - mHiddenMimeTypes) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeTypeArray, + mWindow, + mMimeTypes, + mHiddenMimeTypes) nsMimeTypeArray::nsMimeTypeArray(nsPIDOMWindow* aWindow) : mWindow(aWindow) @@ -224,7 +224,7 @@ nsMimeTypeArray::EnsurePluginMimeTypes() NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsMimeType, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsMimeType, Release) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsMimeType, mWindow, mPluginElement) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsMimeType, mWindow, mPluginElement) nsMimeType::nsMimeType(nsPIDOMWindow* aWindow, nsPluginElement* aPluginElement, uint32_t aPluginTagMimeIndex, const nsAString& aType) diff --git a/dom/base/nsPerformance.cpp b/dom/base/nsPerformance.cpp index d8b0925c7103..8edcff479f81 100644 --- a/dom/base/nsPerformance.cpp +++ b/dom/base/nsPerformance.cpp @@ -22,7 +22,7 @@ using namespace mozilla; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPerformanceTiming, mPerformance) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPerformanceTiming, mPerformance) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceTiming, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceTiming, Release) @@ -337,7 +337,7 @@ nsPerformanceTiming::WrapObject(JSContext *cx) } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsPerformanceNavigation, mPerformance) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPerformanceNavigation, mPerformance) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsPerformanceNavigation, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsPerformanceNavigation, Release) @@ -360,10 +360,10 @@ nsPerformanceNavigation::WrapObject(JSContext *cx) } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_5(nsPerformance, - mWindow, mTiming, - mNavigation, mEntries, - mParentPerformance) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPerformance, + mWindow, mTiming, + mNavigation, mEntries, + mParentPerformance) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPerformance) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPerformance) diff --git a/dom/base/nsPluginArray.cpp b/dom/base/nsPluginArray.cpp index 5204fb49ce97..03d5ec391c7b 100644 --- a/dom/base/nsPluginArray.cpp +++ b/dom/base/nsPluginArray.cpp @@ -66,10 +66,10 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginArray) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(nsPluginArray, - mWindow, - mPlugins, - mHiddenPlugins) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray, + mWindow, + mPlugins, + mHiddenPlugins) static void GetPluginMimeTypes(const nsTArray >& aPlugins, @@ -356,7 +356,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPluginElement) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsPluginElement, mWindow, mMimeTypes) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginElement, mWindow, mMimeTypes) nsPluginElement::nsPluginElement(nsPIDOMWindow* aWindow, nsPluginTag* aPluginTag) diff --git a/dom/base/nsWindowRoot.cpp b/dom/base/nsWindowRoot.cpp index 1130bf66419a..65c53951d06e 100644 --- a/dom/base/nsWindowRoot.cpp +++ b/dom/base/nsWindowRoot.cpp @@ -42,11 +42,11 @@ nsWindowRoot::~nsWindowRoot() } } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(nsWindowRoot, - mWindow, - mListenerManager, - mPopupNode, - mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsWindowRoot, + mWindow, + mListenerManager, + mPopupNode, + mParent) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsWindowRoot) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h index f43992e071a1..36040874eb30 100644 --- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -341,397 +341,16 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(_class, _field) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(_class, _field1,\ - _field2) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_3(_class, _field1,\ - _field2, \ - _field3) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(_class, _field1,\ - _field2, \ - _field3, \ - _field4) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_5(_class, _field1,\ - _field2, \ - _field3, \ - _field4, \ - _field5) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_6(_class, _field1,\ - _field2, \ - _field3, \ - _field4, \ - _field5, \ - _field6) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_7(_class, _field1,\ - _field2, \ - _field3, \ - _field4, \ - _field5, \ - _field6, \ - _field7) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_8(_class, _field1,\ - _field2, \ - _field3, \ - _field4, \ - _field5, \ - _field6, \ - _field7, \ - _field8) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_9(_class, _field1,\ - _field2, \ - _field3, \ - _field4, \ - _field5, \ - _field6, \ - _field7, \ - _field8, \ - _field9) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_10(_class, _field1,\ - _field2, \ - _field3, \ - _field4, \ - _field5, \ - _field6, \ - _field7, \ - _field8, \ - _field9, \ - _field10) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_11(_class, \ - _field1, \ - _field2, \ - _field3, \ - _field4, \ - _field5, \ - _field6, \ - _field7, \ - _field8, \ - _field9, \ - _field10, \ - _field11) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field11) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field11) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_12(_class, \ - _field1, \ - _field2, \ - _field3, \ - _field4, \ - _field5, \ - _field6, \ - _field7, \ - _field8, \ - _field9, \ - _field10, \ - _field11, \ - _field12) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field11) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field12) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field11) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field12) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ - NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) - -#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_13(_class, \ - _field1, \ - _field2, \ - _field3, \ - _field4, \ - _field5, \ - _field6, \ - _field7, \ - _field8, \ - _field9, \ - _field10, \ - _field11, \ - _field12, \ - _field13) \ - NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field11) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field12) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK(_field13) \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ - NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field11) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field12) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field13) \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ +#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(_class, ...) \ + NS_IMPL_CYCLE_COLLECTION_CLASS(_class) \ + NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class) \ + NS_IMPL_CYCLE_COLLECTION_UNLINK(__VA_ARGS__) \ + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ + NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class) \ + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(__VA_ARGS__) \ + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS \ + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class) #endif /* nsWrapperCache_h___ */ diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 5560ead17f32..fe58ec2ba390 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -288,9 +288,24 @@ DOMInterfaces = { 'nativeType': 'nsDOMDataChannel', }, -'DataStoreCursor': { +'DataStore': [{ + 'workers': False +}, { + 'workers': True, + 'nativeType': 'mozilla::dom::workers::WorkerDataStore', + 'implicitJSContext': ['name', 'owner', 'readOnly', 'get', 'remove', + 'clear', 'revisionId', 'getLength', 'sync'] +}], + +'DataStoreCursor': [{ + 'workers': False, + 'wrapperCache': False +}, { + 'workers': True, + 'nativeType': 'mozilla::dom::workers::WorkerDataStoreCursor', 'wrapperCache': False, -}, + 'implicitJSContext': ['store', 'next', 'close'] +}], 'DedicatedWorkerGlobalScope': { 'headerFile': 'mozilla/dom/WorkerScope.h', @@ -1545,6 +1560,7 @@ DOMInterfaces = { 'WorkerNavigator': { 'headerFile': 'mozilla/dom/workers/bindings/Navigator.h', 'workers': True, + 'implicitJSContext': ['getDataStores'], }, 'XMLHttpRequest': [ diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index e0b1eec49f82..3800adcb0ad3 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -5044,7 +5044,7 @@ def getWrapTemplateForType(type, descriptorProvider, result, successCode, $*{innerTemplate} } while (0); if (!JS_DefineElement(cx, returnArray, ${index}, tmp, - nullptr, nullptr, JSPROP_ENUMERATE)) { + JSPROP_ENUMERATE)) { $*{exceptionCode} } } @@ -6787,8 +6787,8 @@ class CGNewResolveHook(CGAbstractBindingMethod): // define it. if (!desc.value().isUndefined() && !JS_DefinePropertyById(cx, obj, id, desc.value(), - desc.getter(), desc.setter(), - desc.attributes())) { + desc.attributes(), + desc.getter(), desc.setter())) { return false; } objp.set(obj); @@ -8688,8 +8688,8 @@ class CGResolveOwnPropertyViaNewresolve(CGAbstractBindingMethod): if (objDesc.object() && !objDesc.value().isUndefined() && !JS_DefinePropertyById(cx, obj, id, objDesc.value(), - objDesc.getter(), objDesc.setter(), - objDesc.attributes())) { + objDesc.attributes(), + objDesc.getter(), objDesc.setter())) { return false; } } @@ -10570,7 +10570,7 @@ class CGDictionary(CGThing): member.location)) propDef = ( - 'JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, nullptr, nullptr, JSPROP_ENUMERATE)' % + 'JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, JSPROP_ENUMERATE)' % self.makeIdName(member.identifier.name)) innerTemplate = wrapForType( diff --git a/dom/bluetooth/BluetoothManager.cpp b/dom/bluetooth/BluetoothManager.cpp index b3425207f4a8..15ffdc732354 100644 --- a/dom/bluetooth/BluetoothManager.cpp +++ b/dom/bluetooth/BluetoothManager.cpp @@ -18,6 +18,7 @@ #include "nsThreadUtils.h" #include "mozilla/dom/bluetooth/BluetoothTypes.h" #include "mozilla/dom/BluetoothManagerBinding.h" +#include "mozilla/Services.h" using namespace mozilla; @@ -199,8 +200,7 @@ BluetoothManager::CheckPermission(nsPIDOMWindow* aWindow) { NS_ASSERTION(aWindow, "Null pointer!"); - nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + nsCOMPtr permMgr = services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, false); uint32_t permission; diff --git a/dom/camera/DOMCameraDetectedFace.cpp b/dom/camera/DOMCameraDetectedFace.cpp index 86bc7c6f38bf..4187995d1c68 100644 --- a/dom/camera/DOMCameraDetectedFace.cpp +++ b/dom/camera/DOMCameraDetectedFace.cpp @@ -8,7 +8,7 @@ using namespace mozilla; using namespace mozilla::dom; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DOMCameraPoint, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMCameraPoint, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCameraPoint) NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCameraPoint) @@ -17,8 +17,8 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCameraPoint) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_5(DOMCameraDetectedFace, mParent, - mBounds, mLeftEye, mRightEye, mMouth) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMCameraDetectedFace, mParent, + mBounds, mLeftEye, mRightEye, mMouth) NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCameraDetectedFace) NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCameraDetectedFace) diff --git a/dom/camera/DOMCameraManager.cpp b/dom/camera/DOMCameraManager.cpp index 8a7614ad5d5f..546f5e2c9470 100644 --- a/dom/camera/DOMCameraManager.cpp +++ b/dom/camera/DOMCameraManager.cpp @@ -23,7 +23,7 @@ using namespace mozilla; using namespace mozilla::dom; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCameraManager, mWindow) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCameraManager, mWindow) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCameraManager) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) @@ -90,7 +90,7 @@ bool nsDOMCameraManager::CheckPermission(nsPIDOMWindow* aWindow) { nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, false); uint32_t permission = nsIPermissionManager::DENY_ACTION; diff --git a/dom/datastore/DataStore.h b/dom/datastore/DataStore.h index 5b4a96f6644d..2326ab10ec03 100644 --- a/dom/datastore/DataStore.h +++ b/dom/datastore/DataStore.h @@ -82,9 +82,6 @@ public: // target of DataStore, so that it can know where to fire the events. void SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv); -protected: - virtual ~DataStore() {} - private: nsRefPtr mStore; }; diff --git a/dom/datastore/DataStoreCursor.cpp b/dom/datastore/DataStoreCursor.cpp index 47c7a7fe7c08..6943051dbdf8 100644 --- a/dom/datastore/DataStoreCursor.cpp +++ b/dom/datastore/DataStoreCursor.cpp @@ -13,8 +13,12 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DataStoreCursor, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DataStoreCursor, Release) +NS_IMPL_CYCLE_COLLECTING_ADDREF(DataStoreCursor) +NS_IMPL_CYCLE_COLLECTING_RELEASE(DataStoreCursor) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DataStoreCursor) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION(DataStoreCursor, mCursor) diff --git a/dom/datastore/DataStoreCursor.h b/dom/datastore/DataStoreCursor.h index 87b09a2d7285..1448d145c227 100644 --- a/dom/datastore/DataStoreCursor.h +++ b/dom/datastore/DataStoreCursor.h @@ -22,11 +22,11 @@ class DataStore; class GlobalObject; class DataStoreCursorImpl; -class DataStoreCursor MOZ_FINAL +class DataStoreCursor MOZ_FINAL : public nsISupports { public: - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(DataStoreCursor) - NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(DataStoreCursor) + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(DataStoreCursor) // WebIDL (internal functions) @@ -48,9 +48,6 @@ public: // API's logic in JS. void SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor); -protected: - virtual ~DataStoreCursor() {} - private: nsRefPtr mCursor; }; diff --git a/dom/datastore/DataStoreService.js b/dom/datastore/DataStoreService.js index efefc860833e..0675de36ab81 100644 --- a/dom/datastore/DataStoreService.js +++ b/dom/datastore/DataStoreService.js @@ -308,7 +308,7 @@ DataStoreService.prototype = { getDataStoreCreate: function(aWindow, aResolve, aStores) { debug("GetDataStoreCreate"); - let results = []; + let results = new aWindow.Array(); if (!aStores.length) { aResolve(results); @@ -342,7 +342,7 @@ DataStoreService.prototype = { debug("GetDataStoreResolve"); let callbackPending = aStores.length; - let results = []; + let results = new aWindow.Array(); if (!callbackPending) { aResolve(results); diff --git a/dom/datastore/tests/file_basic_worker.html b/dom/datastore/tests/file_basic_worker.html new file mode 100644 index 000000000000..1bd15e9b4358 --- /dev/null +++ b/dom/datastore/tests/file_basic_worker.html @@ -0,0 +1,30 @@ + + + + + Test for DataStore - basic operation on a readonly db + + +
+ + + diff --git a/dom/datastore/tests/file_basic_worker.js b/dom/datastore/tests/file_basic_worker.js new file mode 100644 index 000000000000..492bb3f57041 --- /dev/null +++ b/dom/datastore/tests/file_basic_worker.js @@ -0,0 +1,137 @@ + var gStore; + + function is(a, b, msg) { + postMessage((a === b ? 'OK' : 'KO') + ' ' + msg) + } + + function ok(a, msg) { + postMessage((a ? 'OK' : 'KO')+ ' ' + msg) + } + + function cbError() { + postMessage('KO error'); + } + + function finish() { + postMessage('DONE'); + } + + function testGetDataStores() { + navigator.getDataStores('foo').then(function(stores) { + is(stores.length, 1, "getDataStores('foo') returns 1 element"); + is(stores[0].name, 'foo', 'The dataStore.name is foo'); + is(stores[0].readOnly, false, 'The dataStore foo is not in readonly'); + + var store = stores[0]; + ok("get" in store, "store.get exists"); + ok("put" in store, "store.put exists"); + ok("add" in store, "store.add exists"); + ok("remove" in store, "store.remove exists"); + ok("clear" in store, "store.clear exists"); + ok("revisionId" in store, "store.revisionId exists"); + ok("getLength" in store, "store.getLength exists"); + ok("sync" in store, "store.sync exists"); + + gStore = stores[0]; + + runTest(); + }, cbError); + } + + function testStoreGet(id, value) { + gStore.get(id).then(function(what) { + ok(true, "store.get() retrieves data"); + is(what, value, "store.get(" + id + ") returns " + value); + }, function() { + ok(false, "store.get(" + id + ") retrieves data"); + }).then(runTest, cbError); + } + + function testStoreAdd(value) { + return gStore.add(value).then(function(what) { + ok(true, "store.add() is called"); + ok(what > 0, "store.add() returns something"); + return what; + }, cbError); + } + + function testStorePut(value, id) { + return gStore.put(value, id).then(function() { + ok(true, "store.put() is called"); + }, cbError); + } + + function testStoreGetLength(number) { + return gStore.getLength().then(function(n) { + is(number, n, "store.getLength() returns the right number"); + }, cbError); + } + + function testStoreRemove(id) { + return gStore.remove(id).then(function() { + ok(true, "store.remove() is called"); + }, cbError); + } + + function testStoreClear() { + return gStore.clear().then(function() { + ok(true, "store.clear() is called"); + }, cbError); + } + + var tests = [ + // Test for GetDataStore + testGetDataStores, + + // Unknown ID + function() { testStoreGet(42, undefined); }, + function() { testStoreGet(42, undefined); }, // twice + + // Add + Get - number + function() { testStoreAdd(42).then(function(id) { + gId = id; runTest(); }, cbError); }, + function() { testStoreGet(gId, 42); }, + + // Add + Get - boolean + function() { testStoreAdd(true).then(function(id) { + gId = id; runTest(); }, cbError); }, + function() { testStoreGet(gId, true); }, + + // Add + Get - string + function() { testStoreAdd("hello world").then(function(id) { + gId = id; runTest(); }, cbError); }, + function() { testStoreGet(gId, "hello world"); }, + + // Put + Get - string + function() { testStorePut("hello world 2", gId).then(function() { + runTest(); }, cbError); }, + function() { testStoreGet(gId, "hello world 2"); }, + + // getLength + function() { testStoreGetLength(3).then(function() { runTest(); }, cbError); }, + + // Remove + function() { testStoreRemove(gId).then(function(what) { + runTest(); }, cbError); }, + function() { testStoreGet(gId, undefined); }, + + // Remove - wrong ID + function() { testStoreRemove(gId).then(function(what) { + runTest(); }, cbError); }, + + // Clear + function() { testStoreClear().then(function(what) { + runTest(); }, cbError); }, + ]; + + function runTest() { + if (!tests.length) { + finish(); + return; + } + + var test = tests.shift(); + test(); + } + + runTest(); \ No newline at end of file diff --git a/dom/datastore/tests/file_sync.html b/dom/datastore/tests/file_sync.html index 1cfef5ae3e86..3eb1b3c01643 100644 --- a/dom/datastore/tests/file_sync.html +++ b/dom/datastore/tests/file_sync.html @@ -372,7 +372,7 @@ var steps = [ { operation: 'clear', }, { operation: 'add', id: 1, data: 123 }, { operation: 'add', id: 2, data: 42 }, - { operation: 'add', id: 'foobar', data: 2 } ] + { operation: 'add', id: 'foobar', data: 2 } ] testCursor(gCursor, steps); }, @@ -387,7 +387,7 @@ var steps = [ { operation: 'clear', }, { operation: 'add', id: 1, data: 123 }, { operation: 'add', id: 2, data: 43 }, - { operation: 'add', id: 'foobar', data: 2 } ] + { operation: 'add', id: 'foobar', data: 2 } ] testCursor(gCursor, steps); }, @@ -401,7 +401,7 @@ function() { var steps = [ { operation: 'clear', }, { operation: 'add', id: 1, data: 123 }, - { operation: 'add', id: 'foobar', data: 2 } ] + { operation: 'add', id: 'foobar', data: 2 } ] testCursor(gCursor, steps); }, @@ -417,7 +417,7 @@ var steps = [ { operation: 'clear', }, { operation: 'add', id: 1, data: 123 }, { operation: 'add', id: 4, data: 42 }, - { operation: 'add', id: 'foobar', data: 2 } ] + { operation: 'add', id: 'foobar', data: 2 } ] testCursor(gCursor, steps); }, diff --git a/dom/datastore/tests/file_sync_worker.html b/dom/datastore/tests/file_sync_worker.html new file mode 100644 index 000000000000..9f5f32cd7bc7 --- /dev/null +++ b/dom/datastore/tests/file_sync_worker.html @@ -0,0 +1,30 @@ + + + + + Test for DataStore - sync + + +
+ + + diff --git a/dom/datastore/tests/file_sync_worker.js b/dom/datastore/tests/file_sync_worker.js new file mode 100644 index 000000000000..67b3c2e01731 --- /dev/null +++ b/dom/datastore/tests/file_sync_worker.js @@ -0,0 +1,477 @@ + var gStore; + var gRevisions = []; + var gCursor; + var gExpectedEvents = true; + + function is(a, b, msg) { + postMessage((a === b ? 'OK' : 'KO') + ' ' + msg) + } + + function ok(a, msg) { + postMessage((a ? 'OK' : 'KO')+ ' ' + msg) + } + + function cbError() { + postMessage('KO error'); + } + + function finish() { + postMessage('DONE'); + } + + function testGetDataStores() { + navigator.getDataStores('foo').then(function(stores) { + is(stores.length, 1, "getDataStores('foo') returns 1 element"); + + gStore = stores[0]; + gRevisions.push(gStore.revisionId); + + gStore.onchange = function(aEvent) { + ok(gExpectedEvents, "Events received!"); + runTest(); + } + + runTest(); + }, cbError); + } + + function testBasicInterface() { + var cursor = gStore.sync(); + ok(cursor, "Cursor is created"); + + // TODO This needs more love for running on workers. Tend to fire a + // follow-up for this... + // is(cursor.store, gStore, "Cursor.store is the store"); + + ok("next" in cursor, "Cursor.next exists"); + ok("close" in cursor, "Cursor.close exists"); + + cursor.close(); + + runTest(); + } + + function testCursor(cursor, steps) { + if (!steps.length) { + runTest(); + return; + } + + var step = steps.shift(); + cursor.next().then(function(data) { + ok(!!data, "Cursor.next returns data"); + is(data.operation, step.operation, "Waiting for operation: '" + step.operation + "' received '" + data.operation + "'"); + + + switch (data.operation) { + case 'done': + is(/[0-9a-zA-Z]{8}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{4}-[0-9a-zA-Z]{12}/.test(data.revisionId), true, "done has a valid revisionId"); + is (data.revisionId, gRevisions[gRevisions.length-1], "Last revision matches"); + break; + + case 'add': + case 'update': + if ('id' in step) { + is(data.id, step.id, "next() add: id matches: " + data.id + " " + step.id); + } + + if ('data' in step) { + is(data.data, step.data, "next() add: data matches: " + data.data + " " + step.data); + } + + break; + + case 'remove': + if ('id' in step) { + is(data.id, step.id, "next() add: id matches: " + data.id + " " + step.id); + } + + break; + } + + testCursor(cursor, steps); + }); + } + + var tests = [ + // Test for GetDataStore + testGetDataStores, + + // interface test + testBasicInterface, + + // empty DataStore + function() { + var cursor = gStore.sync(); + var steps = [ { operation: 'clear' }, + { operation: 'done' }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + gExpectedEvents = false; + var cursor = gStore.sync('wrong revision ID'); + var steps = [ { operation: 'clear' }, + { operation: 'done' }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[0]); + var steps = [ { operation: 'done' }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + // Test add from scratch + function() { + gExpectedEvents = true; + + gStore.add(1).then(function(id) { + gRevisions.push(gStore.revisionId); + ok(true, "Item: " + id + " added"); + }); + }, + + function() { + gStore.add(2,"foobar").then(function(id) { + gRevisions.push(gStore.revisionId); + ok(true, "Item: " + id + " added"); + }); + }, + + function() { + gStore.add(3,3).then(function(id) { + gRevisions.push(gStore.revisionId); + ok(true, "Item: " + id + " added"); + }); + }, + + function() { + gExpectedEvents = false; + var cursor = gStore.sync(); + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 1 }, + { operation: 'add', id: 3, data: 3 }, + { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync('wrong revision ID'); + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 1 }, + { operation: 'add', id: 3, data: 3 }, + { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[0]); + var steps = [ { operation: 'add', id: 1, data: 1 }, + { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'add', id: 3, data: 3 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[1]); + var steps = [ { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'add', id: 3, data: 3 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[2]); + var steps = [ { operation: 'add', id: 3, data: 3 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[3]); + var steps = [ { operation: 'done' }]; + testCursor(cursor, steps); + }, + + // Test after an update + function() { + gExpectedEvents = true; + gStore.put(123, 1).then(function() { + gRevisions.push(gStore.revisionId); + }); + }, + + function() { + gExpectedEvents = false; + var cursor = gStore.sync(); + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 3, data: 3 }, + { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync('wrong revision ID'); + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 3, data: 3 }, + { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[0]); + var steps = [ { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'add', id: 3, data: 3 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[1]); + var steps = [ { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'add', id: 3, data: 3 }, + { operation: 'update', id: 1, data: 123 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[2]); + var steps = [ { operation: 'add', id: 3, data: 3 }, + { operation: 'update', id: 1, data: 123 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[3]); + var steps = [ { operation: 'update', id: 1, data: 123 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[4]); + var steps = [ { operation: 'done' }]; + testCursor(cursor, steps); + }, + + // Test after a remove + function() { + gExpectedEvents = true; + gStore.remove(3).then(function() { + gRevisions.push(gStore.revisionId); + }); + }, + + function() { + gExpectedEvents = false; + var cursor = gStore.sync(); + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync('wrong revision ID'); + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[0]); + var steps = [ { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[1]); + var steps = [ { operation: 'add', id: 'foobar', data: 2 }, + { operation: 'update', id: 1, data: 123 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[2]); + var steps = [ { operation: 'update', id: 1, data: 123 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[3]); + var steps = [ { operation: 'update', id: 1, data: 123 }, + { operation: 'remove', id: 3 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[4]); + var steps = [ { operation: 'remove', id: 3 }, + { operation: 'done' }]; + testCursor(cursor, steps); + }, + + function() { + var cursor = gStore.sync(gRevisions[5]); + var steps = [ { operation: 'done' }]; + testCursor(cursor, steps); + }, + + // New events when the cursor is active + function() { + gCursor = gStore.sync(); + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 'foobar', data: 2 } ]; + testCursor(gCursor, steps); + }, + + function() { + gStore.add(42, 2).then(function(id) { + ok(true, "Item: " + id + " added"); + gRevisions.push(gStore.revisionId); + runTest(); + }); + }, + + function() { + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 2, data: 42 }, + { operation: 'add', id: 'foobar', data: 2 } ] + testCursor(gCursor, steps); + }, + + function() { + gStore.put(43, 2).then(function(id) { + gRevisions.push(gStore.revisionId); + runTest(); + }); + }, + + function() { + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 2, data: 43 }, + { operation: 'add', id: 'foobar', data: 2 } ] + testCursor(gCursor, steps); + }, + + function() { + gStore.remove(2).then(function(id) { + gRevisions.push(gStore.revisionId); + runTest(); + }); + }, + + function() { + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 'foobar', data: 2 } ] + testCursor(gCursor, steps); + }, + + function() { + gStore.add(42).then(function(id) { + ok(true, "Item: " + id + " added"); + gRevisions.push(gStore.revisionId); + runTest(); + }); + }, + + function() { + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 1, data: 123 }, + { operation: 'add', id: 4, data: 42 }, + { operation: 'add', id: 'foobar', data: 2 } ] + testCursor(gCursor, steps); + }, + + function() { + gStore.clear().then(function() { + gRevisions.push(gStore.revisionId); + runTest(); + }); + }, + + function() { + var steps = [ { operation: 'clear' } ]; + testCursor(gCursor, steps); + }, + + function() { + gStore.add(42).then(function(id) { + ok(true, "Item: " + id + " added"); + gRevisions.push(gStore.revisionId); + runTest(); + }); + }, + + function() { + var steps = [ { operation: 'clear', }, + { operation: 'add', id: 5, data: 42 } ]; + testCursor(gCursor, steps); + }, + + function() { + gStore.clear().then(function() { + gRevisions.push(gStore.revisionId); + runTest(); + }); + }, + + function() { + gStore.add(42).then(function(id) { + ok(true, "Item: " + id + " added"); + gRevisions.push(gStore.revisionId); + runTest(); + }); + }, + + function() { + var steps = [ { operation: 'clear' }, + { operation: 'add', id: 6, data: 42 }, + { operation: 'done'} ]; + testCursor(gCursor, steps); + }, + + function() { + gExpectedEvents = true; + gStore.add(42).then(function(id) { + }); + } + ]; + + function runTest() { + if (!tests.length) { + finish(); + return; + } + + var test = tests.shift(); + test(); + } + + runTest(); \ No newline at end of file diff --git a/dom/datastore/tests/mochitest.ini b/dom/datastore/tests/mochitest.ini index 085deebd6667..6da817d0894a 100644 --- a/dom/datastore/tests/mochitest.ini +++ b/dom/datastore/tests/mochitest.ini @@ -4,6 +4,8 @@ support-files = file_app_install.html file_readonly.html file_basic.html + file_basic_worker.html + file_basic_worker.js file_changes.html file_changes2.html file_app.sjs @@ -11,6 +13,8 @@ support-files = file_app2.template.webapp file_arrays.html file_sync.html + file_sync_worker.html + file_sync_worker.js file_bug924104.html file_certifiedApp.html file_keys.html @@ -27,6 +31,7 @@ support-files = [test_readonly.html] skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage) [test_basic.html] +[test_basic_worker.html] [test_changes.html] skip-if = (toolkit == 'gonk' && debug) #intermittent failures, bug 961021 [test_arrays.html] @@ -34,6 +39,7 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure; time out [test_oop.html] skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage) [test_sync.html] +[test_sync_worker.html] skip-if = (buildapp == 'b2g' && (toolkit != 'gonk' || debug)) # b2g-debug(debug-only failure; time out) b2g-desktop(Bug 931116, b2g desktop specific, initial triage) [test_bug924104.html] [test_certifiedApp.html] diff --git a/dom/datastore/tests/test_basic_worker.html b/dom/datastore/tests/test_basic_worker.html new file mode 100644 index 000000000000..be940e8771b1 --- /dev/null +++ b/dom/datastore/tests/test_basic_worker.html @@ -0,0 +1,127 @@ + + + + + Test for DataStore - basic operation on a readonly db + + + + +
+ + + diff --git a/dom/datastore/tests/test_sync_worker.html b/dom/datastore/tests/test_sync_worker.html new file mode 100644 index 000000000000..904edea96e8f --- /dev/null +++ b/dom/datastore/tests/test_sync_worker.html @@ -0,0 +1,126 @@ + + + + + Test for DataStore - sync + + + + +
+ + + diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index 031769eef3e8..020b3ea39460 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -3140,7 +3140,7 @@ nsDOMDeviceStorage::Init(nsPIDOMWindow* aWindow, const nsAString &aType, // if the caller has the "webapps-manage" permission. if (aType.EqualsLiteral(DEVICESTORAGE_APPS)) { nsCOMPtr permissionManager - = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + = services::GetPermissionManager(); NS_ENSURE_TRUE(permissionManager, NS_ERROR_FAILURE); uint32_t permission; diff --git a/dom/events/ContentEventHandler.cpp b/dom/events/ContentEventHandler.cpp index 08871973db39..04ff83b70cc7 100644 --- a/dom/events/ContentEventHandler.cpp +++ b/dom/events/ContentEventHandler.cpp @@ -50,12 +50,8 @@ ContentEventHandler::ContentEventHandler(nsPresContext* aPresContext) } nsresult -ContentEventHandler::InitCommon() +ContentEventHandler::InitBasic() { - if (mSelection) { - return NS_OK; - } - NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_AVAILABLE); // If text frame which has overflowing selection underline is dirty, @@ -65,11 +61,24 @@ ContentEventHandler::InitCommon() // Flushing notifications can cause mPresShell to be destroyed (bug 577963). NS_ENSURE_TRUE(!mPresShell->IsDestroying(), NS_ERROR_FAILURE); + return NS_OK; +} + +nsresult +ContentEventHandler::InitCommon() +{ + if (mSelection) { + return NS_OK; + } + + nsresult rv = InitBasic(); + NS_ENSURE_SUCCESS(rv, rv); + nsCopySupport::GetSelectionForCopy(mPresShell->GetDocument(), getter_AddRefs(mSelection)); nsCOMPtr firstRange; - nsresult rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange)); + rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange)); // This shell doesn't support selection. if (NS_FAILED(rv)) { return NS_ERROR_NOT_AVAILABLE; @@ -996,11 +1005,14 @@ ContentEventHandler::OnQueryCharacterAtPoint(WidgetQueryContentEvent* aEvent) nsresult ContentEventHandler::OnQueryDOMWidgetHittest(WidgetQueryContentEvent* aEvent) { - nsresult rv = Init(aEvent); + NS_ASSERTION(aEvent, "aEvent must not be null"); + + nsresult rv = InitBasic(); if (NS_FAILED(rv)) { return rv; } + aEvent->mSucceeded = false; aEvent->mReply.mWidgetIsHit = false; NS_ENSURE_TRUE(aEvent->widget, NS_ERROR_FAILURE); diff --git a/dom/events/ContentEventHandler.h b/dom/events/ContentEventHandler.h index 7b977bbb3b63..1fedc29ca819 100644 --- a/dom/events/ContentEventHandler.h +++ b/dom/events/ContentEventHandler.h @@ -68,7 +68,7 @@ protected: nsresult Init(WidgetQueryContentEvent* aEvent); nsresult Init(WidgetSelectionEvent* aEvent); - // InitCommon() is called from each Init(). + nsresult InitBasic(); nsresult InitCommon(); public: diff --git a/dom/events/DeviceMotionEvent.cpp b/dom/events/DeviceMotionEvent.cpp index 10638c287a9b..5ec72db43535 100644 --- a/dom/events/DeviceMotionEvent.cpp +++ b/dom/events/DeviceMotionEvent.cpp @@ -95,7 +95,7 @@ DeviceMotionEvent::Constructor(const GlobalObject& aGlobal, * DeviceAcceleration *****************************************************************************/ -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DeviceAcceleration, mOwner) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DeviceAcceleration, mOwner) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DeviceAcceleration, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DeviceAcceleration, Release) @@ -120,7 +120,7 @@ DeviceAcceleration::~DeviceAcceleration() * DeviceRotationRate *****************************************************************************/ -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(DeviceRotationRate, mOwner) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DeviceRotationRate, mOwner) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DeviceRotationRate, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DeviceRotationRate, Release) diff --git a/dom/events/PaintRequest.cpp b/dom/events/PaintRequest.cpp index 02b9e6eb60ce..d162e27f94c6 100644 --- a/dom/events/PaintRequest.cpp +++ b/dom/events/PaintRequest.cpp @@ -16,7 +16,7 @@ namespace dom { * mozilla::dom::PaintRequest *****************************************************************************/ -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PaintRequest, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaintRequest, mParent) NS_INTERFACE_TABLE_HEAD(PaintRequest) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY @@ -60,7 +60,7 @@ PaintRequest::GetXPCOMReason(nsAString& aResult) * mozilla::dom::PaintRequestList *****************************************************************************/ -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PaintRequestList, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaintRequestList, mParent) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PaintRequestList) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY diff --git a/dom/events/Touch.cpp b/dom/events/Touch.cpp index af5d6cea2d7a..dd2987f624f7 100644 --- a/dom/events/Touch.cpp +++ b/dom/events/Touch.cpp @@ -79,7 +79,7 @@ Touch::PrefEnabled(JSContext* aCx, JSObject* aGlobal) return TouchEvent::PrefEnabled(aCx, aGlobal); } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Touch, mTarget) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Touch, mTarget) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Touch) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY diff --git a/dom/events/TouchEvent.cpp b/dom/events/TouchEvent.cpp index d8626905f628..8fd069bbe69f 100644 --- a/dom/events/TouchEvent.cpp +++ b/dom/events/TouchEvent.cpp @@ -30,7 +30,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TouchList) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(TouchList, mParent, mPoints) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TouchList, mParent, mPoints) NS_IMPL_CYCLE_COLLECTING_ADDREF(TouchList) NS_IMPL_CYCLE_COLLECTING_RELEASE(TouchList) diff --git a/dom/file/ArchiveReader.cpp b/dom/file/ArchiveReader.cpp index 55d6fe2936a7..118971e17cb2 100644 --- a/dom/file/ArchiveReader.cpp +++ b/dom/file/ArchiveReader.cpp @@ -202,11 +202,11 @@ ArchiveReader::GenerateArchiveRequest() return ArchiveRequest::Create(mWindow, this); } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(ArchiveReader, - mBlob, - mWindow, - mData.fileList, - mRequests) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ArchiveReader, + mBlob, + mWindow, + mData.fileList, + mRequests) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ArchiveReader) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY diff --git a/dom/file/ArchiveRequest.cpp b/dom/file/ArchiveRequest.cpp index 5ca3aec58b85..b916cf58638c 100644 --- a/dom/file/ArchiveRequest.cpp +++ b/dom/file/ArchiveRequest.cpp @@ -195,8 +195,7 @@ ArchiveRequest::GetFilenamesResult(JSContext* aCx, NS_ENSURE_TRUE(str, NS_ERROR_OUT_OF_MEMORY); if (NS_FAILED(rv) || - !JS_DefineElement(aCx, array, i, JS::StringValue(str), nullptr, nullptr, - JSPROP_ENUMERATE)) { + !JS_DefineElement(aCx, array, i, str, JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } } @@ -247,8 +246,7 @@ ArchiveRequest::GetFilesResult(JSContext* aCx, nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile), &value); if (NS_FAILED(rv) || - !JS_DefineElement(aCx, array, i, value, nullptr, nullptr, - JSPROP_ENUMERATE)) { + !JS_DefineElement(aCx, array, i, value, JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } } diff --git a/dom/gamepad/Gamepad.cpp b/dom/gamepad/Gamepad.cpp index 5e2d74c2d31c..f2cff65d2ea7 100644 --- a/dom/gamepad/Gamepad.cpp +++ b/dom/gamepad/Gamepad.cpp @@ -19,7 +19,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Gamepad) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(Gamepad, mParent, mButtons) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Gamepad, mParent, mButtons) Gamepad::Gamepad(nsISupports* aParent, const nsAString& aID, uint32_t aIndex, diff --git a/dom/gamepad/GamepadButton.cpp b/dom/gamepad/GamepadButton.cpp index d67821f433eb..a46eecd4573f 100644 --- a/dom/gamepad/GamepadButton.cpp +++ b/dom/gamepad/GamepadButton.cpp @@ -16,7 +16,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GamepadButton) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(GamepadButton, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(GamepadButton, mParent) /* virtual */ JSObject* GamepadButton::WrapObject(JSContext* aCx) diff --git a/dom/indexedDB/CheckPermissionsHelper.cpp b/dom/indexedDB/CheckPermissionsHelper.cpp index 34365d25df36..b5b9c73ece19 100644 --- a/dom/indexedDB/CheckPermissionsHelper.cpp +++ b/dom/indexedDB/CheckPermissionsHelper.cpp @@ -63,8 +63,7 @@ GetIndexedDBPermissions(nsIDOMWindow* aWindow) return PERMISSION_DENIED; } - nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + nsCOMPtr permissionManager = GetPermissionManager(); NS_ENSURE_TRUE(permissionManager, PERMISSION_DENIED); uint32_t permission; @@ -108,8 +107,7 @@ CheckPermissionsHelper::Run() nsIPrincipal* windowPrincipal = sop->GetPrincipal(); NS_ASSERTION(windowPrincipal, "Null principal!"); - nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + nsCOMPtr permissionManager = GetPermissionManager(); NS_ENSURE_STATE(permissionManager); rv = permissionManager->AddFromPrincipal(windowPrincipal, diff --git a/dom/indexedDB/KeyPath.cpp b/dom/indexedDB/KeyPath.cpp index 4d83d92f1432..b9a357113f4e 100644 --- a/dom/indexedDB/KeyPath.cpp +++ b/dom/indexedDB/KeyPath.cpp @@ -169,9 +169,7 @@ GetJSValFromKeyPathString(JSContext* aCx, } if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(), - token.Length(), - OBJECT_TO_JSVAL(dummy), nullptr, nullptr, - JSPROP_ENUMERATE)) { + token.Length(), dummy, JSPROP_ENUMERATE)) { IDB_REPORT_INTERNAL_ERR(); rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; break; @@ -189,8 +187,7 @@ GetJSValFromKeyPathString(JSContext* aCx, } if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(), - token.Length(), OBJECT_TO_JSVAL(dummy), - nullptr, nullptr, JSPROP_ENUMERATE)) { + token.Length(), dummy, JSPROP_ENUMERATE)) { IDB_REPORT_INTERNAL_ERR(); rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; break; diff --git a/dom/ipc/AppProcessChecker.cpp b/dom/ipc/AppProcessChecker.cpp index a3c2b6e72b27..71de38053987 100644 --- a/dom/ipc/AppProcessChecker.cpp +++ b/dom/ipc/AppProcessChecker.cpp @@ -225,7 +225,7 @@ CheckPermission(PContentParent* aActor, } nsCOMPtr pm = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(pm, nsIPermissionManager::DENY_ACTION); // Make sure that `aPermission' is an app permission before checking the origin. diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 07deef6e1340..a9031d6a4e46 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1406,7 +1406,7 @@ ContentChild::RecvAddPermission(const IPC::Permission& permission) { #if MOZ_PERMISSIONS nsCOMPtr permissionManagerIface = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); nsPermissionManager* permissionManager = static_cast(permissionManagerIface.get()); NS_ABORT_IF_FALSE(permissionManager, diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 9aa9192dc4db..7e08f148f065 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1705,7 +1705,7 @@ ContentParent::RecvReadPermissions(InfallibleTArray* aPermissio { #ifdef MOZ_PERMISSIONS nsCOMPtr permissionManagerIface = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); nsPermissionManager* permissionManager = static_cast(permissionManagerIface.get()); NS_ABORT_IF_FALSE(permissionManager, diff --git a/dom/locales/en-US/chrome/accessibility/AccessFu.properties b/dom/locales/en-US/chrome/accessibility/AccessFu.properties index bb145fd2d5e8..f530a3f3910b 100644 --- a/dom/locales/en-US/chrome/accessibility/AccessFu.properties +++ b/dom/locales/en-US/chrome/accessibility/AccessFu.properties @@ -64,7 +64,7 @@ form = form comboboxlist = combo box list comboboxoption = combo box option imagemap = image map -listboxoption = list box option +listboxoption = option listbox = list box flatequation = flat equation gridcell = gridcell diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index bfa49334b4ad..3b416ff731c0 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -1332,6 +1332,8 @@ MediaManager::GetUserMedia(bool aPrivileged, nsCOMPtr onSuccess(aOnSuccess); nsCOMPtr onError(aOnError); + MediaStreamConstraints c(aConstraints); // copy + /** * If we were asked to get a picture, before getting a snapshot, we check if * the calling page is allowed to open a popup. We do this because @@ -1392,8 +1394,6 @@ MediaManager::GetUserMedia(bool aPrivileged, // No need for locking because we always do this in the main thread. listeners->AppendElement(listener); - MediaStreamConstraints c(aConstraints); // copy - // Developer preference for turning off permission check. if (Preferences::GetBool("media.navigator.permission.disabled", false)) { aPrivileged = true; diff --git a/dom/mobileconnection/src/MobileConnection.cpp b/dom/mobileconnection/src/MobileConnection.cpp index bbac80799c17..4221b50e3ce1 100644 --- a/dom/mobileconnection/src/MobileConnection.cpp +++ b/dom/mobileconnection/src/MobileConnection.cpp @@ -157,7 +157,7 @@ MobileConnection::CheckPermission(const char* aType) NS_ENSURE_TRUE(window, false); nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + mozilla::services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, false); uint32_t permission = nsIPermissionManager::DENY_ACTION; diff --git a/dom/permission/PermissionSettings.js b/dom/permission/PermissionSettings.js index 50bb3303a241..a07745ab8dbb 100644 --- a/dom/permission/PermissionSettings.js +++ b/dom/permission/PermissionSettings.js @@ -28,16 +28,6 @@ function PermissionSettings() debug("Constructor"); } -XPCOMUtils.defineLazyServiceGetter(this, - "permissionManager", - "@mozilla.org/permissionmanager;1", - "nsIPermissionManager"); - -XPCOMUtils.defineLazyServiceGetter(this, - "secMan", - "@mozilla.org/scriptsecuritymanager;1", - "nsIScriptSecurityManager"); - XPCOMUtils.defineLazyServiceGetter(this, "appsService", "@mozilla.org/AppsService;1", @@ -48,8 +38,8 @@ PermissionSettings.prototype = { debug("Get called with: " + aPermName + ", " + aManifestURL + ", " + aOrigin + ", " + aBrowserFlag); let uri = Services.io.newURI(aOrigin, null, null); let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); - let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag); - let result = permissionManager.testExactPermanentPermission(principal, aPermName); + let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aBrowserFlag); + let result = Services.perms.testExactPermanentPermission(principal, aPermName); switch (result) { @@ -72,7 +62,7 @@ PermissionSettings.prototype = { debug("isExplicit: " + aPermName + ", " + aManifestURL + ", " + aOrigin); let uri = Services.io.newURI(aOrigin, null, null); let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); - let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag); + let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aBrowserFlag); return isExplicitInPermissionsTable(aPermName, principal.appStatus); }, @@ -108,7 +98,7 @@ PermissionSettings.prototype = { remove: function remove(aPermName, aManifestURL, aOrigin) { let uri = Services.io.newURI(aOrigin, null, null); let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); - let principal = secMan.getAppCodebasePrincipal(uri, appID, true); + let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, true); if (principal.appStatus !== Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED) { let errorMsg = "PermissionSettings.js: '" + aOrigin + "'" + diff --git a/dom/permission/PermissionSettings.jsm b/dom/permission/PermissionSettings.jsm index 2a953319de1a..9c660febd93e 100644 --- a/dom/permission/PermissionSettings.jsm +++ b/dom/permission/PermissionSettings.jsm @@ -22,16 +22,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm", "@mozilla.org/parentprocessmessagemanager;1", "nsIMessageListenerManager"); -XPCOMUtils.defineLazyServiceGetter(this, - "permissionManager", - "@mozilla.org/permissionmanager;1", - "nsIPermissionManager"); - -XPCOMUtils.defineLazyServiceGetter(this, - "secMan", - "@mozilla.org/scriptsecuritymanager;1", - "nsIScriptSecurityManager"); - XPCOMUtils.defineLazyServiceGetter(this, "appsService", "@mozilla.org/AppsService;1", @@ -59,7 +49,7 @@ this.PermissionSettingsModule = { // if the permission is actually explicit (and thus modifiable) or not // on permissionManager also but we currently don't. let perm = - permissionManager.testExactPermissionFromPrincipal(aPrincipal,aPermName); + Services.perms.testExactPermissionFromPrincipal(aPrincipal,aPermName); let isExplicit = isExplicitInPermissionsTable(aPermName, aPrincipal.appStatus); return (aAction === "unknown" && @@ -79,7 +69,7 @@ this.PermissionSettingsModule = { _internalAddPermission: function _internalAddPermission(aData, aAllowAllChanges, aCallbacks) { let uri = Services.io.newURI(aData.origin, null, null); let appID = appsService.getAppLocalIdByManifestURL(aData.manifestURL); - let principal = secMan.getAppCodebasePrincipal(uri, appID, aData.browserFlag); + let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aData.browserFlag); let action; switch (aData.value) @@ -104,7 +94,7 @@ this.PermissionSettingsModule = { if (aAllowAllChanges || this._isChangeAllowed(principal, aData.type, aData.value)) { debug("add: " + aData.origin + " " + appID + " " + action); - permissionManager.addFromPrincipal(principal, aData.type, action); + Services.perms.addFromPrincipal(principal, aData.type, action); return true; } else { debug("add Failure: " + aData.origin + " " + appID + " " + action); @@ -116,8 +106,8 @@ this.PermissionSettingsModule = { debug("getPermission: " + aPermName + ", " + aManifestURL + ", " + aOrigin); let uri = Services.io.newURI(aOrigin, null, null); let appID = appsService.getAppLocalIdByManifestURL(aManifestURL); - let principal = secMan.getAppCodebasePrincipal(uri, appID, aBrowserFlag); - let result = permissionManager.testExactPermissionFromPrincipal(principal, aPermName); + let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(uri, appID, aBrowserFlag); + let result = Services.perms.testExactPermissionFromPrincipal(principal, aPermName); switch (result) { diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index aa8aab4813f3..d998f3b3eaa6 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -1545,8 +1545,8 @@ NPObjWrapper_NewResolve(JSContext *cx, JS::Handle obj, JS::Handle permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, false); uint32_t permission = nsIPermissionManager::DENY_ACTION; diff --git a/dom/promise/Promise.cpp b/dom/promise/Promise.cpp index 2124f8282e2a..ce4c03d83f2a 100644 --- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -13,6 +13,7 @@ #include "mozilla/Preferences.h" #include "PromiseCallback.h" #include "PromiseNativeHandler.h" +#include "PromiseWorkerProxy.h" #include "nsContentUtils.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" @@ -626,9 +627,9 @@ public: AutoDontReportUncaught silenceReporting(cx); JS::Rooted value(cx, aValue); + JS::Rooted values(cx, mValues); if (!JS_WrapValue(cx, &value) || - !JS_DefineElement(cx, mValues, index, value, nullptr, nullptr, - JSPROP_ENUMERATE)) { + !JS_DefineElement(cx, values, index, value, JSPROP_ENUMERATE)) { MOZ_ASSERT(JS_IsExceptionPending(cx)); JS::Rooted exn(cx); JS_GetPendingException(cx, &exn); @@ -694,13 +695,13 @@ public: } void - ResolvedCallback(JS::Handle aValue) + ResolvedCallback(JSContext* aCx, JS::Handle aValue) { mCountdownHolder->SetValue(mIndex, aValue); } void - RejectedCallback(JS::Handle aValue) + RejectedCallback(JSContext* aCx, JS::Handle aValue) { // Should never be attached to Promise as a reject handler. MOZ_ASSERT(false, "AllResolveHandler should never be attached to a Promise's reject handler!"); @@ -1125,5 +1126,200 @@ PromiseReportRejectFeature::Notify(JSContext* aCx, workers::Status aStatus) return true; } +// A WorkerRunnable to resolve/reject the Promise on the worker thread. + +class PromiseWorkerProxyRunnable : public workers::WorkerRunnable +{ +public: + PromiseWorkerProxyRunnable(PromiseWorkerProxy* aPromiseWorkerProxy, + JSStructuredCloneCallbacks* aCallbacks, + JSAutoStructuredCloneBuffer&& aBuffer, + PromiseWorkerProxy::RunCallbackFunc aFunc) + : WorkerRunnable(aPromiseWorkerProxy->GetWorkerPrivate(), + WorkerThreadUnchangedBusyCount) + , mPromiseWorkerProxy(aPromiseWorkerProxy) + , mCallbacks(aCallbacks) + , mBuffer(Move(aBuffer)) + , mFunc(aFunc) + { + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mPromiseWorkerProxy); + } + + virtual bool + WorkerRun(JSContext* aCx, workers::WorkerPrivate* aWorkerPrivate) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(aWorkerPrivate == mWorkerPrivate); + + MOZ_ASSERT(mPromiseWorkerProxy); + nsRefPtr workerPromise = mPromiseWorkerProxy->GetWorkerPromise(); + MOZ_ASSERT(workerPromise); + + // Here we convert the buffer to a JS::Value. + JS::Rooted value(aCx); + if (!mBuffer.read(aCx, &value, mCallbacks, mPromiseWorkerProxy)) { + JS_ClearPendingException(aCx); + return false; + } + + // TODO Bug 975246 - nsRefPtr should support operator |nsRefPtr->*funcType|. + (workerPromise.get()->*mFunc)(aCx, + value, + Promise::PromiseTaskSync::SyncTask); + + // Release the Promise because it has been resolved/rejected for sure. + mPromiseWorkerProxy->CleanUp(aCx); + return true; + } + +protected: + ~PromiseWorkerProxyRunnable() {} + +private: + nsRefPtr mPromiseWorkerProxy; + JSStructuredCloneCallbacks* mCallbacks; + JSAutoStructuredCloneBuffer mBuffer; + + // Function pointer for calling Promise::{ResolveInternal,RejectInternal}. + PromiseWorkerProxy::RunCallbackFunc mFunc; +}; + +PromiseWorkerProxy::PromiseWorkerProxy(WorkerPrivate* aWorkerPrivate, + Promise* aWorkerPromise, + JSStructuredCloneCallbacks* aCallbacks) + : mWorkerPrivate(aWorkerPrivate) + , mWorkerPromise(aWorkerPromise) + , mCleanedUp(false) + , mCallbacks(aCallbacks) + , mCleanUpLock("cleanUpLock") +{ + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(mWorkerPromise); + + // We do this to make sure the worker thread won't shut down before the + // promise is resolved/rejected on the worker thread. + if (!mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), this)) { + MOZ_ASSERT(false, "cannot add the worker feature!"); + return; + } +} + +PromiseWorkerProxy::~PromiseWorkerProxy() +{ + MOZ_ASSERT(mCleanedUp); + MOZ_ASSERT(!mWorkerPromise); +} + +WorkerPrivate* +PromiseWorkerProxy::GetWorkerPrivate() const +{ + // It's ok to race on |mCleanedUp|, because it will never cause us to fire + // the assertion when we should not. + MOZ_ASSERT(!mCleanedUp); + + return mWorkerPrivate; +} + +Promise* +PromiseWorkerProxy::GetWorkerPromise() const +{ + return mWorkerPromise; +} + +void +PromiseWorkerProxy::StoreISupports(nsISupports* aSupports) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsMainThreadPtrHandle supports = + new nsMainThreadPtrHolder(aSupports); + mSupportsArray.AppendElement(supports); +} + +void +PromiseWorkerProxy::RunCallback(JSContext* aCx, + JS::Handle aValue, + RunCallbackFunc aFunc) +{ + MOZ_ASSERT(NS_IsMainThread()); + + MutexAutoLock lock(mCleanUpLock); + // If the worker thread's been cancelled we don't need to resolve the Promise. + if (mCleanedUp) { + return; + } + + // The |aValue| is written into the buffer. Note that we also pass |this| + // into the structured-clone write in order to set its |mSupportsArray| to + // keep objects alive until the structured-clone read/write is done. + JSAutoStructuredCloneBuffer buffer; + if (!buffer.write(aCx, aValue, mCallbacks, this)) { + JS_ClearPendingException(aCx); + MOZ_ASSERT(false, "cannot write the JSAutoStructuredCloneBuffer!"); + } + + nsRefPtr runnable = + new PromiseWorkerProxyRunnable(this, + mCallbacks, + Move(buffer), + aFunc); + + runnable->Dispatch(aCx); +} + +void +PromiseWorkerProxy::ResolvedCallback(JSContext* aCx, + JS::Handle aValue) +{ + RunCallback(aCx, aValue, &Promise::ResolveInternal); +} + +void +PromiseWorkerProxy::RejectedCallback(JSContext* aCx, + JS::Handle aValue) +{ + RunCallback(aCx, aValue, &Promise::RejectInternal); +} + +bool +PromiseWorkerProxy::Notify(JSContext* aCx, Status aStatus) +{ + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx); + + if (aStatus >= Canceling) { + CleanUp(aCx); + } + + return true; +} + +void +PromiseWorkerProxy::CleanUp(JSContext* aCx) +{ + MutexAutoLock lock(mCleanUpLock); + + // |mWorkerPrivate| might not be safe to use anymore if we have already + // cleaned up and RemoveFeature(), so we need to check |mCleanedUp| first. + if (mCleanedUp) { + return; + } + + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx); + + // Release the Promise and remove the PromiseWorkerProxy from the features of + // the worker thread since the Promise has been resolved/rejected or the + // worker thread has been cancelled. + mWorkerPromise = nullptr; + mWorkerPrivate->RemoveFeature(aCx, this); + mCleanedUp = true; +} + } // namespace dom } // namespace mozilla diff --git a/dom/promise/Promise.h b/dom/promise/Promise.h index a22853d58b98..fd372958ae79 100644 --- a/dom/promise/Promise.h +++ b/dom/promise/Promise.h @@ -55,6 +55,8 @@ class Promise MOZ_FINAL : public nsISupports, friend class PromiseResolverTask; friend class PromiseTask; friend class PromiseReportRejectFeature; + friend class PromiseWorkerProxy; + friend class PromiseWorkerProxyRunnable; friend class RejectPromiseCallback; friend class ResolvePromiseCallback; friend class WorkerPromiseResolverTask; diff --git a/dom/promise/PromiseCallback.cpp b/dom/promise/PromiseCallback.cpp index eeecc70ab846..62d1871ed69f 100644 --- a/dom/promise/PromiseCallback.cpp +++ b/dom/promise/PromiseCallback.cpp @@ -338,12 +338,12 @@ NativePromiseCallback::Call(JSContext* aCx, JS::Handle aValue) { if (mState == Promise::Resolved) { - mHandler->ResolvedCallback(aValue); + mHandler->ResolvedCallback(aCx, aValue); return; } if (mState == Promise::Rejected) { - mHandler->RejectedCallback(aValue); + mHandler->RejectedCallback(aCx, aValue); return; } diff --git a/dom/promise/PromiseNativeHandler.h b/dom/promise/PromiseNativeHandler.h index a9f8c505d5d5..bfef812e8fe2 100644 --- a/dom/promise/PromiseNativeHandler.h +++ b/dom/promise/PromiseNativeHandler.h @@ -27,10 +27,10 @@ public: { } virtual void - ResolvedCallback(JS::Handle aValue) = 0; + ResolvedCallback(JSContext* aCx, JS::Handle aValue) = 0; virtual void - RejectedCallback(JS::Handle aValue) = 0; + RejectedCallback(JSContext* aCx, JS::Handle aValue) = 0; }; } // namespace dom diff --git a/dom/promise/PromiseWorkerProxy.h b/dom/promise/PromiseWorkerProxy.h new file mode 100644 index 000000000000..102635d74fad --- /dev/null +++ b/dom/promise/PromiseWorkerProxy.h @@ -0,0 +1,106 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_PromiseWorkerProxy_h +#define mozilla_dom_PromiseWorkerProxy_h + +#include "mozilla/dom/PromiseNativeHandler.h" +#include "mozilla/dom/workers/bindings/WorkerFeature.h" +#include "nsProxyRelease.h" + +namespace mozilla { +namespace dom { + +class Promise; + +namespace workers { +class WorkerPrivate; +} + +// A proxy to catch the resolved/rejected Promise's result from the main thread +// and resolve/reject that on the worker thread eventually. +// +// How to use: +// +// 1. Create a Promise on the worker thread and return it to the content +// script: +// +// nsRefPtr promise = new Promise(workerPrivate->GlobalScope()); +// // Pass |promise| around to the WorkerMainThreadRunnable +// return promise.forget(); +// +// 2. In your WorkerMainThreadRunnable's ctor, create a PromiseWorkerProxy +// which holds a nsRefPtr to the Promise created at #1. +// +// 3. In your WorkerMainThreadRunnable::MainThreadRun(), obtain a Promise on +// the main thread and call its AppendNativeHandler(PromiseNativeHandler*) +// to bind the PromiseWorkerProxy created at #2. +// +// 4. Then the Promise results returned by ResolvedCallback/RejectedCallback +// will be dispatched as a WorkerRunnable to the worker thread to +// resolve/reject the Promise created at #1. + +class PromiseWorkerProxy : public PromiseNativeHandler, + public workers::WorkerFeature +{ + friend class PromiseWorkerProxyRunnable; + + // This overrides the non-threadsafe refcounting in PromiseNativeHandler. + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PromiseWorkerProxy) + +public: + PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate, + Promise* aWorkerPromise, + JSStructuredCloneCallbacks* aCallbacks = nullptr); + + workers::WorkerPrivate* GetWorkerPrivate() const; + + Promise* GetWorkerPromise() const; + + void StoreISupports(nsISupports* aSupports); + + void CleanUp(JSContext* aCx); + +protected: + virtual void ResolvedCallback(JSContext* aCx, + JS::Handle aValue) MOZ_OVERRIDE; + + virtual void RejectedCallback(JSContext* aCx, + JS::Handle aValue) MOZ_OVERRIDE; + + virtual bool Notify(JSContext* aCx, workers::Status aStatus) MOZ_OVERRIDE; + +private: + virtual ~PromiseWorkerProxy(); + + // Function pointer for calling Promise::{ResolveInternal,RejectInternal}. + typedef void (Promise::*RunCallbackFunc)(JSContext*, + JS::Handle, + Promise::PromiseTaskSync); + + void RunCallback(JSContext* aCx, + JS::Handle aValue, + RunCallbackFunc aFunc); + + workers::WorkerPrivate* mWorkerPrivate; + + // This lives on the worker thread. + nsRefPtr mWorkerPromise; + + bool mCleanedUp; // To specify if the cleanUp() has been done. + + JSStructuredCloneCallbacks* mCallbacks; + + // Aimed to keep objects alive when doing the structured-clone read/write, + // which can be added by calling StoreISupports() on the main thread. + nsTArray> mSupportsArray; + + // Ensure the worker and the main thread won't race to access |mCleanedUp|. + Mutex mCleanUpLock; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_PromiseWorkerProxy_h diff --git a/dom/promise/moz.build b/dom/promise/moz.build index 3b59c3779228..ccf91fced4f6 100644 --- a/dom/promise/moz.build +++ b/dom/promise/moz.build @@ -8,7 +8,8 @@ TEST_DIRS += ['tests'] EXPORTS.mozilla.dom += [ 'Promise.h', - 'PromiseNativeHandler.h' + 'PromiseNativeHandler.h', + 'PromiseWorkerProxy.h', ] SOURCES += [ diff --git a/dom/quota/CheckQuotaHelper.cpp b/dom/quota/CheckQuotaHelper.cpp index 5ffcf3591470..fba928dae9b3 100644 --- a/dom/quota/CheckQuotaHelper.cpp +++ b/dom/quota/CheckQuotaHelper.cpp @@ -122,7 +122,7 @@ CheckQuotaHelper::GetQuotaPermission(nsIPrincipal* aPrincipal) "Chrome windows shouldn't track quota!"); nsCOMPtr pm = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(pm, nsIPermissionManager::DENY_ACTION); uint32_t permission; @@ -161,7 +161,7 @@ CheckQuotaHelper::Run() NS_ENSURE_TRUE(sop, NS_ERROR_FAILURE); nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_STATE(permissionManager); rv = permissionManager->AddFromPrincipal(sop->GetPrincipal(), diff --git a/dom/speakermanager/SpeakerManager.cpp b/dom/speakermanager/SpeakerManager.cpp index b10b26d0c5d7..6df0a40ff4ae 100644 --- a/dom/speakermanager/SpeakerManager.cpp +++ b/dom/speakermanager/SpeakerManager.cpp @@ -11,6 +11,7 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsIDocShell.h" #include "AudioChannelService.h" +#include "mozilla/Services.h" namespace mozilla { namespace dom { @@ -147,8 +148,7 @@ SpeakerManager::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) return nullptr; } - nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + nsCOMPtr permMgr = services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, nullptr); uint32_t permission = nsIPermissionManager::DENY_ACTION; diff --git a/dom/src/geolocation/nsGeoPosition.cpp b/dom/src/geolocation/nsGeoPosition.cpp index d0fd37a658cc..ec8bf70515f7 100644 --- a/dom/src/geolocation/nsGeoPosition.cpp +++ b/dom/src/geolocation/nsGeoPosition.cpp @@ -146,7 +146,7 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(Position, mParent, mCoordinates) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Position, mParent, mCoordinates) NS_IMPL_CYCLE_COLLECTING_ADDREF(Position) NS_IMPL_CYCLE_COLLECTING_RELEASE(Position) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Position) @@ -200,7 +200,7 @@ Position::Timestamp() const return rv; } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(Coordinates, mPosition) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Coordinates, mPosition) NS_IMPL_CYCLE_COLLECTING_ADDREF(Coordinates) NS_IMPL_CYCLE_COLLECTING_RELEASE(Coordinates) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Coordinates) diff --git a/dom/src/geolocation/nsGeolocation.cpp b/dom/src/geolocation/nsGeolocation.cpp index 6418d9c8aeda..194732262fc3 100644 --- a/dom/src/geolocation/nsGeolocation.cpp +++ b/dom/src/geolocation/nsGeolocation.cpp @@ -240,7 +240,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PositionError) NS_INTERFACE_MAP_ENTRY(nsIDOMGeoPositionError) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(PositionError, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PositionError, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(PositionError) NS_IMPL_CYCLE_COLLECTING_RELEASE(PositionError) @@ -1032,11 +1032,11 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(Geolocation) NS_IMPL_CYCLE_COLLECTING_RELEASE(Geolocation) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(Geolocation, - mCachedPosition, - mPendingCallbacks, - mWatchingCallbacks, - mPendingRequests) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Geolocation, + mCachedPosition, + mPendingCallbacks, + mWatchingCallbacks, + mPendingRequests) Geolocation::Geolocation() : mLastWatchId(0) diff --git a/dom/src/notification/Notification.cpp b/dom/src/notification/Notification.cpp index de71734b972b..047699c48849 100644 --- a/dom/src/notification/Notification.cpp +++ b/dom/src/notification/Notification.cpp @@ -23,6 +23,7 @@ #include "nsDOMJSUtils.h" #include "nsIScriptSecurityManager.h" #include "mozilla/dom/PermissionMessageUtils.h" +#include "mozilla/Services.h" #include "nsContentPermissionHelper.h" #ifdef MOZ_B2G #include "nsIDOMDesktopNotification.h" @@ -76,8 +77,8 @@ public: JS::Rooted element(aCx, notification->WrapObject(aCx)); NS_ENSURE_TRUE(element, NS_ERROR_FAILURE); - if (!JS_DefineElement(aCx, mNotifications, mCount++, - JS::ObjectValue(*element), nullptr, nullptr, 0)) { + JS::Rooted notifications(aCx, mNotifications); + if (!JS_DefineElement(aCx, notifications, mCount++, element, 0)) { return NS_ERROR_FAILURE; } return NS_OK; @@ -674,7 +675,7 @@ Notification::GetPermissionInternal(nsISupports* aGlobal, ErrorResult& aRv) uint32_t permission = nsIPermissionManager::UNKNOWN_ACTION; nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); permissionManager->TestPermissionFromPrincipal(principal, "desktop-notification", diff --git a/dom/src/storage/DOMStorage.cpp b/dom/src/storage/DOMStorage.cpp index a16dff1290ae..0d527d7082eb 100644 --- a/dom/src/storage/DOMStorage.cpp +++ b/dom/src/storage/DOMStorage.cpp @@ -254,7 +254,7 @@ DOMStorage::CanUseStorage(DOMStorage* aStorage) // IsCallerChrome(). nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (!permissionManager) { return false; } diff --git a/dom/system/OSFileConstants.cpp b/dom/system/OSFileConstants.cpp index 98576f0206a1..6dddc9cccd89 100644 --- a/dom/system/OSFileConstants.cpp +++ b/dom/system/OSFileConstants.cpp @@ -770,7 +770,7 @@ JSObject *GetOrCreateObjectProperty(JSContext *cx, JS::Handle aObject JSMSG_UNEXPECTED_TYPE, aProperty, "not an object"); return nullptr; } - return JS_DefineObject(cx, aObject, aProperty, nullptr, nullptr, + return JS_DefineObject(cx, aObject, aProperty, nullptr, JS::NullPtr(), JSPROP_ENUMERATE); } diff --git a/dom/system/gonk/AudioChannelManager.cpp b/dom/system/gonk/AudioChannelManager.cpp index d4800e1d404f..50cae6c89b44 100644 --- a/dom/system/gonk/AudioChannelManager.cpp +++ b/dom/system/gonk/AudioChannelManager.cpp @@ -11,6 +11,7 @@ #include "nsIInterfaceRequestorUtils.h" #include "AudioChannelManager.h" #include "mozilla/dom/AudioChannelManagerBinding.h" +#include "mozilla/Services.h" using namespace mozilla::hal; @@ -85,7 +86,7 @@ AudioChannelManager::SetVolumeControlChannel(const nsAString& aChannel) // Only normal channel doesn't need permission. if (newChannel != AudioChannel::Normal) { nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (!permissionManager) { return false; } diff --git a/dom/system/nsDeviceSensors.cpp b/dom/system/nsDeviceSensors.cpp index 4517a9480506..d4e8af4c5bdc 100644 --- a/dom/system/nsDeviceSensors.cpp +++ b/dom/system/nsDeviceSensors.cpp @@ -17,6 +17,7 @@ #include "GeneratedEvents.h" #include "mozilla/Preferences.h" #include "mozilla/Attributes.h" +#include "mozilla/Services.h" #include "nsIPermissionManager.h" #include "mozilla/dom/DeviceLightEvent.h" #include "mozilla/dom/DeviceProximityEvent.h" @@ -181,7 +182,7 @@ WindowCannotReceiveSensorEvent (nsPIDOMWindow* aWindow) if (aWindow->GetOuterWindow()->IsBackground()) { nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); NS_ENSURE_TRUE(permMgr, false); uint32_t permission = nsIPermissionManager::DENY_ACTION; permMgr->TestPermissionFromWindow(aWindow, "background-sensors", &permission); diff --git a/dom/telephony/CallsList.cpp b/dom/telephony/CallsList.cpp index 67099fd449ee..68607d9f63ac 100644 --- a/dom/telephony/CallsList.cpp +++ b/dom/telephony/CallsList.cpp @@ -13,9 +13,9 @@ using namespace mozilla::dom; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(CallsList, - mTelephony, - mGroup) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CallsList, + mTelephony, + mGroup) NS_IMPL_CYCLE_COLLECTING_ADDREF(CallsList) NS_IMPL_CYCLE_COLLECTING_RELEASE(CallsList) diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 82f220354e65..14ec8a73f51e 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -368,15 +368,15 @@ var interfaceNamesInGlobalScope = // IMPORTANT: Do not change this list without review from a DOM peer! "GainNode", // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "Gamepad", desktop: true}, + {name: "Gamepad", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "GamepadAxisMoveEvent", desktop: true}, + {name: "GamepadAxisMoveEvent", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "GamepadButtonEvent", desktop: true}, + {name: "GamepadButtonEvent", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "GamepadButton", desktop: true}, + {name: "GamepadButton", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "GamepadEvent", desktop: true}, + {name: "GamepadEvent", b2g: false}, // IMPORTANT: Do not change this list without review from a DOM peer! "HashChangeEvent", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/time/TimeManager.cpp b/dom/time/TimeManager.cpp index ff71659e13ff..b9123bdfc42d 100644 --- a/dom/time/TimeManager.cpp +++ b/dom/time/TimeManager.cpp @@ -21,7 +21,7 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(TimeManager) NS_IMPL_CYCLE_COLLECTING_RELEASE(TimeManager) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(TimeManager, mWindow) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(TimeManager, mWindow) JSObject* TimeManager::WrapObject(JSContext* aCx) diff --git a/dom/webidl/WorkerNavigator.webidl b/dom/webidl/WorkerNavigator.webidl index 0897684c4d7d..54b0b23a7333 100644 --- a/dom/webidl/WorkerNavigator.webidl +++ b/dom/webidl/WorkerNavigator.webidl @@ -7,3 +7,4 @@ interface WorkerNavigator { WorkerNavigator implements NavigatorID; WorkerNavigator implements NavigatorOnLine; +WorkerNavigator implements NavigatorDataStore; diff --git a/dom/workers/DataStore.cpp b/dom/workers/DataStore.cpp new file mode 100644 index 000000000000..53f0d071b36d --- /dev/null +++ b/dom/workers/DataStore.cpp @@ -0,0 +1,889 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DataStore.h" +#include "DataStoreCursor.h" + +#include "mozilla/dom/DataStore.h" +#include "mozilla/dom/DataStoreCursor.h" +#include "mozilla/dom/DataStoreChangeEvent.h" +#include "mozilla/dom/DataStoreBinding.h" +#include "mozilla/dom/DataStoreImplBinding.h" + +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/PromiseWorkerProxy.h" +#include "mozilla/ErrorResult.h" + +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" +#include "WorkerScope.h" + +BEGIN_WORKERS_NAMESPACE + +NS_IMPL_ADDREF_INHERITED(WorkerDataStore, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(WorkerDataStore, DOMEventTargetHelper) + +NS_INTERFACE_MAP_BEGIN(WorkerDataStore) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +WorkerDataStore::WorkerDataStore(WorkerGlobalScope* aScope) + : DOMEventTargetHelper(aScope) +{} + +already_AddRefed +WorkerDataStore::Constructor(GlobalObject& aGlobal, ErrorResult& aRv) +{ + JSContext* cx = aGlobal.GetContext(); + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr store = + new WorkerDataStore(workerPrivate->GlobalScope()); + return store.forget(); +} + +JSObject* +WorkerDataStore::WrapObject(JSContext* aCx) +{ + return DataStoreBinding_workers::Wrap(aCx, this); +} + +// A WorkerMainThreadRunnable which holds a reference to WorkerDataStore. +class DataStoreRunnable : public WorkerMainThreadRunnable +{ +protected: + nsMainThreadPtrHandle mBackingStore; + +public: + DataStoreRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore) + : WorkerMainThreadRunnable(aWorkerPrivate) + , mBackingStore(aBackingStore) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } +}; + +// A DataStoreRunnable to run: +// - DataStore::GetName(...) +// - DataStore::GetOwner(...) +// - DataStore::GetRevisionId(...) +// on the main thread. +class DataStoreGetStringRunnable MOZ_FINAL : public DataStoreRunnable +{ + typedef void + (DataStore::*FuncType)(nsAString&, ErrorResult&); + + FuncType mFunc; + nsAString& mString; + ErrorResult& mRv; + +public: + DataStoreGetStringRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + FuncType aFunc, + nsAString& aString, + ErrorResult& aRv) + : DataStoreRunnable(aWorkerPrivate, aBackingStore) + , mFunc(aFunc) + , mString(aString) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + nsString string; + (mBackingStore.get()->*mFunc)(string, mRv); + mString.Assign(string); + return true; + } +}; + +// A DataStoreRunnable to run DataStore::GetReadOnly(...) on the main +// thread. +class DataStoreGetReadOnlyRunnable MOZ_FINAL : public DataStoreRunnable +{ + ErrorResult& mRv; + +public: + bool mReadOnly; + +public: + DataStoreGetReadOnlyRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + ErrorResult& aRv) + : DataStoreRunnable(aWorkerPrivate, aBackingStore) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + mReadOnly = mBackingStore->GetReadOnly(mRv); + return true; + } +}; + +// A DataStoreRunnable to run DataStore::Get(...) on the main thread. +class DataStoreGetRunnable MOZ_FINAL : public DataStoreRunnable +{ + nsRefPtr mPromiseWorkerProxy; + Sequence mId; + ErrorResult& mRv; + +public: + DataStoreGetRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + Promise* aWorkerPromise, + const Sequence& aId, + ErrorResult& aRv) + : DataStoreRunnable(aWorkerPrivate, aBackingStore) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + if (!mId.AppendElements(aId)) { + mRv.Throw(NS_ERROR_OUT_OF_MEMORY); + } + + mPromiseWorkerProxy = + new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + nsRefPtr promise = mBackingStore->Get(mId, mRv); + promise->AppendNativeHandler(mPromiseWorkerProxy); + return true; + } +}; + +// A DataStoreRunnable to run DataStore::Put(...) on the main thread. +class DataStorePutRunnable MOZ_FINAL : public DataStoreRunnable +{ + nsRefPtr mPromiseWorkerProxy; + JSAutoStructuredCloneBuffer mObjBuffer; + const StringOrUnsignedLong& mId; + const nsString mRevisionId; + ErrorResult& mRv; + +public: + DataStorePutRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + Promise* aWorkerPromise, + JSContext* aCx, + JS::Handle aObj, + const StringOrUnsignedLong& aId, + const nsAString& aRevisionId, + ErrorResult& aRv) + : DataStoreRunnable(aWorkerPrivate, aBackingStore) + , mId(aId) + , mRevisionId(aRevisionId) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + // This needs to be structured cloned while it's still on the worker thread. + if (!mObjBuffer.write(aCx, aObj)) { + JS_ClearPendingException(aCx); + mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); + } + + mPromiseWorkerProxy = + new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + // Get the JSContext for the target window + nsCOMPtr sgo = + do_QueryInterface(static_cast + (mBackingStore.get())->GetOwner()); + MOZ_ASSERT(sgo); + + nsCOMPtr scriptContext = sgo->GetContext(); + AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext() + : nsContentUtils::GetSafeJSContext()); + MOZ_ASSERT(cx); + + JS::Rooted value(cx); + if (!mObjBuffer.read(cx, &value)) { + JS_ClearPendingException(cx); + mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); + return true; + } + + nsRefPtr promise = mBackingStore->Put(cx, + value, + mId, + mRevisionId, + mRv); + promise->AppendNativeHandler(mPromiseWorkerProxy); + return true; + } +}; + +// A DataStoreRunnable to run DataStore::Add(...) on the main thread. +class DataStoreAddRunnable MOZ_FINAL : public DataStoreRunnable +{ + nsRefPtr mPromiseWorkerProxy; + JSAutoStructuredCloneBuffer mObjBuffer; + const Optional& mId; + const nsString mRevisionId; + ErrorResult& mRv; + +public: + DataStoreAddRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + Promise* aWorkerPromise, + JSContext* aCx, + JS::Handle aObj, + const Optional& aId, + const nsAString& aRevisionId, + ErrorResult& aRv) + : DataStoreRunnable(aWorkerPrivate, aBackingStore) + , mId(aId) + , mRevisionId(aRevisionId) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + // This needs to be structured cloned while it's still on the worker thread. + if (!mObjBuffer.write(aCx, aObj)) { + JS_ClearPendingException(aCx); + mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); + } + + mPromiseWorkerProxy = + new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + // Get the JSContext for the target window + nsCOMPtr sgo = + do_QueryInterface(static_cast + (mBackingStore.get())->GetOwner()); + MOZ_ASSERT(sgo); + + nsCOMPtr scriptContext = sgo->GetContext(); + AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext() + : nsContentUtils::GetSafeJSContext()); + MOZ_ASSERT(cx); + + JS::Rooted value(cx); + if (!mObjBuffer.read(cx, &value)) { + JS_ClearPendingException(cx); + mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); + return true; + } + + nsRefPtr promise = mBackingStore->Add(cx, + value, + mId, + mRevisionId, + mRv); + promise->AppendNativeHandler(mPromiseWorkerProxy); + return true; + } +}; + +// A DataStoreRunnable to run DataStore::Remove(...) on the main +// thread. +class DataStoreRemoveRunnable MOZ_FINAL : public DataStoreRunnable +{ + nsRefPtr mPromiseWorkerProxy; + const StringOrUnsignedLong& mId; + const nsString mRevisionId; + ErrorResult& mRv; + +public: + DataStoreRemoveRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + Promise* aWorkerPromise, + const StringOrUnsignedLong& aId, + const nsAString& aRevisionId, + ErrorResult& aRv) + : DataStoreRunnable(aWorkerPrivate, aBackingStore) + , mId(aId) + , mRevisionId(aRevisionId) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + mPromiseWorkerProxy = + new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + nsRefPtr promise = mBackingStore->Remove(mId, mRevisionId, mRv); + promise->AppendNativeHandler(mPromiseWorkerProxy); + return true; + } +}; + +// A DataStoreRunnable to run DataStore::Sync(...) on the main thread. +class DataStoreSyncStoreRunnable MOZ_FINAL : public DataStoreRunnable +{ + WorkerDataStoreCursor* mWorkerCursor; + const nsString mRevisionId; + ErrorResult& mRv; + +public: + DataStoreSyncStoreRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + WorkerDataStoreCursor* aWorkerCursor, + const nsAString& aRevisionId, + ErrorResult& aRv) + : DataStoreRunnable(aWorkerPrivate, aBackingStore) + , mWorkerCursor(aWorkerCursor) + , mRevisionId(aRevisionId) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + // Point WorkerDataStoreCursor to DataStoreCursor. + nsRefPtr cursor = mBackingStore->Sync(mRevisionId, mRv); + nsMainThreadPtrHandle backingCursor = + new nsMainThreadPtrHolder(cursor); + mWorkerCursor->SetBackingDataStoreCursor(backingCursor); + + return true; + } +}; + +void +WorkerDataStore::GetName(JSContext* aCx, nsAString& aName, ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr runnable = + new DataStoreGetStringRunnable(workerPrivate, + mBackingStore, + &DataStore::GetName, + aName, + aRv); + runnable->Dispatch(aCx); +} + +void +WorkerDataStore::GetOwner(JSContext* aCx, nsAString& aOwner, ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr runnable = + new DataStoreGetStringRunnable(workerPrivate, + mBackingStore, + &DataStore::GetOwner, + aOwner, + aRv); + runnable->Dispatch(aCx); +} + +bool +WorkerDataStore::GetReadOnly(JSContext* aCx, ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr runnable = + new DataStoreGetReadOnlyRunnable(workerPrivate, mBackingStore, aRv); + runnable->Dispatch(aCx); + + return runnable->mReadOnly; +} + +already_AddRefed +WorkerDataStore::Get(JSContext* aCx, + const Sequence& aId, + ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr promise = new Promise(workerPrivate->GlobalScope()); + + nsRefPtr runnable = + new DataStoreGetRunnable(workerPrivate, + mBackingStore, + promise, + aId, + aRv); + runnable->Dispatch(aCx); + + return promise.forget(); +} + +already_AddRefed +WorkerDataStore::Put(JSContext* aCx, + JS::Handle aObj, + const StringOrUnsignedLong& aId, + const nsAString& aRevisionId, + ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr promise = new Promise(workerPrivate->GlobalScope()); + + nsRefPtr runnable = + new DataStorePutRunnable(workerPrivate, + mBackingStore, + promise, + aCx, + aObj, + aId, + aRevisionId, + aRv); + runnable->Dispatch(aCx); + + return promise.forget(); +} + +already_AddRefed +WorkerDataStore::Add(JSContext* aCx, + JS::Handle aObj, + const Optional& aId, + const nsAString& aRevisionId, + ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr promise = new Promise(workerPrivate->GlobalScope()); + + nsRefPtr runnable = + new DataStoreAddRunnable(workerPrivate, + mBackingStore, + promise, + aCx, + aObj, + aId, + aRevisionId, + aRv); + runnable->Dispatch(aCx); + + return promise.forget(); +} + +already_AddRefed +WorkerDataStore::Remove(JSContext* aCx, + const StringOrUnsignedLong& aId, + const nsAString& aRevisionId, + ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr promise = new Promise(workerPrivate->GlobalScope()); + + nsRefPtr runnable = + new DataStoreRemoveRunnable(workerPrivate, + mBackingStore, + promise, + aId, + aRevisionId, + aRv); + runnable->Dispatch(aCx); + + return promise.forget(); +} + +// A DataStoreRunnable to run DataStore::Clear(...) on the main thread. +class DataStoreClearRunnable MOZ_FINAL : public DataStoreRunnable +{ + nsRefPtr mPromiseWorkerProxy; + const nsString mRevisionId; + ErrorResult& mRv; + +public: + DataStoreClearRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + Promise* aWorkerPromise, + const nsAString& aRevisionId, + ErrorResult& aRv) + : DataStoreRunnable(aWorkerPrivate, aBackingStore) + , mRevisionId(aRevisionId) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + mPromiseWorkerProxy = + new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + nsRefPtr promise = mBackingStore->Clear(mRevisionId, mRv); + promise->AppendNativeHandler(mPromiseWorkerProxy); + return true; + } +}; + +already_AddRefed +WorkerDataStore::Clear(JSContext* aCx, + const nsAString& aRevisionId, + ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr promise = new Promise(workerPrivate->GlobalScope()); + + nsRefPtr runnable = + new DataStoreClearRunnable(workerPrivate, + mBackingStore, + promise, + aRevisionId, + aRv); + runnable->Dispatch(aCx); + + return promise.forget(); +} + +void +WorkerDataStore::GetRevisionId(JSContext* aCx, + nsAString& aRevisionId, + ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr runnable = + new DataStoreGetStringRunnable(workerPrivate, + mBackingStore, + &DataStore::GetRevisionId, + aRevisionId, + aRv); + runnable->Dispatch(aCx); +} + +// A DataStoreRunnable to run DataStore::GetLength(...) on the main thread. +class DataStoreGetLengthRunnable MOZ_FINAL : public DataStoreRunnable +{ + nsRefPtr mPromiseWorkerProxy; + ErrorResult& mRv; + +public: + DataStoreGetLengthRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + Promise* aWorkerPromise, + ErrorResult& aRv) + : DataStoreRunnable(aWorkerPrivate, aBackingStore) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + mPromiseWorkerProxy = + new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + nsRefPtr promise = mBackingStore->GetLength(mRv); + promise->AppendNativeHandler(mPromiseWorkerProxy); + return true; + } +}; + +already_AddRefed +WorkerDataStore::GetLength(JSContext* aCx, ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr promise = new Promise(workerPrivate->GlobalScope()); + + nsRefPtr runnable = + new DataStoreGetLengthRunnable(workerPrivate, + mBackingStore, + promise, + aRv); + runnable->Dispatch(aCx); + + return promise.forget(); +} + +already_AddRefed +WorkerDataStore::Sync(JSContext* aCx, + const nsAString& aRevisionId, + ErrorResult& aRv) +{ + // Create a WorkerDataStoreCursor on the worker. DataStoreSyncStoreRunnable + // will point that to the DataStoreCursor created on the main thread. + nsRefPtr workerCursor = new WorkerDataStoreCursor(); + + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr runnable = + new DataStoreSyncStoreRunnable(workerPrivate, + mBackingStore, + workerCursor, + aRevisionId, + aRv); + runnable->Dispatch(aCx); + + return workerCursor.forget(); +} + +void +WorkerDataStore::SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv) +{ + NS_NOTREACHED("We don't use this for the WorkerDataStore!"); +} + +void +WorkerDataStore::SetBackingDataStore( + const nsMainThreadPtrHandle& aBackingStore) +{ + mBackingStore = aBackingStore; +} + +void +WorkerDataStore::SetDataStoreChangeEventProxy( + DataStoreChangeEventProxy* aEventProxy) +{ + mEventProxy = aEventProxy; +} + +// A WorkerRunnable to dispatch the DataStoreChangeEvent on the worker thread. +class DispatchDataStoreChangeEventRunnable : public WorkerRunnable +{ +public: + DispatchDataStoreChangeEventRunnable( + DataStoreChangeEventProxy* aDataStoreChangeEventProxy, + DataStoreChangeEvent* aEvent) + : WorkerRunnable(aDataStoreChangeEventProxy->GetWorkerPrivate(), + WorkerThreadUnchangedBusyCount) + , mDataStoreChangeEventProxy(aDataStoreChangeEventProxy) + { + AssertIsOnMainThread(); + MOZ_ASSERT(mDataStoreChangeEventProxy); + + aEvent->GetRevisionId(mRevisionId); + aEvent->GetId(mId); + aEvent->GetOperation(mOperation); + aEvent->GetOwner(mOwner); + } + + virtual bool + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(aWorkerPrivate == mWorkerPrivate); + + MOZ_ASSERT(mDataStoreChangeEventProxy); + + nsRefPtr workerStore = + mDataStoreChangeEventProxy->GetWorkerStore(); + + DataStoreChangeEventInit eventInit; + eventInit.mBubbles = false; + eventInit.mCancelable = false; + eventInit.mRevisionId = mRevisionId; + + // TODO Bug 981984: OwningStringOrUnsignedLong union value cannot be set if + // the type is not matched. + // + // This is a work-around to clean up the OwningStringOrUnsignedLong value + // initialized by DataStoreChangeEventInit, which will always set |mId| to + // a UnsignedLong type by default (see DataStoreChangeEvent.webidl). This + // will fail the later assignment when the type of value we want to assign + // is actually String. + // eventInit.mId.~OwningStringOrUnsignedLong(); + eventInit.mId = mId; + + eventInit.mOperation = mOperation; + eventInit.mOwner = mOwner; + + nsRefPtr event = + DataStoreChangeEvent::Constructor(workerStore, + NS_LITERAL_STRING("change"), + eventInit); + + workerStore->DispatchDOMEvent(nullptr, event, nullptr, nullptr); + return true; + } + +protected: + ~DispatchDataStoreChangeEventRunnable() + {} + +private: + nsRefPtr mDataStoreChangeEventProxy; + + nsString mRevisionId; + Nullable mId; + nsString mOperation; + nsString mOwner; +}; + +DataStoreChangeEventProxy::DataStoreChangeEventProxy( + WorkerPrivate* aWorkerPrivate, + WorkerDataStore* aWorkerStore) + : mWorkerPrivate(aWorkerPrivate) + , mWorkerStore(aWorkerStore) + , mCleanedUp(false) + , mCleanUpLock("cleanUpLock") +{ + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(mWorkerStore); + + // Let the WorkerDataStore keep the DataStoreChangeEventProxy alive to catch + // the coming events until the WorkerDataStore is released. + mWorkerStore->SetDataStoreChangeEventProxy(this); + + // We do this to make sure the worker thread won't shut down before the event + // is dispatched to the WorkerStore on the worker thread. + if (!mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(), this)) { + MOZ_ASSERT(false, "cannot add the worker feature!"); + return; + } +} + +WorkerPrivate* +DataStoreChangeEventProxy::GetWorkerPrivate() const +{ + // It's ok to race on |mCleanedUp|, because it will never cause us to fire + // the assertion when we should not. + MOZ_ASSERT(!mCleanedUp); + + return mWorkerPrivate; +} + +WorkerDataStore* +DataStoreChangeEventProxy::GetWorkerStore() const +{ + return mWorkerStore; +} + +// nsIDOMEventListener implementation. + +NS_IMPL_ISUPPORTS(DataStoreChangeEventProxy, nsIDOMEventListener) + +NS_IMETHODIMP +DataStoreChangeEventProxy::HandleEvent(nsIDOMEvent* aEvent) +{ + AssertIsOnMainThread(); + + MutexAutoLock lock(mCleanUpLock); + // If the worker thread's been cancelled we don't need to dispatch the event. + if (mCleanedUp) { + return NS_OK; + } + + nsRefPtr event = + static_cast(aEvent); + + nsRefPtr runnable = + new DispatchDataStoreChangeEventRunnable(this, event); + + { + AutoSafeJSContext cx; + JSAutoRequest ar(cx); + runnable->Dispatch(cx); + } + + return NS_OK; +} + +// WorkerFeature implementation. + +bool +DataStoreChangeEventProxy::Notify(JSContext* aCx, Status aStatus) +{ + MutexAutoLock lock(mCleanUpLock); + + // |mWorkerPrivate| might not be safe to use anymore if we have already + // cleaned up and RemoveFeature(), so we need to check |mCleanedUp| first. + if (mCleanedUp) { + return true; + } + + MOZ_ASSERT(mWorkerPrivate); + mWorkerPrivate->AssertIsOnWorkerThread(); + MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx); + + // Release the WorkerStore and remove the DataStoreChangeEventProxy from the + // features of the worker thread since the worker thread has been cancelled. + if (aStatus >= Canceling) { + mWorkerStore = nullptr; + mWorkerPrivate->RemoveFeature(aCx, this); + mCleanedUp = true; + } + + return true; +} + +END_WORKERS_NAMESPACE diff --git a/dom/workers/DataStore.h b/dom/workers/DataStore.h new file mode 100644 index 000000000000..927d1cd8ab61 --- /dev/null +++ b/dom/workers/DataStore.h @@ -0,0 +1,140 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_workers_DataStore_h +#define mozilla_dom_workers_DataStore_h + +#include "mozilla/DOMEventTargetHelper.h" +#include "nsProxyRelease.h" + +#include "WorkerFeature.h" + +namespace mozilla { + +class ErrorResult; + +namespace dom { + +class Promise; +class DataStore; +class DataStoreImpl; +class StringOrUnsignedLong; +class OwningStringOrUnsignedLong; + +namespace workers { + +class DataStoreChangeEventProxy; +class WorkerDataStoreCursor; +class WorkerGlobalScope; + +class WorkerDataStore MOZ_FINAL : public DOMEventTargetHelper +{ +public: + NS_DECL_ISUPPORTS_INHERITED + + WorkerDataStore(WorkerGlobalScope* aScope); + + // WebIDL (internal functions) + + static already_AddRefed Constructor(GlobalObject& aGlobal, + ErrorResult& aRv); + + virtual JSObject* WrapObject(JSContext *aCx) MOZ_OVERRIDE; + + // WebIDL (public APIs) + + void GetName(JSContext* aCx, nsAString& aName, ErrorResult& aRv); + + void GetOwner(JSContext* aCx, nsAString& aOwner, ErrorResult& aRv); + + bool GetReadOnly(JSContext* aCx, ErrorResult& aRv); + + already_AddRefed Get(JSContext* aCx, + const Sequence& aId, + ErrorResult& aRv); + + already_AddRefed Put(JSContext* aCx, + JS::Handle aObj, + const StringOrUnsignedLong& aId, + const nsAString& aRevisionId, + ErrorResult& aRv); + + already_AddRefed Add(JSContext* aCx, + JS::Handle aObj, + const Optional& aId, + const nsAString& aRevisionId, + ErrorResult& aRv); + + already_AddRefed Remove(JSContext* aCx, + const StringOrUnsignedLong& aId, + const nsAString& aRevisionId, + ErrorResult& aRv); + + already_AddRefed Clear(JSContext* aCx, + const nsAString& aRevisionId, + ErrorResult& aRv); + + void GetRevisionId(JSContext* aCx, nsAString& aRevisionId, ErrorResult& aRv); + + already_AddRefed GetLength(JSContext* aCx, ErrorResult& aRv); + + already_AddRefed Sync(JSContext* aCx, + const nsAString& aRevisionId, + ErrorResult& aRv); + + IMPL_EVENT_HANDLER(change) + + // We don't use this for the WorkerDataStore. + void SetDataStoreImpl(DataStoreImpl& aStore, ErrorResult& aRv); + + void SetBackingDataStore( + const nsMainThreadPtrHandle& aBackingStore); + + void SetDataStoreChangeEventProxy(DataStoreChangeEventProxy* aEventProxy); + +protected: + virtual ~WorkerDataStore() {} + +private: + nsMainThreadPtrHandle mBackingStore; + nsRefPtr mEventProxy; +}; + +class DataStoreChangeEventProxy MOZ_FINAL : public nsIDOMEventListener + , public WorkerFeature +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIDOMEVENTLISTENER + + DataStoreChangeEventProxy(WorkerPrivate* aWorkerPrivate, + WorkerDataStore* aWorkerStore); + + WorkerPrivate* GetWorkerPrivate() const; + + WorkerDataStore* GetWorkerStore() const; + +protected: + // WorkerFeature implementation. + + bool Notify(JSContext* aCx, Status aStatus) MOZ_OVERRIDE; + +private: + ~DataStoreChangeEventProxy() {}; + + WorkerPrivate* mWorkerPrivate; + + nsRefPtr mWorkerStore; + + bool mCleanedUp; // To specify if the worker has been cancelled. + + // Ensure the worker and the main thread won't race to access |mCleanedUp|. + Mutex mCleanUpLock; +}; + +} //namespace workers +} //namespace dom +} //namespace mozilla + +#endif \ No newline at end of file diff --git a/dom/workers/DataStoreCursor.cpp b/dom/workers/DataStoreCursor.cpp new file mode 100644 index 000000000000..4376be40f6a3 --- /dev/null +++ b/dom/workers/DataStoreCursor.cpp @@ -0,0 +1,233 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DataStore.h" +#include "DataStoreCursor.h" + +#include "mozilla/dom/DataStore.h" +#include "mozilla/dom/DataStoreCursor.h" +#include "mozilla/dom/DataStoreBinding.h" +#include "mozilla/dom/DataStoreImplBinding.h" + +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/PromiseWorkerProxy.h" +#include "mozilla/ErrorResult.h" + +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" +#include "WorkerScope.h" + +BEGIN_WORKERS_NAMESPACE + +already_AddRefed +WorkerDataStoreCursor::Constructor(GlobalObject& aGlobal, ErrorResult& aRv) +{ + MOZ_ASSERT(!NS_IsMainThread()); + nsRefPtr workerCursor = new WorkerDataStoreCursor(); + return workerCursor.forget(); +} + +JSObject* +WorkerDataStoreCursor::WrapObject(JSContext* aCx) +{ + return DataStoreCursorBinding_workers::Wrap(aCx, this); +} + +// A WorkerMainThreadRunnable which holds a reference to DataStoreCursor. +class DataStoreCursorRunnable : public WorkerMainThreadRunnable +{ +protected: + nsMainThreadPtrHandle mBackingCursor; + +public: + DataStoreCursorRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingCursor) + : WorkerMainThreadRunnable(aWorkerPrivate) + , mBackingCursor(aBackingCursor) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } +}; + +// A DataStoreCursorRunnable to run DataStoreCursor::GetStore(...) on the main +// thread. +class DataStoreCursorGetStoreRunnable MOZ_FINAL : public DataStoreCursorRunnable +{ + WorkerDataStore* mWorkerStore; + ErrorResult& mRv; + nsRefPtr mEventProxy; + +public: + DataStoreCursorGetStoreRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingCursor, + WorkerDataStore* aWorkerStore, + ErrorResult& aRv) + : DataStoreCursorRunnable(aWorkerPrivate, aBackingCursor) + , mWorkerStore(aWorkerStore) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + // When we're on the worker thread, prepare an DataStoreChangeEventProxy. + mEventProxy = new DataStoreChangeEventProxy(aWorkerPrivate, mWorkerStore); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + nsRefPtr store = mBackingCursor->GetStore(mRv); + + // Add |mEventProxy| as an event listner to DataStore; + if (NS_FAILED(store->AddEventListener(NS_LITERAL_STRING("change"), + mEventProxy, + false, + false, + 2))) { + NS_WARNING("Failed to add event listener!"); + return false; + } + + // Point WorkerDataStore to DataStore. + nsMainThreadPtrHandle backingStore = + new nsMainThreadPtrHolder(store); + mWorkerStore->SetBackingDataStore(backingStore); + + return true; + } +}; + +// A DataStoreCursorRunnable to run DataStoreCursor::Next(...) on the main +// thread. +class DataStoreCursorNextRunnable MOZ_FINAL : public DataStoreCursorRunnable +{ + nsRefPtr mPromiseWorkerProxy; + ErrorResult& mRv; + +public: + DataStoreCursorNextRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingCursor, + Promise* aWorkerPromise, + ErrorResult& aRv) + : DataStoreCursorRunnable(aWorkerPrivate, aBackingCursor) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + mPromiseWorkerProxy = + new PromiseWorkerProxy(aWorkerPrivate, aWorkerPromise); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + nsRefPtr promise = mBackingCursor->Next(mRv); + promise->AppendNativeHandler(mPromiseWorkerProxy); + return true; + } +}; + +// A DataStoreCursorRunnable to run DataStoreCursor::Close(...) on the main +// thread. +class DataStoreCursorCloseRunnable MOZ_FINAL : public DataStoreCursorRunnable +{ + ErrorResult& mRv; + +public: + DataStoreCursorCloseRunnable(WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingCursor, + ErrorResult& aRv) + : DataStoreCursorRunnable(aWorkerPrivate, aBackingCursor) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + mBackingCursor->Close(mRv); + return true; + } +}; + +already_AddRefed +WorkerDataStoreCursor::GetStore(JSContext* aCx, ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + // Create a WorkerDataStore on the worker. DataStoreCursorGetStoreRunnable + // will point that to the DataStore created on the main thread. + nsRefPtr workerStore = + new WorkerDataStore(workerPrivate->GlobalScope()); + + nsRefPtr runnable = + new DataStoreCursorGetStoreRunnable(workerPrivate, + mBackingCursor, + workerStore, + aRv); + runnable->Dispatch(aCx); + + return workerStore.forget(); +} + +already_AddRefed +WorkerDataStoreCursor::Next(JSContext* aCx, ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr promise = new Promise(workerPrivate->GlobalScope()); + + nsRefPtr runnable = + new DataStoreCursorNextRunnable(workerPrivate, + mBackingCursor, + promise, + aRv); + runnable->Dispatch(aCx); + + return promise.forget(); +} + +void +WorkerDataStoreCursor::Close(JSContext* aCx, ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr runnable = + new DataStoreCursorCloseRunnable(workerPrivate, mBackingCursor, aRv); + runnable->Dispatch(aCx); +} + +void +WorkerDataStoreCursor::SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor) +{ + NS_NOTREACHED("We don't use this for the WorkerDataStoreCursor!"); +} + +void +WorkerDataStoreCursor::SetBackingDataStoreCursor( + const nsMainThreadPtrHandle& aBackingCursor) +{ + mBackingCursor = aBackingCursor; +} + +END_WORKERS_NAMESPACE diff --git a/dom/workers/DataStoreCursor.h b/dom/workers/DataStoreCursor.h new file mode 100644 index 000000000000..b50dcd1e18bc --- /dev/null +++ b/dom/workers/DataStoreCursor.h @@ -0,0 +1,62 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_workers_DataStoreCursor_h +#define mozilla_dom_workers_DataStoreCursor_h + +#include "nsProxyRelease.h" + +namespace mozilla { + +class ErrorResult; + +namespace dom { + +class Promise; +class GlobalObject; +class DataStoreCursor; +class DataStoreCursorImpl; + +namespace workers { + +class WorkerDataStore; + +class WorkerDataStoreCursor MOZ_FINAL +{ +public: + NS_INLINE_DECL_REFCOUNTING(WorkerDataStoreCursor) + + // WebIDL (internal functions) + + static already_AddRefed Constructor(GlobalObject& aGlobal, + ErrorResult& aRv); + + JSObject* WrapObject(JSContext *aCx); + + // WebIDL (public APIs) + + already_AddRefed GetStore(JSContext *aCx, ErrorResult& aRv); + + already_AddRefed Next(JSContext *aCx, ErrorResult& aRv); + + void Close(JSContext *aCx, ErrorResult& aRv); + + // We don't use this for the WorkerDataStore. + void SetDataStoreCursorImpl(DataStoreCursorImpl& aCursor); + + void SetBackingDataStoreCursor( + const nsMainThreadPtrHandle& aBackingCursor); + +protected: + virtual ~WorkerDataStoreCursor() {} + +private: + nsMainThreadPtrHandle mBackingCursor; +}; + +} //namespace workers +} //namespace dom +} //namespace mozilla + +#endif \ No newline at end of file diff --git a/dom/workers/Navigator.cpp b/dom/workers/Navigator.cpp index 9db904f53037..ada356fcc079 100644 --- a/dom/workers/Navigator.cpp +++ b/dom/workers/Navigator.cpp @@ -3,12 +3,22 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "Navigator.h" +#include "DataStore.h" +#include "mozilla/dom/DataStore.h" +#include "mozilla/dom/DataStoreBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/PromiseWorkerProxy.h" #include "mozilla/dom/WorkerNavigatorBinding.h" +#include "Navigator.h" +#include "nsProxyRelease.h" #include "RuntimeService.h" +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" +#include "WorkerScope.h" + BEGIN_WORKERS_NAMESPACE NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WorkerNavigator) @@ -39,4 +49,222 @@ WorkerNavigator::WrapObject(JSContext* aCx) return WorkerNavigatorBinding_workers::Wrap(aCx, this); } +// A WorkerMainThreadRunnable to synchronously add DataStoreChangeEventProxy on +// the main thread. We need this because we have to access |mBackingStore| on +// the main thread. +class DataStoreAddEventListenerRunnable : public WorkerMainThreadRunnable +{ + nsMainThreadPtrHandle mBackingStore; + DataStoreChangeEventProxy* mEventProxy; + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + // Add |mEventProxy| as an event listner to DataStore. + if (NS_FAILED(mBackingStore->AddEventListener(NS_LITERAL_STRING("change"), + mEventProxy, + false, + false, + 2))) { + MOZ_ASSERT(false, "failed to add event listener!"); + return false; + } + + return true; + } + +public: + DataStoreAddEventListenerRunnable( + WorkerPrivate* aWorkerPrivate, + const nsMainThreadPtrHandle& aBackingStore, + DataStoreChangeEventProxy* aEventProxy) + : WorkerMainThreadRunnable(aWorkerPrivate) + , mBackingStore(aBackingStore) + , mEventProxy(aEventProxy) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + } +}; + +#define WORKER_DATA_STORES_TAG JS_SCTAG_USER_MIN + +static JSObject* +GetDataStoresStructuredCloneCallbacksRead(JSContext* aCx, + JSStructuredCloneReader* aReader, + uint32_t aTag, + uint32_t aData, + void* aClosure) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + if (aTag != WORKER_DATA_STORES_TAG) { + MOZ_ASSERT(false, "aTag must be WORKER_DATA_STORES_TAG!"); + return nullptr; + } + + NS_ASSERTION(!aData, "aData should be empty"); + + // Read the holder from the buffer, which points to the data store. + nsMainThreadPtrHolder* dataStoreholder; + if (!JS_ReadBytes(aReader, &dataStoreholder, sizeof(dataStoreholder))) { + MOZ_ASSERT(false, "cannot read bytes for dataStoreholder!"); + return nullptr; + } + + nsRefPtr workerStore = + new WorkerDataStore(workerPrivate->GlobalScope()); + nsMainThreadPtrHandle backingStore = dataStoreholder; + + // When we're on the worker thread, prepare a DataStoreChangeEventProxy. + nsRefPtr eventProxy = + new DataStoreChangeEventProxy(workerPrivate, workerStore); + + // Add the DataStoreChangeEventProxy as an event listener on the main thread. + nsRefPtr runnable = + new DataStoreAddEventListenerRunnable(workerPrivate, + backingStore, + eventProxy); + runnable->Dispatch(aCx); + + // Point WorkerDataStore to DataStore. + workerStore->SetBackingDataStore(backingStore); + + JS::Rooted global(aCx, JS::CurrentGlobalOrNull(aCx)); + if (!global) { + MOZ_ASSERT(false, "cannot get global!"); + return nullptr; + } + + JS::Rooted workerStoreObj(aCx, workerStore->WrapObject(aCx)); + if (!JS_WrapObject(aCx, &workerStoreObj)) { + MOZ_ASSERT(false, "cannot wrap object for workerStoreObj!"); + return nullptr; + } + + return workerStoreObj; +} + +static bool +GetDataStoresStructuredCloneCallbacksWrite(JSContext* aCx, + JSStructuredCloneWriter* aWriter, + JS::Handle aObj, + void* aClosure) +{ + AssertIsOnMainThread(); + + PromiseWorkerProxy* proxy = static_cast(aClosure); + NS_ASSERTION(proxy, "must have proxy!"); + + if (!JS_WriteUint32Pair(aWriter, WORKER_DATA_STORES_TAG, 0)) { + MOZ_ASSERT(false, "cannot write pair for WORKER_DATA_STORES_TAG!"); + return false; + } + + JS::Rooted storeObj(aCx, aObj); + + DataStore* store = nullptr; + nsresult rv = UNWRAP_OBJECT(DataStore, storeObj, store); + if (NS_FAILED(rv)) { + MOZ_ASSERT(false, "cannot unwrap the DataStore object!"); + return false; + } + + // We keep the data store alive here. + proxy->StoreISupports(store); + + // Construct the nsMainThreadPtrHolder pointing to the data store. + nsMainThreadPtrHolder* dataStoreholder = + new nsMainThreadPtrHolder(store); + + // And write the dataStoreholder into the buffer. + if (!JS_WriteBytes(aWriter, &dataStoreholder, sizeof(dataStoreholder))) { + MOZ_ASSERT(false, "cannot write bytes for dataStoreholder!"); + return false; + } + + return true; +} + +static JSStructuredCloneCallbacks kGetDataStoresStructuredCloneCallbacks = { + GetDataStoresStructuredCloneCallbacksRead, + GetDataStoresStructuredCloneCallbacksWrite, + nullptr +}; + +// A WorkerMainThreadRunnable to run WorkerNavigator::GetDataStores(...) on the +// main thread. +class NavigatorGetDataStoresRunnable MOZ_FINAL : public WorkerMainThreadRunnable +{ + nsRefPtr mPromiseWorkerProxy; + const nsString mName; + ErrorResult& mRv; + +public: + NavigatorGetDataStoresRunnable(WorkerPrivate* aWorkerPrivate, + Promise* aWorkerPromise, + const nsAString& aName, + ErrorResult& aRv) + : WorkerMainThreadRunnable(aWorkerPrivate) + , mName(aName) + , mRv(aRv) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + + mPromiseWorkerProxy = + new PromiseWorkerProxy(aWorkerPrivate, + aWorkerPromise, + &kGetDataStoresStructuredCloneCallbacks); + } + +protected: + virtual bool + MainThreadRun() MOZ_OVERRIDE + { + AssertIsOnMainThread(); + + // Walk up to the containing window. + WorkerPrivate* wp = mWorkerPrivate; + while (wp->GetParent()) { + wp = wp->GetParent(); + } + nsPIDOMWindow* window = wp->GetWindow(); + + // TODO SharedWorker has null window. Don't need to worry about at this + // point, though. + if (!window) { + mRv.Throw(NS_ERROR_FAILURE); + return false; + } + + nsRefPtr promise = Navigator::GetDataStores(window, mName, mRv); + promise->AppendNativeHandler(mPromiseWorkerProxy); + return true; + } +}; + +already_AddRefed +WorkerNavigator::GetDataStores(JSContext* aCx, + const nsAString& aName, + ErrorResult& aRv) +{ + WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); + MOZ_ASSERT(workerPrivate); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr promise = new Promise(workerPrivate->GlobalScope()); + + nsRefPtr runnable = + new NavigatorGetDataStoresRunnable(workerPrivate, promise, aName, aRv); + runnable->Dispatch(aCx); + + return promise.forget(); +} + END_WORKERS_NAMESPACE diff --git a/dom/workers/Navigator.h b/dom/workers/Navigator.h index e5183b3b8ad6..e3577b06a465 100644 --- a/dom/workers/Navigator.h +++ b/dom/workers/Navigator.h @@ -10,6 +10,16 @@ #include "nsString.h" #include "nsWrapperCache.h" +// Need this to use Navigator::HasDataStoreSupport() in +// WorkerNavigatorBinding.cpp +#include "mozilla/dom/Navigator.h" + +namespace mozilla { +namespace dom { +class Promise; +} +} + BEGIN_WORKERS_NAMESPACE class WorkerNavigator MOZ_FINAL : public nsWrapperCache @@ -97,6 +107,10 @@ public: { mOnline = aOnline; } + + already_AddRefed GetDataStores(JSContext* aCx, + const nsAString& aName, + ErrorResult& aRv); }; END_WORKERS_NAMESPACE diff --git a/dom/workers/URL.cpp b/dom/workers/URL.cpp index f80594ebdf0d..0a9a3f741a7c 100644 --- a/dom/workers/URL.cpp +++ b/dom/workers/URL.cpp @@ -63,63 +63,8 @@ private: nsRefPtr mURL; }; -// Base class for the URL runnable objects. -class URLRunnable : public nsRunnable -{ -protected: - WorkerPrivate* mWorkerPrivate; - nsCOMPtr mSyncLoopTarget; - -protected: - URLRunnable(WorkerPrivate* aWorkerPrivate) - : mWorkerPrivate(aWorkerPrivate) - { - mWorkerPrivate->AssertIsOnWorkerThread(); - } - -public: - bool - Dispatch(JSContext* aCx) - { - mWorkerPrivate->AssertIsOnWorkerThread(); - - AutoSyncLoopHolder syncLoop(mWorkerPrivate); - - mSyncLoopTarget = syncLoop.EventTarget(); - - if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) { - JS_ReportError(aCx, "Failed to dispatch to main thread!"); - return false; - } - - return syncLoop.Run(); - } - -private: - NS_IMETHOD Run() - { - AssertIsOnMainThread(); - - MainThreadRun(); - - nsRefPtr response = - new MainThreadStopSyncLoopRunnable(mWorkerPrivate, - mSyncLoopTarget.forget(), - true); - if (!response->Dispatch(nullptr)) { - NS_WARNING("Failed to dispatch response!"); - } - - return NS_OK; - } - -protected: - virtual void - MainThreadRun() = 0; -}; - // This class creates an URL from a DOM Blob on the main thread. -class CreateURLRunnable : public URLRunnable +class CreateURLRunnable : public WorkerMainThreadRunnable { private: nsIDOMBlob* mBlob; @@ -129,14 +74,14 @@ public: CreateURLRunnable(WorkerPrivate* aWorkerPrivate, nsIDOMBlob* aBlob, const mozilla::dom::objectURLOptions& aOptions, nsString& aURL) - : URLRunnable(aWorkerPrivate), + : WorkerMainThreadRunnable(aWorkerPrivate), mBlob(aBlob), mURL(aURL) { MOZ_ASSERT(aBlob); } - void + bool MainThreadRun() { AssertIsOnMainThread(); @@ -149,7 +94,7 @@ public: doc = window->GetExtantDoc(); if (!doc) { SetDOMStringToNull(mURL); - return; + return false; } principal = doc->NodePrincipal(); @@ -166,7 +111,7 @@ public: if (NS_FAILED(rv)) { NS_WARNING("Failed to add data entry for the blob!"); SetDOMStringToNull(mURL); - return; + return false; } if (doc) { @@ -176,11 +121,12 @@ public: } mURL = NS_ConvertUTF8toUTF16(url); + return true; } }; // This class revokes an URL on the main thread. -class RevokeURLRunnable : public URLRunnable +class RevokeURLRunnable : public WorkerMainThreadRunnable { private: const nsString mURL; @@ -188,11 +134,11 @@ private: public: RevokeURLRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aURL) - : URLRunnable(aWorkerPrivate), + : WorkerMainThreadRunnable(aWorkerPrivate), mURL(aURL) {} - void + bool MainThreadRun() { AssertIsOnMainThread(); @@ -204,7 +150,7 @@ public: if (window) { doc = window->GetExtantDoc(); if (!doc) { - return; + return false; } principal = doc->NodePrincipal(); @@ -232,11 +178,13 @@ public: if (!window) { mWorkerPrivate->UnregisterHostObjectURI(url); } + + return true; } }; // This class creates a URL object on the main thread. -class ConstructorRunnable : public URLRunnable +class ConstructorRunnable : public WorkerMainThreadRunnable { private: const nsString mURL; @@ -251,7 +199,7 @@ public: ConstructorRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aURL, const nsAString& aBase, mozilla::ErrorResult& aRv) - : URLRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate) , mURL(aURL) , mBase(aBase) , mRv(aRv) @@ -262,7 +210,7 @@ public: ConstructorRunnable(WorkerPrivate* aWorkerPrivate, const nsAString& aURL, URLProxy* aBaseProxy, mozilla::ErrorResult& aRv) - : URLRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate) , mURL(aURL) , mBaseProxy(aBaseProxy) , mRv(aRv) @@ -270,7 +218,7 @@ public: mWorkerPrivate->AssertIsOnWorkerThread(); } - void + bool MainThreadRun() { AssertIsOnMainThread(); @@ -279,7 +227,7 @@ public: nsCOMPtr ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); if (NS_FAILED(rv)) { mRv.Throw(rv); - return; + return true; } nsCOMPtr baseURL; @@ -289,7 +237,7 @@ public: getter_AddRefs(baseURL)); if (NS_FAILED(rv)) { mRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); - return; + return true; } } else { baseURL = mBaseProxy->URI(); @@ -300,10 +248,11 @@ public: getter_AddRefs(url)); if (NS_FAILED(rv)) { mRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); - return; + return true; } mRetval = new URLProxy(new mozilla::dom::URL(url)); + return true; } URLProxy* @@ -336,7 +285,7 @@ private: }; // This class is the generic getter for any URL property. -class GetterRunnable : public URLRunnable +class GetterRunnable : public WorkerMainThreadRunnable { public: enum GetterType { @@ -356,7 +305,7 @@ public: GetterRunnable(WorkerPrivate* aWorkerPrivate, GetterType aType, nsString& aValue, URLProxy* aURLProxy) - : URLRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate) , mValue(aValue) , mType(aType) , mURLProxy(aURLProxy) @@ -364,7 +313,7 @@ public: mWorkerPrivate->AssertIsOnWorkerThread(); } - void + bool MainThreadRun() { AssertIsOnMainThread(); @@ -414,6 +363,8 @@ public: mURLProxy->URL()->GetHash(mValue); break; } + + return true; } private: @@ -423,7 +374,7 @@ private: }; // This class is the generic setter for any URL property. -class SetterRunnable : public URLRunnable +class SetterRunnable : public WorkerMainThreadRunnable { public: enum SetterType { @@ -442,7 +393,7 @@ public: SetterRunnable(WorkerPrivate* aWorkerPrivate, SetterType aType, const nsAString& aValue, URLProxy* aURLProxy, mozilla::ErrorResult& aRv) - : URLRunnable(aWorkerPrivate) + : WorkerMainThreadRunnable(aWorkerPrivate) , mValue(aValue) , mType(aType) , mURLProxy(aURLProxy) @@ -451,7 +402,7 @@ public: mWorkerPrivate->AssertIsOnWorkerThread(); } - void + bool MainThreadRun() { AssertIsOnMainThread(); @@ -497,6 +448,8 @@ public: mURLProxy->URL()->SetHash(mValue); break; } + + return true; } private: diff --git a/dom/workers/WorkerRunnable.cpp b/dom/workers/WorkerRunnable.cpp index 92e216a9b899..cd034b21fdd8 100644 --- a/dom/workers/WorkerRunnable.cpp +++ b/dom/workers/WorkerRunnable.cpp @@ -481,6 +481,46 @@ MainThreadWorkerControlRunnable::PostDispatch(JSContext* aCx, NS_IMPL_ISUPPORTS_INHERITED0(WorkerControlRunnable, WorkerRunnable) +WorkerMainThreadRunnable::WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate) +: mWorkerPrivate(aWorkerPrivate) +{ + mWorkerPrivate->AssertIsOnWorkerThread(); +} + +bool +WorkerMainThreadRunnable::Dispatch(JSContext* aCx) +{ + mWorkerPrivate->AssertIsOnWorkerThread(); + + AutoSyncLoopHolder syncLoop(mWorkerPrivate); + + mSyncLoopTarget = syncLoop.EventTarget(); + + if (NS_FAILED(NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL))) { + JS_ReportError(aCx, "Failed to dispatch to main thread!"); + return false; + } + + return syncLoop.Run(); +} + +NS_IMETHODIMP +WorkerMainThreadRunnable::Run() +{ + AssertIsOnMainThread(); + + bool runResult = MainThreadRun(); + + nsRefPtr response = + new MainThreadStopSyncLoopRunnable(mWorkerPrivate, + mSyncLoopTarget.forget(), + runResult); + + MOZ_ALWAYS_TRUE(response->Dispatch(nullptr)); + + return NS_OK; +} + bool WorkerSameThreadRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) diff --git a/dom/workers/WorkerRunnable.h b/dom/workers/WorkerRunnable.h index f51f3f48a9d0..cd154746c154 100644 --- a/dom/workers/WorkerRunnable.h +++ b/dom/workers/WorkerRunnable.h @@ -12,6 +12,7 @@ #include "mozilla/Atomics.h" #include "nsISupportsImpl.h" +#include "nsThreadUtils.h" /* nsRunnable */ class JSContext; class nsIEventTarget; @@ -342,6 +343,28 @@ protected: bool aRunResult) MOZ_OVERRIDE; }; +// Base class for the runnable objects, which makes a synchronous call to +// dispatch the tasks from the worker thread to the main thread. +// +// Note that the derived class must override MainThreadRun. +class WorkerMainThreadRunnable : public nsRunnable +{ +protected: + WorkerPrivate* mWorkerPrivate; + nsCOMPtr mSyncLoopTarget; + + WorkerMainThreadRunnable(WorkerPrivate* aWorkerPrivate); + ~WorkerMainThreadRunnable() {} + + virtual bool MainThreadRun() = 0; + +public: + bool Dispatch(JSContext* aCx); + +private: + NS_IMETHOD Run() MOZ_OVERRIDE; +}; + END_WORKERS_NAMESPACE #endif // mozilla_dom_workers_workerrunnable_h__ diff --git a/dom/workers/moz.build b/dom/workers/moz.build index b4aa027d90dd..e437a1eb625f 100644 --- a/dom/workers/moz.build +++ b/dom/workers/moz.build @@ -19,6 +19,8 @@ EXPORTS.mozilla.dom.workers += [ # Stuff needed for the bindings, not really public though. EXPORTS.mozilla.dom.workers.bindings += [ + 'DataStore.h', + 'DataStoreCursor.h', 'FileReaderSync.h', 'Location.h', 'MessagePort.h', @@ -32,6 +34,8 @@ EXPORTS.mozilla.dom.workers.bindings += [ SOURCES += [ 'ChromeWorkerScope.cpp', + 'DataStore.cpp', + 'DataStoreCursor.cpp', 'File.cpp', 'FileReaderSync.cpp', 'Location.cpp', diff --git a/dom/workers/test/navigator_worker.js b/dom/workers/test/navigator_worker.js index 49811e134b17..cb22a82fa6ac 100644 --- a/dom/workers/test/navigator_worker.js +++ b/dom/workers/test/navigator_worker.js @@ -2,10 +2,13 @@ * Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ + +// IMPORTANT: Do not change the list below without review from a DOM peer! var supportedProps = [ "appCodeName", "appName", "appVersion", + { name: "getDataStores", b2g: true }, "platform", "product", "taintEnabled", @@ -13,26 +16,55 @@ var supportedProps = [ "onLine" ]; +var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent); +var isB2G = !isDesktop && !navigator.userAgent.contains("Android"); + +// Prepare the interface map showing if a propery should exist in this build. +// For example, if interfaceMap[foo] = true means navigator.foo should exist. +var interfaceMap = {}; + +for (var prop of supportedProps) { + if (typeof(prop) === "string") { + interfaceMap[prop] = true; + continue; + } + + if (prop.b2g === !isB2G) { + interfaceMap[prop.name] = false; + continue; + } + + interfaceMap[prop.name] = true; +} + for (var prop in navigator) { // Make sure the list is current! - if (supportedProps.indexOf(prop) == -1) { + if (!interfaceMap[prop]) { throw "Navigator has the '" + prop + "' property that isn't in the list!"; } } var obj; -for (var index = 0; index < supportedProps.length; index++) { - var prop = supportedProps[index]; +for (var prop in interfaceMap) { + // Skip the property that is not supposed to exist in this build. + if (!interfaceMap[prop]) { + continue; + } if (typeof navigator[prop] == "undefined") { throw "Navigator has no '" + prop + "' property!"; } - obj = { - name: prop, - value: prop === "taintEnabled" ? navigator[prop]() : navigator[prop] - }; + obj = { name: prop }; + + if (prop === "taintEnabled") { + obj.value = navigator[prop](); + } else if (prop === "getDataStores") { + obj.value = typeof navigator[prop]; + } else { + obj.value = navigator[prop]; + } postMessage(JSON.stringify(obj)); } diff --git a/dom/workers/test/test_navigator.html b/dom/workers/test/test_navigator.html index 056f9bac0282..680064e8d606 100644 --- a/dom/workers/test/test_navigator.html +++ b/dom/workers/test/test_navigator.html @@ -40,6 +40,12 @@ Tests of DOM Worker Navigator return; } + if (args.name === "getDataStores") { + var type = typeof navigator[args.name]; + is(type, args.value, "getDataStores() exists and it's a function."); + return; + } + is(navigator[args.name], args.value, "Mismatched navigator string for " + args.name + "!"); }; diff --git a/dom/xbl/XBLChildrenElement.cpp b/dom/xbl/XBLChildrenElement.cpp index c1089135a121..d6caab73e0e3 100644 --- a/dom/xbl/XBLChildrenElement.cpp +++ b/dom/xbl/XBLChildrenElement.cpp @@ -75,7 +75,7 @@ XBLChildrenElement::ParseAttribute(int32_t aNamespaceID, using namespace mozilla::dom; -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsAnonymousContentList, mParent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsAnonymousContentList, mParent) NS_IMPL_CYCLE_COLLECTING_ADDREF(nsAnonymousContentList) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsAnonymousContentList) diff --git a/dom/xbl/nsXBLProtoImplField.cpp b/dom/xbl/nsXBLProtoImplField.cpp index 40bbd449641a..b0419a77859f 100644 --- a/dom/xbl/nsXBLProtoImplField.cpp +++ b/dom/xbl/nsXBLProtoImplField.cpp @@ -365,10 +365,10 @@ nsXBLProtoImplField::InstallAccessors(JSContext* aCx, return NS_ERROR_OUT_OF_MEMORY; } - if (!::JS_DefinePropertyById(aCx, aTargetClassObject, id, JS::UndefinedValue(), + if (!::JS_DefinePropertyById(aCx, aTargetClassObject, id, JS::UndefinedHandleValue, + AccessorAttributes(), JS_DATA_TO_FUNC_PTR(JSPropertyOp, get.get()), - JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, set.get()), - AccessorAttributes())) { + JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, set.get()))) { return NS_ERROR_OUT_OF_MEMORY; } @@ -444,8 +444,7 @@ nsXBLProtoImplField::InstallField(JS::Handle aBoundNode, if (!JS_WrapValue(cx, &result) || !::JS_DefineUCProperty(cx, aBoundNode, reinterpret_cast(mName), - name.Length(), result, nullptr, nullptr, - mJSAttributes)) { + name.Length(), result, mJSAttributes)) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/dom/xbl/nsXBLProtoImplMethod.cpp b/dom/xbl/nsXBLProtoImplMethod.cpp index 69d0340e1678..10b7cb605b7f 100644 --- a/dom/xbl/nsXBLProtoImplMethod.cpp +++ b/dom/xbl/nsXBLProtoImplMethod.cpp @@ -114,11 +114,10 @@ nsXBLProtoImplMethod::InstallMember(JSContext* aCx, JS::Rooted method(aCx, JS_CloneFunctionObject(aCx, jsMethodObject, globalObject)); NS_ENSURE_TRUE(method, NS_ERROR_OUT_OF_MEMORY); - JS::Rooted value(aCx, JS::ObjectValue(*method)); if (!::JS_DefineUCProperty(aCx, aTargetClassObject, static_cast(mName), - name.Length(), value, - nullptr, nullptr, JSPROP_ENUMERATE)) { + name.Length(), method, + JSPROP_ENUMERATE)) { return NS_ERROR_OUT_OF_MEMORY; } } diff --git a/dom/xbl/nsXBLProtoImplProperty.cpp b/dom/xbl/nsXBLProtoImplProperty.cpp index 1924d8e36443..b8ea3d375f5d 100644 --- a/dom/xbl/nsXBLProtoImplProperty.cpp +++ b/dom/xbl/nsXBLProtoImplProperty.cpp @@ -148,10 +148,9 @@ nsXBLProtoImplProperty::InstallMember(JSContext *aCx, nsDependentString name(mName); if (!::JS_DefineUCProperty(aCx, aTargetClassObject, static_cast(mName), - name.Length(), JSVAL_VOID, + name.Length(), JS::UndefinedHandleValue, mJSAttributes, JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter.get()), - JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get()), - mJSAttributes)) + JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get()))) return NS_ERROR_OUT_OF_MEMORY; } return NS_OK; diff --git a/editor/composer/src/nsEditorSpellCheck.cpp b/editor/composer/src/nsEditorSpellCheck.cpp index 90a08f700846..e78100a564c8 100644 --- a/editor/composer/src/nsEditorSpellCheck.cpp +++ b/editor/composer/src/nsEditorSpellCheck.cpp @@ -752,6 +752,12 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher) // otherwise, get language from preferences nsAutoString preferedDict(Preferences::GetLocalizedString("spellchecker.dictionary")); + // Replace '_' with '-' in case the user has an underscore stored in their + // pref, see bug 992118 for how this could have happened. + int32_t underScore = preferedDict.FindChar('_'); + if (underScore != -1) { + preferedDict.Replace(underScore, 1, '-'); + } if (dictName.IsEmpty()) { dictName.Assign(preferedDict); } @@ -845,6 +851,11 @@ nsEditorSpellCheck::DictionaryFetched(DictionaryFetcher* aFetcher) if (dot_pos != -1) { lang = Substring(lang, 0, dot_pos - 1); } + // Replace '_' with '-' + int32_t underScore = lang.FindChar('_'); + if (underScore != -1) { + lang.Replace(underScore, 1, '-'); + } rv = SetCurrentDictionary(lang); } if (NS_FAILED(rv)) { diff --git a/extensions/cookie/nsPopupWindowManager.cpp b/extensions/cookie/nsPopupWindowManager.cpp index 52e51c8a09e8..d95fb7440af7 100644 --- a/extensions/cookie/nsPopupWindowManager.cpp +++ b/extensions/cookie/nsPopupWindowManager.cpp @@ -11,6 +11,7 @@ #include "nsIPrefBranch.h" #include "nsIPrincipal.h" #include "nsIURI.h" +#include "mozilla/Services.h" /** * The Popup Window Manager maintains popup window permissions by website. @@ -40,7 +41,7 @@ nsresult nsPopupWindowManager::Init() { nsresult rv; - mPermissionManager = do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + mPermissionManager = mozilla::services::GetPermissionManager(); nsCOMPtr prefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); diff --git a/gfx/gl/ScopedGLHelpers.cpp b/gfx/gl/ScopedGLHelpers.cpp index f352bbcdee74..adb41f107ae4 100644 --- a/gfx/gl/ScopedGLHelpers.cpp +++ b/gfx/gl/ScopedGLHelpers.cpp @@ -102,6 +102,7 @@ ScopedBindTextureUnit::UnwrapImpl() { ScopedTexture::ScopedTexture(GLContext* aGL) : ScopedGLWrapper(aGL) { + MOZ_ASSERT(mGL->IsCurrent()); mGL->fGenTextures(1, &mTexture); } @@ -111,10 +112,47 @@ ScopedTexture::UnwrapImpl() // Check that we're not falling out of scope after // the current context changed. MOZ_ASSERT(mGL->IsCurrent()); - mGL->fDeleteTextures(1, &mTexture); } + +/* ScopedFramebuffer **************************************************************/ + +ScopedFramebuffer::ScopedFramebuffer(GLContext* aGL) + : ScopedGLWrapper(aGL) +{ + MOZ_ASSERT(mGL->IsCurrent()); + mGL->fGenFramebuffers(1, &mFB); +} + +void +ScopedFramebuffer::UnwrapImpl() +{ + // Check that we're not falling out of scope after + // the current context changed. + MOZ_ASSERT(mGL->IsCurrent()); + mGL->fDeleteFramebuffers(1, &mFB); +} + + +/* ScopedRenderbuffer **************************************************************/ + +ScopedRenderbuffer::ScopedRenderbuffer(GLContext* aGL) + : ScopedGLWrapper(aGL) +{ + MOZ_ASSERT(mGL->IsCurrent()); + mGL->fGenRenderbuffers(1, &mRB); +} + +void +ScopedRenderbuffer::UnwrapImpl() +{ + // Check that we're not falling out of scope after + // the current context changed. + MOZ_ASSERT(mGL->IsCurrent()); + mGL->fDeleteRenderbuffers(1, &mRB); +} + /* ScopedBindTexture **********************************************************/ void ScopedBindTexture::Init(GLenum aTarget) diff --git a/gfx/gl/ScopedGLHelpers.h b/gfx/gl/ScopedGLHelpers.h index 3a8a0c18a2fc..c55121c02dca 100644 --- a/gfx/gl/ScopedGLHelpers.h +++ b/gfx/gl/ScopedGLHelpers.h @@ -120,6 +120,40 @@ protected: }; +struct ScopedFramebuffer + : public ScopedGLWrapper +{ + friend struct ScopedGLWrapper; + +protected: + GLuint mFB; + +public: + ScopedFramebuffer(GLContext* aGL); + GLuint FB() { return mFB; } + +protected: + void UnwrapImpl(); +}; + + +struct ScopedRenderbuffer + : public ScopedGLWrapper +{ + friend struct ScopedGLWrapper; + +protected: + GLuint mRB; + +public: + ScopedRenderbuffer(GLContext* aGL); + GLuint RB() { return mRB; } + +protected: + void UnwrapImpl(); +}; + + struct ScopedBindTexture : public ScopedGLWrapper { diff --git a/gfx/layers/CopyableCanvasLayer.cpp b/gfx/layers/CopyableCanvasLayer.cpp index ed8479e30601..68b93cda8d7f 100644 --- a/gfx/layers/CopyableCanvasLayer.cpp +++ b/gfx/layers/CopyableCanvasLayer.cpp @@ -95,9 +95,6 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) } if (mGLContext) { - RefPtr readSurf; - RefPtr resultSurf; - SharedSurface_GL* sharedSurf = nullptr; if (mStream) { sharedSurf = SharedSurface_GL::Cast(mStream->SwapConsumer()); @@ -114,60 +111,51 @@ CopyableCanvasLayer::UpdateTarget(DrawTarget* aDestTarget) SurfaceFormat format = (GetContentFlags() & CONTENT_OPAQUE) ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::B8G8R8A8; + bool needsPremult = sharedSurf->HasAlpha() && !mIsGLAlphaPremult; + // Try to read back directly into aDestTarget's output buffer if (aDestTarget) { - resultSurf = aDestTarget->Snapshot(); - if (!resultSurf) { - resultSurf = GetTempSurface(readSize, format); + uint8_t* destData; + IntSize destSize; + int32_t destStride; + SurfaceFormat destFormat; + if (aDestTarget->LockBits(&destData, &destSize, &destStride, &destFormat)) { + if (destSize == readSize && destFormat == format) { + RefPtr data = + Factory::CreateWrappingDataSourceSurface(destData, destStride, destSize, destFormat); + mGLContext->Screen()->Readback(sharedSurf, data); + if (needsPremult) { + PremultiplySurface(data); + } + aDestTarget->ReleaseBits(destData); + return; + } + aDestTarget->ReleaseBits(destData); } + } + + RefPtr resultSurf; + if (sharedSurf->Type() == SharedSurfaceType::Basic && !needsPremult) { + SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(sharedSurf); + resultSurf = sharedSurf_Basic->GetData(); } else { - resultSurf = GetTempSurface(readSize, format); + RefPtr data = GetTempSurface(readSize, format); + // Readback handles Flush/MarkDirty. + mGLContext->Screen()->Readback(sharedSurf, data); + if (needsPremult) { + PremultiplySurface(data); + } + resultSurf = data; } MOZ_ASSERT(resultSurf); - MOZ_ASSERT(sharedSurf->APIType() == APITypeT::OpenGL); - SharedSurface_GL* surfGL = SharedSurface_GL::Cast(sharedSurf); - if (surfGL->Type() == SharedSurfaceType::Basic) { - // sharedSurf_Basic->mData must outlive readSurf. Alas, readSurf may not - // leave the scope it was declared in. - SharedSurface_Basic* sharedSurf_Basic = SharedSurface_Basic::Cast(surfGL); - readSurf = sharedSurf_Basic->GetData(); + if (aDestTarget) { + aDestTarget->CopySurface(resultSurf, + IntRect(0, 0, readSize.width, readSize.height), + IntPoint(0, 0)); } else { - if (resultSurf->GetSize() != readSize || - !(readSurf = resultSurf->GetDataSurface()) || - readSurf->GetFormat() != format) - { - readSurf = GetTempSurface(readSize, format); - } - - // Readback handles Flush/MarkDirty. - mGLContext->Screen()->Readback(surfGL, readSurf); - } - MOZ_ASSERT(readSurf); - - bool needsPremult = surfGL->HasAlpha() && !mIsGLAlphaPremult; - if (needsPremult) { - PremultiplySurface(readSurf); - } - - if (readSurf != resultSurf) { - RefPtr resultDataSurface = - resultSurf->GetDataSurface(); - RefPtr dt = - Factory::CreateDrawTargetForData(BackendType::CAIRO, - resultDataSurface->GetData(), - resultDataSurface->GetSize(), - resultDataSurface->Stride(), - resultDataSurface->GetFormat()); - IntSize readSize = readSurf->GetSize(); - dt->CopySurface(readSurf, - IntRect(0, 0, readSize.width, readSize.height), - IntPoint(0, 0)); - } - - // If !aDestSurface then we will end up painting using mSurface, so - // stick our surface into mSurface, so that the Paint() path is the same. - if (!aDestTarget) { + // If !aDestSurface then we will end up painting using mSurface, so + // stick our surface into mSurface, so that the Paint() path is the same. mSurface = resultSurf; } } @@ -178,13 +166,10 @@ CopyableCanvasLayer::GetTempSurface(const IntSize& aSize, const SurfaceFormat aFormat) { if (!mCachedTempSurface || - aSize.width != mCachedSize.width || - aSize.height != mCachedSize.height || - aFormat != mCachedFormat) + aSize != mCachedTempSurface->GetSize() || + aFormat != mCachedTempSurface->GetFormat()) { mCachedTempSurface = Factory::CreateDataSourceSurface(aSize, aFormat); - mCachedSize = aSize; - mCachedFormat = aFormat; } return mCachedTempSurface; diff --git a/gfx/layers/CopyableCanvasLayer.h b/gfx/layers/CopyableCanvasLayer.h index 5507979d3877..5b04397b8c4e 100644 --- a/gfx/layers/CopyableCanvasLayer.h +++ b/gfx/layers/CopyableCanvasLayer.h @@ -61,8 +61,6 @@ protected: bool mNeedsYFlip; RefPtr mCachedTempSurface; - gfx::IntSize mCachedSize; - gfx::SurfaceFormat mCachedFormat; gfx::DataSourceSurface* GetTempSurface(const gfx::IntSize& aSize, const gfx::SurfaceFormat aFormat); diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 592d553c8f62..ae5482594728 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -738,11 +738,11 @@ SetShadowProperties(Layer* aLayer) } void -CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, - const TargetConfig& aTargetConfig, - bool aIsFirstPaint, - bool aScheduleComposite) +CompositorParent::ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig, + bool aIsFirstPaint) { + MOZ_ASSERT(IsInCompositorThread()); + if (!aIsFirstPaint && !mCompositionManager->IsFirstPaint() && mCompositionManager->RequiresReorientation(aTargetConfig.orientation())) { @@ -752,6 +752,15 @@ CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, mForceCompositionTask = NewRunnableMethod(this, &CompositorParent::ForceComposition); ScheduleTask(mForceCompositionTask, gfxPrefs::OrientationSyncMillis()); } +} + +void +CompositorParent::ShadowLayersUpdated(LayerTransactionParent* aLayerTree, + const TargetConfig& aTargetConfig, + bool aIsFirstPaint, + bool aScheduleComposite) +{ + ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint); // Instruct the LayerManager to update its render bounds now. Since all the orientation // change, dimension change would be done at the stage, update the size here is free of @@ -1250,7 +1259,12 @@ CrossProcessCompositorParent::ShadowLayersUpdated( bool aScheduleComposite) { uint64_t id = aLayerTree->GetId(); + MOZ_ASSERT(id != 0); + MOZ_ASSERT(sIndirectLayerTrees[id].mParent); + + sIndirectLayerTrees[id].mParent->ScheduleRotationOnCompositorThread(aTargetConfig, aIsFirstPaint); + Layer* shadowRoot = aLayerTree->GetRoot(); if (shadowRoot) { SetShadowProperties(shadowRoot); diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index b0cc866524b7..3af7111e178b 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -129,6 +129,12 @@ public: virtual void ScheduleComposition(); void NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint, bool aScheduleComposite); + /** + * Check rotation info and schedule a rendering task if needed. + * Only can be called from compositor thread. + */ + void ScheduleRotationOnCompositorThread(const TargetConfig& aTargetConfig, bool aIsFirstPaint); + /** * Returns the unique layer tree identifier that corresponds to the root * tree of this compositor. diff --git a/gfx/src/nsScriptableRegion.cpp b/gfx/src/nsScriptableRegion.cpp index 6b66d58729df..a861e08e25e3 100644 --- a/gfx/src/nsScriptableRegion.cpp +++ b/gfx/src/nsScriptableRegion.cpp @@ -148,10 +148,10 @@ NS_IMETHODIMP nsScriptableRegion::GetRects(JSContext* aCx, JS::MutableHandlex), nullptr, nullptr, JSPROP_ENUMERATE) || - !JS_DefineElement(aCx, destArray, n + 1, INT_TO_JSVAL(rect->y), nullptr, nullptr, JSPROP_ENUMERATE) || - !JS_DefineElement(aCx, destArray, n + 2, INT_TO_JSVAL(rect->width), nullptr, nullptr, JSPROP_ENUMERATE) || - !JS_DefineElement(aCx, destArray, n + 3, INT_TO_JSVAL(rect->height), nullptr, nullptr, JSPROP_ENUMERATE)) { + if (!JS_DefineElement(aCx, destArray, n, rect->x, JSPROP_ENUMERATE) || + !JS_DefineElement(aCx, destArray, n + 1, rect->y, JSPROP_ENUMERATE) || + !JS_DefineElement(aCx, destArray, n + 2, rect->width, JSPROP_ENUMERATE) || + !JS_DefineElement(aCx, destArray, n + 3, rect->height, JSPROP_ENUMERATE)) { return NS_ERROR_FAILURE; } n += 4; diff --git a/gfx/thebes/gfxPlatformFontList.cpp b/gfx/thebes/gfxPlatformFontList.cpp index 6a93ea5e2492..4888673afeee 100644 --- a/gfx/thebes/gfxPlatformFontList.cpp +++ b/gfx/thebes/gfxPlatformFontList.cpp @@ -244,16 +244,17 @@ gfxPlatformFontList::InitOtherFamilyNamesProc(nsStringHashKey::KeyType aKey, struct ReadFaceNamesData { ReadFaceNamesData(gfxPlatformFontList *aFontList, TimeStamp aStartTime) - : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false) + : mFontList(aFontList), mStartTime(aStartTime), mTimedOut(false), + mFirstChar(0) {} gfxPlatformFontList *mFontList; TimeStamp mStartTime; bool mTimedOut; - // if mFirstChar is not empty, only load facenames for families + // if mFirstChar is not 0, only load facenames for families // that start with this character - nsString mFirstChar; + char16_t mFirstChar; }; gfxFontEntry* @@ -265,8 +266,7 @@ gfxPlatformFontList::SearchFamiliesForFaceName(const nsAString& aFaceName) ReadFaceNamesData faceNameListsData(this, start); // iterate over familes starting with the same letter - faceNameListsData.mFirstChar.Assign(aFaceName.CharAt(0)); - ToLowerCase(faceNameListsData.mFirstChar); + faceNameListsData.mFirstChar = ToLowerCase(aFaceName.CharAt(0)); mFontFamilies.Enumerate(gfxPlatformFontList::ReadFaceNamesProc, &faceNameListsData); lookup = FindFaceName(aFaceName); @@ -299,14 +299,10 @@ gfxPlatformFontList::ReadFaceNamesProc(nsStringHashKey::KeyType aKey, gfxPlatformFontList *fc = data->mFontList; // when filtering, skip names that don't start with the filter character - if (!(data->mFirstChar.IsEmpty())) { - char16_t firstChar = aKey.CharAt(0); - nsAutoString firstCharStr(&firstChar, 1); - ToLowerCase(firstCharStr); - if (!firstCharStr.Equals(data->mFirstChar)) { - return PL_DHASH_NEXT; - } + if (data->mFirstChar && ToLowerCase(aKey.CharAt(0)) != data->mFirstChar) { + return PL_DHASH_NEXT; } + aFamilyEntry->ReadFaceNames(fc, fc->NeedFullnamePostscriptNames()); TimeDuration elapsed = TimeStamp::Now() - data->mStartTime; diff --git a/hal/android/AndroidGamepad.cpp b/hal/android/AndroidGamepad.cpp new file mode 100644 index 000000000000..2a80d817b89e --- /dev/null +++ b/hal/android/AndroidGamepad.cpp @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "Hal.h" +#include "AndroidBridge.h" + +using namespace mozilla::hal; + +namespace mozilla { +namespace hal_impl { + +void +StartMonitoringGamepadStatus() +{ + mozilla::widget::android::GeckoAppShell::StartMonitoringGamepad(); +} + +void +StopMonitoringGamepadStatus() +{ + mozilla::widget::android::GeckoAppShell::StopMonitoringGamepad(); +} + +} // hal_impl +} // mozilla diff --git a/hal/moz.build b/hal/moz.build index 9cf12a108328..f21846124d4c 100644 --- a/hal/moz.build +++ b/hal/moz.build @@ -48,6 +48,10 @@ elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'linux': UNIFIED_SOURCES += [ 'linux/LinuxGamepad.cpp' ] +elif CONFIG['MOZ_GAMEPAD_BACKEND'] == 'android': + UNIFIED_SOURCES += [ + 'android/AndroidGamepad.cpp' + ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': UNIFIED_SOURCES += [ diff --git a/js/ipc/JavaScriptChild.cpp b/js/ipc/JavaScriptChild.cpp index a7b8e9b0f216..33bfca17f360 100644 --- a/js/ipc/JavaScriptChild.cpp +++ b/js/ipc/JavaScriptChild.cpp @@ -257,14 +257,14 @@ JavaScriptChild::AnswerDefineProperty(const ObjectId &objId, const nsString &id, if (!toDescriptor(cx, descriptor, &desc)) return false; - if (!js::CheckDefineProperty(cx, obj, internedId, desc.value(), desc.getter(), - desc.setter(), desc.attributes())) + if (!js::CheckDefineProperty(cx, obj, internedId, desc.value(), desc.attributes(), + desc.getter(), desc.setter())) { return fail(cx, rs); } - if (!JS_DefinePropertyById(cx, obj, internedId, desc.value(), desc.getter(), - desc.setter(), desc.attributes())) + if (!JS_DefinePropertyById(cx, obj, internedId, desc.value(), desc.attributes(), + desc.getter(), desc.setter())) { return fail(cx, rs); } diff --git a/js/ipc/JavaScriptShared.cpp b/js/ipc/JavaScriptShared.cpp index 4ac9ed15cc87..cf74071dd4a1 100644 --- a/js/ipc/JavaScriptShared.cpp +++ b/js/ipc/JavaScriptShared.cpp @@ -455,8 +455,6 @@ JavaScriptShared::Unwrap(JSContext *cx, const InfallibleTArray &aCpow name.BeginReading(), name.Length(), v, - nullptr, - nullptr, JSPROP_ENUMERATE)) { return false; diff --git a/js/public/Value.h b/js/public/Value.h index 0e59e52c3594..7946a1a22471 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -1897,6 +1897,8 @@ namespace JS { extern JS_PUBLIC_DATA(const HandleValue) NullHandleValue; extern JS_PUBLIC_DATA(const HandleValue) UndefinedHandleValue; +extern JS_PUBLIC_DATA(const HandleValue) TrueHandleValue; +extern JS_PUBLIC_DATA(const HandleValue) FalseHandleValue; } diff --git a/js/src/assembler/assembler/X86Assembler.h b/js/src/assembler/assembler/X86Assembler.h index 91ff1c62a4de..956ea1749fde 100644 --- a/js/src/assembler/assembler/X86Assembler.h +++ b/js/src/assembler/assembler/X86Assembler.h @@ -1956,7 +1956,7 @@ public: JmpSrc movl_ripr(RegisterID dst) { - spew("movl \?(%%rip), %s", + spew("movl ?(%%rip), %s", nameIReg(dst)); m_formatter.oneByteRipOp(OP_MOV_GvEv, (RegisterID)dst, 0); return JmpSrc(m_formatter.size()); @@ -1964,7 +1964,7 @@ public: JmpSrc movl_rrip(RegisterID src) { - spew("movl %s, \?(%%rip)", + spew("movl %s, ?(%%rip)", nameIReg(src)); m_formatter.oneByteRipOp(OP_MOV_EvGv, (RegisterID)src, 0); return JmpSrc(m_formatter.size()); @@ -1972,7 +1972,7 @@ public: JmpSrc movq_ripr(RegisterID dst) { - spew("movl \?(%%rip), %s", + spew("movl ?(%%rip), %s", nameIReg(dst)); m_formatter.oneByteRipOp64(OP_MOV_GvEv, dst, 0); return JmpSrc(m_formatter.size()); @@ -2184,7 +2184,7 @@ public: JmpSrc leaq_rip(RegisterID dst) { - spew("leaq \?(%%rip), %s", + spew("leaq ?(%%rip), %s", nameIReg(dst)); m_formatter.oneByteRipOp64(OP_LEA, dst, 0); return JmpSrc(m_formatter.size()); @@ -2781,7 +2781,7 @@ public: #else JmpSrc movsd_ripr(XMMRegisterID dst) { - spew("movsd \?(%%rip), %s", + spew("movsd ?(%%rip), %s", nameFPReg(dst)); m_formatter.prefix(PRE_SSE_F2); m_formatter.twoByteRipOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, 0); @@ -2789,7 +2789,7 @@ public: } JmpSrc movss_ripr(XMMRegisterID dst) { - spew("movss \?(%%rip), %s", + spew("movss ?(%%rip), %s", nameFPReg(dst)); m_formatter.prefix(PRE_SSE_F3); m_formatter.twoByteRipOp(OP2_MOVSD_VsdWsd, (RegisterID)dst, 0); @@ -2797,7 +2797,7 @@ public: } JmpSrc movsd_rrip(XMMRegisterID src) { - spew("movsd %s, \?(%%rip)", + spew("movsd %s, ?(%%rip)", nameFPReg(src)); m_formatter.prefix(PRE_SSE_F2); m_formatter.twoByteRipOp(OP2_MOVSD_WsdVsd, (RegisterID)src, 0); diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index bf4b85e82c91..865a7dbe50e0 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -1136,7 +1136,7 @@ WriteBarrierPost(JSRuntime *rt, ValueMap *map, const HashableValue &key) { #ifdef JSGC_GENERATIONAL typedef OrderedHashMap UnbarrieredMap; - rt->gcStoreBuffer.putGeneric(OrderedHashTableRef( + rt->gc.storeBuffer.putGeneric(OrderedHashTableRef( reinterpret_cast(map), key.get())); #endif } @@ -1146,7 +1146,7 @@ WriteBarrierPost(JSRuntime *rt, ValueSet *set, const HashableValue &key) { #ifdef JSGC_GENERATIONAL typedef OrderedHashSet UnbarrieredSet; - rt->gcStoreBuffer.putGeneric(OrderedHashTableRef( + rt->gc.storeBuffer.putGeneric(OrderedHashTableRef( reinterpret_cast(set), key.get())); #endif } diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 513248f4f30a..fdd06603112e 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -238,7 +238,7 @@ GC(JSContext *cx, unsigned argc, jsval *vp) } #ifndef JS_MORE_DETERMINISTIC - size_t preBytes = cx->runtime()->gcBytes; + size_t preBytes = cx->runtime()->gc.bytes; #endif if (compartment) @@ -250,7 +250,7 @@ GC(JSContext *cx, unsigned argc, jsval *vp) char buf[256] = { '\0' }; #ifndef JS_MORE_DETERMINISTIC JS_snprintf(buf, sizeof(buf), "before %lu, after %lu\n", - (unsigned long)preBytes, (unsigned long)cx->runtime()->gcBytes); + (unsigned long)preBytes, (unsigned long)cx->runtime()->gc.bytes); #endif JSString *str = JS_NewStringCopyZ(cx, buf); if (!str) @@ -265,7 +265,7 @@ MinorGC(JSContext *cx, unsigned argc, jsval *vp) CallArgs args = CallArgsFromVp(argc, vp); #ifdef JSGC_GENERATIONAL if (args.get(0) == BooleanValue(true)) - cx->runtime()->gcStoreBuffer.setAboutToOverflow(); + cx->runtime()->gc.storeBuffer.setAboutToOverflow(); MinorGC(cx, gcreason::API); #endif @@ -445,7 +445,7 @@ GCPreserveCode(JSContext *cx, unsigned argc, jsval *vp) return false; } - cx->runtime()->alwaysPreserveCode = true; + cx->runtime()->gc.alwaysPreserveCode = true; args.rval().setUndefined(); return true; @@ -513,7 +513,7 @@ SelectForGC(JSContext *cx, unsigned argc, Value *vp) JSRuntime *rt = cx->runtime(); for (unsigned i = 0; i < args.length(); i++) { if (args[i].isObject()) { - if (!rt->gcSelectedForMarking.append(&args[i].toObject())) + if (!rt->gc.selectedForMarking.append(&args[i].toObject())) return false; } } @@ -564,7 +564,7 @@ GCState(JSContext *cx, unsigned argc, jsval *vp) } const char *state; - gc::State globalState = cx->runtime()->gcIncrementalState; + gc::State globalState = cx->runtime()->gc.incrementalState; if (globalState == gc::NO_INCREMENTAL) state = "none"; else if (globalState == gc::MARK) @@ -1127,10 +1127,14 @@ ShellObjectMetadataCallback(JSContext *cx, JSObject **pmetadata) } int stackIndex = 0; + RootedId id(cx); + RootedValue callee(cx); for (NonBuiltinScriptFrameIter iter(cx); !iter.done(); ++iter) { if (iter.isFunctionFrame() && iter.compartment() == cx->compartment()) { - if (!JS_DefinePropertyById(cx, stack, INT_TO_JSID(stackIndex), ObjectValue(*iter.callee()), - JS_PropertyStub, JS_StrictPropertyStub, 0)) + id = INT_TO_JSID(stackIndex); + RootedObject callee(cx, iter.callee()); + if (!JS_DefinePropertyById(cx, stack, id, callee, 0, + JS_PropertyStub, JS_StrictPropertyStub)) { return false; } diff --git a/js/src/configure.in b/js/src/configure.in index 4071ec5d656d..59bf1a1747ea 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -2086,112 +2086,17 @@ dnl Check for .hidden assembler directive and visibility attribute. dnl Borrowed from glibc configure.in dnl =============================================================== if test "$GNU_CC"; then - AC_CACHE_CHECK(for visibility(hidden) attribute, - ac_cv_visibility_hidden, - [cat > conftest.c </dev/null 2>&1; then - if egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then - ac_cv_visibility_hidden=yes - fi - fi - rm -f conftest.[cs] - ]) - if test "$ac_cv_visibility_hidden" = "yes"; then - AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE) - - AC_CACHE_CHECK(for visibility(default) attribute, - ac_cv_visibility_default, - [cat > conftest.c </dev/null 2>&1; then - if ! egrep '\.(hidden|private_extern).*foo' conftest.s >/dev/null; then - ac_cv_visibility_default=yes - fi - fi - rm -f conftest.[cs] - ]) - if test "$ac_cv_visibility_default" = "yes"; then - AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE) - - AC_CACHE_CHECK(for visibility pragma support, - ac_cv_visibility_pragma, - [cat > conftest.c </dev/null 2>&1; then - if egrep '\.(hidden|private_extern).*foo_hidden' conftest.s >/dev/null; then - if ! egrep '\.(hidden|private_extern).*foo_default' conftest.s > /dev/null; then - ac_cv_visibility_pragma=yes - fi - fi - fi - rm -f conftest.[cs] - ]) - if test "$ac_cv_visibility_pragma" = "yes"; then - AC_CACHE_CHECK(For gcc visibility bug with class-level attributes (GCC bug 26905), - ac_cv_have_visibility_class_bug, - [cat > conftest.c < /dev/null 2>&1 ; then - ac_cv_have_visibility_class_bug=yes - else - if test `egrep -c '@PLT|\\$stub' conftest.S` = 0; then - ac_cv_have_visibility_class_bug=yes - fi - fi - rm -rf conftest.{c,S} - ]) - - AC_CACHE_CHECK(For x86_64 gcc visibility bug with builtins (GCC bug 20297), - ac_cv_have_visibility_builtin_bug, - [cat > conftest.c < -#pragma GCC visibility pop - -__attribute__ ((visibility ("default"))) void Func() { - char c[[100]]; - memset(c, 0, sizeof(c)); -} -EOF - ac_cv_have_visibility_builtin_bug=no - if ! ${CC-cc} ${CFLAGS} ${DSO_PIC_CFLAGS} ${DSO_LDOPTS} -O2 -S -o conftest.S conftest.c > /dev/null 2>&1 ; then - ac_cv_have_visibility_builtin_bug=yes - else - if test `grep -c "@PLT" conftest.S` = 0; then - ac_cv_visibility_builtin_bug=yes - fi - fi - rm -f conftest.{c,S} - ]) - if test "$ac_cv_have_visibility_builtin_bug" = "no" -a \ - "$ac_cv_have_visibility_class_bug" = "no"; then - VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h' - WRAP_SYSTEM_INCLUDES=1 - else - VISIBILITY_FLAGS='-fvisibility=hidden' - fi # have visibility pragma bug - fi # have visibility pragma - fi # have visibility(default) attribute - fi # have visibility(hidden) attribute + AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE) + AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE) + case "${OS_TARGET}" in + Darwin|Android) + VISIBILITY_FLAGS='-fvisibility=hidden' + ;; + *) + VISIBILITY_FLAGS='-I$(DIST)/system_wrappers -include $(topsrcdir)/config/gcc_hidden.h' + WRAP_SYSTEM_INCLUDES=1 + ;; + esac fi # GNU_CC # visibility hidden flag for Sun Studio on Solaris @@ -2199,6 +2104,15 @@ if test "$SOLARIS_SUNPRO_CC"; then VISIBILITY_FLAGS='-xldscope=hidden' fi # Sun Studio on Solaris +case "${OS_TARGET}" in +WINNT|Darwin|Android) + ;; +*) + STL_FLAGS='-I$(DIST)/stl_wrappers' + WRAP_STL_INCLUDES=1 + ;; +esac + AC_SUBST(WRAP_SYSTEM_INCLUDES) AC_SUBST(VISIBILITY_FLAGS) diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index aeff10e83bd8..c99085f178ac 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -4701,7 +4701,7 @@ AddFieldToArray(JSContext* cx, if (!JS_DefineUCProperty(cx, fieldObj, name->chars(), name->length(), - OBJECT_TO_JSVAL(typeObj), nullptr, nullptr, + typeObj, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) return false; @@ -4833,9 +4833,9 @@ StructType::DefineInternal(JSContext* cx, JSObject* typeObj_, JSObject* fieldsOb // Add the field to the StructType's 'prototype' property. if (!JS_DefineUCProperty(cx, prototype, - name->chars(), name->length(), JSVAL_VOID, - StructType::FieldGetter, StructType::FieldSetter, - JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT)) + name->chars(), name->length(), UndefinedHandleValue, + JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_PERMANENT, + StructType::FieldGetter, StructType::FieldSetter)) return false; size_t fieldSize = CType::GetSize(fieldType); diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h index 2ee1793f5038..69af2a4bd2f0 100644 --- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -124,11 +124,11 @@ class AutoStopVerifyingBarriers MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : runtime(rt) { - restartPreVerifier = !isShutdown && rt->gcVerifyPreData; - restartPostVerifier = !isShutdown && rt->gcVerifyPostData && JS::IsGenerationalGCEnabled(rt); - if (rt->gcVerifyPreData) + restartPreVerifier = !isShutdown && rt->gc.verifyPreData; + restartPostVerifier = !isShutdown && rt->gc.verifyPostData && JS::IsGenerationalGCEnabled(rt); + if (rt->gc.verifyPreData) EndVerifyPreBarriers(rt); - if (rt->gcVerifyPostData) + if (rt->gc.verifyPostData) EndVerifyPostBarriers(rt); MOZ_GUARD_OBJECT_NOTIFIER_INIT; } diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h new file mode 100644 index 000000000000..2c12d6dccfc1 --- /dev/null +++ b/js/src/gc/GCRuntime.h @@ -0,0 +1,390 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef gc_GCRuntime_h +#define gc_GCRuntime_h + +#include "jsgc.h" + +#include "gc/Heap.h" +#ifdef JSGC_GENERATIONAL +# include "gc/Nursery.h" +#endif +#include "gc/Statistics.h" +#ifdef JSGC_GENERATIONAL +# include "gc/StoreBuffer.h" +#endif +#include "gc/Tracer.h" + +namespace js { + +struct ScriptAndCounts +{ + /* This structure is stored and marked from the JSRuntime. */ + JSScript *script; + ScriptCounts scriptCounts; + + PCCounts &getPCCounts(jsbytecode *pc) const { + return scriptCounts.pcCountsVector[script->pcToOffset(pc)]; + } + + jit::IonScriptCounts *getIonCounts() const { + return scriptCounts.ionCounts; + } +}; + +typedef Vector ScriptAndCountsVector; + +namespace gc { + +typedef Vector ZoneVector; + +class MarkingValidator; + +struct ConservativeGCData +{ + /* + * The GC scans conservatively between ThreadData::nativeStackBase and + * nativeStackTop unless the latter is nullptr. + */ + uintptr_t *nativeStackTop; + + union { + jmp_buf jmpbuf; + uintptr_t words[JS_HOWMANY(sizeof(jmp_buf), sizeof(uintptr_t))]; + } registerSnapshot; + + ConservativeGCData() { + mozilla::PodZero(this); + } + + ~ConservativeGCData() { +#ifdef JS_THREADSAFE + /* + * The conservative GC scanner should be disabled when the thread leaves + * the last request. + */ + JS_ASSERT(!hasStackToScan()); +#endif + } + + MOZ_NEVER_INLINE void recordStackTop(); + +#ifdef JS_THREADSAFE + void updateForRequestEnd() { + nativeStackTop = nullptr; + } +#endif + + bool hasStackToScan() const { + return !!nativeStackTop; + } +}; + +class GCRuntime +{ + public: + GCRuntime(JSRuntime *rt); + + public: // Internal state, public for now + + /* Embedders can use this zone however they wish. */ + JS::Zone *systemZone; + + /* List of compartments and zones (protected by the GC lock). */ + js::gc::ZoneVector zones; + + js::gc::SystemPageAllocator pageAllocator; + + /* + * Set of all GC chunks with at least one allocated thing. The + * conservative GC uses it to quickly check if a possible GC thing points + * into an allocated chunk. + */ + js::GCChunkSet chunkSet; + + /* + * Doubly-linked lists of chunks from user and system compartments. The GC + * allocates its arenas from the corresponding list and when all arenas + * in the list head are taken, then the chunk is removed from the list. + * During the GC when all arenas in a chunk become free, that chunk is + * removed from the list and scheduled for release. + */ + js::gc::Chunk *systemAvailableChunkListHead; + js::gc::Chunk *userAvailableChunkListHead; + js::gc::ChunkPool chunkPool; + + js::RootedValueMap rootsHash; + + /* This is updated by both the main and GC helper threads. */ + mozilla::Atomic bytes; + + size_t maxBytes; + size_t maxMallocBytes; + + /* + * Number of the committed arenas in all GC chunks including empty chunks. + */ + mozilla::Atomic numArenasFreeCommitted; + js::GCMarker marker; + void *verifyPreData; + void *verifyPostData; + bool chunkAllocationSinceLastGC; + int64_t nextFullGCTime; + int64_t lastGCTime; + int64_t jitReleaseTime; + + JSGCMode mode; + + size_t allocationThreshold; + bool highFrequencyGC; + uint64_t highFrequencyTimeThreshold; + uint64_t highFrequencyLowLimitBytes; + uint64_t highFrequencyHighLimitBytes; + double highFrequencyHeapGrowthMax; + double highFrequencyHeapGrowthMin; + double lowFrequencyHeapGrowth; + bool dynamicHeapGrowth; + bool dynamicMarkSlice; + uint64_t decommitThreshold; + + /* During shutdown, the GC needs to clean up every possible object. */ + bool shouldCleanUpEverything; + + /* + * The gray bits can become invalid if UnmarkGray overflows the stack. A + * full GC will reset this bit, since it fills in all the gray bits. + */ + bool grayBitsValid; + + /* + * These flags must be kept separate so that a thread requesting a + * compartment GC doesn't cancel another thread's concurrent request for a + * full GC. + */ + volatile uintptr_t isNeeded; + + js::gcstats::Statistics stats; + + /* Incremented on every GC slice. */ + uint64_t number; + + /* The number at the time of the most recent GC's first slice. */ + uint64_t startNumber; + + /* Whether the currently running GC can finish in multiple slices. */ + bool isIncremental; + + /* Whether all compartments are being collected in first GC slice. */ + bool isFull; + + /* The reason that an interrupt-triggered GC should be called. */ + JS::gcreason::Reason triggerReason; + + /* + * If this is true, all marked objects must belong to a compartment being + * GCed. This is used to look for compartment bugs. + */ + bool strictCompartmentChecking; + +#ifdef DEBUG + /* + * If this is 0, all cross-compartment proxies must be registered in the + * wrapper map. This checking must be disabled temporarily while creating + * new wrappers. When non-zero, this records the recursion depth of wrapper + * creation. + */ + uintptr_t disableStrictProxyCheckingCount; +#else + uintptr_t unused1; +#endif + + /* + * The current incremental GC phase. This is also used internally in + * non-incremental GC. + */ + js::gc::State incrementalState; + + /* Indicates that the last incremental slice exhausted the mark stack. */ + bool lastMarkSlice; + + /* Whether any sweeping will take place in the separate GC helper thread. */ + bool sweepOnBackgroundThread; + + /* Whether any black->gray edges were found during marking. */ + bool foundBlackGrayEdges; + + /* List head of zones to be swept in the background. */ + JS::Zone *sweepingZones; + + /* Index of current zone group (for stats). */ + unsigned zoneGroupIndex; + + /* + * Incremental sweep state. + */ + JS::Zone *zoneGroups; + JS::Zone *currentZoneGroup; + int sweepPhase; + JS::Zone *sweepZone; + int sweepKindIndex; + bool abortSweepAfterCurrentGroup; + + /* + * List head of arenas allocated during the sweep phase. + */ + js::gc::ArenaHeader *arenasAllocatedDuringSweep; + +#ifdef DEBUG + js::gc::MarkingValidator *markingValidator; +#endif + + /* + * Indicates that a GC slice has taken place in the middle of an animation + * frame, rather than at the beginning. In this case, the next slice will be + * delayed so that we don't get back-to-back slices. + */ + volatile uintptr_t interFrameGC; + + /* Default budget for incremental GC slice. See SliceBudget in jsgc.h. */ + int64_t sliceBudget; + + /* + * We disable incremental GC if we encounter a js::Class with a trace hook + * that does not implement write barriers. + */ + bool incrementalEnabled; + + /* + * GGC can be enabled from the command line while testing. + */ + unsigned generationalDisabled; + + /* + * This is true if we are in the middle of a brain transplant (e.g., + * JS_TransplantObject) or some other operation that can manipulate + * dead zones. + */ + bool manipulatingDeadZones; + + /* + * This field is incremented each time we mark an object inside a + * zone with no incoming cross-compartment pointers. Typically if + * this happens it signals that an incremental GC is marking too much + * stuff. At various times we check this counter and, if it has changed, we + * run an immediate, non-incremental GC to clean up the dead + * zones. This should happen very rarely. + */ + unsigned objectsMarkedInDeadZones; + + bool poke; + + volatile js::HeapState heapState; + +#ifdef JSGC_GENERATIONAL + js::Nursery nursery; + js::gc::StoreBuffer storeBuffer; +#endif + + /* + * These options control the zealousness of the GC. The fundamental values + * are nextScheduled and gcDebugCompartmentGC. At every allocation, + * nextScheduled is decremented. When it reaches zero, we do either a + * full or a compartmental GC, based on debugCompartmentGC. + * + * At this point, if zeal_ is one of the types that trigger periodic + * collection, then nextScheduled is reset to the value of + * zealFrequency. Otherwise, no additional GCs take place. + * + * You can control these values in several ways: + * - Pass the -Z flag to the shell (see the usage info for details) + * - Call zeal() or schedulegc() from inside shell-executed JS code + * (see the help for details) + * + * If gzZeal_ == 1 then we perform GCs in select places (during MaybeGC and + * whenever a GC poke happens). This option is mainly useful to embedders. + * + * We use zeal_ == 4 to enable write barrier verification. See the comment + * in jsgc.cpp for more information about this. + * + * zeal_ values from 8 to 10 periodically run different types of + * incremental GC. + */ +#ifdef JS_GC_ZEAL + int zealMode; + int zealFrequency; + int nextScheduled; + bool deterministicOnly; + int incrementalLimit; + + js::Vector selectedForMarking; +#endif + + bool validate; + bool fullCompartmentChecks; + + JSGCCallback callback; + JS::GCSliceCallback sliceCallback; + JSFinalizeCallback finalizeCallback; + + void *callbackData; + + /* + * Malloc counter to measure memory pressure for GC scheduling. It runs + * from maxMallocBytes down to zero. + */ + mozilla::Atomic mallocBytes; + + /* + * Whether a GC has been triggered as a result of mallocBytes falling + * below zero. + */ + mozilla::Atomic mallocGCTriggered; + + /* + * The trace operations to trace embedding-specific GC roots. One is for + * tracing through black roots and the other is for tracing through gray + * roots. The black/gray distinction is only relevant to the cycle + * collector. + */ + typedef js::Vector ExtraTracerVector; + ExtraTracerVector blackRootTracers; + ExtraTracer grayRootTracer; + + /* + * The GC can only safely decommit memory when the page size of the + * running process matches the compiled arena size. + */ + size_t systemPageSize; + + /* The OS allocation granularity may not match the page size. */ + size_t systemAllocGranularity; + + /* Strong references on scripts held for PCCount profiling API. */ + js::ScriptAndCountsVector *scriptAndCountsVector; + + /* Always preserve JIT code during GCs, for testing. */ + bool alwaysPreserveCode; + +#ifdef DEBUG + size_t noGCOrAllocationCheck; +#endif + + /* Synchronize GC heap access between main thread and GCHelperThread. */ + PRLock *lock; + mozilla::DebugOnly lockOwner; + + friend class js::GCHelperThread; + + js::GCHelperThread helperThread; + + ConservativeGCData conservativeGC; +}; + +} /* namespace gc */ +} /* namespace js */ + +#endif diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index d6d2664fd669..109dac9d500b 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -821,15 +821,7 @@ struct Chunk static Chunk *allocate(JSRuntime *rt); - void decommitAllArenas(JSRuntime *rt) { - decommittedArenas.clear(true); - MarkPagesUnused(rt, &arenas[0], ArenasPerChunk * ArenaSize); - - info.freeArenasHead = nullptr; - info.lastDecommittedArenaOffset = 0; - info.numArenasFree = ArenasPerChunk; - info.numArenasFreeCommitted = 0; - } + void decommitAllArenas(JSRuntime *rt); /* Must be called with the GC lock taken. */ static inline void release(JSRuntime *rt, Chunk *chunk); diff --git a/js/src/gc/Iteration.cpp b/js/src/gc/Iteration.cpp index 3b1582d606b5..0c58dee6cffc 100644 --- a/js/src/gc/Iteration.cpp +++ b/js/src/gc/Iteration.cpp @@ -43,7 +43,7 @@ IterateCompartmentsArenasCells(JSRuntime *rt, Zone *zone, void *data, for (ArenaIter aiter(zone, AllocKind(thingKind)); !aiter.done(); aiter.next()) { ArenaHeader *aheader = aiter.get(); (*arenaCallback)(rt, data, aheader->getArena(), traceKind, thingSize); - for (CellIterUnderGC iter(aheader); !iter.done(); iter.next()) + for (ArenaCellIterUnderGC iter(aheader); !iter.done(); iter.next()) (*cellCallback)(rt, data, iter.getCell(), traceKind, thingSize); } } @@ -84,7 +84,7 @@ js::IterateChunks(JSRuntime *rt, void *data, IterateChunkCallback chunkCallback) { AutoPrepareForTracing prep(rt, SkipAtoms); - for (js::GCChunkSet::Range r = rt->gcChunkSet.all(); !r.empty(); r.popFront()) + for (js::GCChunkSet::Range r = rt->gc.chunkSet.all(); !r.empty(); r.popFront()) chunkCallback(rt, data, r.front()); } @@ -96,14 +96,14 @@ js::IterateScripts(JSRuntime *rt, JSCompartment *compartment, AutoPrepareForTracing prep(rt, SkipAtoms); if (compartment) { - for (CellIterUnderGC i(compartment->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIterUnderGC i(compartment->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->compartment() == compartment) scriptCallback(rt, data, script); } } else { for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) { - for (CellIterUnderGC i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) + for (ZoneCellIterUnderGC i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) scriptCallback(rt, data, i.get()); } } @@ -116,7 +116,7 @@ js::IterateGrayObjects(Zone *zone, GCThingCallback cellCallback, void *data) AutoPrepareForTracing prep(zone->runtimeFromMainThread(), SkipAtoms); for (size_t finalizeKind = 0; finalizeKind <= FINALIZE_OBJECT_LAST; finalizeKind++) { - for (CellIterUnderGC i(zone, AllocKind(finalizeKind)); !i.done(); i.next()) { + for (ZoneCellIterUnderGC i(zone, AllocKind(finalizeKind)); !i.done(); i.next()) { JSObject *obj = i.get(); if (obj->isMarked(GRAY)) cellCallback(data, obj); diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 106768a33d47..edf18ba97c2a 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -169,7 +169,7 @@ CheckMarkedThing(JSTracer *trc, T *thing) DebugOnly rt = trc->runtime(); - JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && rt->gcManipulatingDeadZones, + JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && rt->gc.manipulatingDeadZones, !thing->zone()->scheduledForDestruction); JS_ASSERT(CurrentThreadCanAccessRuntime(rt)); @@ -181,7 +181,7 @@ CheckMarkedThing(JSTracer *trc, T *thing) JS_ASSERT(MapTypeToTraceKind::kind == GetGCThingTraceKind(thing)); - JS_ASSERT_IF(rt->gcStrictCompartmentChecking, + JS_ASSERT_IF(rt->gc.strictCompartmentChecking, thing->zone()->isCollecting() || rt->isAtomsZone(thing->zone())); JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc) && AsGCMarker(trc)->getMarkColor() == GRAY, @@ -247,8 +247,8 @@ MarkInternal(JSTracer *trc, T **thingp) #define JS_ROOT_MARKING_ASSERT(trc) \ JS_ASSERT_IF(IS_GC_MARKING_TRACER(trc), \ - trc->runtime()->gcIncrementalState == NO_INCREMENTAL || \ - trc->runtime()->gcIncrementalState == MARK_ROOTS); + trc->runtime()->gc.incrementalState == NO_INCREMENTAL || \ + trc->runtime()->gc.incrementalState == MARK_ROOTS); namespace js { namespace gc { @@ -339,7 +339,7 @@ IsMarked(T **thingp) JS_ASSERT(thingp); JS_ASSERT(*thingp); #ifdef JSGC_GENERATIONAL - Nursery &nursery = (*thingp)->runtimeFromMainThread()->gcNursery; + Nursery &nursery = (*thingp)->runtimeFromMainThread()->gc.nursery; if (nursery.isInside(*thingp)) return nursery.getForwardedPointer(thingp); #endif @@ -364,7 +364,7 @@ IsAboutToBeFinalized(T **thingp) return false; #ifdef JSGC_GENERATIONAL - Nursery &nursery = rt->gcNursery; + Nursery &nursery = rt->gc.nursery; JS_ASSERT_IF(!rt->isHeapMinorCollecting(), !nursery.isInside(thing)); if (rt->isHeapMinorCollecting()) { if (nursery.isInside(thing)) @@ -394,8 +394,8 @@ UpdateIfRelocated(JSRuntime *rt, T **thingp) { JS_ASSERT(thingp); #ifdef JSGC_GENERATIONAL - if (*thingp && rt->isHeapMinorCollecting() && rt->gcNursery.isInside(*thingp)) - rt->gcNursery.getForwardedPointer(thingp); + if (*thingp && rt->isHeapMinorCollecting() && rt->gc.nursery.isInside(*thingp)) + rt->gc.nursery.getForwardedPointer(thingp); #endif return *thingp; } @@ -784,7 +784,7 @@ ShouldMarkCrossCompartment(JSTracer *trc, JSObject *src, Cell *cell) */ if (cell->isMarked(GRAY)) { JS_ASSERT(!zone->isCollecting()); - trc->runtime()->gcFoundBlackGrayEdges = true; + trc->runtime()->gc.foundBlackGrayEdges = true; } return zone->isGCMarking(); } else { @@ -1288,7 +1288,7 @@ template static void PushArenaTyped(GCMarker *gcmarker, ArenaHeader *aheader) { - for (CellIterUnderGC i(aheader); !i.done(); i.next()) + for (ArenaCellIterUnderGC i(aheader); !i.done(); i.next()) PushMarkStack(gcmarker, i.get()); } @@ -1540,7 +1540,7 @@ GCMarker::processMarkStackTop(SliceBudget &budget) // if the gloal has no custom trace hook of it's own, or has been moved to a different // compartment, and so can't have one. JS_ASSERT_IF(runtime()->gcMode() == JSGC_MODE_INCREMENTAL && - runtime()->gcIncrementalEnabled && + runtime()->gc.incrementalEnabled && !(clasp->trace == JS_GlobalObjectTraceHook && (!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())), @@ -1586,10 +1586,10 @@ GCMarker::drainMarkStack(SliceBudget &budget) struct AutoCheckCompartment { JSRuntime *runtime; AutoCheckCompartment(JSRuntime *rt) : runtime(rt) { - JS_ASSERT(!rt->gcStrictCompartmentChecking); - runtime->gcStrictCompartmentChecking = true; + JS_ASSERT(!rt->gc.strictCompartmentChecking); + runtime->gc.strictCompartmentChecking = true; } - ~AutoCheckCompartment() { runtime->gcStrictCompartmentChecking = false; } + ~AutoCheckCompartment() { runtime->gc.strictCompartmentChecking = false; } } acc(rt); #endif @@ -1739,7 +1739,7 @@ UnmarkGrayChildren(JSTracer *trc, void **thingp, JSGCTraceKind kind) * If we run out of stack, we take a more drastic measure: require that * we GC again before the next CC. */ - trc->runtime()->gcGrayBitsValid = false; + trc->runtime()->gc.grayBitsValid = false; return; } diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index d5137c40cc30..f55e1f313744 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -358,7 +358,7 @@ IsAboutToBeFinalized(const js::jit::VMFunction **vmfunc) * Preserves entries in the WeakCache * iff the JitCode has been marked. */ - return true; + return false; } inline bool diff --git a/js/src/gc/Memory.cpp b/js/src/gc/Memory.cpp index cc772d73f383..d3f6d01a5bff 100644 --- a/js/src/gc/Memory.cpp +++ b/js/src/gc/Memory.cpp @@ -12,35 +12,34 @@ using namespace js; using namespace js::gc; -static bool -DecommitEnabled(JSRuntime *rt) +bool +SystemPageAllocator::decommitEnabled() { - return rt->gcSystemPageSize == ArenaSize; + return pageSize == ArenaSize; } #if defined(XP_WIN) #include "jswin.h" #include -void -gc::InitMemorySubsystem(JSRuntime *rt) +SystemPageAllocator::SystemPageAllocator() { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); - rt->gcSystemPageSize = sysinfo.dwPageSize; - rt->gcSystemAllocGranularity = sysinfo.dwAllocationGranularity; + pageSize = sysinfo.dwPageSize; + allocGranularity = sysinfo.dwAllocationGranularity; } void * -gc::MapAlignedPages(JSRuntime *rt, size_t size, size_t alignment) +SystemPageAllocator::mapAlignedPages(size_t size, size_t alignment) { JS_ASSERT(size >= alignment); JS_ASSERT(size % alignment == 0); - JS_ASSERT(size % rt->gcSystemPageSize == 0); - JS_ASSERT(alignment % rt->gcSystemAllocGranularity == 0); + JS_ASSERT(size % pageSize == 0); + JS_ASSERT(alignment % allocGranularity == 0); /* Special case: If we want allocation alignment, no further work is needed. */ - if (alignment == rt->gcSystemAllocGranularity) { + if (alignment == allocGranularity) { return VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); } @@ -60,12 +59,12 @@ gc::MapAlignedPages(JSRuntime *rt, size_t size, size_t alignment) * Since we're going to unmap the whole thing anyway, the first * mapping doesn't have to commit pages. */ - size_t reserveSize = size + alignment - rt->gcSystemPageSize; + size_t reserveSize = size + alignment - pageSize; p = VirtualAlloc(nullptr, reserveSize, MEM_RESERVE, PAGE_READWRITE); if (!p) return nullptr; void *chunkStart = (void *)AlignBytes(uintptr_t(p), alignment); - UnmapPages(rt, p, reserveSize); + unmapPages(p, reserveSize); p = VirtualAlloc(chunkStart, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); /* Failure here indicates a race with another thread, so try again. */ @@ -76,31 +75,31 @@ gc::MapAlignedPages(JSRuntime *rt, size_t size, size_t alignment) } void -gc::UnmapPages(JSRuntime *rt, void *p, size_t size) +SystemPageAllocator::unmapPages(void *p, size_t size) { JS_ALWAYS_TRUE(VirtualFree(p, 0, MEM_RELEASE)); } bool -gc::MarkPagesUnused(JSRuntime *rt, void *p, size_t size) +SystemPageAllocator::markPagesUnused(void *p, size_t size) { - if (!DecommitEnabled(rt)) + if (!decommitEnabled()) return true; - JS_ASSERT(uintptr_t(p) % rt->gcSystemPageSize == 0); + JS_ASSERT(uintptr_t(p) % pageSize == 0); LPVOID p2 = VirtualAlloc(p, size, MEM_RESET, PAGE_READWRITE); return p2 == p; } bool -gc::MarkPagesInUse(JSRuntime *rt, void *p, size_t size) +SystemPageAllocator::markPagesInUse(void *p, size_t size) { - JS_ASSERT(uintptr_t(p) % rt->gcSystemPageSize == 0); + JS_ASSERT(uintptr_t(p) % pageSize == 0); return true; } size_t -gc::GetPageFaultCount() +SystemPageAllocator::GetPageFaultCount() { PROCESS_MEMORY_COUNTERS pmc; if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) @@ -109,7 +108,7 @@ gc::GetPageFaultCount() } void * -gc::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment) +SystemPageAllocator::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment) { // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform. return nullptr; @@ -117,7 +116,7 @@ gc::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment // Deallocate mapped memory for object. void -gc::DeallocateMappedContent(void *p, size_t length) +SystemPageAllocator::DeallocateMappedContent(void *p, size_t length) { // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform. } @@ -131,19 +130,18 @@ gc::DeallocateMappedContent(void *p, size_t length) # define MAP_NOSYNC 0 #endif -void -gc::InitMemorySubsystem(JSRuntime *rt) +SystemPageAllocator::SystemPageAllocator() { - rt->gcSystemPageSize = rt->gcSystemAllocGranularity = size_t(sysconf(_SC_PAGESIZE)); + pageSize = allocGranularity = size_t(sysconf(_SC_PAGESIZE)); } void * -gc::MapAlignedPages(JSRuntime *rt, size_t size, size_t alignment) +SystemPageAllocator::mapAlignedPages(size_t size, size_t alignment) { JS_ASSERT(size >= alignment); JS_ASSERT(size % alignment == 0); - JS_ASSERT(size % rt->gcSystemPageSize == 0); - JS_ASSERT(alignment % rt->gcSystemAllocGranularity == 0); + JS_ASSERT(size % pageSize == 0); + JS_ASSERT(alignment % allocGranularity == 0); int prot = PROT_READ | PROT_WRITE; int flags = MAP_PRIVATE | MAP_ANON | MAP_ALIGN | MAP_NOSYNC; @@ -155,33 +153,33 @@ gc::MapAlignedPages(JSRuntime *rt, size_t size, size_t alignment) } void -gc::UnmapPages(JSRuntime *rt, void *p, size_t size) +SystemPageAllocator::unmapPages(void *p, size_t size) { JS_ALWAYS_TRUE(0 == munmap((caddr_t)p, size)); } bool -gc::MarkPagesUnused(JSRuntime *rt, void *p, size_t size) +SystemPageAllocator::markPagesUnused(void *p, size_t size) { - JS_ASSERT(uintptr_t(p) % rt->gcSystemPageSize == 0); + JS_ASSERT(uintptr_t(p) % pageSize == 0); return true; } bool -gc::MarkPagesInUse(JSRuntime *rt, void *p, size_t size) +SystemPageAllocator::markPagesInUse(void *p, size_t size) { - JS_ASSERT(uintptr_t(p) % rt->gcSystemPageSize == 0); + JS_ASSERT(uintptr_t(p) % pageSize == 0); return true; } size_t -gc::GetPageFaultCount() +SystemPageAllocator::GetPageFaultCount() { return 0; } void * -gc::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment) +SystemPageAllocator::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment) { // Not implemented. return nullptr; @@ -189,7 +187,7 @@ gc::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment // Deallocate mapped memory for object. void -gc::DeallocateMappedContent(void *p, size_t length) +SystemPageAllocator::DeallocateMappedContent(void *p, size_t length) { // Not implemented. } @@ -203,10 +201,9 @@ gc::DeallocateMappedContent(void *p, size_t length) #include #include -void -gc::InitMemorySubsystem(JSRuntime *rt) +SystemPageAllocator::SystemPageAllocator() { - rt->gcSystemPageSize = rt->gcSystemAllocGranularity = size_t(sysconf(_SC_PAGESIZE)); + pageSize = allocGranularity = size_t(sysconf(_SC_PAGESIZE)); } static inline void * @@ -244,18 +241,18 @@ MapMemory(size_t length, int prot, int flags, int fd, off_t offset) } void * -gc::MapAlignedPages(JSRuntime *rt, size_t size, size_t alignment) +SystemPageAllocator::mapAlignedPages(size_t size, size_t alignment) { JS_ASSERT(size >= alignment); JS_ASSERT(size % alignment == 0); - JS_ASSERT(size % rt->gcSystemPageSize == 0); - JS_ASSERT(alignment % rt->gcSystemAllocGranularity == 0); + JS_ASSERT(size % pageSize == 0); + JS_ASSERT(alignment % allocGranularity == 0); int prot = PROT_READ | PROT_WRITE; int flags = MAP_PRIVATE | MAP_ANON; /* Special case: If we want page alignment, no further work is needed. */ - if (alignment == rt->gcSystemAllocGranularity) { + if (alignment == allocGranularity) { void *region = MapMemory(size, prot, flags, -1, 0); if (region == MAP_FAILED) return nullptr; @@ -284,31 +281,31 @@ gc::MapAlignedPages(JSRuntime *rt, size_t size, size_t alignment) } void -gc::UnmapPages(JSRuntime *rt, void *p, size_t size) +SystemPageAllocator::unmapPages(void *p, size_t size) { JS_ALWAYS_TRUE(0 == munmap(p, size)); } bool -gc::MarkPagesUnused(JSRuntime *rt, void *p, size_t size) +SystemPageAllocator::markPagesUnused(void *p, size_t size) { - if (!DecommitEnabled(rt)) + if (!decommitEnabled()) return false; - JS_ASSERT(uintptr_t(p) % rt->gcSystemPageSize == 0); + JS_ASSERT(uintptr_t(p) % pageSize == 0); int result = madvise(p, size, MADV_DONTNEED); return result != -1; } bool -gc::MarkPagesInUse(JSRuntime *rt, void *p, size_t size) +SystemPageAllocator::markPagesInUse(void *p, size_t size) { - JS_ASSERT(uintptr_t(p) % rt->gcSystemPageSize == 0); + JS_ASSERT(uintptr_t(p) % pageSize == 0); return true; } size_t -gc::GetPageFaultCount() +SystemPageAllocator::GetPageFaultCount() { struct rusage usage; int err = getrusage(RUSAGE_SELF, &usage); @@ -318,7 +315,7 @@ gc::GetPageFaultCount() } void * -gc::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment) +SystemPageAllocator::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment) { #define NEED_PAGE_ALIGNED 0 size_t pa_start; // Page aligned starting @@ -367,7 +364,7 @@ gc::AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment } void -gc::DeallocateMappedContent(void *p, size_t length) +SystemPageAllocator::DeallocateMappedContent(void *p, size_t length) { void *pa_start; // Page aligned starting size_t page_size = sysconf(_SC_PAGESIZE); // Page size diff --git a/js/src/gc/Memory.h b/js/src/gc/Memory.h index dbbbcb91288c..a77e09f4b302 100644 --- a/js/src/gc/Memory.h +++ b/js/src/gc/Memory.h @@ -14,41 +14,49 @@ struct JSRuntime; namespace js { namespace gc { -// Sanity check that our compiled configuration matches the currently running -// instance and initialize any runtime data needed for allocation. -void -InitMemorySubsystem(JSRuntime *rt); +class SystemPageAllocator +{ + public: + // Sanity check that our compiled configuration matches the currently + // running instance and initialize any runtime data needed for allocation. + SystemPageAllocator(); -// Allocate or deallocate pages from the system with the given alignment. -void * -MapAlignedPages(JSRuntime *rt, size_t size, size_t alignment); + size_t systemPageSize() { return pageSize; } + size_t systemAllocGranularity() { return allocGranularity; } -void -UnmapPages(JSRuntime *rt, void *p, size_t size); + // Allocate or deallocate pages from the system with the given alignment. + void *mapAlignedPages(size_t size, size_t alignment); + void unmapPages(void *p, size_t size); -// Tell the OS that the given pages are not in use, so they should not -// be written to a paging file. This may be a no-op on some platforms. -bool -MarkPagesUnused(JSRuntime *rt, void *p, size_t size); + // Tell the OS that the given pages are not in use, so they should not be + // written to a paging file. This may be a no-op on some platforms. + bool markPagesUnused(void *p, size_t size); -// Undo |MarkPagesUnused|: tell the OS that the given pages are of interest -// and should be paged in and out normally. This may be a no-op on some -// platforms. -bool -MarkPagesInUse(JSRuntime *rt, void *p, size_t size); + // Undo |MarkPagesUnused|: tell the OS that the given pages are of interest + // and should be paged in and out normally. This may be a no-op on some + // platforms. + bool markPagesInUse(void *p, size_t size); -// Returns #(hard faults) + #(soft faults) -size_t -GetPageFaultCount(); + // Returns #(hard faults) + #(soft faults) + static size_t GetPageFaultCount(); -// Allocate memory mapped content. -// The offset must be aligned according to alignment requirement. -void * -AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment); + // Allocate memory mapped content. + // The offset must be aligned according to alignment requirement. + static void *AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment); -// Deallocate memory mapped content. -void -DeallocateMappedContent(void *p, size_t length); + // Deallocate memory mapped content. + static void DeallocateMappedContent(void *p, size_t length); + + private: + bool decommitEnabled(); + + // The GC can only safely decommit memory when the page size of the + // running process matches the compiled arena size. + size_t pageSize; + + // The OS allocation granularity may not match the page size. + size_t allocGranularity; +}; } // namespace gc } // namespace js diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index 3eeb0ce2320f..458a6ed9c0ee 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -53,7 +53,7 @@ js::Nursery::init() if (!hugeSlots.init()) return false; - void *heap = MapAlignedPages(runtime(), NurserySize, Alignment); + void *heap = runtime()->gc.pageAllocator.mapAlignedPages(NurserySize, Alignment); if (!heap) return false; @@ -79,7 +79,23 @@ js::Nursery::init() js::Nursery::~Nursery() { if (start()) - UnmapPages(runtime(), (void *)start(), NurserySize); + runtime()->gc.pageAllocator.unmapPages((void *)start(), NurserySize); +} + +void +js::Nursery::updateDecommittedRegion() +{ +#ifndef JS_GC_ZEAL + if (numActiveChunks_ < NumNurseryChunks) { + // Bug 994054: madvise on MacOS is too slow to make this + // optimization worthwhile. +# ifndef XP_MACOSX + uintptr_t decommitStart = chunk(numActiveChunks_).start(); + JS_ASSERT(decommitStart == AlignBytes(decommitStart, 1 << 20)); + runtime()->gc.pageAllocator.markPagesUnused((void *)decommitStart, heapEnd() - decommitStart); +# endif + } +#endif } void @@ -92,7 +108,7 @@ js::Nursery::enable() setCurrentChunk(0); currentStart_ = position(); #ifdef JS_GC_ZEAL - if (runtime()->gcZeal_ == ZealGenerationalGCValue) + if (runtime()->gc.zealMode == ZealGenerationalGCValue) enterZealMode(); #endif } @@ -114,7 +130,7 @@ js::Nursery::isEmpty() const JS_ASSERT(runtime_); if (!isEnabled()) return true; - JS_ASSERT_IF(runtime_->gcZeal_ != ZealGenerationalGCValue, currentStart_ == start()); + JS_ASSERT_IF(runtime_->gc.zealMode != ZealGenerationalGCValue, currentStart_ == start()); return position() == currentStart_; } @@ -308,7 +324,7 @@ class MinorCollectionTracer : public JSTracer savedRuntimeNeedBarrier(rt->needsBarrier()), disableStrictProxyChecking(rt) { - rt->gcNumber++; + rt->gc.number++; /* * We disable the runtime needsBarrier() check so that pre-barriers do @@ -325,7 +341,7 @@ class MinorCollectionTracer : public JSTracer * sweep their dead views. Incremental collection also use these lists, * so we may need to save and restore their contents here. */ - if (rt->gcIncrementalState != NO_INCREMENTAL) { + if (rt->gc.incrementalState != NO_INCREMENTAL) { for (GCCompartmentsIter c(rt); !c.done(); c.next()) { if (!ArrayBufferObject::saveArrayBufferList(c, liveArrayBuffers)) CrashAtUnhandlableOOM("OOM while saving live array buffers"); @@ -336,7 +352,7 @@ class MinorCollectionTracer : public JSTracer ~MinorCollectionTracer() { runtime()->setNeedsBarrier(savedRuntimeNeedBarrier); - if (runtime()->gcIncrementalState != NO_INCREMENTAL) + if (runtime()->gc.incrementalState != NO_INCREMENTAL) ArrayBufferObject::restoreArrayBufferLists(liveArrayBuffers); } }; @@ -724,7 +740,7 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason, TypeObjectList if (isEmpty()) return; - rt->gcStats.count(gcstats::STAT_MINOR_GC); + rt->gc.stats.count(gcstats::STAT_MINOR_GC); TIME_START(total); @@ -734,7 +750,7 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason, TypeObjectList MinorCollectionTracer trc(rt, this); // Mark the store buffer. This must happen first. - StoreBuffer &sb = rt->gcStoreBuffer; + StoreBuffer &sb = rt->gc.storeBuffer; TIME_START(markValues); sb.markValues(&trc); TIME_END(markValues); @@ -836,13 +852,13 @@ js::Nursery::collect(JSRuntime *rt, JS::gcreason::Reason reason, TypeObjectList TIME_END(sweep); TIME_START(clearStoreBuffer); - rt->gcStoreBuffer.clear(); + rt->gc.storeBuffer.clear(); TIME_END(clearStoreBuffer); // We ignore gcMaxBytes when allocating for minor collection. However, if we // overflowed, we disable the nursery. The next time we allocate, we'll fail // because gcBytes >= gcMaxBytes. - if (rt->gcBytes >= rt->gcMaxBytes) + if (rt->gc.bytes >= rt->gc.maxBytes) disable(); TIME_END(total); @@ -906,7 +922,7 @@ js::Nursery::sweep(JSRuntime *rt) for (int i = 0; i < NumNurseryChunks; ++i) initChunk(i); - if (rt->gcZeal_ == ZealGenerationalGCValue) { + if (rt->gc.zealMode == ZealGenerationalGCValue) { MOZ_ASSERT(numActiveChunks_ == NumNurseryChunks); /* Only reset the alloc point when we are close to the end. */ @@ -931,7 +947,8 @@ void js::Nursery::growAllocableSpace() { #ifdef JS_GC_ZEAL - MOZ_ASSERT_IF(runtime()->gcZeal_ == ZealGenerationalGCValue, numActiveChunks_ == NumNurseryChunks); + MOZ_ASSERT_IF(runtime()->gc.zealMode == ZealGenerationalGCValue, + numActiveChunks_ == NumNurseryChunks); #endif numActiveChunks_ = Min(numActiveChunks_ * 2, NumNurseryChunks); } @@ -940,7 +957,7 @@ void js::Nursery::shrinkAllocableSpace() { #ifdef JS_GC_ZEAL - if (runtime()->gcZeal_ == ZealGenerationalGCValue) + if (runtime()->gc.zealMode == ZealGenerationalGCValue) return; #endif numActiveChunks_ = Max(numActiveChunks_ - 1, 1); diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 0631e867f738..f1c760a91cd5 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -216,19 +216,7 @@ class Nursery initChunk(chunkno); } - void updateDecommittedRegion() { -#ifndef JS_GC_ZEAL - if (numActiveChunks_ < NumNurseryChunks) { - // Bug 994054: madvise on MacOS is too slow to make this - // optimization worthwhile. -# ifndef XP_MACOSX - uintptr_t decommitStart = chunk(numActiveChunks_).start(); - JS_ASSERT(decommitStart == AlignBytes(decommitStart, 1 << 20)); - gc::MarkPagesUnused(runtime(), (void *)decommitStart, heapEnd() - decommitStart); -# endif - } -#endif - } + void updateDecommittedRegion(); MOZ_ALWAYS_INLINE uintptr_t allocationEnd() const { JS_ASSERT(numActiveChunks_ > 0); diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 155ebafa0bb8..fe90c97a4eca 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -143,7 +143,7 @@ IsAddressableGCThing(JSRuntime *rt, uintptr_t w, Chunk *chunk = Chunk::fromAddress(addr); - if (!rt->gcChunkSet.has(chunk)) + if (!rt->gc.chunkSet.has(chunk)) return CGCT_NOTCHUNK; /* @@ -223,7 +223,7 @@ MarkIfGCThingWord(JSTracer *trc, uintptr_t w) JS_ASSERT(tmp == thing); #ifdef DEBUG - if (trc->runtime()->gcIncrementalState == MARK_ROOTS) + if (trc->runtime()->gc.incrementalState == MARK_ROOTS) trc->runtime()->mainThread.gcSavedRoots.append( PerThreadData::SavedGCRoot(thing, traceKind)); #endif @@ -300,11 +300,11 @@ MarkConservativeStackRoots(JSTracer *trc, bool useSavedRoots) return; } - if (rt->gcIncrementalState == MARK_ROOTS) + if (rt->gc.incrementalState == MARK_ROOTS) rt->mainThread.gcSavedRoots.clearAndFree(); #endif - ConservativeGCData *cgcd = &rt->conservativeGC; + ConservativeGCData *cgcd = &rt->gc.conservativeGC; if (!cgcd->hasStackToScan()) { #ifdef JS_THREADSAFE JS_ASSERT(!rt->requestDepth); @@ -691,7 +691,7 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots) rt->markSelfHostingGlobal(trc); } - for (RootRange r = rt->gcRootsHash.all(); !r.empty(); r.popFront()) { + for (RootRange r = rt->gc.rootsHash.all(); !r.empty(); r.popFront()) { const RootEntry &entry = r.front(); const char *name = entry.value().name ? entry.value().name : "root"; JSGCRootType type = entry.value().type; @@ -712,8 +712,8 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots) MarkPersistentRootedChains(trc); - if (rt->scriptAndCountsVector) { - ScriptAndCountsVector &vec = *rt->scriptAndCountsVector; + if (rt->gc.scriptAndCountsVector) { + ScriptAndCountsVector &vec = *rt->gc.scriptAndCountsVector; for (size_t i = 0; i < vec.length(); i++) MarkScriptRoot(trc, &vec[i].script, "scriptAndCountsVector"); } @@ -737,7 +737,7 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots) /* Do not discard scripts with counts while profiling. */ if (rt->profilingScripts && !rt->isHeapMinorCollecting()) { - for (CellIterUnderGC i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIterUnderGC i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->hasScriptCounts()) { MarkScriptRoot(trc, &script, "profilingScripts"); @@ -788,15 +788,15 @@ js::gc::MarkRuntime(JSTracer *trc, bool useSavedRoots) * the nursery should be in the store buffer, and we want to avoid the * time taken to trace all these roots. */ - for (size_t i = 0; i < rt->gcBlackRootTracers.length(); i++) { - const JSRuntime::ExtraTracer &e = rt->gcBlackRootTracers[i]; + for (size_t i = 0; i < rt->gc.blackRootTracers.length(); i++) { + const ExtraTracer &e = rt->gc.blackRootTracers[i]; (*e.op)(trc, e.data); } /* During GC, we don't mark gray roots at this stage. */ - if (JSTraceDataOp op = rt->gcGrayRootTracer.op) { + if (JSTraceDataOp op = rt->gc.grayRootTracer.op) { if (!IS_GC_MARKING_TRACER(trc)) - (*op)(trc, rt->gcGrayRootTracer.data); + (*op)(trc, rt->gc.grayRootTracer.data); } } } @@ -806,7 +806,7 @@ js::gc::BufferGrayRoots(GCMarker *gcmarker) { JSRuntime *rt = gcmarker->runtime(); gcmarker->startBufferingGrayRoots(); - if (JSTraceDataOp op = rt->gcGrayRootTracer.op) - (*op)(gcmarker, rt->gcGrayRootTracer.data); + if (JSTraceDataOp op = rt->gc.grayRootTracer.op) + (*op)(gcmarker, rt->gc.grayRootTracer.data); gcmarker->endBufferingGrayRoots(); } diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 12e5b42836af..23bc64cc2dc5 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -21,6 +21,7 @@ #include "vm/Runtime.h" using namespace js; +using namespace js::gc; using namespace js::gcstats; using mozilla::PodArrayZero; @@ -521,7 +522,7 @@ Statistics::beginGC() sccTimes.clearAndFree(); nonincrementalReason = nullptr; - preBytes = runtime->gcBytes; + preBytes = runtime->gc.bytes; } void @@ -547,7 +548,7 @@ Statistics::endGC() (*cb)(JS_TELEMETRY_GC_MARK_ROOTS_MS, t(phaseTimes[PHASE_MARK_ROOTS])); (*cb)(JS_TELEMETRY_GC_MARK_GRAY_MS, t(phaseTimes[PHASE_SWEEP_MARK_GRAY])); (*cb)(JS_TELEMETRY_GC_NON_INCREMENTAL, !!nonincrementalReason); - (*cb)(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gcIncrementalEnabled); + (*cb)(JS_TELEMETRY_GC_INCREMENTAL_DISABLED, !runtime->gc.incrementalEnabled); (*cb)(JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, t(sccTotal)); (*cb)(JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, t(sccLongest)); @@ -567,11 +568,11 @@ Statistics::beginSlice(int collectedCount, int zoneCount, int compartmentCount, this->zoneCount = zoneCount; this->compartmentCount = compartmentCount; - bool first = runtime->gcIncrementalState == gc::NO_INCREMENTAL; + bool first = runtime->gc.incrementalState == gc::NO_INCREMENTAL; if (first) beginGC(); - SliceData data(reason, PRMJ_Now(), gc::GetPageFaultCount()); + SliceData data(reason, PRMJ_Now(), SystemPageAllocator::GetPageFaultCount()); (void) slices.append(data); /* Ignore any OOMs here. */ if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) @@ -580,7 +581,7 @@ Statistics::beginSlice(int collectedCount, int zoneCount, int compartmentCount, // Slice callbacks should only fire for the outermost level if (++gcDepth == 1) { bool wasFullGC = collectedCount == zoneCount; - if (JS::GCSliceCallback cb = runtime->gcSliceCallback) + if (JS::GCSliceCallback cb = runtime->gc.sliceCallback) (*cb)(runtime, first ? JS::GC_CYCLE_BEGIN : JS::GC_SLICE_BEGIN, JS::GCDescription(!wasFullGC)); } @@ -590,21 +591,21 @@ void Statistics::endSlice() { slices.back().end = PRMJ_Now(); - slices.back().endFaults = gc::GetPageFaultCount(); + slices.back().endFaults = SystemPageAllocator::GetPageFaultCount(); if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) { (*cb)(JS_TELEMETRY_GC_SLICE_MS, t(slices.back().end - slices.back().start)); (*cb)(JS_TELEMETRY_GC_RESET, !!slices.back().resetReason); } - bool last = runtime->gcIncrementalState == gc::NO_INCREMENTAL; + bool last = runtime->gc.incrementalState == gc::NO_INCREMENTAL; if (last) endGC(); // Slice callbacks should only fire for the outermost level if (--gcDepth == 0) { bool wasFullGC = collectedCount == zoneCount; - if (JS::GCSliceCallback cb = runtime->gcSliceCallback) + if (JS::GCSliceCallback cb = runtime->gc.sliceCallback) (*cb)(runtime, last ? JS::GC_CYCLE_END : JS::GC_SLICE_END, JS::GCDescription(!wasFullGC)); } diff --git a/js/src/gc/StoreBuffer.cpp b/js/src/gc/StoreBuffer.cpp index b3a8f996de4e..328a5de07fbe 100644 --- a/js/src/gc/StoreBuffer.cpp +++ b/js/src/gc/StoreBuffer.cpp @@ -26,7 +26,7 @@ StoreBuffer::SlotsEdge::mark(JSTracer *trc) { JSObject *obj = object(); - if (trc->runtime()->gcNursery.isInside(obj)) + if (trc->runtime()->gc.nursery.isInside(obj)) return; if (!obj->isNative()) { @@ -337,7 +337,7 @@ JS::HeapCellPostBarrier(js::gc::Cell **cellp) { JS_ASSERT(*cellp); JSRuntime *runtime = (*cellp)->runtimeFromMainThread(); - runtime->gcStoreBuffer.putRelocatableCell(cellp); + runtime->gc.storeBuffer.putRelocatableCell(cellp); } JS_PUBLIC_API(void) @@ -346,7 +346,7 @@ JS::HeapCellRelocate(js::gc::Cell **cellp) /* Called with old contents of *pp before overwriting. */ JS_ASSERT(*cellp); JSRuntime *runtime = (*cellp)->runtimeFromMainThread(); - runtime->gcStoreBuffer.removeRelocatableCell(cellp); + runtime->gc.storeBuffer.removeRelocatableCell(cellp); } JS_PUBLIC_API(void) @@ -356,7 +356,7 @@ JS::HeapValuePostBarrier(JS::Value *valuep) if (valuep->isString() && StringIsPermanentAtom(valuep->toString())) return; JSRuntime *runtime = static_cast(valuep->toGCThing())->runtimeFromMainThread(); - runtime->gcStoreBuffer.putRelocatableValue(valuep); + runtime->gc.storeBuffer.putRelocatableValue(valuep); } JS_PUBLIC_API(void) @@ -367,7 +367,7 @@ JS::HeapValueRelocate(JS::Value *valuep) if (valuep->isString() && StringIsPermanentAtom(valuep->toString())) return; JSRuntime *runtime = static_cast(valuep->toGCThing())->runtimeFromMainThread(); - runtime->gcStoreBuffer.removeRelocatableValue(valuep); + runtime->gc.storeBuffer.removeRelocatableValue(valuep); } template class StoreBuffer::MonoTypeBuffer; diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index edabb860431e..18692ba175a3 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -508,7 +508,7 @@ GCMarker::markDelayedChildren(ArenaHeader *aheader) bool always = aheader->allocatedDuringIncremental; aheader->markOverflow = 0; - for (CellIterUnderGC i(aheader); !i.done(); i.next()) { + for (ArenaCellIterUnderGC i(aheader); !i.done(); i.next()) { Cell *t = i.getCell(); if (always || t->isMarked()) { t->markIfUnmarked(); @@ -531,8 +531,8 @@ bool GCMarker::markDelayedChildren(SliceBudget &budget) { gcstats::MaybeAutoPhase ap; - if (runtime()->gcIncrementalState == MARK) - ap.construct(runtime()->gcStats, gcstats::PHASE_MARK_DELAYED); + if (runtime()->gc.incrementalState == MARK) + ap.construct(runtime()->gc.stats, gcstats::PHASE_MARK_DELAYED); JS_ASSERT(unmarkedArenaStackTop); do { @@ -669,6 +669,6 @@ js::SetMarkStackLimit(JSRuntime *rt, size_t limit) { JS_ASSERT(!rt->isHeapBusy()); AutoStopVerifyingBarriers pauseVerification(rt, false); - rt->gcMarker.setMaxCapacity(limit); + rt->gc.marker.setMaxCapacity(limit); } diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index e7292b4de56b..9b9416fefbc3 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -103,7 +103,7 @@ struct VerifyPreTracer : JSTracer NodeMap nodemap; VerifyPreTracer(JSRuntime *rt, JSTraceCallback callback) - : JSTracer(rt, callback), noggc(rt), number(rt->gcNumber), count(0), root(nullptr) + : JSTracer(rt, callback), noggc(rt), number(rt->gc.number), count(0), root(nullptr) {} ~VerifyPreTracer() { @@ -171,7 +171,7 @@ NextNode(VerifyNode *node) void gc::StartVerifyPreBarriers(JSRuntime *rt) { - if (rt->gcVerifyPreData || rt->gcIncrementalState != NO_INCREMENTAL) + if (rt->gc.verifyPreData || rt->gc.incrementalState != NO_INCREMENTAL) return; /* @@ -180,7 +180,7 @@ gc::StartVerifyPreBarriers(JSRuntime *rt) * starting the pre barrier verifier if the post barrier verifier is already * running. */ - if (rt->gcVerifyPostData) + if (rt->gc.verifyPostData) return; MinorGC(rt, JS::gcreason::EVICT_NURSERY); @@ -190,10 +190,10 @@ gc::StartVerifyPreBarriers(JSRuntime *rt) if (!IsIncrementalGCSafe(rt)) return; - for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) + for (GCChunkSet::Range r(rt->gc.chunkSet.all()); !r.empty(); r.popFront()) r.front()->bitmap.clear(); - rt->gcNumber++; + rt->gc.number++; VerifyPreTracer *trc = js_new(rt, JSTraceCallback(nullptr)); if (!trc) @@ -219,7 +219,7 @@ gc::StartVerifyPreBarriers(JSRuntime *rt) trc->curnode = MakeNode(trc, nullptr, JSGCTraceKind(0)); /* We want MarkRuntime to save the roots to gcSavedRoots. */ - rt->gcIncrementalState = MARK_ROOTS; + rt->gc.incrementalState = MARK_ROOTS; /* Make all the roots be edges emanating from the root node. */ MarkRuntime(trc); @@ -245,9 +245,9 @@ gc::StartVerifyPreBarriers(JSRuntime *rt) node = NextNode(node); } - rt->gcVerifyPreData = trc; - rt->gcIncrementalState = MARK; - rt->gcMarker.start(); + rt->gc.verifyPreData = trc; + rt->gc.incrementalState = MARK; + rt->gc.marker.start(); rt->setNeedsBarrier(true); for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { @@ -259,9 +259,9 @@ gc::StartVerifyPreBarriers(JSRuntime *rt) return; oom: - rt->gcIncrementalState = NO_INCREMENTAL; + rt->gc.incrementalState = NO_INCREMENTAL; js_delete(trc); - rt->gcVerifyPreData = nullptr; + rt->gc.verifyPreData = nullptr; } static bool @@ -323,7 +323,7 @@ gc::EndVerifyPreBarriers(JSRuntime *rt) AutoPrepareForTracing prep(rt, SkipAtoms); - VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData; + VerifyPreTracer *trc = (VerifyPreTracer *)rt->gc.verifyPreData; if (!trc) return; @@ -344,11 +344,11 @@ gc::EndVerifyPreBarriers(JSRuntime *rt) * We need to bump gcNumber so that the methodjit knows that jitcode has * been discarded. */ - JS_ASSERT(trc->number == rt->gcNumber); - rt->gcNumber++; + JS_ASSERT(trc->number == rt->gc.number); + rt->gc.number++; - rt->gcVerifyPreData = nullptr; - rt->gcIncrementalState = NO_INCREMENTAL; + rt->gc.verifyPreData = nullptr; + rt->gc.incrementalState = NO_INCREMENTAL; if (!compartmentCreated && IsIncrementalGCSafe(rt)) { trc->setTraceCallback(CheckEdge); @@ -368,8 +368,8 @@ gc::EndVerifyPreBarriers(JSRuntime *rt) } } - rt->gcMarker.reset(); - rt->gcMarker.stop(); + rt->gc.marker.reset(); + rt->gc.marker.stop(); js_delete(trc); } @@ -389,7 +389,7 @@ struct VerifyPostTracer : JSTracer EdgeSet *edges; VerifyPostTracer(JSRuntime *rt, JSTraceCallback callback) - : JSTracer(rt, callback), number(rt->gcNumber), count(0) + : JSTracer(rt, callback), number(rt->gc.number), count(0) {} }; @@ -402,21 +402,21 @@ void gc::StartVerifyPostBarriers(JSRuntime *rt) { #ifdef JSGC_GENERATIONAL - if (rt->gcVerifyPostData || - rt->gcIncrementalState != NO_INCREMENTAL) + if (rt->gc.verifyPostData || + rt->gc.incrementalState != NO_INCREMENTAL) { return; } MinorGC(rt, JS::gcreason::EVICT_NURSERY); - rt->gcNumber++; + rt->gc.number++; VerifyPostTracer *trc = js_new(rt, JSTraceCallback(nullptr)); if (!trc) return; - rt->gcVerifyPostData = trc; + rt->gc.verifyPostData = trc; #endif } @@ -432,7 +432,7 @@ PostVerifierCollectStoreBufferEdges(JSTracer *jstrc, void **thingp, JSGCTraceKin /* The store buffer may store extra, non-cross-generational edges. */ JSObject *dst = *reinterpret_cast(thingp); - if (trc->runtime()->gcNursery.isInside(thingp) || !trc->runtime()->gcNursery.isInside(dst)) + if (trc->runtime()->gc.nursery.isInside(thingp) || !trc->runtime()->gc.nursery.isInside(dst)) return; /* @@ -468,9 +468,9 @@ PostVerifierVisitEdge(JSTracer *jstrc, void **thingp, JSGCTraceKind kind) return; /* Filter out non cross-generational edges. */ - JS_ASSERT(!trc->runtime()->gcNursery.isInside(thingp)); + JS_ASSERT(!trc->runtime()->gc.nursery.isInside(thingp)); JSObject *dst = *reinterpret_cast(thingp); - if (!trc->runtime()->gcNursery.isInside(dst)) + if (!trc->runtime()->gc.nursery.isInside(dst)) return; /* @@ -492,20 +492,20 @@ js::gc::EndVerifyPostBarriers(JSRuntime *rt) VerifyPostTracer::EdgeSet edges; AutoPrepareForTracing prep(rt, SkipAtoms); - VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData; + VerifyPostTracer *trc = (VerifyPostTracer *)rt->gc.verifyPostData; /* Visit every entry in the store buffer and put the edges in a hash set. */ trc->setTraceCallback(PostVerifierCollectStoreBufferEdges); if (!edges.init()) goto oom; trc->edges = &edges; - rt->gcStoreBuffer.markAll(trc); + rt->gc.storeBuffer.markAll(trc); /* Walk the heap to find any edges not the the |edges| set. */ trc->setTraceCallback(PostVerifierVisitEdge); for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { for (size_t kind = 0; kind < FINALIZE_LIMIT; ++kind) { - for (CellIterUnderGC cells(zone, AllocKind(kind)); !cells.done(); cells.next()) { + for (ZoneCellIterUnderGC cells(zone, AllocKind(kind)); !cells.done(); cells.next()) { Cell *src = cells.getCell(); JS_TraceChildren(trc, src, MapAllocToTraceKind(AllocKind(kind))); } @@ -514,7 +514,7 @@ js::gc::EndVerifyPostBarriers(JSRuntime *rt) oom: js_delete(trc); - rt->gcVerifyPostData = nullptr; + rt->gc.verifyPostData = nullptr; #endif } @@ -523,7 +523,7 @@ oom: static void VerifyPreBarriers(JSRuntime *rt) { - if (rt->gcVerifyPreData) + if (rt->gc.verifyPreData) EndVerifyPreBarriers(rt); else StartVerifyPreBarriers(rt); @@ -532,7 +532,7 @@ VerifyPreBarriers(JSRuntime *rt) static void VerifyPostBarriers(JSRuntime *rt) { - if (rt->gcVerifyPostData) + if (rt->gc.verifyPostData) EndVerifyPostBarriers(rt); else StartVerifyPostBarriers(rt); @@ -556,8 +556,8 @@ MaybeVerifyPreBarriers(JSRuntime *rt, bool always) if (rt->mainThread.suppressGC) return; - if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData) { - if (++trc->count < rt->gcZealFrequency && !always) + if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gc.verifyPreData) { + if (++trc->count < rt->gc.zealFrequency && !always) return; EndVerifyPreBarriers(rt); @@ -573,11 +573,11 @@ MaybeVerifyPostBarriers(JSRuntime *rt, bool always) if (rt->gcZeal() != ZealVerifierPostValue) return; - if (rt->mainThread.suppressGC || !rt->gcStoreBuffer.isEnabled()) + if (rt->mainThread.suppressGC || !rt->gc.storeBuffer.isEnabled()) return; - if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData) { - if (++trc->count < rt->gcZealFrequency && !always) + if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gc.verifyPostData) { + if (++trc->count < rt->gc.zealFrequency && !always) return; EndVerifyPostBarriers(rt); @@ -596,14 +596,14 @@ js::gc::MaybeVerifyBarriers(JSContext *cx, bool always) void js::gc::FinishVerifier(JSRuntime *rt) { - if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gcVerifyPreData) { + if (VerifyPreTracer *trc = (VerifyPreTracer *)rt->gc.verifyPreData) { js_delete(trc); - rt->gcVerifyPreData = nullptr; + rt->gc.verifyPreData = nullptr; } #ifdef JSGC_GENERATIONAL - if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gcVerifyPostData) { + if (VerifyPostTracer *trc = (VerifyPostTracer *)rt->gc.verifyPostData) { js_delete(trc); - rt->gcVerifyPostData = nullptr; + rt->gc.verifyPostData = nullptr; } #endif } diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 463f48ee8e2d..1f16e11fd783 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -22,7 +22,7 @@ using namespace js; using namespace js::gc; JS::Zone::Zone(JSRuntime *rt) - : JS::shadow::Zone(rt, &rt->gcMarker), + : JS::shadow::Zone(rt, &rt->gc.marker), allocator(this), ionUsingBarriers_(false), active(false), @@ -49,13 +49,14 @@ JS::Zone::Zone(JSRuntime *rt) JS_ASSERT(reinterpret_cast(this) == static_cast(this)); - setGCMaxMallocBytes(rt->gcMaxMallocBytes * 0.9); + setGCMaxMallocBytes(rt->gc.maxMallocBytes * 0.9); } Zone::~Zone() { - if (this == runtimeFromMainThread()->systemZone) - runtimeFromMainThread()->systemZone = nullptr; + JSRuntime *rt = runtimeFromMainThread(); + if (this == rt->gc.systemZone) + rt->gc.systemZone = nullptr; #ifdef JS_ION js_delete(jitZone_); @@ -115,7 +116,7 @@ Zone::sweep(FreeOp *fop, bool releaseTypes, bool *oom) releaseTypes = false; { - gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_DISCARD_ANALYSIS); + gcstats::AutoPhase ap(fop->runtime()->gc.stats, gcstats::PHASE_DISCARD_ANALYSIS); types.sweep(fop, releaseTypes, oom); } @@ -133,11 +134,11 @@ Zone::sweepBreakpoints(FreeOp *fop) * to iterate over the scripts belonging to a single compartment in a zone. */ - gcstats::AutoPhase ap1(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_TABLES); - gcstats::AutoPhase ap2(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_TABLES_BREAKPOINT); + gcstats::AutoPhase ap1(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_TABLES); + gcstats::AutoPhase ap2(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_TABLES_BREAKPOINT); JS_ASSERT(isGCSweeping()); - for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); JS_ASSERT(script->zone()->isGCSweeping()); if (!script->hasAnyBreakpointsOrStepMode()) @@ -177,7 +178,7 @@ Zone::discardJitCode(FreeOp *fop) # ifdef DEBUG /* Assert no baseline scripts are marked as active. */ - for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); JS_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active()); } @@ -189,7 +190,7 @@ Zone::discardJitCode(FreeOp *fop) /* Only mark OSI points if code is being discarded. */ jit::InvalidateAll(fop, this); - for (CellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIterUnderGC i(this, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); jit::FinishInvalidation(fop, script); @@ -229,7 +230,7 @@ Zone::gcNumber() { // Zones in use by exclusive threads are not collected, and threads using // them cannot access the main runtime's gcNumber without racing. - return usedByExclusiveThread ? 0 : runtimeFromMainThread()->gcNumber; + return usedByExclusiveThread ? 0 : runtimeFromMainThread()->gc.number; } #ifdef JS_ION diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index cbbde6b2e833..c5becb540f57 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -357,8 +357,8 @@ class ZonesIter { public: ZonesIter(JSRuntime *rt, ZoneSelector selector) { - it = rt->zones.begin(); - end = rt->zones.end(); + it = rt->gc.zones.begin(); + end = rt->gc.zones.end(); if (selector == SkipAtoms) { JS_ASSERT(rt->isAtomsZone(*it)); diff --git a/js/src/jit-test/tests/asm.js/testBug999790.js b/js/src/jit-test/tests/asm.js/testBug999790.js new file mode 100644 index 000000000000..b67343433cf8 --- /dev/null +++ b/js/src/jit-test/tests/asm.js/testBug999790.js @@ -0,0 +1,69 @@ +function CanBeConstructed(f) { + var caught = false; + try { + new f; + } catch (e) { + caught = true; + } + return !caught; +} + +function IsConstructedFunction(f) { + return f.hasOwnProperty('length') + && f.hasOwnProperty('name') + && f.hasOwnProperty('arguments') + && f.hasOwnProperty('caller') + && f.hasOwnProperty('prototype') + && f.prototype.hasOwnProperty('constructor') + && f.prototype.constructor === f; +} + +function IsntConstructedFunction(f) { + return !f.hasOwnProperty('length') + && !f.hasOwnProperty('name') + && !f.hasOwnProperty('arguments') + && !f.hasOwnProperty('caller') + && !f.hasOwnProperty('prototype') +} + +var m = function() { + "use asm" + function g(){} + return g; +}; +assertEq(CanBeConstructed(m), true, "asm.js modules can't be constructed"); + +var objM = new m; +assertEq(IsConstructedFunction(objM), true); + +var g = m(); +assertEq(CanBeConstructed(g), true, "asm.js functions can't be constructed"); +// g is a ctor returning an primitive value, thus an empty object +assertEq(Object.getOwnPropertyNames(new g).length, 0); + +var n = function() { + "use asm" + function g(){return 42.0} + function h(){return 42} + return { + g: g, + h: h + }; +}; +assertEq(CanBeConstructed(n), true, "asm.js modules can't be constructed"); + +var objN = new n; +// objN is an object with attributes g and h +assertEq(IsntConstructedFunction(objN), true); +assertEq(objN.hasOwnProperty('g'), true); +assertEq(objN.hasOwnProperty('h'), true); + +assertEq(IsConstructedFunction(objN.g), true); +assertEq(IsConstructedFunction(objN.h), true); + +var h = n().h; +assertEq(CanBeConstructed(h), true, "asm.js functions can't be constructed"); +// h is a ctor returning an primitive value, thus an empty object +assertEq(Object.getOwnPropertyNames(new h).length, 0); + +assertEq(typeof(function() {"use asm"; return {}}.prototype) !== 'undefined', true); diff --git a/js/src/jit-test/tests/ion/bug1003694.js b/js/src/jit-test/tests/ion/bug1003694.js new file mode 100644 index 000000000000..7999510f19d7 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1003694.js @@ -0,0 +1,9 @@ +function f(i) { + if (i >= 10) + return; + var d = 3 + Math.abs(); + f(i ? i + 1 : 1); + bailout(); +} + +f(0); diff --git a/js/src/jit/AsmJS.cpp b/js/src/jit/AsmJS.cpp index fe1691183ae9..3649f3dbb83d 100644 --- a/js/src/jit/AsmJS.cpp +++ b/js/src/jit/AsmJS.cpp @@ -6605,21 +6605,21 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit // JSContext *cx = activation->cx(); // Activation *act = cx->mainThread().activation(); // act.active_ = true; - // act.prevIonTop_ = cx->mainThread().ionTop; + // act.prevJitTop_ = cx->mainThread().jitTop; // act.prevJitJSContext_ = cx->mainThread().jitJSContext; // cx->mainThread().jitJSContext = cx; // On the ARM store8() uses the secondScratchReg (lr) as a temp. size_t offsetOfActivation = offsetof(JSRuntime, mainThread) + PerThreadData::offsetOfActivation(); - size_t offsetOfIonTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, ionTop); + size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop); size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitJSContext); masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg3); masm.loadPtr(Address(reg3, JSContext::offsetOfRuntime()), reg0); masm.loadPtr(Address(reg0, offsetOfActivation), reg1); masm.store8(Imm32(1), Address(reg1, JitActivation::offsetOfActiveUint8())); - masm.loadPtr(Address(reg0, offsetOfIonTop), reg2); - masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevIonTop())); + masm.loadPtr(Address(reg0, offsetOfJitTop), reg2); + masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitTop())); masm.loadPtr(Address(reg0, offsetOfJitJSContext), reg2); masm.storePtr(reg2, Address(reg1, JitActivation::offsetOfPrevJitJSContext())); masm.storePtr(reg3, Address(reg0, offsetOfJitJSContext)); @@ -6647,20 +6647,20 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit // JSContext *cx = activation->cx(); // Activation *act = cx->mainThread().activation(); // act.active_ = false; - // cx->mainThread().ionTop = prevIonTop_; + // cx->mainThread().jitTop = prevJitTop_; // cx->mainThread().jitJSContext = prevJitJSContext_; // On the ARM store8() uses the secondScratchReg (lr) as a temp. size_t offsetOfActivation = offsetof(JSRuntime, mainThread) + PerThreadData::offsetOfActivation(); - size_t offsetOfIonTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, ionTop); + size_t offsetOfJitTop = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitTop); size_t offsetOfJitJSContext = offsetof(JSRuntime, mainThread) + offsetof(PerThreadData, jitJSContext); masm.loadPtr(Address(reg0, AsmJSActivation::offsetOfContext()), reg0); masm.loadPtr(Address(reg0, JSContext::offsetOfRuntime()), reg0); masm.loadPtr(Address(reg0, offsetOfActivation), reg1); masm.store8(Imm32(0), Address(reg1, JitActivation::offsetOfActiveUint8())); - masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevIonTop()), reg2); - masm.storePtr(reg2, Address(reg0, offsetOfIonTop)); + masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitTop()), reg2); + masm.storePtr(reg2, Address(reg0, offsetOfJitTop)); masm.loadPtr(Address(reg1, JitActivation::offsetOfPrevJitJSContext()), reg2); masm.storePtr(reg2, Address(reg0, offsetOfJitJSContext)); } diff --git a/js/src/jit/AsmJSLink.cpp b/js/src/jit/AsmJSLink.cpp index f4dd71ea986b..81a64c2e061b 100644 --- a/js/src/jit/AsmJSLink.cpp +++ b/js/src/jit/AsmJSLink.cpp @@ -515,6 +515,16 @@ CallAsmJS(JSContext *cx, unsigned argc, Value *vp) return false; } + if (callArgs.isConstructing()) { + // By spec, when a function is called as a constructor and this function + // returns a primary type, which is the case for all asm.js exported + // functions, the returned value is discarded and an empty object is + // returned instead. + JSObject *obj = NewBuiltinClassInstance(cx, &JSObject::class_); + callArgs.rval().set(ObjectValue(*obj)); + return true; + } + switch (func.returnType()) { case AsmJSModule::Return_Void: callArgs.rval().set(UndefinedValue()); @@ -536,7 +546,7 @@ NewExportedFunction(JSContext *cx, const AsmJSModule::ExportedFunction &func, { RootedPropertyName name(cx, func.name()); JSFunction *fun = NewFunction(cx, NullPtr(), CallAsmJS, func.numArgs(), - JSFunction::NATIVE_FUN, cx->global(), name, + JSFunction::ASMJS_CTOR, cx->global(), name, JSFunction::ExtendedFinalizeKind); if (!fun) return nullptr; @@ -798,8 +808,8 @@ js::NewAsmJSModuleFunction(ExclusiveContext *cx, JSFunction *origFun, HandleObje { RootedPropertyName name(cx, origFun->name()); - JSFunction::Flags flags = origFun->isLambda() ? JSFunction::NATIVE_LAMBDA_FUN - : JSFunction::NATIVE_FUN; + JSFunction::Flags flags = origFun->isLambda() ? JSFunction::ASMJS_LAMBDA_CTOR + : JSFunction::ASMJS_CTOR; JSFunction *moduleFun = NewFunction(cx, NullPtr(), LinkAsmJS, origFun->nargs(), flags, NullPtr(), name, JSFunction::ExtendedFinalizeKind, TenuredObject); diff --git a/js/src/jit/Bailouts.cpp b/js/src/jit/Bailouts.cpp index 9231d8dda93e..9ffd825eec21 100644 --- a/js/src/jit/Bailouts.cpp +++ b/js/src/jit/Bailouts.cpp @@ -75,7 +75,7 @@ jit::Bailout(BailoutStack *sp, BaselineBailoutInfo **bailoutInfo) JS_ASSERT(bailoutInfo); // We don't have an exit frame. - cx->mainThread().ionTop = nullptr; + cx->mainThread().jitTop = nullptr; JitActivationIterator jitActivations(cx->runtime()); IonBailoutIterator iter(jitActivations, sp); JitActivation *activation = jitActivations->asJit(); @@ -109,7 +109,7 @@ jit::InvalidationBailout(InvalidationBailoutStack *sp, size_t *frameSizeOut, JSContext *cx = GetJSContextFromJitCode(); // We don't have an exit frame. - cx->mainThread().ionTop = nullptr; + cx->mainThread().jitTop = nullptr; JitActivationIterator jitActivations(cx->runtime()); IonBailoutIterator iter(jitActivations, sp); JitActivation *activation = jitActivations->asJit(); @@ -177,7 +177,7 @@ jit::ExceptionHandlerBailout(JSContext *cx, const InlineFrameIterator &frame, // operation callback like a timeout handler. MOZ_ASSERT_IF(!excInfo.propagatingIonExceptionForDebugMode(), cx->isExceptionPending()); - cx->mainThread().ionTop = nullptr; + cx->mainThread().jitTop = nullptr; JitActivationIterator jitActivations(cx->runtime()); IonBailoutIterator iter(jitActivations, frame.frame()); JitActivation *activation = jitActivations->asJit(); diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index f451ac5fa6a8..0a5ef388d676 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -779,7 +779,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC, Value v; if (!iter.moreFrames() && i == exprStackSlots - 1 && - cx->runtime()->hasIonReturnOverride()) + cx->runtime()->jitRuntime()->hasIonReturnOverride()) { // If coming from an invalidation bailout, and this is the topmost // value, and a value override has been specified, don't read from the @@ -787,7 +787,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC, JS_ASSERT(invalidate); iter.skip(); IonSpew(IonSpew_BaselineBailouts, " [Return Override]"); - v = cx->runtime()->takeIonReturnOverride(); + v = cx->runtime()->jitRuntime()->takeIonReturnOverride(); } else if (excInfo && excInfo->propagatingIonExceptionForDebugMode()) { // If we are in the middle of propagating an exception from Ion by // bailing to baseline due to debug mode, we might not have all diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 96c76a80d086..371de9d5feed 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -408,7 +408,8 @@ BaselineCompiler::emitEpilogue() #ifdef JSGC_GENERATIONAL // On input: // R2.scratchReg() contains object being written to. -// Otherwise, baseline stack will be synced, so all other registers are usable as scratch. +// Called with the baseline stack synced, except for R0 which is preserved. +// All other registers are usable as scratch. // This calls: // void PostWriteBarrier(JSRuntime *rt, JSObject *obj); bool @@ -418,6 +419,7 @@ BaselineCompiler::emitOutOfLinePostBarrierSlot() Register objReg = R2.scratchReg(); GeneralRegisterSet regs(GeneralRegisterSet::All()); + regs.take(R0); regs.take(objReg); regs.take(BaselineFrameReg); Register scratch = regs.takeAny(); @@ -428,6 +430,7 @@ BaselineCompiler::emitOutOfLinePostBarrierSlot() #elif defined(JS_CODEGEN_MIPS) masm.push(ra); #endif + masm.pushValue(R0); masm.setupUnalignedABICall(2, scratch); masm.movePtr(ImmPtr(cx->runtime()), scratch); @@ -435,6 +438,7 @@ BaselineCompiler::emitOutOfLinePostBarrierSlot() masm.passABIArg(objReg); masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, PostWriteBarrier)); + masm.popValue(R0); masm.ret(); return true; } @@ -2096,16 +2100,15 @@ BaselineCompiler::emit_JSOP_SETALIASEDVAR() frame.push(R0); #ifdef JSGC_GENERATIONAL - // Fully sync the stack if post-barrier is needed. + // Only R0 is live at this point. // Scope coordinate object is already in R2.scratchReg(). - frame.syncStack(0); Register temp = R1.scratchReg(); Label skipBarrier; - masm.branchTestObject(Assembler::NotEqual, R0, &skipBarrier); - masm.branchPtrInNurseryRange(objReg, temp, &skipBarrier); + masm.branchPtrInNurseryRange(Assembler::Equal, objReg, temp, &skipBarrier); + masm.branchValueIsNurseryObject(Assembler::NotEqual, R0, temp, &skipBarrier); - masm.call(&postBarrierSlot_); + masm.call(&postBarrierSlot_); // Won't clobber R0 masm.bind(&skipBarrier); #endif @@ -2461,11 +2464,12 @@ BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get) frame.push(R0); } else { masm.patchableCallPreBarrier(argAddr, MIRType_Value); - storeValue(frame.peek(-1), argAddr, R0); + masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R0); + masm.storeValue(R0, argAddr); #ifdef JSGC_GENERATIONAL - // Fully sync the stack if post-barrier is needed. - frame.syncStack(0); + MOZ_ASSERT(frame.numUnsyncedSlots() == 0); + Register temp = R1.scratchReg(); // Reload the arguments object @@ -2473,7 +2477,9 @@ BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get) masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfArgsObj()), reg); Label skipBarrier; - masm.branchPtrInNurseryRange(reg, temp, &skipBarrier); + + masm.branchPtrInNurseryRange(Assembler::Equal, reg, temp, &skipBarrier); + masm.branchValueIsNurseryObject(Assembler::NotEqual, R0, temp, &skipBarrier); masm.call(&postBarrierSlot_); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index ded9da3d6282..9c4b0aa681ac 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -734,16 +734,9 @@ inline bool ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val, Register scratch, GeneralRegisterSet saveRegs) { - Nursery &nursery = cx->runtime()->gcNursery; - Label skipBarrier; - masm.branchTestObject(Assembler::NotEqual, val, &skipBarrier); - - masm.branchPtrInNurseryRange(obj, scratch, &skipBarrier); - - Register valReg = masm.extractObject(val, scratch); - masm.branchPtr(Assembler::Below, valReg, ImmWord(nursery.start()), &skipBarrier); - masm.branchPtr(Assembler::AboveOrEqual, valReg, ImmWord(nursery.heapEnd()), &skipBarrier); + masm.branchPtrInNurseryRange(Assembler::Equal, obj, scratch, &skipBarrier); + masm.branchValueIsNurseryObject(Assembler::NotEqual, val, scratch, &skipBarrier); // void PostWriteBarrier(JSRuntime *rt, JSObject *obj); #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS) @@ -3433,7 +3426,7 @@ IsCacheableGetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *sh #ifdef JSGC_GENERATIONAL // Information from get prop call ICs may be used directly from Ion code, // and should not be nursery allocated. - if (cx->runtime()->gcNursery.isInside(holder) || cx->runtime()->gcNursery.isInside(func)) + if (cx->runtime()->gc.nursery.isInside(holder) || cx->runtime()->gc.nursery.isInside(func)) return false; #endif @@ -3552,7 +3545,7 @@ IsCacheableSetPropCall(JSContext *cx, JSObject *obj, JSObject *holder, Shape *sh #ifdef JSGC_GENERATIONAL // Information from set prop call ICs may be used directly from Ion code, // and should not be nursery allocated. - if (cx->runtime()->gcNursery.isInside(holder) || cx->runtime()->gcNursery.isInside(func)) + if (cx->runtime()->gc.nursery.isInside(holder) || cx->runtime()->gc.nursery.isInside(func)) return false; #endif diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 63faf00e93d2..98caae885f80 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -128,7 +128,7 @@ EnterBaseline(JSContext *cx, EnterJitData &data) data.osrFrame->clearRunningInJit(); } - JS_ASSERT(!cx->runtime()->hasIonReturnOverride()); + JS_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride()); // Jit callers wrap primitive constructor return. if (!data.result.isMagic() && data.constructing && data.result.isPrimitive()) @@ -456,7 +456,7 @@ BaselineScript::Destroy(FreeOp *fop, BaselineScript *script) * in invalid store buffer entries. Assert that if we do destroy scripts * outside of a GC that we at least emptied the nursery first. */ - JS_ASSERT(fop->runtime()->gcNursery.isEmpty()); + JS_ASSERT(fop->runtime()->gc.nursery.isEmpty()); #endif fop->delete_(script); } @@ -922,7 +922,7 @@ void jit::ToggleBaselineSPS(JSRuntime *runtime, bool enable) { for (ZonesIter zone(runtime, SkipAtoms); !zone.done(); zone.next()) { - for (gc::CellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (!script->hasBaselineScript()) continue; diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 41bbf046c1ae..e2dc2dc36df8 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1875,10 +1875,11 @@ CodeGenerator::visitPostWriteBarrierO(LPostWriteBarrierO *lir) JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject())); #endif } else { - masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin()); + masm.branchPtrInNurseryRange(Assembler::Equal, ToRegister(lir->object()), temp, + ool->rejoin()); } - masm.branchPtrInNurseryRange(ToRegister(lir->value()), temp, ool->entry()); + masm.branchPtrInNurseryRange(Assembler::Equal, ToRegister(lir->value()), temp, ool->entry()); masm.bind(ool->rejoin()); #endif @@ -1901,11 +1902,12 @@ CodeGenerator::visitPostWriteBarrierV(LPostWriteBarrierV *lir) JS_ASSERT(!nursery.isInside(&lir->object()->toConstant()->toObject())); #endif } else { - masm.branchPtrInNurseryRange(ToRegister(lir->object()), temp, ool->rejoin()); + masm.branchPtrInNurseryRange(Assembler::Equal, ToRegister(lir->object()), temp, + ool->rejoin()); } ValueOperand value = ToValue(lir, LPostWriteBarrierV::Input); - masm.branchValueIsNurseryObject(value, temp, ool->entry()); + masm.branchValueIsNurseryObject(Assembler::Equal, value, temp, ool->entry()); masm.bind(ool->rejoin()); #endif @@ -2728,7 +2730,19 @@ CodeGenerator::generateArgumentsChecks(bool bailout) // Reserve the amount of stack the actual frame will use. We have to undo // this before falling through to the method proper though, because the // monomorphic call case will bypass this entire path. - masm.reserveStack(frameSize()); + + // On windows, we cannot skip very far down the stack without touching the + // memory pages in-between. This is a corner-case code for situations where the + // Ion frame data for a piece of code is very large. To handle this special case, + // for frames over 1k in size we allocate memory on the stack incrementally, touching + // it as we go. + uint32_t frameSizeLeft = frameSize(); + while (frameSizeLeft > 1024) { + masm.reserveStack(1024); + masm.store32(Imm32(0), Address(StackPointer, 0)); + frameSizeLeft -= 1024; + } + masm.reserveStack(frameSizeLeft); // No registers are allocated yet, so it's safe to grab anything. Register temp = GeneralRegisterSet(EntryTempMask).getAny(); diff --git a/js/src/jit/CompileWrappers.cpp b/js/src/jit/CompileWrappers.cpp index 2fb1c3971fc0..011597f709cb 100644 --- a/js/src/jit/CompileWrappers.cpp +++ b/js/src/jit/CompileWrappers.cpp @@ -35,9 +35,9 @@ CompileRuntime::mainThread() } const void * -CompileRuntime::addressOfIonTop() +CompileRuntime::addressOfJitTop() { - return &runtime()->mainThread.ionTop; + return &runtime()->mainThread.jitTop; } const void * @@ -68,7 +68,7 @@ CompileRuntime::addressOfLastCachedNativeIterator() const void * CompileRuntime::addressOfGCZeal() { - return &runtime()->gcZeal_; + return &runtime()->gc.zealMode; } #endif @@ -170,7 +170,7 @@ CompileRuntime::maybeGetMathCache() const Nursery & CompileRuntime::gcNursery() { - return runtime()->gcNursery; + return runtime()->gc.nursery; } #endif diff --git a/js/src/jit/CompileWrappers.h b/js/src/jit/CompileWrappers.h index 17dd303d181f..16e738f43d9d 100644 --- a/js/src/jit/CompileWrappers.h +++ b/js/src/jit/CompileWrappers.h @@ -33,8 +33,8 @@ class CompileRuntime js::PerThreadData *mainThread(); - // &mainThread.ionTop - const void *addressOfIonTop(); + // &mainThread.jitTop + const void *addressOfJitTop(); // rt->mainThread.jitStackLimit; const void *addressOfJitStackLimit(); diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index 3e9675f855fa..2f6df6bac7ed 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -163,7 +163,8 @@ JitRuntime::JitRuntime() functionWrappers_(nullptr), osrTempData_(nullptr), flusher_(nullptr), - ionCodeProtected_(false) + ionCodeProtected_(false), + ionReturnOverride_(MagicValue(JS_ARG_POISON)) { } @@ -569,7 +570,7 @@ JitRuntime::Mark(JSTracer *trc) { JS_ASSERT(!trc->runtime()->isHeapMinorCollecting()); Zone *zone = trc->runtime()->atomsCompartment()->zone(); - for (gc::CellIterUnderGC i(zone, gc::FINALIZE_JITCODE); !i.done(); i.next()) { + for (gc::ZoneCellIterUnderGC i(zone, gc::FINALIZE_JITCODE); !i.done(); i.next()) { JitCode *code = i.get(); MarkJitCodeRoot(trc, &code, "wrapper"); } @@ -1235,7 +1236,7 @@ jit::ToggleBarriers(JS::Zone *zone, bool needs) IonContext ictx(CompileRuntime::get(rt)); AutoFlushCache afc("ToggleBarriers", rt->jitRuntime()); - for (gc::CellIterUnderGC i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (gc::ZoneCellIterUnderGC i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->hasIonScript()) script->ionScript()->toggleBarriers(needs); @@ -1533,20 +1534,31 @@ GenerateLIR(MIRGenerator *mir) { MIRGraph &graph = mir->graph(); + TraceLogger *logger; + if (GetIonContext()->runtime->onMainThread()) + logger = TraceLoggerForMainThread(GetIonContext()->runtime); + else + logger = TraceLoggerForCurrentThread(); + LIRGraph *lir = mir->alloc().lifoAlloc()->new_(&graph); if (!lir || !lir->init()) return nullptr; LIRGenerator lirgen(mir, graph, *lir); - if (!lirgen.generate()) - return nullptr; - IonSpewPass("Generate LIR"); + { + AutoTraceLog log(logger, TraceLogger::GenerateLIR); + if (!lirgen.generate()) + return nullptr; + IonSpewPass("Generate LIR"); - if (mir->shouldCancel("Generate LIR")) - return nullptr; + if (mir->shouldCancel("Generate LIR")) + return nullptr; + } AllocationIntegrityState integrity(*lir); + TraceLogStartEvent(logger, TraceLogger::RegisterAllocation); + switch (mir->optimizationInfo().registerAllocator()) { case RegisterAllocator_LSRA: { #ifdef DEBUG @@ -1608,12 +1620,17 @@ GenerateLIR(MIRGenerator *mir) if (mir->shouldCancel("Allocate Registers")) return nullptr; - // Now that all optimization and register allocation is done, re-introduce - // critical edges to avoid unnecessary jumps. - if (!UnsplitEdges(lir)) - return nullptr; - IonSpewPass("Unsplit Critical Edges"); - AssertBasicGraphCoherency(graph); + TraceLogStopEvent(logger, TraceLogger::RegisterAllocation); + + { + AutoTraceLog log(logger, TraceLogger::UnsplitEdges); + // Now that all optimization and register allocation is done, re-introduce + // critical edges to avoid unnecessary jumps. + if (!UnsplitEdges(lir)) + return nullptr; + IonSpewPass("Unsplit Critical Edges"); + AssertBasicGraphCoherency(graph); + } return lir; } @@ -1621,6 +1638,13 @@ GenerateLIR(MIRGenerator *mir) CodeGenerator * GenerateCode(MIRGenerator *mir, LIRGraph *lir) { + TraceLogger *logger; + if (GetIonContext()->runtime->onMainThread()) + logger = TraceLoggerForMainThread(GetIonContext()->runtime); + else + logger = TraceLoggerForCurrentThread(); + AutoTraceLog log(logger, TraceLogger::GenerateCode); + CodeGenerator *codegen = js_new(mir, lir); if (!codegen) return nullptr; @@ -1730,7 +1754,7 @@ OffThreadCompilationAvailable(JSContext *cx) // when running off thread. return cx->runtime()->canUseParallelIonCompilation() && WorkerThreadState().cpuCount > 1 - && cx->runtime()->gcIncrementalState == gc::NO_INCREMENTAL + && cx->runtime()->gc.incrementalState == gc::NO_INCREMENTAL && !cx->runtime()->profilingScripts; #else return false; @@ -2383,7 +2407,7 @@ EnterIon(JSContext *cx, EnterJitData &data) /* scopeChain = */ nullptr, 0, data.result.address()); } - JS_ASSERT(!cx->runtime()->hasIonReturnOverride()); + JS_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride()); // Jit callers wrap primitive constructor return. if (!data.result.isMagic() && data.constructing && data.result.isPrimitive()) @@ -2491,7 +2515,7 @@ jit::FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args) CALL_GENERATED_CODE(enter, jitcode, args.length() + 1, args.array() - 1, /* osrFrame = */nullptr, calleeToken, /* scopeChain = */ nullptr, 0, result.address()); - JS_ASSERT(!cx->runtime()->hasIonReturnOverride()); + JS_ASSERT(!cx->runtime()->jitRuntime()->hasIonReturnOverride()); args.rval().set(result); @@ -2500,13 +2524,13 @@ jit::FastInvoke(JSContext *cx, HandleFunction fun, CallArgs &args) } static void -InvalidateActivation(FreeOp *fop, uint8_t *ionTop, bool invalidateAll) +InvalidateActivation(FreeOp *fop, uint8_t *jitTop, bool invalidateAll) { IonSpew(IonSpew_Invalidate, "BEGIN invalidating activation"); size_t frameno = 1; - for (JitFrameIterator it(ionTop, SequentialExecution); !it.done(); ++it, ++frameno) { + for (JitFrameIterator it(jitTop, SequentialExecution); !it.done(); ++it, ++frameno) { JS_ASSERT_IF(frameno == 1, it.type() == JitFrame_Exit); #ifdef DEBUG @@ -2845,13 +2869,13 @@ jit::FinishInvalidation(FreeOp *fop, JSScript *script); void jit::MarkValueFromIon(JSRuntime *rt, Value *vp) { - gc::MarkValueUnbarriered(&rt->gcMarker, vp, "write barrier"); + gc::MarkValueUnbarriered(&rt->gc.marker, vp, "write barrier"); } void jit::MarkShapeFromIon(JSRuntime *rt, Shape **shapep) { - gc::MarkShapeUnbarriered(&rt->gcMarker, shapep, "write barrier"); + gc::MarkShapeUnbarriered(&rt->gc.marker, shapep, "write barrier"); } void @@ -3071,7 +3095,7 @@ AutoDebugModeInvalidation::~AutoDebugModeInvalidation() } } - for (gc::CellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (gc::ZoneCellIter i(zone, gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->compartment() == comp_ || zone_) { FinishInvalidation(fop, script); diff --git a/js/src/jit/IonFrames-inl.h b/js/src/jit/IonFrames-inl.h index 31dfe2d67e65..ddfff14e14d9 100644 --- a/js/src/jit/IonFrames-inl.h +++ b/js/src/jit/IonFrames-inl.h @@ -84,13 +84,13 @@ GetTopBaselineFrame(JSContext *cx) inline JSScript * GetTopIonJSScript(JSContext *cx, void **returnAddrOut = nullptr) { - return GetTopIonJSScript(cx->mainThread().ionTop, returnAddrOut, SequentialExecution); + return GetTopIonJSScript(cx->mainThread().jitTop, returnAddrOut, SequentialExecution); } inline JSScript * GetTopIonJSScript(ForkJoinContext *cx, void **returnAddrOut = nullptr) { - return GetTopIonJSScript(cx->perThreadData->ionTop, returnAddrOut, ParallelExecution); + return GetTopIonJSScript(cx->perThreadData->jitTop, returnAddrOut, ParallelExecution); } } // namespace jit diff --git a/js/src/jit/IonFrames.cpp b/js/src/jit/IonFrames.cpp index f1a22ff54777..a4d38e9d00b8 100644 --- a/js/src/jit/IonFrames.cpp +++ b/js/src/jit/IonFrames.cpp @@ -75,14 +75,14 @@ ReadFrameBooleanSlot(IonJSFrameLayout *fp, int32_t slot) return *(bool *)((char *)fp + OffsetOfFrameSlot(slot)); } -JitFrameIterator::JitFrameIterator(JSContext *cx) - : current_(cx->mainThread().ionTop), +JitFrameIterator::JitFrameIterator(ThreadSafeContext *cx) + : current_(cx->perThreadData->jitTop), type_(JitFrame_Exit), returnAddressToFp_(nullptr), frameSize_(0), cachedSafepointIndex_(nullptr), activation_(nullptr), - mode_(SequentialExecution) + mode_(cx->isForkJoinContext() ? ParallelExecution : SequentialExecution) { } @@ -93,7 +93,7 @@ JitFrameIterator::JitFrameIterator(const ActivationIterator &activations) frameSize_(0), cachedSafepointIndex_(nullptr), activation_(activations->asJit()), - mode_(SequentialExecution) + mode_(activation_->cx()->isForkJoinContext() ? ParallelExecution : SequentialExecution) { } @@ -615,8 +615,8 @@ HandleException(ResumeFromException *rfe) // This may happen if a callVM function causes an invalidation (setting the // override), and then fails, bypassing the bailout handlers that would // otherwise clear the return override. - if (cx->runtime()->hasIonReturnOverride()) - cx->runtime()->takeIonReturnOverride(); + if (cx->runtime()->jitRuntime()->hasIonReturnOverride()) + cx->runtime()->jitRuntime()->takeIonReturnOverride(); JitFrameIterator iter(cx); while (!iter.isEntry()) { @@ -715,13 +715,13 @@ HandleException(ResumeFromException *rfe) ++iter; if (current) { - // Unwind the frame by updating ionTop. This is necessary so that + // Unwind the frame by updating jitTop. This is necessary so that // (1) debugger exception unwind and leave frame hooks don't see this // frame when they use ScriptFrameIter, and (2) ScriptFrameIter does // not crash when accessing an IonScript that's destroyed by the // ionScript->decref call. EnsureExitFrame(current); - cx->mainThread().ionTop = (uint8_t *)current; + cx->mainThread().jitTop = (uint8_t *)current; } if (overrecursed) { @@ -737,7 +737,7 @@ void HandleParallelFailure(ResumeFromException *rfe) { ForkJoinContext *cx = ForkJoinContext::current(); - JitFrameIterator iter(cx->perThreadData->ionTop, ParallelExecution); + JitFrameIterator iter(cx->perThreadData->jitTop, ParallelExecution); parallel::Spew(parallel::SpewBailouts, "Bailing from VM reentry"); @@ -965,7 +965,7 @@ UpdateIonJSFrameForMinorGC(JSTracer *trc, const JitFrameIterator &frame) for (GeneralRegisterBackwardIterator iter(safepoint.allGprSpills()); iter.more(); iter++) { --spill; if (slotsRegs.has(*iter)) - trc->runtime()->gcNursery.forwardBufferPointer(reinterpret_cast(spill)); + trc->runtime()->gc.nursery.forwardBufferPointer(reinterpret_cast(spill)); } // Skip to the right place in the safepoint @@ -979,7 +979,7 @@ UpdateIonJSFrameForMinorGC(JSTracer *trc, const JitFrameIterator &frame) while (safepoint.getSlotsOrElementsSlot(&slot)) { HeapSlot **slots = reinterpret_cast(layout->slotRef(slot)); - trc->runtime()->gcNursery.forwardBufferPointer(slots); + trc->runtime()->gc.nursery.forwardBufferPointer(slots); } } #endif @@ -1275,7 +1275,7 @@ GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes) JSRuntime *rt = cx->runtime(); // Recover the return address. - JitFrameIterator it(rt->mainThread.ionTop, SequentialExecution); + JitFrameIterator it(rt->mainThread.jitTop, SequentialExecution); // If the previous frame is a rectifier frame (maybe unwound), // skip past it. @@ -1302,7 +1302,7 @@ GetPcScript(JSContext *cx, JSScript **scriptRes, jsbytecode **pcRes) if (MOZ_UNLIKELY(rt->ionPcScriptCache == nullptr)) { rt->ionPcScriptCache = (PcScriptCache *)js_malloc(sizeof(struct PcScriptCache)); if (rt->ionPcScriptCache) - rt->ionPcScriptCache->clear(rt->gcNumber); + rt->ionPcScriptCache->clear(rt->gc.number); } // Attempt to lookup address in cache. @@ -1628,12 +1628,20 @@ SnapshotIterator::fromInstructionResult(uint32_t index) const return (*instructionResults_)[index]; } +void +SnapshotIterator::settleOnFrame() +{ + // Check that the current instruction can still be use. + MOZ_ASSERT(snapshot_.numAllocationsRead() == 0); + while (!instruction()->isResumePoint()) + skipInstruction(); +} + void SnapshotIterator::nextFrame() { nextInstruction(); - while (!instruction()->isResumePoint()) - skipInstruction(); + settleOnFrame(); } IonScript * @@ -1699,8 +1707,7 @@ InlineFrameIteratorMaybeGC::findNextFrame() // Settle on the outermost frame without evaluating any instructions before // looking for a pc. - if (!si_.instruction()->isResumePoint()) - si_.nextFrame(); + si_.settleOnFrame(); pc_ = script_->offsetToPC(si_.pcOffset()); #ifdef DEBUG diff --git a/js/src/jit/IonFrames.h b/js/src/jit/IonFrames.h index 92f62108ed07..49e0d7c31904 100644 --- a/js/src/jit/IonFrames.h +++ b/js/src/jit/IonFrames.h @@ -283,9 +283,9 @@ MakeFrameDescriptor(uint32_t frameSize, FrameType type) // Returns the JSScript associated with the topmost Ion frame. inline JSScript * -GetTopIonJSScript(uint8_t *ionTop, void **returnAddrOut, ExecutionMode mode) +GetTopIonJSScript(uint8_t *jitTop, void **returnAddrOut, ExecutionMode mode) { - JitFrameIterator iter(ionTop, mode); + JitFrameIterator iter(jitTop, mode); JS_ASSERT(iter.type() == JitFrame_Exit); ++iter; diff --git a/js/src/jit/IonLinker.h b/js/src/jit/IonLinker.h index 84907feb1731..d7371a9ad7b9 100644 --- a/js/src/jit/IonLinker.h +++ b/js/src/jit/IonLinker.h @@ -67,7 +67,7 @@ class Linker masm.link(code); #ifdef JSGC_GENERATIONAL if (masm.embedsNurseryPointers()) - cx->runtime()->gcStoreBuffer.putWholeCell(code); + cx->runtime()->gc.storeBuffer.putWholeCell(code); #endif return code; } diff --git a/js/src/jit/JSONSpewer.cpp b/js/src/jit/JSONSpewer.cpp index 4258a3629cb5..9492f040d5b6 100644 --- a/js/src/jit/JSONSpewer.cpp +++ b/js/src/jit/JSONSpewer.cpp @@ -228,6 +228,8 @@ JSONSpewer::spewMResumePoint(MResumePoint *rp) for (MResumePoint *iter = rp; iter; iter = iter->caller()) { for (int i = iter->numOperands() - 1; i >= 0; i--) integerValue(iter->getOperand(i)->id()); + if (iter->caller()) + stringValue("|"); } endList(); diff --git a/js/src/jit/JitCompartment.h b/js/src/jit/JitCompartment.h index 4c7bbb86d5d1..c70dce480233 100644 --- a/js/src/jit/JitCompartment.h +++ b/js/src/jit/JitCompartment.h @@ -216,6 +216,20 @@ class JitRuntime // IonScripts in the runtime. InlineList backedgeList_; + // In certain cases, we want to optimize certain opcodes to typed instructions, + // to avoid carrying an extra register to feed into an unbox. Unfortunately, + // that's not always possible. For example, a GetPropertyCacheT could return a + // typed double, but if it takes its out-of-line path, it could return an + // object, and trigger invalidation. The invalidation bailout will consider the + // return value to be a double, and create a garbage Value. + // + // To allow the GetPropertyCacheT optimization, we allow the ability for + // GetPropertyCache to override the return value at the top of the stack - the + // value that will be temporarily corrupt. This special override value is set + // only in callVM() targets that are about to return *and* have invalidated + // their callee. + js::Value ionReturnOverride_; + private: JitCode *generateExceptionTailStub(JSContext *cx); JitCode *generateBailoutTailStub(JSContext *cx); @@ -341,6 +355,20 @@ class JitRuntime JitCode *forkJoinGetSliceStub() const { return forkJoinGetSliceStub_; } + + bool hasIonReturnOverride() const { + return !ionReturnOverride_.isMagic(JS_ARG_POISON); + } + js::Value takeIonReturnOverride() { + js::Value v = ionReturnOverride_; + ionReturnOverride_ = js::MagicValue(JS_ARG_POISON); + return v; + } + void setIonReturnOverride(const js::Value &v) { + JS_ASSERT(!hasIonReturnOverride()); + JS_ASSERT(!v.isMagic()); + ionReturnOverride_ = v; + } }; class JitZone @@ -460,7 +488,7 @@ ShouldPreserveParallelJITCode(JSRuntime *rt, JSScript *script, bool increase = f { IonScript *parallelIon = script->parallelIonScript(); uint32_t age = increase ? parallelIon->increaseParallelAge() : parallelIon->parallelAge(); - return age < jit::IonScript::MAX_PARALLEL_AGE && !rt->gcShouldCleanUpEverything; + return age < jit::IonScript::MAX_PARALLEL_AGE && !rt->gc.shouldCleanUpEverything; } // On windows systems, really large frames need to be incrementally touched. diff --git a/js/src/jit/JitFrameIterator-inl.h b/js/src/jit/JitFrameIterator-inl.h index 1211d0f4dd2d..09fba2df3098 100644 --- a/js/src/jit/JitFrameIterator-inl.h +++ b/js/src/jit/JitFrameIterator-inl.h @@ -19,8 +19,8 @@ namespace jit { template inline -InlineFrameIteratorMaybeGC::InlineFrameIteratorMaybeGC( - JSContext *cx, const IonBailoutIterator *iter) +InlineFrameIteratorMaybeGC::InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, + const IonBailoutIterator *iter) : frame_(iter), framesRead_(0), frameCount_(UINT32_MAX), diff --git a/js/src/jit/JitFrameIterator.h b/js/src/jit/JitFrameIterator.h index 362658c42bd9..2c548c1004fc 100644 --- a/js/src/jit/JitFrameIterator.h +++ b/js/src/jit/JitFrameIterator.h @@ -107,7 +107,7 @@ class JitFrameIterator mode_(mode) { } - explicit JitFrameIterator(JSContext *cx); + explicit JitFrameIterator(ThreadSafeContext *cx); explicit JitFrameIterator(const ActivationIterator &activations); explicit JitFrameIterator(IonJSFrameLayout *fp, ExecutionMode mode); @@ -355,6 +355,7 @@ class SnapshotIterator public: // Handle iterating over frames of the snapshots. void nextFrame(); + void settleOnFrame(); inline bool moreFrames() const { // The last instruction is recovering the innermost frame, so as long as @@ -491,7 +492,7 @@ class InlineFrameIteratorMaybeGC } public: - InlineFrameIteratorMaybeGC(JSContext *cx, const JitFrameIterator *iter) + InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, const JitFrameIterator *iter) : callee_(cx), script_(cx) { @@ -505,9 +506,9 @@ class InlineFrameIteratorMaybeGC resetOn(iter); } - InlineFrameIteratorMaybeGC(JSContext *cx, const IonBailoutIterator *iter); + InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, const IonBailoutIterator *iter); - InlineFrameIteratorMaybeGC(JSContext *cx, const InlineFrameIteratorMaybeGC *iter) + InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, const InlineFrameIteratorMaybeGC *iter) : frame_(iter ? iter->frame_ : nullptr), framesRead_(0), frameCount_(iter ? iter->frameCount_ : UINT32_MAX), @@ -547,7 +548,7 @@ class InlineFrameIteratorMaybeGC } template - void readFrameArgsAndLocals(JSContext *cx, ArgOp &argOp, LocalOp &localOp, + void readFrameArgsAndLocals(ThreadSafeContext *cx, ArgOp &argOp, LocalOp &localOp, JSObject **scopeChain, Value *rval, ArgumentsObject **argsObj, Value *thisv, ReadFrameArgsBehavior behavior) const @@ -616,7 +617,9 @@ class InlineFrameIteratorMaybeGC } template - void unaliasedForEachActual(JSContext *cx, Op op, ReadFrameArgsBehavior behavior) const { + void unaliasedForEachActual(ThreadSafeContext *cx, Op op, + ReadFrameArgsBehavior behavior) const + { Nop nop; readFrameArgsAndLocals(cx, op, nop, nullptr, nullptr, nullptr, nullptr, behavior); } diff --git a/js/src/jit/PcScriptCache.h b/js/src/jit/PcScriptCache.h index 889b6644a9b8..60af08dde52c 100644 --- a/js/src/jit/PcScriptCache.h +++ b/js/src/jit/PcScriptCache.h @@ -45,8 +45,8 @@ struct PcScriptCache JSScript **scriptRes, jsbytecode **pcRes) { // If a GC occurred, lazily clear the cache now. - if (gcNumber != rt->gcNumber) { - clear(rt->gcNumber); + if (gcNumber != rt->gc.number) { + clear(rt->gc.number); return false; } diff --git a/js/src/jit/RematerializedFrame.cpp b/js/src/jit/RematerializedFrame.cpp index a8a95503393c..a0517decfa69 100644 --- a/js/src/jit/RematerializedFrame.cpp +++ b/js/src/jit/RematerializedFrame.cpp @@ -28,7 +28,8 @@ struct CopyValueToRematerializedFrame } }; -RematerializedFrame::RematerializedFrame(JSContext *cx, uint8_t *top, InlineFrameIterator &iter) +RematerializedFrame::RematerializedFrame(ThreadSafeContext *cx, uint8_t *top, + InlineFrameIterator &iter) : prevUpToDate_(false), top_(top), frameNo_(iter.frameNo()), @@ -41,7 +42,7 @@ RematerializedFrame::RematerializedFrame(JSContext *cx, uint8_t *top, InlineFram } /* static */ RematerializedFrame * -RematerializedFrame::New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter) +RematerializedFrame::New(ThreadSafeContext *cx, uint8_t *top, InlineFrameIterator &iter) { unsigned numFormals = iter.isFunctionFrame() ? iter.callee()->nargs() : 0; size_t numBytes = sizeof(RematerializedFrame) + diff --git a/js/src/jit/RematerializedFrame.h b/js/src/jit/RematerializedFrame.h index 0a0174b2e50e..6e66231040f6 100644 --- a/js/src/jit/RematerializedFrame.h +++ b/js/src/jit/RematerializedFrame.h @@ -41,10 +41,11 @@ class RematerializedFrame Value thisValue_; Value slots_[1]; - RematerializedFrame(JSContext *cx, uint8_t *top, InlineFrameIterator &iter); + RematerializedFrame(ThreadSafeContext *cx, uint8_t *top, InlineFrameIterator &iter); public: - static RematerializedFrame *New(JSContext *cx, uint8_t *top, InlineFrameIterator &iter); + static RematerializedFrame *New(ThreadSafeContext *cx, uint8_t *top, + InlineFrameIterator &iter); bool prevUpToDate() const { return prevUpToDate_; diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index 0ae0566f55ed..709ae84060ab 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -554,7 +554,7 @@ NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot // the initializing writes. The interpreter, however, may have allocated // the call object tenured, so barrier as needed before re-entering. if (!IsInsideNursery(cx->runtime(), obj)) - cx->runtime()->gcStoreBuffer.putWholeCell(obj); + cx->runtime()->gc.storeBuffer.putWholeCell(obj); #endif return obj; @@ -573,7 +573,7 @@ NewSingletonCallObject(JSContext *cx, HandleShape shape, HeapSlot *slots) // the call object tenured, so barrier as needed before re-entering. MOZ_ASSERT(!IsInsideNursery(cx->runtime(), obj), "singletons are created in the tenured heap"); - cx->runtime()->gcStoreBuffer.putWholeCell(obj); + cx->runtime()->gc.storeBuffer.putWholeCell(obj); #endif return obj; @@ -714,7 +714,7 @@ void PostWriteBarrier(JSRuntime *rt, JSObject *obj) { JS_ASSERT(!IsInsideNursery(rt, obj)); - rt->gcStoreBuffer.putWholeCell(obj); + rt->gc.storeBuffer.putWholeCell(obj); } void @@ -804,12 +804,12 @@ DebugEpilogue(JSContext *cx, BaselineFrame *frame, jsbytecode *pc, bool ok) } if (!ok) { - // Pop this frame by updating ionTop, so that the exception handling + // Pop this frame by updating jitTop, so that the exception handling // code will start at the previous frame. IonJSFrameLayout *prefix = frame->framePrefix(); EnsureExitFrame(prefix); - cx->mainThread().ionTop = (uint8_t *)prefix; + cx->mainThread().jitTop = (uint8_t *)prefix; } return ok; @@ -1096,6 +1096,12 @@ SetDenseElement(JSContext *cx, HandleObject obj, int32_t index, HandleValue valu return SetObjectElement(cx, obj, indexVal, value, strict); } +void +AutoDetectInvalidation::setReturnOverride() +{ + cx_->runtime()->jitRuntime()->setIonReturnOverride(*rval_); +} + #ifdef DEBUG void AssertValidObjectPtr(JSContext *cx, JSObject *obj) diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 7386e6e9a375..e343b3186409 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -556,6 +556,8 @@ class AutoDetectInvalidation Value *rval_; bool disabled_; + void setReturnOverride(); + public: AutoDetectInvalidation(JSContext *cx, Value *rval, IonScript *ionScript = nullptr); @@ -566,7 +568,7 @@ class AutoDetectInvalidation ~AutoDetectInvalidation() { if (!disabled_ && ionScript_->invalidated()) - cx_->runtime()->setIonReturnOverride(*rval_); + setReturnOverride(); } }; diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index c2affe2b5dbe..4d5c881c4915 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -3503,8 +3503,9 @@ MacroAssemblerARMCompat::storeTypeTag(ImmTag tag, Register base, Register index, } void -MacroAssemblerARMCompat::linkExitFrame() { - uint8_t *dest = (uint8_t*)GetIonContext()->runtime->addressOfIonTop(); +MacroAssemblerARMCompat::linkExitFrame() +{ + uint8_t *dest = (uint8_t*)GetIonContext()->runtime->addressOfJitTop(); movePtr(ImmPtr(dest), ScratchRegister); ma_str(StackPointer, Operand(ScratchRegister, 0)); } @@ -3512,7 +3513,7 @@ MacroAssemblerARMCompat::linkExitFrame() { void MacroAssemblerARMCompat::linkParallelExitFrame(const Register &pt) { - ma_str(StackPointer, Operand(pt, offsetof(PerThreadData, ionTop))); + ma_str(StackPointer, Operand(pt, offsetof(PerThreadData, jitTop))); } // ARM says that all reads of pc will return 8 higher than the @@ -4349,8 +4350,10 @@ MacroAssemblerARMCompat::jumpWithPatch(RepatchLabel *label, Condition cond) #ifdef JSGC_GENERATIONAL void -MacroAssemblerARMCompat::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) +MacroAssemblerARMCompat::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, + Label *label) { + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); JS_ASSERT(ptr != temp); JS_ASSERT(ptr != secondScratchReg_); @@ -4359,16 +4362,20 @@ MacroAssemblerARMCompat::branchPtrInNurseryRange(Register ptr, Register temp, La ma_mov(Imm32(startChunk), secondScratchReg_); as_rsb(secondScratchReg_, secondScratchReg_, lsr(ptr, Nursery::ChunkShift)); - branch32(Assembler::Below, secondScratchReg_, Imm32(Nursery::NumNurseryChunks), label); + branch32(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + secondScratchReg_, Imm32(Nursery::NumNurseryChunks), label); } void -MacroAssemblerARMCompat::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) +MacroAssemblerARMCompat::branchValueIsNurseryObject(Condition cond, ValueOperand value, + Register temp, Label *label) { + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + Label done; - branchTestObject(Assembler::NotEqual, value, &done); - branchPtrInNurseryRange(value.payloadReg(), temp, label); + branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); + branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); bind(&done); } diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index 6e26f1971dba..fb924993fa7f 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1599,8 +1599,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM } #ifdef JSGC_GENERATIONAL - void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); - void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); + void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label); + void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label); #endif }; diff --git a/js/src/jit/mips/MacroAssembler-mips.cpp b/js/src/jit/mips/MacroAssembler-mips.cpp index cee93a56a3c5..dcbbfb324e9a 100644 --- a/js/src/jit/mips/MacroAssembler-mips.cpp +++ b/js/src/jit/mips/MacroAssembler-mips.cpp @@ -2834,7 +2834,7 @@ MacroAssemblerMIPSCompat::storeTypeTag(ImmTag tag, Register base, Register index void MacroAssemblerMIPSCompat::linkExitFrame() { - uint8_t *dest = (uint8_t*)GetIonContext()->runtime->addressOfIonTop(); + uint8_t *dest = (uint8_t*)GetIonContext()->runtime->addressOfJitTop(); movePtr(ImmPtr(dest), ScratchRegister); ma_sw(StackPointer, Address(ScratchRegister, 0)); } @@ -2842,7 +2842,7 @@ MacroAssemblerMIPSCompat::linkExitFrame() void MacroAssemblerMIPSCompat::linkParallelExitFrame(const Register &pt) { - ma_sw(StackPointer, Address(pt, offsetof(PerThreadData, ionTop))); + ma_sw(StackPointer, Address(pt, offsetof(PerThreadData, jitTop))); } // This macrosintruction calls the ion code and pushes the return address to diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp index 9a9f995b7c3a..838a26853f14 100644 --- a/js/src/jit/x64/MacroAssembler-x64.cpp +++ b/js/src/jit/x64/MacroAssembler-x64.cpp @@ -370,27 +370,33 @@ MacroAssemblerX64::handleFailureWithHandlerTail() #ifdef JSGC_GENERATIONAL void -MacroAssemblerX64::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) +MacroAssemblerX64::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label) { + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); JS_ASSERT(ptr != temp); JS_ASSERT(ptr != ScratchReg); const Nursery &nursery = GetIonContext()->runtime->gcNursery(); movePtr(ImmWord(-ptrdiff_t(nursery.start())), ScratchReg); addPtr(ptr, ScratchReg); - branchPtr(Assembler::Below, ScratchReg, Imm32(Nursery::NurserySize), label); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + ScratchReg, Imm32(Nursery::NurserySize), label); } void -MacroAssemblerX64::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) +MacroAssemblerX64::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, + Label *label) { + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + // 'Value' representing the start of the nursery tagged as a JSObject const Nursery &nursery = GetIonContext()->runtime->gcNursery(); Value start = ObjectValue(*reinterpret_cast(nursery.start())); movePtr(ImmWord(-ptrdiff_t(start.asRawBits())), ScratchReg); addPtr(value.valueReg(), ScratchReg); - branchPtr(Assembler::Below, ScratchReg, Imm32(Nursery::NurserySize), label); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + ScratchReg, Imm32(Nursery::NurserySize), label); } #endif diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index e495210d3e7c..6c21b932a113 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -1301,10 +1301,9 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared } // Save an exit frame (which must be aligned to the stack pointer) to - // ThreadData::ionTop of the main thread. + // PerThreadData::jitTop of the main thread. void linkExitFrame() { - storePtr(StackPointer, - AbsoluteAddress(GetIonContext()->runtime->addressOfIonTop())); + storePtr(StackPointer, AbsoluteAddress(GetIonContext()->runtime->addressOfJitTop())); } void callWithExitFrame(JitCode *target, Register dynStack) { @@ -1317,7 +1316,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared // Save an exit frame to the thread data of the current thread, given a // register that holds a PerThreadData *. void linkParallelExitFrame(const Register &pt) { - storePtr(StackPointer, Address(pt, offsetof(PerThreadData, ionTop))); + storePtr(StackPointer, Address(pt, offsetof(PerThreadData, jitTop))); } // See CodeGeneratorX64 calls to noteAsmJSGlobalAccess. @@ -1335,8 +1334,8 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared } #ifdef JSGC_GENERATIONAL - void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); - void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); + void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label); + void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label); #endif }; diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index d36f4d32c5c2..f42f9506af8e 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -390,24 +390,30 @@ MacroAssemblerX86::branchTestValue(Condition cond, const ValueOperand &value, co #ifdef JSGC_GENERATIONAL void -MacroAssemblerX86::branchPtrInNurseryRange(Register ptr, Register temp, Label *label) +MacroAssemblerX86::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, + Label *label) { + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); JS_ASSERT(ptr != temp); JS_ASSERT(temp != InvalidReg); // A temp register is required for x86. const Nursery &nursery = GetIonContext()->runtime->gcNursery(); movePtr(ImmWord(-ptrdiff_t(nursery.start())), temp); addPtr(ptr, temp); - branchPtr(Assembler::Below, temp, Imm32(Nursery::NurserySize), label); + branchPtr(cond == Assembler::Equal ? Assembler::Below : Assembler::AboveOrEqual, + temp, Imm32(Nursery::NurserySize), label); } void -MacroAssemblerX86::branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label) +MacroAssemblerX86::branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, + Label *label) { + JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual); + Label done; - branchTestObject(Assembler::NotEqual, value, &done); - branchPtrInNurseryRange(value.payloadReg(), temp, label); + branchTestObject(Assembler::NotEqual, value, cond == Assembler::Equal ? &done : label); + branchPtrInNurseryRange(cond, value.payloadReg(), temp, label); bind(&done); } diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index d7131e73c8ac..b300f6a8bf25 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -1098,9 +1098,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } // Save an exit frame (which must be aligned to the stack pointer) to - // ThreadData::ionTop of the main thread. + // PerThreadData::jitTop of the main thread. void linkExitFrame() { - movl(StackPointer, Operand(AbsoluteAddress(GetIonContext()->runtime->addressOfIonTop()))); + movl(StackPointer, Operand(AbsoluteAddress(GetIonContext()->runtime->addressOfJitTop()))); } void callWithExitFrame(JitCode *target, Register dynStack) { @@ -1120,12 +1120,12 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared // Save an exit frame to the thread data of the current thread, given a // register that holds a PerThreadData *. void linkParallelExitFrame(const Register &pt) { - movl(StackPointer, Operand(pt, offsetof(PerThreadData, ionTop))); + movl(StackPointer, Operand(pt, offsetof(PerThreadData, jitTop))); } #ifdef JSGC_GENERATIONAL - void branchPtrInNurseryRange(Register ptr, Register temp, Label *label); - void branchValueIsNurseryObject(ValueOperand value, Register temp, Label *label); + void branchPtrInNurseryRange(Condition cond, Register ptr, Register temp, Label *label); + void branchValueIsNurseryObject(Condition cond, ValueOperand value, Register temp, Label *label); #endif }; diff --git a/js/src/jsapi-tests/testAddPropertyPropcache.cpp b/js/src/jsapi-tests/testAddPropertyPropcache.cpp index e208975f6f82..d3ef0abecb31 100644 --- a/js/src/jsapi-tests/testAddPropertyPropcache.cpp +++ b/js/src/jsapi-tests/testAddPropertyPropcache.cpp @@ -49,14 +49,12 @@ BEGIN_TEST(testAddPropertyHook) CHECK(JS_DefineProperty(cx, global, "arr", arr, JSPROP_ENUMERATE, JS_PropertyStub, JS_StrictPropertyStub)); + JS::RootedObject arrObj(cx, &arr.toObject()); for (int i = 0; i < ExpectedCount; ++i) { obj = JS_NewObject(cx, &AddPropertyClass, JS::NullPtr(), JS::NullPtr()); CHECK(obj); - JS::RootedValue vobj(cx, OBJECT_TO_JSVAL(obj)); - JS::RootedObject arrObj(cx, arr.toObjectOrNull()); - CHECK(JS_DefineElement(cx, arrObj, i, vobj, - JS_PropertyStub, JS_StrictPropertyStub, - JSPROP_ENUMERATE)); + CHECK(JS_DefineElement(cx, arrObj, i, obj, JSPROP_ENUMERATE, + JS_PropertyStub, JS_StrictPropertyStub)); } // Now add a prop to each of the objects, but make sure to do diff --git a/js/src/jsapi-tests/testGCFinalizeCallback.cpp b/js/src/jsapi-tests/testGCFinalizeCallback.cpp index c911001af919..730581b35633 100644 --- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp +++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp @@ -17,7 +17,7 @@ BEGIN_TEST(testGCFinalizeCallback) /* Full GC, non-incremental. */ FinalizeCalls = 0; JS_GC(rt); - CHECK(rt->gcIsFull); + CHECK(rt->gc.isFull); CHECK(checkSingleGroup()); CHECK(checkFinalizeStatus()); CHECK(checkFinalizeIsCompartmentGC(false)); @@ -26,8 +26,8 @@ BEGIN_TEST(testGCFinalizeCallback) FinalizeCalls = 0; JS::PrepareForFullGC(rt); JS::IncrementalGC(rt, JS::gcreason::API, 1000000); - CHECK(rt->gcIncrementalState == js::gc::NO_INCREMENTAL); - CHECK(rt->gcIsFull); + CHECK(rt->gc.incrementalState == js::gc::NO_INCREMENTAL); + CHECK(rt->gc.isFull); CHECK(checkMultipleGroups()); CHECK(checkFinalizeStatus()); CHECK(checkFinalizeIsCompartmentGC(false)); @@ -43,7 +43,7 @@ BEGIN_TEST(testGCFinalizeCallback) FinalizeCalls = 0; JS::PrepareZoneForGC(global1->zone()); JS::GCForReason(rt, JS::gcreason::API); - CHECK(!rt->gcIsFull); + CHECK(!rt->gc.isFull); CHECK(checkSingleGroup()); CHECK(checkFinalizeStatus()); CHECK(checkFinalizeIsCompartmentGC(true)); @@ -54,7 +54,7 @@ BEGIN_TEST(testGCFinalizeCallback) JS::PrepareZoneForGC(global2->zone()); JS::PrepareZoneForGC(global3->zone()); JS::GCForReason(rt, JS::gcreason::API); - CHECK(!rt->gcIsFull); + CHECK(!rt->gc.isFull); CHECK(checkSingleGroup()); CHECK(checkFinalizeStatus()); CHECK(checkFinalizeIsCompartmentGC(true)); @@ -63,8 +63,8 @@ BEGIN_TEST(testGCFinalizeCallback) FinalizeCalls = 0; JS::PrepareZoneForGC(global1->zone()); JS::IncrementalGC(rt, JS::gcreason::API, 1000000); - CHECK(rt->gcIncrementalState == js::gc::NO_INCREMENTAL); - CHECK(!rt->gcIsFull); + CHECK(rt->gc.incrementalState == js::gc::NO_INCREMENTAL); + CHECK(!rt->gc.isFull); CHECK(checkSingleGroup()); CHECK(checkFinalizeStatus()); CHECK(checkFinalizeIsCompartmentGC(true)); @@ -75,8 +75,8 @@ BEGIN_TEST(testGCFinalizeCallback) JS::PrepareZoneForGC(global2->zone()); JS::PrepareZoneForGC(global3->zone()); JS::IncrementalGC(rt, JS::gcreason::API, 1000000); - CHECK(rt->gcIncrementalState == js::gc::NO_INCREMENTAL); - CHECK(!rt->gcIsFull); + CHECK(rt->gc.incrementalState == js::gc::NO_INCREMENTAL); + CHECK(!rt->gc.isFull); CHECK(checkMultipleGroups()); CHECK(checkFinalizeStatus()); CHECK(checkFinalizeIsCompartmentGC(true)); @@ -89,13 +89,13 @@ BEGIN_TEST(testGCFinalizeCallback) JS_SetGCZeal(cx, 9, 1000000); JS::PrepareForFullGC(rt); js::GCDebugSlice(rt, true, 1); - CHECK(rt->gcIncrementalState == js::gc::MARK); - CHECK(rt->gcIsFull); + CHECK(rt->gc.incrementalState == js::gc::MARK); + CHECK(rt->gc.isFull); JS::RootedObject global4(cx, createGlobal()); js::GCDebugSlice(rt, true, 1); - CHECK(rt->gcIncrementalState == js::gc::NO_INCREMENTAL); - CHECK(!rt->gcIsFull); + CHECK(rt->gc.incrementalState == js::gc::NO_INCREMENTAL); + CHECK(!rt->gc.isFull); CHECK(checkMultipleGroups()); CHECK(checkFinalizeStatus()); diff --git a/js/src/jsapi-tests/testLookup.cpp b/js/src/jsapi-tests/testLookup.cpp index 97a2d077af90..0163c5a76a58 100644 --- a/js/src/jsapi-tests/testLookup.cpp +++ b/js/src/jsapi-tests/testLookup.cpp @@ -68,7 +68,7 @@ document_resolve(JSContext *cx, JS::HandleObject obj, JS::HandleId id, if (!docAll) return false; JS::Rooted allValue(cx, ObjectValue(*docAll)); - bool ok = JS_DefinePropertyById(cx, obj, id, allValue, nullptr, nullptr, 0); + bool ok = JS_DefinePropertyById(cx, obj, id, allValue, 0); objp.set(ok ? obj.get() : nullptr); return ok; } diff --git a/js/src/jsapi-tests/testPropCache.cpp b/js/src/jsapi-tests/testPropCache.cpp index 7c1b51259521..4d86cecf4162 100644 --- a/js/src/jsapi-tests/testPropCache.cpp +++ b/js/src/jsapi-tests/testPropCache.cpp @@ -27,7 +27,7 @@ BEGIN_TEST(testPropCache_bug505798) { g_counter = 0; EXEC("var x = {};"); - CHECK(JS_DefineObject(cx, global, "y", &CounterClass, nullptr, JSPROP_ENUMERATE)); + CHECK(JS_DefineObject(cx, global, "y", &CounterClass, JS::NullPtr(), JSPROP_ENUMERATE)); EXEC("var arr = [x, y];\n" "for (var i = 0; i < arr.length; i++)\n" " arr[i].p = 1;\n"); diff --git a/js/src/jsapi-tests/testResolveRecursion.cpp b/js/src/jsapi-tests/testResolveRecursion.cpp index 9193f502021a..df56ecee3a8a 100644 --- a/js/src/jsapi-tests/testResolveRecursion.cpp +++ b/js/src/jsapi-tests/testResolveRecursion.cpp @@ -96,7 +96,7 @@ doResolve(JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp) CHECK_EQUAL(resolveEntryCount, 1); EVAL("obj2.y = true", &v); CHECK_SAME(v, JSVAL_TRUE); - CHECK(JS_DefinePropertyById(cx, obj, id, JSVAL_FALSE, nullptr, nullptr, 0)); + CHECK(JS_DefinePropertyById(cx, obj, id, JS::FalseHandleValue, 0)); objp.set(obj); return true; } @@ -108,7 +108,7 @@ doResolve(JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp) } else if (JS_FlatStringEqualsAscii(str, "y")) { if (obj == obj2) { CHECK_EQUAL(resolveEntryCount, 2); - CHECK(JS_DefinePropertyById(cx, obj, id, JSVAL_NULL, nullptr, nullptr, 0)); + CHECK(JS_DefinePropertyById(cx, obj, id, JS::NullHandleValue, 0)); EVAL("obj1.x", &v); CHECK(v.isUndefined()); EVAL("obj1.y", &v); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 1996d085b9d0..f68906fec37f 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -158,7 +158,7 @@ namespace js { void AssertHeapIsIdle(JSRuntime *rt) { - JS_ASSERT(rt->heapState == js::Idle); + JS_ASSERT(rt->gc.heapState == js::Idle); } void @@ -718,7 +718,7 @@ StopRequest(JSContext *cx) if (rt->requestDepth != 1) { rt->requestDepth--; } else { - rt->conservativeGC.updateForRequestEnd(); + rt->gc.conservativeGC.updateForRequestEnd(); rt->requestDepth = 0; rt->triggerActivityCallback(false); } @@ -1613,17 +1613,17 @@ JS_PUBLIC_API(bool) JS_AddExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) { AssertHeapIsIdle(rt); - return !!rt->gcBlackRootTracers.append(JSRuntime::ExtraTracer(traceOp, data)); + return !!rt->gc.blackRootTracers.append(ExtraTracer(traceOp, data)); } JS_PUBLIC_API(void) JS_RemoveExtraGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) { AssertHeapIsIdle(rt); - for (size_t i = 0; i < rt->gcBlackRootTracers.length(); i++) { - JSRuntime::ExtraTracer *e = &rt->gcBlackRootTracers[i]; + for (size_t i = 0; i < rt->gc.blackRootTracers.length(); i++) { + ExtraTracer *e = &rt->gc.blackRootTracers[i]; if (e->op == traceOp && e->data == data) { - rt->gcBlackRootTracers.erase(e); + rt->gc.blackRootTracers.erase(e); break; } } @@ -1897,15 +1897,15 @@ JS_PUBLIC_API(void) JS_SetGCCallback(JSRuntime *rt, JSGCCallback cb, void *data) { AssertHeapIsIdle(rt); - rt->gcCallback = cb; - rt->gcCallbackData = data; + rt->gc.callback = cb; + rt->gc.callbackData = data; } JS_PUBLIC_API(void) JS_SetFinalizeCallback(JSRuntime *rt, JSFinalizeCallback cb) { AssertHeapIsIdle(rt); - rt->gcFinalizeCallback = cb; + rt->gc.finalizeCallback = cb; } JS_PUBLIC_API(bool) @@ -1925,51 +1925,51 @@ JS_SetGCParameter(JSRuntime *rt, JSGCParamKey key, uint32_t value) { switch (key) { case JSGC_MAX_BYTES: { - JS_ASSERT(value >= rt->gcBytes); - rt->gcMaxBytes = value; + JS_ASSERT(value >= rt->gc.bytes); + rt->gc.maxBytes = value; break; } case JSGC_MAX_MALLOC_BYTES: rt->setGCMaxMallocBytes(value); break; case JSGC_SLICE_TIME_BUDGET: - rt->gcSliceBudget = SliceBudget::TimeBudget(value); + rt->gc.sliceBudget = SliceBudget::TimeBudget(value); break; case JSGC_MARK_STACK_LIMIT: js::SetMarkStackLimit(rt, value); break; case JSGC_HIGH_FREQUENCY_TIME_LIMIT: - rt->gcHighFrequencyTimeThreshold = value; + rt->gc.highFrequencyTimeThreshold = value; break; case JSGC_HIGH_FREQUENCY_LOW_LIMIT: - rt->gcHighFrequencyLowLimitBytes = value * 1024 * 1024; + rt->gc.highFrequencyLowLimitBytes = value * 1024 * 1024; break; case JSGC_HIGH_FREQUENCY_HIGH_LIMIT: - rt->gcHighFrequencyHighLimitBytes = value * 1024 * 1024; + rt->gc.highFrequencyHighLimitBytes = value * 1024 * 1024; break; case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX: - rt->gcHighFrequencyHeapGrowthMax = value / 100.0; - MOZ_ASSERT(rt->gcHighFrequencyHeapGrowthMax / 0.85 > 1.0); + rt->gc.highFrequencyHeapGrowthMax = value / 100.0; + MOZ_ASSERT(rt->gc.highFrequencyHeapGrowthMax / 0.85 > 1.0); break; case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN: - rt->gcHighFrequencyHeapGrowthMin = value / 100.0; - MOZ_ASSERT(rt->gcHighFrequencyHeapGrowthMin / 0.85 > 1.0); + rt->gc.highFrequencyHeapGrowthMin = value / 100.0; + MOZ_ASSERT(rt->gc.highFrequencyHeapGrowthMin / 0.85 > 1.0); break; case JSGC_LOW_FREQUENCY_HEAP_GROWTH: - rt->gcLowFrequencyHeapGrowth = value / 100.0; - MOZ_ASSERT(rt->gcLowFrequencyHeapGrowth / 0.9 > 1.0); + rt->gc.lowFrequencyHeapGrowth = value / 100.0; + MOZ_ASSERT(rt->gc.lowFrequencyHeapGrowth / 0.9 > 1.0); break; case JSGC_DYNAMIC_HEAP_GROWTH: - rt->gcDynamicHeapGrowth = value; + rt->gc.dynamicHeapGrowth = value; break; case JSGC_DYNAMIC_MARK_SLICE: - rt->gcDynamicMarkSlice = value; + rt->gc.dynamicMarkSlice = value; break; case JSGC_ALLOCATION_THRESHOLD: - rt->gcAllocationThreshold = value * 1024 * 1024; + rt->gc.allocationThreshold = value * 1024 * 1024; break; case JSGC_DECOMMIT_THRESHOLD: - rt->gcDecommitThreshold = value * 1024 * 1024; + rt->gc.decommitThreshold = value * 1024 * 1024; break; default: JS_ASSERT(key == JSGC_MODE); @@ -1986,42 +1986,42 @@ JS_GetGCParameter(JSRuntime *rt, JSGCParamKey key) { switch (key) { case JSGC_MAX_BYTES: - return uint32_t(rt->gcMaxBytes); + return uint32_t(rt->gc.maxBytes); case JSGC_MAX_MALLOC_BYTES: - return rt->gcMaxMallocBytes; + return rt->gc.maxMallocBytes; case JSGC_BYTES: - return uint32_t(rt->gcBytes); + return uint32_t(rt->gc.bytes); case JSGC_MODE: return uint32_t(rt->gcMode()); case JSGC_UNUSED_CHUNKS: - return uint32_t(rt->gcChunkPool.getEmptyCount()); + return uint32_t(rt->gc.chunkPool.getEmptyCount()); case JSGC_TOTAL_CHUNKS: - return uint32_t(rt->gcChunkSet.count() + rt->gcChunkPool.getEmptyCount()); + return uint32_t(rt->gc.chunkSet.count() + rt->gc.chunkPool.getEmptyCount()); case JSGC_SLICE_TIME_BUDGET: - return uint32_t(rt->gcSliceBudget > 0 ? rt->gcSliceBudget / PRMJ_USEC_PER_MSEC : 0); + return uint32_t(rt->gc.sliceBudget > 0 ? rt->gc.sliceBudget / PRMJ_USEC_PER_MSEC : 0); case JSGC_MARK_STACK_LIMIT: - return rt->gcMarker.maxCapacity(); + return rt->gc.marker.maxCapacity(); case JSGC_HIGH_FREQUENCY_TIME_LIMIT: - return rt->gcHighFrequencyTimeThreshold; + return rt->gc.highFrequencyTimeThreshold; case JSGC_HIGH_FREQUENCY_LOW_LIMIT: - return rt->gcHighFrequencyLowLimitBytes / 1024 / 1024; + return rt->gc.highFrequencyLowLimitBytes / 1024 / 1024; case JSGC_HIGH_FREQUENCY_HIGH_LIMIT: - return rt->gcHighFrequencyHighLimitBytes / 1024 / 1024; + return rt->gc.highFrequencyHighLimitBytes / 1024 / 1024; case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX: - return uint32_t(rt->gcHighFrequencyHeapGrowthMax * 100); + return uint32_t(rt->gc.highFrequencyHeapGrowthMax * 100); case JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN: - return uint32_t(rt->gcHighFrequencyHeapGrowthMin * 100); + return uint32_t(rt->gc.highFrequencyHeapGrowthMin * 100); case JSGC_LOW_FREQUENCY_HEAP_GROWTH: - return uint32_t(rt->gcLowFrequencyHeapGrowth * 100); + return uint32_t(rt->gc.lowFrequencyHeapGrowth * 100); case JSGC_DYNAMIC_HEAP_GROWTH: - return rt->gcDynamicHeapGrowth; + return rt->gc.dynamicHeapGrowth; case JSGC_DYNAMIC_MARK_SLICE: - return rt->gcDynamicMarkSlice; + return rt->gc.dynamicMarkSlice; case JSGC_ALLOCATION_THRESHOLD: - return rt->gcAllocationThreshold / 1024 / 1024; + return rt->gc.allocationThreshold / 1024 / 1024; default: JS_ASSERT(key == JSGC_NUMBER); - return uint32_t(rt->gcNumber); + return uint32_t(rt->gc.number); } } @@ -2501,7 +2501,7 @@ JS_NewGlobalObject(JSContext *cx, const JSClass *clasp, JSPrincipals *principals Zone *zone; if (options.zoneSpecifier() == JS::SystemZone) - zone = rt->systemZone; + zone = rt->gc.systemZone; else if (options.zoneSpecifier() == JS::FreshZone) zone = nullptr; else @@ -2512,9 +2512,9 @@ JS_NewGlobalObject(JSContext *cx, const JSClass *clasp, JSPrincipals *principals return nullptr; // Lazily create the system zone. - if (!rt->systemZone && options.zoneSpecifier() == JS::SystemZone) { - rt->systemZone = compartment->zone(); - rt->systemZone->isSystem = true; + if (!rt->gc.systemZone && options.zoneSpecifier() == JS::SystemZone) { + rt->gc.systemZone = compartment->zone(); + rt->gc.systemZone->isSystem = true; } Rooted global(cx); @@ -2974,22 +2974,62 @@ DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue val } JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext *cx, JSObject *objArg, jsid idArg, jsval valueArg, - JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) +JS_DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) { - RootedObject obj(cx, objArg); - RootedId id(cx, idArg); - RootedValue value(cx, valueArg); return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter), attrs, 0); } JS_PUBLIC_API(bool) -JS_DefineElement(JSContext *cx, JSObject *objArg, uint32_t index, jsval valueArg, - JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) +JS_DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleObject valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + RootedValue value(cx, ObjectValue(*valueArg)); + return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter), + attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleString valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + RootedValue value(cx, StringValue(valueArg)); + return DefinePropertyById(cx, obj, id, value, GetterWrapper(getter), SetterWrapper(setter), + attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, int32_t valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + Value value = Int32Value(valueArg); + return DefinePropertyById(cx, obj, id, HandleValue::fromMarkedLocation(&value), + GetterWrapper(getter), SetterWrapper(setter), attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, uint32_t valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + Value value = UINT_TO_JSVAL(valueArg); + return DefinePropertyById(cx, obj, id, HandleValue::fromMarkedLocation(&value), + GetterWrapper(getter), SetterWrapper(setter), attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext *cx, HandleObject obj, HandleId id, double valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + Value value = NumberValue(valueArg); + return DefinePropertyById(cx, obj, id, HandleValue::fromMarkedLocation(&value), + GetterWrapper(getter), SetterWrapper(setter), attrs, 0); +} + +static bool +DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) { - RootedObject obj(cx, objArg); - RootedValue value(cx, valueArg); AutoRooterGetterSetter gsRoot(cx, attrs, &getter, &setter); AssertHeapIsIdle(cx); CHECK_REQUEST(cx); @@ -3000,6 +3040,56 @@ JS_DefineElement(JSContext *cx, JSObject *objArg, uint32_t index, jsval valueArg attrs, 0); } +JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleValue value, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + return DefineElement(cx, obj, index, value, attrs, getter, setter); +} + +JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleObject valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + RootedValue value(cx, ObjectValue(*valueArg)); + return DefineElement(cx, obj, index, value, attrs, getter, setter); +} + +JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, HandleString valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + RootedValue value(cx, StringValue(valueArg)); + return DefineElement(cx, obj, index, value, attrs, getter, setter); +} + +JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, int32_t valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + Value value = Int32Value(valueArg); + return DefineElement(cx, obj, index, HandleValue::fromMarkedLocation(&value), + attrs, getter, setter); +} + +JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, uint32_t valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + Value value = UINT_TO_JSVAL(valueArg); + return DefineElement(cx, obj, index, HandleValue::fromMarkedLocation(&value), + attrs, getter, setter); +} + +JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, HandleObject obj, uint32_t index, double valueArg, + unsigned attrs, JSPropertyOp getter, JSStrictPropertyOp setter) +{ + Value value = NumberValue(valueArg); + return DefineElement(cx, obj, index, HandleValue::fromMarkedLocation(&value), + attrs, getter, setter); +} + static bool DefineProperty(JSContext *cx, HandleObject obj, const char *name, HandleValue value, const JSPropertyOpWrapper &getter, const JSStrictPropertyOpWrapper &setter, @@ -3147,14 +3237,61 @@ DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t nam } JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen, - jsval valueArg, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs) +JS_DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, + HandleValue value, unsigned attrs, + JSPropertyOp getter, JSStrictPropertyOp setter) { - RootedObject obj(cx, objArg); - RootedValue value(cx, valueArg); return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); } +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, + HandleObject valueArg, unsigned attrs, + JSPropertyOp getter, JSStrictPropertyOp setter) +{ + RootedValue value(cx, ObjectValue(*valueArg)); + return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, + HandleString valueArg, unsigned attrs, + JSPropertyOp getter, JSStrictPropertyOp setter) +{ + RootedValue value(cx, StringValue(valueArg)); + return DefineUCProperty(cx, obj, name, namelen, value, getter, setter, attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, + int32_t valueArg, unsigned attrs, + JSPropertyOp getter, JSStrictPropertyOp setter) +{ + Value value = Int32Value(valueArg); + return DefineUCProperty(cx, obj, name, namelen, HandleValue::fromMarkedLocation(&value), + getter, setter, attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, + uint32_t valueArg, unsigned attrs, + JSPropertyOp getter, JSStrictPropertyOp setter) +{ + Value value = UINT_TO_JSVAL(valueArg); + return DefineUCProperty(cx, obj, name, namelen, HandleValue::fromMarkedLocation(&value), + getter, setter, attrs, 0); +} + +JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen, + double valueArg, unsigned attrs, + JSPropertyOp getter, JSStrictPropertyOp setter) +{ + Value value = NumberValue(valueArg); + return DefineUCProperty(cx, obj, name, namelen, HandleValue::fromMarkedLocation(&value), + getter, setter, attrs, 0); +} + JS_PUBLIC_API(bool) JS_DefineOwnProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue descriptor, bool *bp) { @@ -3166,11 +3303,9 @@ JS_DefineOwnProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue d } JS_PUBLIC_API(JSObject *) -JS_DefineObject(JSContext *cx, JSObject *objArg, const char *name, const JSClass *jsclasp, - JSObject *protoArg, unsigned attrs) +JS_DefineObject(JSContext *cx, HandleObject obj, const char *name, const JSClass *jsclasp, + HandleObject proto, unsigned attrs) { - RootedObject obj(cx, objArg); - RootedObject proto(cx, protoArg); AssertHeapIsIdle(cx); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, proto); @@ -6068,7 +6203,7 @@ JS_SetGCZeal(JSContext *cx, uint8_t zeal, uint32_t frequency) JS_PUBLIC_API(void) JS_ScheduleGC(JSContext *cx, uint32_t count) { - cx->runtime()->gcNextScheduled = count; + cx->runtime()->gc.nextScheduled = count; } #endif diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 608830ad6a9a..3ebff3a6fa4f 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2786,8 +2786,9 @@ extern JS_PUBLIC_API(JSObject *) JS_New(JSContext *cx, JS::HandleObject ctor, const JS::HandleValueArray& args); extern JS_PUBLIC_API(JSObject *) -JS_DefineObject(JSContext *cx, JSObject *obj, const char *name, const JSClass *clasp, - JSObject *proto, unsigned attrs); +JS_DefineObject(JSContext *cx, JS::HandleObject obj, const char *name, + const JSClass *clasp = nullptr, JS::HandleObject proto = JS::NullPtr(), + unsigned attrs = 0); extern JS_PUBLIC_API(bool) JS_DefineConstDoubles(JSContext *cx, JS::HandleObject obj, const JSConstDoubleSpec *cds); @@ -2826,8 +2827,34 @@ JS_DefineProperty(JSContext *cx, JS::HandleObject obj, const char *name, double JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); extern JS_PUBLIC_API(bool) -JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value, - JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); +JS_DefinePropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleString value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, int32_t value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, uint32_t value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefinePropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, double value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); extern JS_PUBLIC_API(bool) JS_DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, @@ -3048,10 +3075,34 @@ extern JS_PUBLIC_API(bool) JS_DeletePropertyById2(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *succeeded); extern JS_PUBLIC_API(bool) -JS_DefineUCProperty(JSContext *cx, JSObject *obj, - const jschar *name, size_t namelen, jsval value, - JSPropertyOp getter, JSStrictPropertyOp setter, - unsigned attrs); +JS_DefineUCProperty(JSContext *cx, JS::HandleObject obj, const jschar *name, size_t namelen, + JS::HandleValue value, unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, JS::HandleObject obj, const jschar *name, size_t namelen, + JS::HandleObject value, unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, JS::HandleObject obj, const jschar *name, size_t namelen, + JS::HandleString value, unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, JS::HandleObject obj, const jschar *name, size_t namelen, + int32_t value, unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, JS::HandleObject obj, const jschar *name, size_t namelen, + uint32_t value, unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineUCProperty(JSContext *cx, JS::HandleObject obj, const jschar *name, size_t namelen, + double value, unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); extern JS_PUBLIC_API(bool) JS_AlreadyHasOwnUCProperty(JSContext *cx, JS::HandleObject obj, const jschar *name, @@ -3100,8 +3151,34 @@ extern JS_PUBLIC_API(bool) JS_SetArrayLength(JSContext *cx, JS::Handle obj, uint32_t length); extern JS_PUBLIC_API(bool) -JS_DefineElement(JSContext *cx, JSObject *obj, uint32_t index, jsval value, - JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); +JS_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleObject value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleString value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, int32_t value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, uint32_t value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); + +extern JS_PUBLIC_API(bool) +JS_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, double value, + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); extern JS_PUBLIC_API(bool) JS_AlreadyHasOwnElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *foundp); diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index c1779a61d672..654f89cb0131 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -145,6 +145,7 @@ struct ThreadSafeContext : ContextFriendFields, public MallocProvider { friend struct StackBaseShape; + friend class Activation; friend UnownedBaseShape *BaseShape::lookupUnowned(ThreadSafeContext *cx, const StackBaseShape &base); friend Shape *JSObject::lookupChildProperty(ThreadSafeContext *cx, @@ -223,7 +224,7 @@ struct ThreadSafeContext : ContextFriendFields, inline js::Nursery &nursery() { JS_ASSERT(hasNursery()); - return runtime_->gcNursery; + return runtime_->gc.nursery; } #endif @@ -289,7 +290,7 @@ struct ThreadSafeContext : ContextFriendFields, void *runtimeAddressForJit() { return runtime_; } void *stackLimitAddress(StackKind kind) { return &runtime_->mainThread.nativeStackLimit[kind]; } void *stackLimitAddressForJitCode(StackKind kind); - size_t gcSystemPageSize() { return runtime_->gcSystemPageSize; } + size_t gcSystemPageSize() { return runtime_->gc.pageAllocator.systemPageSize(); } bool signalHandlersInstalled() const { return runtime_->signalHandlersInstalled(); } bool jitSupportsFloatingPoint() const { return runtime_->jitSupportsFloatingPoint; } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 5f1c33d0b69d..ec231ee99559 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -258,7 +258,7 @@ JSCompartment::putWrapper(JSContext *cx, const CrossCompartmentKey &wrapped, con if (success && (nursery.isInside(wrapped.wrapped) || nursery.isInside(wrapped.debugger))) { WrapperMapRef ref(&crossCompartmentWrappers, wrapped); - cx->runtime()->gcStoreBuffer.putGeneric(ref); + cx->runtime()->gc.storeBuffer.putGeneric(ref); } #endif @@ -557,7 +557,7 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes) JSRuntime *rt = runtimeFromMainThread(); { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_TABLES); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_TABLES); /* Remove dead references held weakly by the compartment. */ @@ -616,8 +616,8 @@ JSCompartment::sweepCrossCompartmentWrappers() { JSRuntime *rt = runtimeFromMainThread(); - gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_SWEEP_TABLES); - gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TABLES_WRAPPER); + gcstats::AutoPhase ap1(rt->gc.stats, gcstats::PHASE_SWEEP_TABLES); + gcstats::AutoPhase ap2(rt->gc.stats, gcstats::PHASE_SWEEP_TABLES_WRAPPER); /* Remove dead wrappers from the table. */ for (WrapperMap::Enum e(crossCompartmentWrappers); !e.empty(); e.popFront()) { @@ -721,7 +721,7 @@ CreateLazyScriptsForCompartment(JSContext *cx) // which do not have an uncompiled enclosing script. The last condition is // so that we don't compile lazy scripts whose enclosing scripts failed to // compile, indicating that the lazy script did not escape the script. - for (gc::CellIter i(cx->zone(), gc::FINALIZE_LAZY_SCRIPT); !i.done(); i.next()) { + for (gc::ZoneCellIter i(cx->zone(), gc::FINALIZE_LAZY_SCRIPT); !i.done(); i.next()) { LazyScript *lazy = i.get(); JSFunction *fun = lazy->functionNonDelazifying(); if (fun->compartment() == cx->compartment() && @@ -894,7 +894,7 @@ JSCompartment::removeDebuggeeUnderGC(FreeOp *fop, void JSCompartment::clearBreakpointsIn(FreeOp *fop, js::Debugger *dbg, JSObject *handler) { - for (gc::CellIter i(zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (gc::ZoneCellIter i(zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->compartment() == this && script->hasAnyBreakpointsOrStepMode()) script->clearBreakpointsIn(fop, dbg, handler); @@ -905,7 +905,7 @@ void JSCompartment::clearTraps(FreeOp *fop) { MinorGC(fop->runtime(), JS::gcreason::EVICT_NURSERY); - for (gc::CellIter i(zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (gc::ZoneCellIter i(zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->compartment() == this && script->hasAnyBreakpointsOrStepMode()) script->clearTraps(fop); diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index aea38933c69f..7daca6bd7a5a 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -59,8 +59,8 @@ js::ForgetSourceHook(JSRuntime *rt) JS_FRIEND_API(void) JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data) { - rt->gcGrayRootTracer.op = traceOp; - rt->gcGrayRootTracer.data = data; + rt->gc.grayRootTracer.op = traceOp; + rt->gc.grayRootTracer.data = data; } JS_FRIEND_API(JSString *) @@ -632,7 +632,7 @@ js::TraceWeakMaps(WeakMapTracer *trc) extern JS_FRIEND_API(bool) js::AreGCGrayBitsValid(JSRuntime *rt) { - return rt->gcGrayBitsValid; + return rt->gc.grayBitsValid; } JS_FRIEND_API(bool) @@ -857,27 +857,27 @@ js::IsContextRunningJS(JSContext *cx) JS_FRIEND_API(JS::GCSliceCallback) JS::SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback) { - JS::GCSliceCallback old = rt->gcSliceCallback; - rt->gcSliceCallback = callback; + JS::GCSliceCallback old = rt->gc.sliceCallback; + rt->gc.sliceCallback = callback; return old; } JS_FRIEND_API(bool) JS::WasIncrementalGC(JSRuntime *rt) { - return rt->gcIsIncremental; + return rt->gc.isIncremental; } jschar * GCDescription::formatMessage(JSRuntime *rt) const { - return rt->gcStats.formatMessage(); + return rt->gc.stats.formatMessage(); } jschar * GCDescription::formatJSON(JSRuntime *rt, uint64_t timestamp) const { - return rt->gcStats.formatJSON(timestamp); + return rt->gc.stats.formatJSON(timestamp); } JS_FRIEND_API(void) @@ -899,36 +899,36 @@ JS::NotifyDidPaint(JSRuntime *rt) return; } - if (JS::IsIncrementalGCInProgress(rt) && !rt->gcInterFrameGC) { + if (JS::IsIncrementalGCInProgress(rt) && !rt->gc.interFrameGC) { JS::PrepareForIncrementalGC(rt); GCSlice(rt, GC_NORMAL, gcreason::REFRESH_FRAME); } - rt->gcInterFrameGC = false; + rt->gc.interFrameGC = false; } JS_FRIEND_API(bool) JS::IsIncrementalGCEnabled(JSRuntime *rt) { - return rt->gcIncrementalEnabled && rt->gcMode() == JSGC_MODE_INCREMENTAL; + return rt->gc.incrementalEnabled && rt->gcMode() == JSGC_MODE_INCREMENTAL; } JS_FRIEND_API(bool) JS::IsIncrementalGCInProgress(JSRuntime *rt) { - return rt->gcIncrementalState != gc::NO_INCREMENTAL && !rt->gcVerifyPreData; + return rt->gc.incrementalState != gc::NO_INCREMENTAL && !rt->gc.verifyPreData; } JS_FRIEND_API(void) JS::DisableIncrementalGC(JSRuntime *rt) { - rt->gcIncrementalEnabled = false; + rt->gc.incrementalEnabled = false; } JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt) : runtime(rt) #if defined(JSGC_GENERATIONAL) && defined(JS_GC_ZEAL) - , restartVerifier(rt->gcVerifyPostData) + , restartVerifier(rt->gc.verifyPostData) #endif { #ifdef JSGC_GENERATIONAL @@ -938,21 +938,21 @@ JS::AutoDisableGenerationalGC::AutoDisableGenerationalGC(JSRuntime *rt) gc::EndVerifyPostBarriers(rt); #endif MinorGC(rt, JS::gcreason::API); - rt->gcNursery.disable(); - rt->gcStoreBuffer.disable(); + rt->gc.nursery.disable(); + rt->gc.storeBuffer.disable(); } #endif - ++rt->gcGenerationalDisabled; + ++rt->gc.generationalDisabled; } JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC() { - JS_ASSERT(runtime->gcGenerationalDisabled > 0); - --runtime->gcGenerationalDisabled; + JS_ASSERT(runtime->gc.generationalDisabled > 0); + --runtime->gc.generationalDisabled; #ifdef JSGC_GENERATIONAL - if (runtime->gcGenerationalDisabled == 0) { - runtime->gcNursery.enable(); - runtime->gcStoreBuffer.enable(); + if (runtime->gc.generationalDisabled == 0) { + runtime->gc.nursery.enable(); + runtime->gc.storeBuffer.enable(); #ifdef JS_GC_ZEAL if (restartVerifier) gc::StartVerifyPostBarriers(runtime); @@ -964,13 +964,13 @@ JS::AutoDisableGenerationalGC::~AutoDisableGenerationalGC() extern JS_FRIEND_API(bool) JS::IsGenerationalGCEnabled(JSRuntime *rt) { - return rt->gcGenerationalDisabled == 0; + return rt->gc.generationalDisabled == 0; } JS_FRIEND_API(bool) JS::IsIncrementalBarrierNeeded(JSRuntime *rt) { - return rt->gcIncrementalState == gc::MARK && !rt->isHeapBusy(); + return rt->gc.incrementalState == gc::MARK && !rt->isHeapBusy(); } JS_FRIEND_API(bool) @@ -1034,7 +1034,7 @@ JS::IncrementalValueBarrier(const Value &v) JS_FRIEND_API(void) JS::PokeGC(JSRuntime *rt) { - rt->gcPoke = true; + rt->gc.poke = true; } JS_FRIEND_API(JSCompartment *) @@ -1203,7 +1203,7 @@ js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg, { RootedObject obj(cx, objArg); RootedId id(cx, idArg); - JS_ASSERT(cx->runtime()->heapState == js::Idle); + JS_ASSERT(cx->runtime()->gc.heapState == js::Idle); CHECK_REQUEST(cx); assertSameCompartment(cx, obj, id, descriptor.value()); if (descriptor.hasGetterObject()) @@ -1240,7 +1240,7 @@ JS_StoreObjectPostBarrierCallback(JSContext* cx, { JSRuntime *rt = cx->runtime(); if (IsInsideNursery(rt, key)) - rt->gcStoreBuffer.putCallback(callback, key, data); + rt->gc.storeBuffer.putCallback(callback, key, data); } extern JS_FRIEND_API(void) @@ -1250,6 +1250,6 @@ JS_StoreStringPostBarrierCallback(JSContext* cx, { JSRuntime *rt = cx->runtime(); if (IsInsideNursery(rt, key)) - rt->gcStoreBuffer.putCallback(callback, key, data); + rt->gc.storeBuffer.putCallback(callback, key, data); } #endif /* JSGC_GENERATIONAL */ diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index c9b7c4efeb71..6d5a5365efa0 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1444,7 +1444,7 @@ JS_GetArrayBufferViewData(JSObject *obj); * object that would return true for JS_IsArrayBufferViewObject(). */ extern JS_FRIEND_API(JSObject *) -JS_GetArrayBufferViewBuffer(JSContext *cx, JSObject *obj); +JS_GetArrayBufferViewBuffer(JSContext *cx, JS::HandleObject obj); typedef enum { ChangeData, @@ -2060,7 +2060,8 @@ DefaultValue(JSContext *cx, JS::HandleObject obj, JSType hint, JS::MutableHandle */ extern JS_FRIEND_API(bool) CheckDefineProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, - JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); + unsigned attrs, + JSPropertyOp getter = nullptr, JSStrictPropertyOp setter = nullptr); } /* namespace js */ diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 015d5156c80d..9e1aafca6fe6 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -193,7 +193,7 @@ ResolveInterpretedFunctionPrototype(JSContext *cx, HandleObject obj) { #ifdef DEBUG JSFunction *fun = &obj->as(); - JS_ASSERT(fun->isInterpreted()); + JS_ASSERT(fun->isInterpreted() || fun->isAsmJSNative()); JS_ASSERT(!fun->isFunctionPrototype()); #endif diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 2ed65a64ac65..a17e99b43f4d 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -46,13 +46,14 @@ class JSFunction : public JSObject SELF_HOSTED_CTOR = 0x0200, /* function is self-hosted builtin constructor and must be constructible but not decompilable. */ HAS_REST = 0x0400, /* function has a rest (...) parameter */ - // 0x0800 is available + ASMJS = 0x0800, /* function is an asm.js module or exported function */ INTERPRETED_LAZY = 0x1000, /* function is interpreted but doesn't have a script yet */ ARROW = 0x2000, /* ES6 '(args) => body' syntax */ /* Derived Flags values for convenience: */ NATIVE_FUN = 0, - NATIVE_LAMBDA_FUN = NATIVE_FUN | LAMBDA, + ASMJS_CTOR = ASMJS | NATIVE_CTOR, + ASMJS_LAMBDA_CTOR = ASMJS | NATIVE_CTOR | LAMBDA, INTERPRETED_LAMBDA = INTERPRETED | LAMBDA, INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW }; @@ -118,6 +119,7 @@ class JSFunction : public JSObject /* Possible attributes of a native function: */ bool isNativeConstructor() const { return flags() & NATIVE_CTOR; } + bool isAsmJSNative() const { return flags() & ASMJS; } /* Possible attributes of an interpreted function: */ bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; } @@ -147,7 +149,7 @@ class JSFunction : public JSObject /* Compound attributes: */ bool isBuiltin() const { - return isNative() || isSelfHostedBuiltin(); + return (isNative() && !isAsmJSNative()) || isSelfHostedBuiltin(); } bool isInterpretedConstructor() const { // Note: the JITs inline this check, so be careful when making changes diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 5693476fb3c8..d17d96f5906f 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -393,7 +393,7 @@ ArenaHeader::checkSynchronizedWithFreeList() const * list in the zone can mutate at any moment. We cannot do any * checks in this case. */ - if (IsBackgroundFinalized(getAllocKind()) && zone->runtimeFromAnyThread()->gcHelperThread.onBackgroundThread()) + if (IsBackgroundFinalized(getAllocKind()) && zone->runtimeFromAnyThread()->gc.helperThread.onBackgroundThread()) return; FreeSpan firstSpan = FreeSpan::decodeOffsets(arenaAddress(), firstFreeSpanOffsets); @@ -443,62 +443,44 @@ Arena::finalize(FreeOp *fop, AllocKind thingKind, size_t thingSize) JS_ASSERT(!aheader.markOverflow); JS_ASSERT(!aheader.allocatedDuringIncremental); - uintptr_t thing = thingsStart(thingKind); + uintptr_t firstThing = thingsStart(thingKind); + uintptr_t firstThingOrSuccessorOfLastMarkedThing = firstThing; uintptr_t lastByte = thingsEnd() - 1; - FreeSpan nextFree(aheader.getFirstFreeSpan()); - nextFree.checkSpan(); - FreeSpan newListHead; FreeSpan *newListTail = &newListHead; - uintptr_t newFreeSpanStart = 0; - bool allClear = true; - DebugOnly nmarked = 0; - for (;; thing += thingSize) { - JS_ASSERT(thing <= lastByte + 1); - if (thing == nextFree.first) { - JS_ASSERT(nextFree.last <= lastByte); - if (nextFree.last == lastByte) - break; - JS_ASSERT(Arena::isAligned(nextFree.last, thingSize)); - if (!newFreeSpanStart) - newFreeSpanStart = thing; - thing = nextFree.last; - nextFree = *nextFree.nextSpan(); - nextFree.checkSpan(); - } else { - T *t = reinterpret_cast(thing); - if (t->isMarked()) { - allClear = false; - nmarked++; - if (newFreeSpanStart) { - JS_ASSERT(thing >= thingsStart(thingKind) + thingSize); - newListTail->first = newFreeSpanStart; - newListTail->last = thing - thingSize; - newListTail = newListTail->nextSpanUnchecked(thingSize); - newFreeSpanStart = 0; - } - } else { - if (!newFreeSpanStart) - newFreeSpanStart = thing; - t->finalize(fop); - JS_POISON(t, JS_SWEPT_TENURED_PATTERN, thingSize); + size_t nmarked = 0; + + for (ArenaCellIterUnderFinalize i(&aheader); !i.done(); i.next()) { + T *t = i.get(); + if (t->isMarked()) { + uintptr_t thing = reinterpret_cast(t); + if (thing != firstThingOrSuccessorOfLastMarkedThing) { + // We just finished passing over one or more free things, + // so record a new FreeSpan. + newListTail->first = firstThingOrSuccessorOfLastMarkedThing; + newListTail->last = thing - thingSize; + newListTail = newListTail->nextSpanUnchecked(thingSize); } + firstThingOrSuccessorOfLastMarkedThing = thing + thingSize; + nmarked++; + } else { + t->finalize(fop); + JS_POISON(t, JS_SWEPT_TENURED_PATTERN, thingSize); } } - if (allClear) { + // Complete the last FreeSpan. + newListTail->first = firstThingOrSuccessorOfLastMarkedThing; + newListTail->last = lastByte; + + if (nmarked == 0) { JS_ASSERT(newListTail == &newListHead); - JS_ASSERT(!newFreeSpanStart || - newFreeSpanStart == thingsStart(thingKind)); + JS_ASSERT(newListTail->first == thingsStart(thingKind)); JS_EXTRA_POISON(data, JS_SWEPT_TENURED_PATTERN, sizeof(data)); return true; } - newListTail->first = newFreeSpanStart ? newFreeSpanStart : nextFree.first; - JS_ASSERT(Arena::isAligned(newListTail->first, thingSize)); - newListTail->last = lastByte; - #ifdef DEBUG size_t nfree = 0; for (const FreeSpan *span = &newListHead; span != newListTail; span = span->nextSpan()) { @@ -506,13 +488,13 @@ Arena::finalize(FreeOp *fop, AllocKind thingKind, size_t thingSize) JS_ASSERT(Arena::isAligned(span->first, thingSize)); JS_ASSERT(Arena::isAligned(span->last, thingSize)); nfree += (span->last - span->first) / thingSize + 1; - JS_ASSERT(nfree + nmarked <= thingsPerArena(thingSize)); } + JS_ASSERT(Arena::isAligned(newListTail->first, thingSize)); + JS_ASSERT(newListTail->last == lastByte); nfree += (newListTail->last + 1 - newListTail->first) / thingSize; JS_ASSERT(nfree + nmarked == thingsPerArena(thingSize)); #endif aheader.setFirstFreeSpan(&newListHead); - return false; } @@ -628,13 +610,13 @@ FinalizeArenas(FreeOp *fop, static inline Chunk * AllocChunk(JSRuntime *rt) { - return static_cast(MapAlignedPages(rt, ChunkSize, ChunkSize)); + return static_cast(rt->gc.pageAllocator.mapAlignedPages(ChunkSize, ChunkSize)); } static inline void FreeChunk(JSRuntime *rt, Chunk *p) { - UnmapPages(rt, static_cast(p), ChunkSize); + rt->gc.pageAllocator.unmapPages(static_cast(p), ChunkSize); } inline bool @@ -645,16 +627,16 @@ ChunkPool::wantBackgroundAllocation(JSRuntime *rt) const * allocation if we have empty chunks or when the runtime needs just few * of them. */ - return rt->gcHelperThread.canBackgroundAllocate() && + return rt->gc.helperThread.canBackgroundAllocate() && emptyCount == 0 && - rt->gcChunkSet.count() >= 4; + rt->gc.chunkSet.count() >= 4; } /* Must be called with the GC lock taken. */ inline Chunk * ChunkPool::get(JSRuntime *rt) { - JS_ASSERT(this == &rt->gcChunkPool); + JS_ASSERT(this == &rt->gc.chunkPool); Chunk *chunk = emptyChunkListHead; if (chunk) { @@ -669,10 +651,10 @@ ChunkPool::get(JSRuntime *rt) JS_ASSERT(chunk->info.numArenasFreeCommitted == 0); } JS_ASSERT(chunk->unused()); - JS_ASSERT(!rt->gcChunkSet.has(chunk)); + JS_ASSERT(!rt->gc.chunkSet.has(chunk)); if (wantBackgroundAllocation(rt)) - rt->gcHelperThread.startBackgroundAllocationIfIdle(); + rt->gc.helperThread.startBackgroundAllocationIfIdle(); return chunk; } @@ -691,7 +673,7 @@ ChunkPool::put(Chunk *chunk) Chunk * ChunkPool::expire(JSRuntime *rt, bool releaseAll) { - JS_ASSERT(this == &rt->gcChunkPool); + JS_ASSERT(this == &rt->gc.chunkPool); /* * Return old empty chunks to the system while preserving the order of @@ -705,7 +687,7 @@ ChunkPool::expire(JSRuntime *rt, bool releaseAll) JS_ASSERT(emptyCount); Chunk *chunk = *chunkp; JS_ASSERT(chunk->unused()); - JS_ASSERT(!rt->gcChunkSet.has(chunk)); + JS_ASSERT(!rt->gc.chunkSet.has(chunk)); JS_ASSERT(chunk->info.age <= MAX_EMPTY_CHUNK_AGE); if (releaseAll || chunk->info.age == MAX_EMPTY_CHUNK_AGE || freeChunkCount++ > MAX_EMPTY_CHUNK_COUNT) @@ -748,7 +730,7 @@ Chunk::allocate(JSRuntime *rt) if (!chunk) return nullptr; chunk->init(rt); - rt->gcStats.count(gcstats::STAT_NEW_CHUNK); + rt->gc.stats.count(gcstats::STAT_NEW_CHUNK); return chunk; } @@ -764,9 +746,9 @@ Chunk::release(JSRuntime *rt, Chunk *chunk) inline void Chunk::prepareToBeFreed(JSRuntime *rt) { - JS_ASSERT(rt->gcNumArenasFreeCommitted >= info.numArenasFreeCommitted); - rt->gcNumArenasFreeCommitted -= info.numArenasFreeCommitted; - rt->gcStats.count(gcstats::STAT_DESTROY_CHUNK); + JS_ASSERT(rt->gc.numArenasFreeCommitted >= info.numArenasFreeCommitted); + rt->gc.numArenasFreeCommitted -= info.numArenasFreeCommitted; + rt->gc.stats.count(gcstats::STAT_DESTROY_CHUNK); #ifdef DEBUG /* @@ -777,6 +759,17 @@ Chunk::prepareToBeFreed(JSRuntime *rt) #endif } +void Chunk::decommitAllArenas(JSRuntime *rt) +{ + decommittedArenas.clear(true); + rt->gc.pageAllocator.markPagesUnused(&arenas[0], ArenasPerChunk * ArenaSize); + + info.freeArenasHead = nullptr; + info.lastDecommittedArenaOffset = 0; + info.numArenasFree = ArenasPerChunk; + info.numArenasFreeCommitted = 0; +} + void Chunk::init(JSRuntime *rt) { @@ -807,8 +800,8 @@ GetAvailableChunkList(Zone *zone) { JSRuntime *rt = zone->runtimeFromAnyThread(); return zone->isSystem - ? &rt->gcSystemAvailableChunkListHead - : &rt->gcUserAvailableChunkListHead; + ? &rt->gc.systemAvailableChunkListHead + : &rt->gc.userAvailableChunkListHead; } inline void @@ -877,7 +870,7 @@ Chunk::fetchNextDecommittedArena() decommittedArenas.unset(offset); Arena *arena = &arenas[offset]; - MarkPagesInUse(info.trailer.runtime, arena, ArenaSize); + info.trailer.runtime->gc.pageAllocator.markPagesInUse(arena, ArenaSize); arena->aheader.setAsNotAllocated(); return &arena->aheader; @@ -888,13 +881,13 @@ Chunk::fetchNextFreeArena(JSRuntime *rt) { JS_ASSERT(info.numArenasFreeCommitted > 0); JS_ASSERT(info.numArenasFreeCommitted <= info.numArenasFree); - JS_ASSERT(info.numArenasFreeCommitted <= rt->gcNumArenasFreeCommitted); + JS_ASSERT(info.numArenasFreeCommitted <= rt->gc.numArenasFreeCommitted); ArenaHeader *aheader = info.freeArenasHead; info.freeArenasHead = aheader->next; --info.numArenasFreeCommitted; --info.numArenasFree; - --rt->gcNumArenasFreeCommitted; + --rt->gc.numArenasFreeCommitted; return aheader; } @@ -905,7 +898,7 @@ Chunk::allocateArena(Zone *zone, AllocKind thingKind) JS_ASSERT(hasAvailableArenas()); JSRuntime *rt = zone->runtimeFromAnyThread(); - if (!rt->isHeapMinorCollecting() && rt->gcBytes >= rt->gcMaxBytes) + if (!rt->isHeapMinorCollecting() && rt->gc.bytes >= rt->gc.maxBytes) return nullptr; ArenaHeader *aheader = MOZ_LIKELY(info.numArenasFreeCommitted > 0) @@ -915,7 +908,7 @@ Chunk::allocateArena(Zone *zone, AllocKind thingKind) if (MOZ_UNLIKELY(!hasAvailableArenas())) removeFromAvailableList(); - rt->gcBytes += ArenaSize; + rt->gc.bytes += ArenaSize; zone->gcBytes += ArenaSize; if (zone->gcBytes >= zone->gcTriggerBytes) { @@ -934,7 +927,7 @@ Chunk::addArenaToFreeList(JSRuntime *rt, ArenaHeader *aheader) info.freeArenasHead = aheader; ++info.numArenasFreeCommitted; ++info.numArenasFree; - ++rt->gcNumArenasFreeCommitted; + ++rt->gc.numArenasFreeCommitted; } void @@ -952,14 +945,14 @@ Chunk::releaseArena(ArenaHeader *aheader) Zone *zone = aheader->zone; JSRuntime *rt = zone->runtimeFromAnyThread(); AutoLockGC maybeLock; - if (rt->gcHelperThread.sweeping()) + if (rt->gc.helperThread.sweeping()) maybeLock.lock(rt); - JS_ASSERT(rt->gcBytes >= ArenaSize); + JS_ASSERT(rt->gc.bytes >= ArenaSize); JS_ASSERT(zone->gcBytes >= ArenaSize); - if (rt->gcHelperThread.sweeping()) + if (rt->gc.helperThread.sweeping()) zone->reduceGCTriggerBytes(zone->gcHeapGrowthFactor * ArenaSize); - rt->gcBytes -= ArenaSize; + rt->gc.bytes -= ArenaSize; zone->gcBytes -= ArenaSize; aheader->setAsNotAllocated(); @@ -972,11 +965,11 @@ Chunk::releaseArena(ArenaHeader *aheader) } else if (!unused()) { JS_ASSERT(info.prevp); } else { - rt->gcChunkSet.remove(this); + rt->gc.chunkSet.remove(this); removeFromAvailableList(); JS_ASSERT(info.numArenasFree == ArenasPerChunk); decommitAllArenas(rt); - rt->gcChunkPool.put(this); + rt->gc.chunkPool.put(this); } } @@ -990,19 +983,19 @@ PickChunk(Zone *zone) if (chunk) return chunk; - chunk = rt->gcChunkPool.get(rt); + chunk = rt->gc.chunkPool.get(rt); if (!chunk) return nullptr; - rt->gcChunkAllocationSinceLastGC = true; + rt->gc.chunkAllocationSinceLastGC = true; /* * 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); + GCChunkSet::AddPtr p = rt->gc.chunkSet.lookupForAdd(chunk); JS_ASSERT(!p); - if (!rt->gcChunkSet.add(p, chunk)) { + if (!rt->gc.chunkSet.add(p, chunk)) { Chunk::release(rt, chunk); return nullptr; } @@ -1014,30 +1007,121 @@ PickChunk(Zone *zone) return chunk; } +js::gc::GCRuntime::GCRuntime(JSRuntime *rt) : + systemZone(nullptr), + systemAvailableChunkListHead(nullptr), + userAvailableChunkListHead(nullptr), + bytes(0), + maxBytes(0), + maxMallocBytes(0), + numArenasFreeCommitted(0), + marker(rt), + verifyPreData(nullptr), + verifyPostData(nullptr), + chunkAllocationSinceLastGC(false), + nextFullGCTime(0), + lastGCTime(0), + jitReleaseTime(0), + allocationThreshold(30 * 1024 * 1024), + highFrequencyGC(false), + highFrequencyTimeThreshold(1000), + highFrequencyLowLimitBytes(100 * 1024 * 1024), + highFrequencyHighLimitBytes(500 * 1024 * 1024), + highFrequencyHeapGrowthMax(3.0), + highFrequencyHeapGrowthMin(1.5), + lowFrequencyHeapGrowth(1.5), + dynamicHeapGrowth(false), + dynamicMarkSlice(false), + decommitThreshold(32 * 1024 * 1024), + shouldCleanUpEverything(false), + grayBitsValid(false), + isNeeded(0), + stats(rt), + number(0), + startNumber(0), + isFull(false), + triggerReason(JS::gcreason::NO_REASON), + strictCompartmentChecking(false), +#ifdef DEBUG + disableStrictProxyCheckingCount(0), +#endif + incrementalState(gc::NO_INCREMENTAL), + lastMarkSlice(false), + sweepOnBackgroundThread(false), + foundBlackGrayEdges(false), + sweepingZones(nullptr), + zoneGroupIndex(0), + zoneGroups(nullptr), + currentZoneGroup(nullptr), + sweepPhase(0), + sweepZone(nullptr), + sweepKindIndex(0), + abortSweepAfterCurrentGroup(false), + arenasAllocatedDuringSweep(nullptr), +#ifdef DEBUG + markingValidator(nullptr), +#endif + interFrameGC(0), + sliceBudget(SliceBudget::Unlimited), + incrementalEnabled(true), + generationalDisabled(0), + manipulatingDeadZones(false), + objectsMarkedInDeadZones(0), + poke(false), + heapState(Idle), +#ifdef JSGC_GENERATIONAL + nursery(rt), + storeBuffer(rt, nursery), +#endif +#ifdef JS_GC_ZEAL + zealMode(0), + zealFrequency(0), + nextScheduled(0), + deterministicOnly(false), + incrementalLimit(0), +#endif + validate(true), + fullCompartmentChecks(false), + callback(nullptr), + sliceCallback(nullptr), + finalizeCallback(nullptr), + mallocBytes(0), + mallocGCTriggered(false), + scriptAndCountsVector(nullptr), + alwaysPreserveCode(false), +#ifdef DEBUG + noGCOrAllocationCheck(0), +#endif + lock(nullptr), + lockOwner(nullptr), + helperThread(rt) +{ +} + #ifdef JS_GC_ZEAL extern void js::SetGCZeal(JSRuntime *rt, uint8_t zeal, uint32_t frequency) { - if (rt->gcVerifyPreData) + if (rt->gc.verifyPreData) VerifyBarriers(rt, PreBarrierVerifier); - if (rt->gcVerifyPostData) + if (rt->gc.verifyPostData) VerifyBarriers(rt, PostBarrierVerifier); #ifdef JSGC_GENERATIONAL - if (rt->gcZeal_ == ZealGenerationalGCValue) { + if (rt->gc.zealMode == ZealGenerationalGCValue) { MinorGC(rt, JS::gcreason::DEBUG_GC); - rt->gcNursery.leaveZealMode(); + rt->gc.nursery.leaveZealMode(); } if (zeal == ZealGenerationalGCValue) - rt->gcNursery.enterZealMode(); + rt->gc.nursery.enterZealMode(); #endif bool schedule = zeal >= js::gc::ZealAllocValue; - rt->gcZeal_ = zeal; - rt->gcZealFrequency = frequency; - rt->gcNextScheduled = schedule ? frequency : 0; + rt->gc.zealMode = zeal; + rt->gc.zealFrequency = frequency; + rt->gc.nextScheduled = schedule ? frequency : 0; } static bool @@ -1089,33 +1173,31 @@ static const int64_t JIT_SCRIPT_RELEASE_TYPES_INTERVAL = 60 * 1000 * 1000; bool js_InitGC(JSRuntime *rt, uint32_t maxbytes) { - InitMemorySubsystem(rt); - - if (!rt->gcChunkSet.init(INITIAL_CHUNK_CAPACITY)) + if (!rt->gc.chunkSet.init(INITIAL_CHUNK_CAPACITY)) return false; - if (!rt->gcRootsHash.init(256)) + if (!rt->gc.rootsHash.init(256)) return false; - if (!rt->gcHelperThread.init()) + if (!rt->gc.helperThread.init()) return false; /* * Separate gcMaxMallocBytes from gcMaxBytes but initialize to maxbytes * for default backward API compatibility. */ - rt->gcMaxBytes = maxbytes; + rt->gc.maxBytes = maxbytes; rt->setGCMaxMallocBytes(maxbytes); #ifndef JS_MORE_DETERMINISTIC - rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_RELEASE_TYPES_INTERVAL; + rt->gc.jitReleaseTime = PRMJ_Now() + JIT_SCRIPT_RELEASE_TYPES_INTERVAL; #endif #ifdef JSGC_GENERATIONAL - if (!rt->gcNursery.init()) + if (!rt->gc.nursery.init()) return false; - if (!rt->gcStoreBuffer.enable()) + if (!rt->gc.storeBuffer.enable()) return false; #endif @@ -1130,7 +1212,7 @@ js_InitGC(JSRuntime *rt, uint32_t maxbytes) static void RecordNativeStackTopForGC(JSRuntime *rt) { - ConservativeGCData *cgcd = &rt->conservativeGC; + ConservativeGCData *cgcd = &rt->gc.conservativeGC; #ifdef JS_THREADSAFE /* Record the stack top here only if we are called from a request. */ @@ -1147,7 +1229,7 @@ js_FinishGC(JSRuntime *rt) * Wait until the background finalization stops and the helper thread * shuts down before we forcefully release any remaining GC memory. */ - rt->gcHelperThread.finish(); + rt->gc.helperThread.finish(); #ifdef JS_GC_ZEAL /* Free memory associated with GC verification. */ @@ -1163,20 +1245,20 @@ js_FinishGC(JSRuntime *rt) } } - rt->zones.clear(); + rt->gc.zones.clear(); - rt->gcSystemAvailableChunkListHead = nullptr; - rt->gcUserAvailableChunkListHead = nullptr; - if (rt->gcChunkSet.initialized()) { - for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront()) + rt->gc.systemAvailableChunkListHead = nullptr; + rt->gc.userAvailableChunkListHead = nullptr; + if (rt->gc.chunkSet.initialized()) { + for (GCChunkSet::Range r(rt->gc.chunkSet.all()); !r.empty(); r.popFront()) Chunk::release(rt, r.front()); - rt->gcChunkSet.clear(); + rt->gc.chunkSet.clear(); } - rt->gcChunkPool.expireAndFree(rt, true); + rt->gc.chunkPool.expireAndFree(rt, true); - if (rt->gcRootsHash.initialized()) - rt->gcRootsHash.clear(); + if (rt->gc.rootsHash.initialized()) + rt->gc.rootsHash.clear(); rt->functionPersistentRooteds.clear(); rt->idPersistentRooteds.clear(); @@ -1200,10 +1282,10 @@ AddRoot(JSRuntime *rt, T *rp, const char *name, JSGCRootType rootType) * or ModifyBusyCount in workers). We need a read barrier to cover these * cases. */ - if (rt->gcIncrementalState != NO_INCREMENTAL) + if (rt->gc.incrementalState != NO_INCREMENTAL) BarrierOwner::result::writeBarrierPre(*rp); - return rt->gcRootsHash.put((void *)rp, RootInfo(name, rootType)); + return rt->gc.rootsHash.put((void *)rp, RootInfo(name, rootType)); } template @@ -1267,8 +1349,8 @@ js::RemoveRawValueRoot(JSContext *cx, Value *vp) void js::RemoveRoot(JSRuntime *rt, void *rp) { - rt->gcRootsHash.remove(rp); - rt->gcPoke = true; + rt->gc.rootsHash.remove(rp); + rt->gc.poke = true; } typedef RootedValueMap::Range RootRange; @@ -1278,7 +1360,7 @@ typedef RootedValueMap::Enum RootEnum; static size_t ComputeTriggerBytes(Zone *zone, size_t lastBytes, size_t maxBytes, JSGCInvocationKind gckind) { - size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, zone->runtimeFromMainThread()->gcAllocationThreshold); + size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, zone->runtimeFromMainThread()->gc.allocationThreshold); double trigger = double(base) * zone->gcHeapGrowthFactor; return size_t(Min(double(maxBytes), trigger)); } @@ -1296,33 +1378,33 @@ Zone::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind) */ JSRuntime *rt = runtimeFromMainThread(); - if (!rt->gcDynamicHeapGrowth) { + if (!rt->gc.dynamicHeapGrowth) { gcHeapGrowthFactor = 3.0; } else if (lastBytes < 1 * 1024 * 1024) { - gcHeapGrowthFactor = rt->gcLowFrequencyHeapGrowth; + gcHeapGrowthFactor = rt->gc.lowFrequencyHeapGrowth; } else { - JS_ASSERT(rt->gcHighFrequencyHighLimitBytes > rt->gcHighFrequencyLowLimitBytes); + JS_ASSERT(rt->gc.highFrequencyHighLimitBytes > rt->gc.highFrequencyLowLimitBytes); uint64_t now = PRMJ_Now(); - if (rt->gcLastGCTime && rt->gcLastGCTime + rt->gcHighFrequencyTimeThreshold * PRMJ_USEC_PER_MSEC > now) { - if (lastBytes <= rt->gcHighFrequencyLowLimitBytes) { - gcHeapGrowthFactor = rt->gcHighFrequencyHeapGrowthMax; - } else if (lastBytes >= rt->gcHighFrequencyHighLimitBytes) { - gcHeapGrowthFactor = rt->gcHighFrequencyHeapGrowthMin; + if (rt->gc.lastGCTime && rt->gc.lastGCTime + rt->gc.highFrequencyTimeThreshold * PRMJ_USEC_PER_MSEC > now) { + if (lastBytes <= rt->gc.highFrequencyLowLimitBytes) { + gcHeapGrowthFactor = rt->gc.highFrequencyHeapGrowthMax; + } else if (lastBytes >= rt->gc.highFrequencyHighLimitBytes) { + gcHeapGrowthFactor = rt->gc.highFrequencyHeapGrowthMin; } else { - double k = (rt->gcHighFrequencyHeapGrowthMin - rt->gcHighFrequencyHeapGrowthMax) - / (double)(rt->gcHighFrequencyHighLimitBytes - rt->gcHighFrequencyLowLimitBytes); - gcHeapGrowthFactor = (k * (lastBytes - rt->gcHighFrequencyLowLimitBytes) - + rt->gcHighFrequencyHeapGrowthMax); - JS_ASSERT(gcHeapGrowthFactor <= rt->gcHighFrequencyHeapGrowthMax - && gcHeapGrowthFactor >= rt->gcHighFrequencyHeapGrowthMin); + double k = (rt->gc.highFrequencyHeapGrowthMin - rt->gc.highFrequencyHeapGrowthMax) + / (double)(rt->gc.highFrequencyHighLimitBytes - rt->gc.highFrequencyLowLimitBytes); + gcHeapGrowthFactor = (k * (lastBytes - rt->gc.highFrequencyLowLimitBytes) + + rt->gc.highFrequencyHeapGrowthMax); + JS_ASSERT(gcHeapGrowthFactor <= rt->gc.highFrequencyHeapGrowthMax + && gcHeapGrowthFactor >= rt->gc.highFrequencyHeapGrowthMin); } - rt->gcHighFrequencyGC = true; + rt->gc.highFrequencyGC = true; } else { - gcHeapGrowthFactor = rt->gcLowFrequencyHeapGrowth; - rt->gcHighFrequencyGC = false; + gcHeapGrowthFactor = rt->gc.lowFrequencyHeapGrowth; + rt->gc.highFrequencyGC = false; } } - gcTriggerBytes = ComputeTriggerBytes(this, lastBytes, rt->gcMaxBytes, gckind); + gcTriggerBytes = ComputeTriggerBytes(this, lastBytes, rt->gc.maxBytes, gckind); } void @@ -1330,7 +1412,7 @@ Zone::reduceGCTriggerBytes(size_t amount) { JS_ASSERT(amount > 0); JS_ASSERT(gcTriggerBytes >= amount); - if (gcTriggerBytes - amount < runtimeFromAnyThread()->gcAllocationThreshold * gcHeapGrowthFactor) + if (gcTriggerBytes - amount < runtimeFromAnyThread()->gc.allocationThreshold * gcHeapGrowthFactor) return; gcTriggerBytes -= amount; } @@ -1367,7 +1449,7 @@ ArenaLists::prepareForIncrementalGC(JSRuntime *rt) if (!headSpan->isEmpty()) { ArenaHeader *aheader = headSpan->arenaHeader(); aheader->allocatedDuringIncremental = true; - rt->gcMarker.delayMarkingArena(aheader); + rt->gc.marker.delayMarkingArena(aheader); } } } @@ -1375,8 +1457,8 @@ ArenaLists::prepareForIncrementalGC(JSRuntime *rt) static inline void PushArenaAllocatedDuringSweep(JSRuntime *runtime, ArenaHeader *arena) { - arena->setNextAllocDuringSweep(runtime->gcArenasAllocatedDuringSweep); - runtime->gcArenasAllocatedDuringSweep = arena; + arena->setNextAllocDuringSweep(runtime->gc.arenasAllocatedDuringSweep); + runtime->gc.arenasAllocatedDuringSweep = arena; } inline void * @@ -1447,7 +1529,7 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind) if (MOZ_UNLIKELY(zone->wasGCStarted())) { if (zone->needsBarrier()) { aheader->allocatedDuringIncremental = true; - zone->runtimeFromMainThread()->gcMarker.delayMarkingArena(aheader); + zone->runtimeFromMainThread()->gc.marker.delayMarkingArena(aheader); } else if (zone->isGCSweeping()) { PushArenaAllocatedDuringSweep(zone->runtimeFromMainThread(), aheader); } @@ -1480,7 +1562,7 @@ ArenaLists::allocateFromArenaInline(Zone *zone, AllocKind thingKind) if (MOZ_UNLIKELY(zone->wasGCStarted())) { if (zone->needsBarrier()) { aheader->allocatedDuringIncremental = true; - zone->runtimeFromMainThread()->gcMarker.delayMarkingArena(aheader); + zone->runtimeFromMainThread()->gc.marker.delayMarkingArena(aheader); } else if (zone->isGCSweeping()) { PushArenaAllocatedDuringSweep(zone->runtimeFromMainThread(), aheader); } @@ -1578,7 +1660,7 @@ ArenaLists::queueForBackgroundSweep(FreeOp *fop, AllocKind thingKind) JS_ASSERT(IsBackgroundFinalized(thingKind)); #ifdef JS_THREADSAFE - JS_ASSERT(!fop->runtime()->gcHelperThread.sweeping()); + JS_ASSERT(!fop->runtime()->gc.helperThread.sweeping()); #endif ArenaList *al = &arenaLists[thingKind]; @@ -1650,7 +1732,7 @@ ArenaLists::backgroundFinalize(FreeOp *fop, ArenaHeader *listHead, bool onBackgr void ArenaLists::queueObjectsForSweep(FreeOp *fop) { - gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_OBJECT); + gcstats::AutoPhase ap(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_OBJECT); finalizeNow(fop, FINALIZE_OBJECT0); finalizeNow(fop, FINALIZE_OBJECT2); @@ -1670,7 +1752,7 @@ ArenaLists::queueObjectsForSweep(FreeOp *fop) void ArenaLists::queueStringsForSweep(FreeOp *fop) { - gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_STRING); + gcstats::AutoPhase ap(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_STRING); queueForBackgroundSweep(fop, FINALIZE_FAT_INLINE_STRING); queueForBackgroundSweep(fop, FINALIZE_STRING); @@ -1681,7 +1763,7 @@ ArenaLists::queueStringsForSweep(FreeOp *fop) void ArenaLists::queueScriptsForSweep(FreeOp *fop) { - gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_SCRIPT); + gcstats::AutoPhase ap(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_SCRIPT); queueForForegroundSweep(fop, FINALIZE_SCRIPT); queueForForegroundSweep(fop, FINALIZE_LAZY_SCRIPT); } @@ -1689,14 +1771,14 @@ ArenaLists::queueScriptsForSweep(FreeOp *fop) void ArenaLists::queueJitCodeForSweep(FreeOp *fop) { - gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_JITCODE); + gcstats::AutoPhase ap(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_JITCODE); queueForForegroundSweep(fop, FINALIZE_JITCODE); } void ArenaLists::queueShapesForSweep(FreeOp *fop) { - gcstats::AutoPhase ap(fop->runtime()->gcStats, gcstats::PHASE_SWEEP_SHAPE); + gcstats::AutoPhase ap(fop->runtime()->gc.stats, gcstats::PHASE_SWEEP_SHAPE); queueForBackgroundSweep(fop, FINALIZE_SHAPE); queueForBackgroundSweep(fop, FINALIZE_BASE_SHAPE); @@ -1742,7 +1824,7 @@ ArenaLists::refillFreeList(ThreadSafeContext *cx, AllocKind thingKind) Zone *zone = cx->allocator()->zone_; bool runGC = cx->allowGC() && allowGC && - cx->asJSContext()->runtime()->gcIncrementalState != NO_INCREMENTAL && + cx->asJSContext()->runtime()->gc.incrementalState != NO_INCREMENTAL && zone->gcBytes > zone->gcTriggerBytes; #ifdef JS_THREADSAFE @@ -1772,7 +1854,7 @@ ArenaLists::refillFreeList(ThreadSafeContext *cx, AllocKind thingKind) if (secondAttempt) break; - cx->asJSContext()->runtime()->gcHelperThread.waitBackgroundSweepEnd(); + cx->asJSContext()->runtime()->gc.helperThread.waitBackgroundSweepEnd(); } } else { #ifdef JS_THREADSAFE @@ -1879,11 +1961,11 @@ js::MarkCompartmentActive(InterpreterFrame *fp) static void RequestInterrupt(JSRuntime *rt, JS::gcreason::Reason reason) { - if (rt->gcIsNeeded) + if (rt->gc.isNeeded) return; - rt->gcIsNeeded = true; - rt->gcTriggerReason = reason; + rt->gc.isNeeded = true; + rt->gc.triggerReason = reason; rt->requestInterrupt(JSRuntime::RequestInterruptMainThread); } @@ -1965,17 +2047,17 @@ js::MaybeGC(JSContext *cx) return; } - if (rt->gcIsNeeded) { + if (rt->gc.isNeeded) { GCSlice(rt, GC_NORMAL, JS::gcreason::MAYBEGC); return; } - double factor = rt->gcHighFrequencyGC ? 0.85 : 0.9; + double factor = rt->gc.highFrequencyGC ? 0.85 : 0.9; Zone *zone = cx->zone(); if (zone->gcBytes > 1024 * 1024 && zone->gcBytes >= factor * zone->gcTriggerBytes && - rt->gcIncrementalState == NO_INCREMENTAL && - !rt->gcHelperThread.sweeping()) + rt->gc.incrementalState == NO_INCREMENTAL && + !rt->gc.helperThread.sweeping()) { PrepareZoneForGC(zone); GCSlice(rt, GC_NORMAL, JS::gcreason::MAYBEGC); @@ -1989,14 +2071,14 @@ js::MaybeGC(JSContext *cx) * tolerate this. */ int64_t now = PRMJ_Now(); - if (rt->gcNextFullGCTime && rt->gcNextFullGCTime <= now) { - if (rt->gcChunkAllocationSinceLastGC || - rt->gcNumArenasFreeCommitted > rt->gcDecommitThreshold) + if (rt->gc.nextFullGCTime && rt->gc.nextFullGCTime <= now) { + if (rt->gc.chunkAllocationSinceLastGC || + rt->gc.numArenasFreeCommitted > rt->gc.decommitThreshold) { JS::PrepareForFullGC(rt); GCSlice(rt, GC_SHRINK, JS::gcreason::MAYBEGC); } else { - rt->gcNextFullGCTime = now + GC_IDLE_FULL_SPAN; + rt->gc.nextFullGCTime = now + GC_IDLE_FULL_SPAN; } } #endif @@ -2056,7 +2138,7 @@ DecommitArenasFromAvailableList(JSRuntime *rt, Chunk **availableListHeadp) Maybe maybeUnlock; if (!rt->isHeapBusy()) maybeUnlock.construct(rt); - ok = MarkPagesUnused(rt, aheader->getArena(), ArenaSize); + ok = rt->gc.pageAllocator.markPagesUnused(aheader->getArena(), ArenaSize); } if (ok) { @@ -2086,7 +2168,7 @@ DecommitArenasFromAvailableList(JSRuntime *rt, Chunk **availableListHeadp) JS_ASSERT(chunk->info.prevp); } - if (rt->gcChunkAllocationSinceLastGC || !ok) { + if (rt->gc.chunkAllocationSinceLastGC || !ok) { /* * The allocator thread has started to get new chunks. We should stop * to avoid decommitting arenas in just allocated chunks. @@ -2114,15 +2196,15 @@ DecommitArenasFromAvailableList(JSRuntime *rt, Chunk **availableListHeadp) static void DecommitArenas(JSRuntime *rt) { - DecommitArenasFromAvailableList(rt, &rt->gcSystemAvailableChunkListHead); - DecommitArenasFromAvailableList(rt, &rt->gcUserAvailableChunkListHead); + DecommitArenasFromAvailableList(rt, &rt->gc.systemAvailableChunkListHead); + DecommitArenasFromAvailableList(rt, &rt->gc.userAvailableChunkListHead); } /* Must be called with the GC lock taken. */ static void ExpireChunksAndArenas(JSRuntime *rt, bool shouldShrink) { - if (Chunk *toFree = rt->gcChunkPool.expire(rt, shouldShrink)) { + if (Chunk *toFree = rt->gc.chunkPool.expire(rt, shouldShrink)) { AutoUnlockGC unlock(rt); FreeChunkList(rt, toFree); } @@ -2140,7 +2222,7 @@ SweepBackgroundThings(JSRuntime* rt, bool onBackgroundThread) */ FreeOp fop(rt, false); for (int phase = 0 ; phase < BackgroundPhaseCount ; ++phase) { - for (Zone *zone = rt->gcSweepingZones; zone; zone = zone->gcNextGraphNode) { + for (Zone *zone = rt->gc.sweepingZones; zone; zone = zone->gcNextGraphNode) { for (int index = 0 ; index < BackgroundPhaseLength[phase] ; ++index) { AllocKind kind = BackgroundPhases[phase][index]; ArenaHeader *arenas = zone->allocator.arenas.arenaListsToSweep[kind]; @@ -2150,14 +2232,14 @@ SweepBackgroundThings(JSRuntime* rt, bool onBackgroundThread) } } - rt->gcSweepingZones = nullptr; + rt->gc.sweepingZones = nullptr; } #ifdef JS_THREADSAFE static void AssertBackgroundSweepingFinished(JSRuntime *rt) { - JS_ASSERT(!rt->gcSweepingZones); + JS_ASSERT(!rt->gc.sweepingZones); for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { for (unsigned i = 0; i < FINALIZE_LIMIT; ++i) { JS_ASSERT(!zone->allocator.arenas.arenaListsToSweep[i]); @@ -2193,9 +2275,9 @@ GCHelperThread::init() } #ifdef JS_THREADSAFE - if (!(wakeup = PR_NewCondVar(rt->gcLock))) + if (!(wakeup = PR_NewCondVar(rt->gc.lock))) return false; - if (!(done = PR_NewCondVar(rt->gcLock))) + if (!(done = PR_NewCondVar(rt->gc.lock))) return false; thread = PR_CreateThread(PR_USER_THREAD, threadMain, this, PR_PRIORITY_NORMAL, @@ -2211,7 +2293,7 @@ GCHelperThread::init() void GCHelperThread::finish() { - if (!rt->useHelperThreads() || !rt->gcLock) { + if (!rt->useHelperThreads() || !rt->gc.lock) { JS_ASSERT(state == IDLE); return; } @@ -2270,10 +2352,10 @@ GCHelperThread::threadMain(void *arg) void GCHelperThread::wait(PRCondVar *which) { - rt->gcLockOwner = nullptr; + rt->gc.lockOwner = nullptr; PR_WaitCondVar(which, PR_INTERVAL_NO_TIMEOUT); #ifdef DEBUG - rt->gcLockOwner = PR_GetCurrentThread(); + rt->gc.lockOwner = PR_GetCurrentThread(); #endif } @@ -2317,8 +2399,8 @@ GCHelperThread::threadLoop() if (!chunk) break; JS_ASSERT(chunk->info.numArenasFreeCommitted == 0); - rt->gcChunkPool.put(chunk); - } while (state == ALLOCATING && rt->gcChunkPool.wantBackgroundAllocation(rt)); + rt->gc.chunkPool.put(chunk); + } while (state == ALLOCATING && rt->gc.chunkPool.wantBackgroundAllocation(rt)); if (state == ALLOCATING) state = IDLE; break; @@ -2390,7 +2472,7 @@ GCHelperThread::waitBackgroundSweepEnd() AutoLockGC lock(rt); while (state == SWEEPING) wait(done); - if (rt->gcIncrementalState == NO_INCREMENTAL) + if (rt->gc.incrementalState == NO_INCREMENTAL) AssertBackgroundSweepingFinished(rt); #endif /* JS_THREADSAFE */ } @@ -2409,7 +2491,7 @@ GCHelperThread::waitBackgroundSweepOrAllocEnd() state = CANCEL_ALLOCATION; while (state == SWEEPING || state == CANCEL_ALLOCATION) wait(done); - if (rt->gcIncrementalState == NO_INCREMENTAL) + if (rt->gc.incrementalState == NO_INCREMENTAL) AssertBackgroundSweepingFinished(rt); #endif /* JS_THREADSAFE */ } @@ -2506,10 +2588,10 @@ ReleaseObservedTypes(JSRuntime *rt) #ifndef JS_MORE_DETERMINISTIC int64_t now = PRMJ_Now(); - if (now >= rt->gcJitReleaseTime) + if (now >= rt->gc.jitReleaseTime) releaseTypes = true; if (releaseTypes) - rt->gcJitReleaseTime = now + JIT_SCRIPT_RELEASE_TYPES_INTERVAL; + rt->gc.jitReleaseTime = now + JIT_SCRIPT_RELEASE_TYPES_INTERVAL; #endif return releaseTypes; @@ -2565,11 +2647,11 @@ SweepZones(FreeOp *fop, bool lastGC) JSZoneCallback callback = rt->destroyZoneCallback; /* Skip the atomsCompartment zone. */ - Zone **read = rt->zones.begin() + 1; - Zone **end = rt->zones.end(); + Zone **read = rt->gc.zones.begin() + 1; + Zone **end = rt->gc.zones.end(); Zone **write = read; - JS_ASSERT(rt->zones.length() >= 1); - JS_ASSERT(rt->isAtomsZone(rt->zones[0])); + JS_ASSERT(rt->gc.zones.length() >= 1); + JS_ASSERT(rt->isAtomsZone(rt->gc.zones[0])); while (read < end) { Zone *zone = *read++; @@ -2590,7 +2672,7 @@ SweepZones(FreeOp *fop, bool lastGC) } *write++ = zone; } - rt->zones.resize(write - rt->zones.begin()); + rt->gc.zones.resize(write - rt->gc.zones.begin()); } static void @@ -2617,10 +2699,10 @@ static bool ShouldPreserveJITCode(JSCompartment *comp, int64_t currentTime) { JSRuntime *rt = comp->runtimeFromMainThread(); - if (rt->gcShouldCleanUpEverything) + if (rt->gc.shouldCleanUpEverything) return false; - if (rt->alwaysPreserveCode) + if (rt->gc.alwaysPreserveCode) return true; if (comp->lastAnimationTime + PRMJ_USEC_PER_SEC >= currentTime) return true; @@ -2710,14 +2792,14 @@ CheckCompartmentCallback(JSTracer *trcArg, void **thingp, JSGCTraceKind kind) static void CheckForCompartmentMismatches(JSRuntime *rt) { - if (rt->gcDisableStrictProxyCheckingCount) + if (rt->gc.disableStrictProxyCheckingCount) return; CompartmentCheckTracer trc(rt, CheckCompartmentCallback); for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) { trc.zone = zone; for (size_t thingKind = 0; thingKind < FINALIZE_LAST; thingKind++) { - for (CellIterUnderGC i(zone, AllocKind(thingKind)); !i.done(); i.next()) { + for (ZoneCellIterUnderGC i(zone, AllocKind(thingKind)); !i.done(); i.next()) { trc.src = i.getCell(); trc.srcKind = MapAllocToTraceKind(AllocKind(thingKind)); trc.compartment = CompartmentOfCell(trc.src, trc.srcKind); @@ -2734,11 +2816,11 @@ BeginMarkPhase(JSRuntime *rt) int64_t currentTime = PRMJ_Now(); #ifdef DEBUG - if (rt->gcFullCompartmentChecks) + if (rt->gc.fullCompartmentChecks) CheckForCompartmentMismatches(rt); #endif - rt->gcIsFull = true; + rt->gc.isFull = true; bool any = false; for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { @@ -2755,7 +2837,7 @@ BeginMarkPhase(JSRuntime *rt) zone->setGCState(Zone::Mark); } } else { - rt->gcIsFull = false; + rt->gc.isFull = false; } zone->scheduledForDestruction = false; @@ -2770,7 +2852,7 @@ BeginMarkPhase(JSRuntime *rt) c->zone()->setPreservingCode(true); } - if (!rt->gcShouldCleanUpEverything) { + if (!rt->gc.shouldCleanUpEverything) { #ifdef JS_ION if (JSCompartment *comp = jit::TopmostJitActivationCompartment(rt)) comp->zone()->setPreservingCode(true); @@ -2787,7 +2869,7 @@ BeginMarkPhase(JSRuntime *rt) * on. If the value of keepAtoms() changes between GC slices, then we'll * cancel the incremental GC. See IsIncrementalGCSafe. */ - if (rt->gcIsFull && !rt->keepAtoms()) { + if (rt->gc.isFull && !rt->keepAtoms()) { Zone *atomsZone = rt->atomsCompartment()->zone(); if (atomsZone->isGCScheduled()) { JS_ASSERT(!atomsZone->isCollecting()); @@ -2807,26 +2889,26 @@ BeginMarkPhase(JSRuntime *rt) * arenas. This purge call ensures that we only mark arenas that have had * allocations after the incremental GC started. */ - if (rt->gcIsIncremental) { + if (rt->gc.isIncremental) { for (GCZonesIter zone(rt); !zone.done(); zone.next()) zone->allocator.arenas.purge(); } - rt->gcMarker.start(); - JS_ASSERT(!rt->gcMarker.callback); - JS_ASSERT(IS_GC_MARKING_TRACER(&rt->gcMarker)); + rt->gc.marker.start(); + JS_ASSERT(!rt->gc.marker.callback); + JS_ASSERT(IS_GC_MARKING_TRACER(&rt->gc.marker)); /* For non-incremental GC the following sweep discards the jit code. */ - if (rt->gcIsIncremental) { + if (rt->gc.isIncremental) { for (GCZonesIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_MARK_DISCARD_CODE); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_MARK_DISCARD_CODE); zone->discardJitCode(rt->defaultFreeOp()); } } - GCMarker *gcmarker = &rt->gcMarker; + GCMarker *gcmarker = &rt->gc.marker; - rt->gcStartNumber = rt->gcNumber; + rt->gc.startNumber = rt->gc.number; /* * We must purge the runtime at the beginning of an incremental GC. The @@ -2838,15 +2920,15 @@ BeginMarkPhase(JSRuntime *rt) * a GC hazard would exist. */ { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_PURGE); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_PURGE); PurgeRuntime(rt); } /* * Mark phase. */ - gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_MARK); - gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_MARK_ROOTS); + gcstats::AutoPhase ap1(rt->gc.stats, gcstats::PHASE_MARK); + gcstats::AutoPhase ap2(rt->gc.stats, gcstats::PHASE_MARK_ROOTS); for (GCZonesIter zone(rt); !zone.done(); zone.next()) { /* Unmark everything in the zones being collected. */ @@ -2858,11 +2940,11 @@ BeginMarkPhase(JSRuntime *rt) WeakMapBase::resetCompartmentWeakMapList(c); } - if (rt->gcIsFull) + if (rt->gc.isFull) UnmarkScriptData(rt); MarkRuntime(gcmarker); - if (rt->gcIsIncremental) + if (rt->gc.isIncremental) BufferGrayRoots(gcmarker); /* @@ -2912,7 +2994,7 @@ BeginMarkPhase(JSRuntime *rt) if (!zone->maybeAlive && !rt->isAtomsZone(zone)) zone->scheduledForDestruction = true; } - rt->gcFoundBlackGrayEdges = false; + rt->gc.foundBlackGrayEdges = false; return true; } @@ -2921,11 +3003,11 @@ template static void MarkWeakReferences(JSRuntime *rt, gcstats::Phase phase) { - GCMarker *gcmarker = &rt->gcMarker; + GCMarker *gcmarker = &rt->gc.marker; JS_ASSERT(gcmarker->isDrained()); - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_MARK); - gcstats::AutoPhase ap1(rt->gcStats, phase); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_MARK); + gcstats::AutoPhase ap1(rt->gc.stats, phase); for (;;) { bool markedAny = false; @@ -2954,19 +3036,19 @@ template static void MarkGrayReferences(JSRuntime *rt) { - GCMarker *gcmarker = &rt->gcMarker; + GCMarker *gcmarker = &rt->gc.marker; { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_MARK); - gcstats::AutoPhase ap1(rt->gcStats, gcstats::PHASE_SWEEP_MARK_GRAY); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_MARK); + gcstats::AutoPhase ap1(rt->gc.stats, gcstats::PHASE_SWEEP_MARK_GRAY); gcmarker->setMarkColorGray(); if (gcmarker->hasBufferedGrayRoots()) { for (ZoneIterT zone(rt); !zone.done(); zone.next()) gcmarker->markBufferedGrayRoots(zone); } else { - JS_ASSERT(!rt->gcIsIncremental); - if (JSTraceDataOp op = rt->gcGrayRootTracer.op) - (*op)(gcmarker, rt->gcGrayRootTracer.data); + JS_ASSERT(!rt->gc.isIncremental); + if (JSTraceDataOp op = rt->gc.grayRootTracer.op) + (*op)(gcmarker, rt->gc.grayRootTracer.data); } SliceBudget budget; gcmarker->drainMarkStack(budget); @@ -3042,10 +3124,10 @@ js::gc::MarkingValidator::nonIncrementalMark() if (!map.init()) return; - GCMarker *gcmarker = &runtime->gcMarker; + GCMarker *gcmarker = &runtime->gc.marker; /* Save existing mark bits. */ - for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) { + for (GCChunkSet::Range r(runtime->gc.chunkSet.all()); !r.empty(); r.popFront()) { ChunkBitmap *bitmap = &r.front()->bitmap; ChunkBitmap *entry = js_new(); if (!entry) @@ -3083,31 +3165,31 @@ js::gc::MarkingValidator::nonIncrementalMark() } /* Re-do all the marking, but non-incrementally. */ - js::gc::State state = runtime->gcIncrementalState; - runtime->gcIncrementalState = MARK_ROOTS; + js::gc::State state = runtime->gc.incrementalState; + runtime->gc.incrementalState = MARK_ROOTS; JS_ASSERT(gcmarker->isDrained()); gcmarker->reset(); - for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) + for (GCChunkSet::Range r(runtime->gc.chunkSet.all()); !r.empty(); r.popFront()) r.front()->bitmap.clear(); { - gcstats::AutoPhase ap1(runtime->gcStats, gcstats::PHASE_MARK); - gcstats::AutoPhase ap2(runtime->gcStats, gcstats::PHASE_MARK_ROOTS); + gcstats::AutoPhase ap1(runtime->gc.stats, gcstats::PHASE_MARK); + gcstats::AutoPhase ap2(runtime->gc.stats, gcstats::PHASE_MARK_ROOTS); MarkRuntime(gcmarker, true); } { - gcstats::AutoPhase ap1(runtime->gcStats, gcstats::PHASE_MARK); + gcstats::AutoPhase ap1(runtime->gc.stats, gcstats::PHASE_MARK); SliceBudget budget; - runtime->gcIncrementalState = MARK; - runtime->gcMarker.drainMarkStack(budget); + runtime->gc.incrementalState = MARK; + runtime->gc.marker.drainMarkStack(budget); } - runtime->gcIncrementalState = SWEEP; + runtime->gc.incrementalState = SWEEP; { - gcstats::AutoPhase ap(runtime->gcStats, gcstats::PHASE_SWEEP); + gcstats::AutoPhase ap(runtime->gc.stats, gcstats::PHASE_SWEEP); MarkAllWeakReferences(runtime, gcstats::PHASE_SWEEP_MARK_WEAK); /* Update zone state for gray marking. */ @@ -3126,7 +3208,7 @@ js::gc::MarkingValidator::nonIncrementalMark() } /* Take a copy of the non-incremental mark state and restore the original. */ - for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) { + for (GCChunkSet::Range r(runtime->gc.chunkSet.all()); !r.empty(); r.popFront()) { Chunk *chunk = r.front(); ChunkBitmap *bitmap = &chunk->bitmap; ChunkBitmap *entry = map.lookup(chunk)->value(); @@ -3140,7 +3222,7 @@ js::gc::MarkingValidator::nonIncrementalMark() WeakMapBase::restoreCompartmentWeakMapLists(weakmaps); ArrayBufferObject::restoreArrayBufferLists(arrayBuffers); - runtime->gcIncrementalState = state; + runtime->gc.incrementalState = state; } void @@ -3154,7 +3236,7 @@ js::gc::MarkingValidator::validate() if (!initialized) return; - for (GCChunkSet::Range r(runtime->gcChunkSet.all()); !r.empty(); r.popFront()) { + for (GCChunkSet::Range r(runtime->gc.chunkSet.all()); !r.empty(); r.popFront()) { Chunk *chunk = r.front(); BitmapMap::Ptr ptr = map.lookup(chunk); if (!ptr) @@ -3205,11 +3287,11 @@ static void ComputeNonIncrementalMarkingForValidation(JSRuntime *rt) { #ifdef DEBUG - JS_ASSERT(!rt->gcMarkingValidator); - if (rt->gcIsIncremental && rt->gcValidate) - rt->gcMarkingValidator = js_new(rt); - if (rt->gcMarkingValidator) - rt->gcMarkingValidator->nonIncrementalMark(); + JS_ASSERT(!rt->gc.markingValidator); + if (rt->gc.isIncremental && rt->gc.validate) + rt->gc.markingValidator = js_new(rt); + if (rt->gc.markingValidator) + rt->gc.markingValidator->nonIncrementalMark(); #endif } @@ -3217,8 +3299,8 @@ static void ValidateIncrementalMarking(JSRuntime *rt) { #ifdef DEBUG - if (rt->gcMarkingValidator) - rt->gcMarkingValidator->validate(); + if (rt->gc.markingValidator) + rt->gc.markingValidator->validate(); #endif } @@ -3226,8 +3308,8 @@ static void FinishMarkingValidation(JSRuntime *rt) { #ifdef DEBUG - js_delete(rt->gcMarkingValidator); - rt->gcMarkingValidator = nullptr; + js_delete(rt->gc.markingValidator); + rt->gc.markingValidator = nullptr; #endif } @@ -3329,17 +3411,17 @@ static void FindZoneGroups(JSRuntime *rt) { ComponentFinder finder(rt->mainThread.nativeStackLimit[StackForSystemCode]); - if (!rt->gcIsIncremental) + if (!rt->gc.isIncremental) finder.useOneComponent(); for (GCZonesIter zone(rt); !zone.done(); zone.next()) { JS_ASSERT(zone->isGCMarking()); finder.addNode(zone); } - rt->gcZoneGroups = finder.getResultsList(); - rt->gcCurrentZoneGroup = rt->gcZoneGroups; - rt->gcZoneGroupIndex = 0; - JS_ASSERT_IF(!rt->gcIsIncremental, !rt->gcCurrentZoneGroup->nextGroup()); + rt->gc.zoneGroups = finder.getResultsList(); + rt->gc.currentZoneGroup = rt->gc.zoneGroups; + rt->gc.zoneGroupIndex = 0; + JS_ASSERT_IF(!rt->gc.isIncremental, !rt->gc.currentZoneGroup->nextGroup()); } static void @@ -3348,18 +3430,18 @@ ResetGrayList(JSCompartment* comp); static void GetNextZoneGroup(JSRuntime *rt) { - rt->gcCurrentZoneGroup = rt->gcCurrentZoneGroup->nextGroup(); - ++rt->gcZoneGroupIndex; - if (!rt->gcCurrentZoneGroup) { - rt->gcAbortSweepAfterCurrentGroup = false; + rt->gc.currentZoneGroup = rt->gc.currentZoneGroup->nextGroup(); + ++rt->gc.zoneGroupIndex; + if (!rt->gc.currentZoneGroup) { + rt->gc.abortSweepAfterCurrentGroup = false; return; } - if (!rt->gcIsIncremental) - ComponentFinder::mergeGroups(rt->gcCurrentZoneGroup); + if (!rt->gc.isIncremental) + ComponentFinder::mergeGroups(rt->gc.currentZoneGroup); - if (rt->gcAbortSweepAfterCurrentGroup) { - JS_ASSERT(!rt->gcIsIncremental); + if (rt->gc.abortSweepAfterCurrentGroup) { + JS_ASSERT(!rt->gc.isIncremental); for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { JS_ASSERT(!zone->gcNextGraphComponent); JS_ASSERT(zone->isGCMarking()); @@ -3375,8 +3457,8 @@ GetNextZoneGroup(JSRuntime *rt) ResetGrayList(comp); } - rt->gcAbortSweepAfterCurrentGroup = false; - rt->gcCurrentZoneGroup = nullptr; + rt->gc.abortSweepAfterCurrentGroup = false; + rt->gc.currentZoneGroup = nullptr; } } @@ -3487,12 +3569,12 @@ MarkIncomingCrossCompartmentPointers(JSRuntime *rt, const uint32_t color) { JS_ASSERT(color == BLACK || color == GRAY); - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_MARK); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_MARK); static const gcstats::Phase statsPhases[] = { gcstats::PHASE_SWEEP_MARK_INCOMING_BLACK, gcstats::PHASE_SWEEP_MARK_INCOMING_GRAY }; - gcstats::AutoPhase ap1(rt->gcStats, statsPhases[color]); + gcstats::AutoPhase ap1(rt->gc.stats, statsPhases[color]); bool unlinkList = color == GRAY; @@ -3510,11 +3592,11 @@ MarkIncomingCrossCompartmentPointers(JSRuntime *rt, const uint32_t color) if (color == GRAY) { if (IsObjectMarked(&src) && src->isMarked(GRAY)) - MarkGCThingUnbarriered(&rt->gcMarker, (void**)&dst, + MarkGCThingUnbarriered(&rt->gc.marker, (void**)&dst, "cross-compartment gray pointer"); } else { if (IsObjectMarked(&src) && !src->isMarked(GRAY)) - MarkGCThingUnbarriered(&rt->gcMarker, (void**)&dst, + MarkGCThingUnbarriered(&rt->gc.marker, (void**)&dst, "cross-compartment black pointer"); } } @@ -3524,7 +3606,7 @@ MarkIncomingCrossCompartmentPointers(JSRuntime *rt, const uint32_t color) } SliceBudget budget; - rt->gcMarker.drainMarkStack(budget); + rt->gc.marker.drainMarkStack(budget); } static bool @@ -3633,9 +3715,9 @@ EndMarkingZoneGroup(JSRuntime *rt) } /* Mark incoming gray pointers from previously swept compartments. */ - rt->gcMarker.setMarkColorGray(); + rt->gc.marker.setMarkColorGray(); MarkIncomingCrossCompartmentPointers(rt, GRAY); - rt->gcMarker.setMarkColorBlack(); + rt->gc.marker.setMarkColorBlack(); /* Mark gray roots and mark transitively inside the current compartment group. */ MarkGrayReferencesInCurrentGroup(rt); @@ -3646,7 +3728,7 @@ EndMarkingZoneGroup(JSRuntime *rt) zone->setGCState(Zone::Mark); } - JS_ASSERT(rt->gcMarker.isDrained()); + JS_ASSERT(rt->gc.marker.isDrained()); } static void @@ -3675,16 +3757,16 @@ BeginSweepingZoneGroup(JSRuntime *rt) ValidateIncrementalMarking(rt); - FreeOp fop(rt, rt->gcSweepOnBackgroundThread); + FreeOp fop(rt, rt->gc.sweepOnBackgroundThread); { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_FINALIZE_START); - if (rt->gcFinalizeCallback) - rt->gcFinalizeCallback(&fop, JSFINALIZE_GROUP_START, !rt->gcIsFull /* unused */); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_FINALIZE_START); + if (rt->gc.finalizeCallback) + rt->gc.finalizeCallback(&fop, JSFINALIZE_GROUP_START, !rt->gc.isFull /* unused */); } if (sweepingAtoms) { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_ATOMS); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_ATOMS); rt->sweepAtoms(); } @@ -3699,21 +3781,21 @@ BeginSweepingZoneGroup(JSRuntime *rt) Debugger::sweepAll(&fop); { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_COMPARTMENTS); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_COMPARTMENTS); for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_DISCARD_CODE); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_DISCARD_CODE); zone->discardJitCode(&fop); } bool releaseTypes = ReleaseObservedTypes(rt); for (GCCompartmentGroupIter c(rt); !c.done(); c.next()) { - gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex); + gcstats::AutoSCC scc(rt->gc.stats, rt->gc.zoneGroupIndex); c->sweep(&fop, releaseTypes && !c->zone()->isPreservingCode()); } for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex); + gcstats::AutoSCC scc(rt->gc.stats, rt->gc.zoneGroupIndex); // If there is an OOM while sweeping types, the type information // will be deoptimized so that it is still correct (i.e. @@ -3742,38 +3824,38 @@ BeginSweepingZoneGroup(JSRuntime *rt) * Objects are finalized immediately but this may change in the future. */ for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex); + gcstats::AutoSCC scc(rt->gc.stats, rt->gc.zoneGroupIndex); zone->allocator.arenas.queueObjectsForSweep(&fop); } for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex); + gcstats::AutoSCC scc(rt->gc.stats, rt->gc.zoneGroupIndex); zone->allocator.arenas.queueStringsForSweep(&fop); } for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex); + gcstats::AutoSCC scc(rt->gc.stats, rt->gc.zoneGroupIndex); zone->allocator.arenas.queueScriptsForSweep(&fop); } #ifdef JS_ION for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex); + gcstats::AutoSCC scc(rt->gc.stats, rt->gc.zoneGroupIndex); zone->allocator.arenas.queueJitCodeForSweep(&fop); } #endif for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(rt->gcStats, rt->gcZoneGroupIndex); + gcstats::AutoSCC scc(rt->gc.stats, rt->gc.zoneGroupIndex); zone->allocator.arenas.queueShapesForSweep(&fop); zone->allocator.arenas.gcShapeArenasToSweep = zone->allocator.arenas.arenaListsToSweep[FINALIZE_SHAPE]; } - rt->gcSweepPhase = 0; - rt->gcSweepZone = rt->gcCurrentZoneGroup; - rt->gcSweepKindIndex = 0; + rt->gc.sweepPhase = 0; + rt->gc.sweepZone = rt->gc.currentZoneGroup; + rt->gc.sweepKindIndex = 0; { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_FINALIZE_END); - if (rt->gcFinalizeCallback) - rt->gcFinalizeCallback(&fop, JSFINALIZE_GROUP_END, !rt->gcIsFull /* unused */); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_FINALIZE_END); + if (rt->gc.finalizeCallback) + rt->gc.finalizeCallback(&fop, JSFINALIZE_GROUP_END, !rt->gc.isFull /* unused */); } } @@ -3787,8 +3869,8 @@ EndSweepingZoneGroup(JSRuntime *rt) } /* Reset the list of arenas marked as being allocated during sweep phase. */ - while (ArenaHeader *arena = rt->gcArenasAllocatedDuringSweep) { - rt->gcArenasAllocatedDuringSweep = arena->getNextAllocDuringSweep(); + while (ArenaHeader *arena = rt->gc.arenasAllocatedDuringSweep) { + rt->gc.arenasAllocatedDuringSweep = arena->getNextAllocDuringSweep(); arena->unsetAllocDuringSweep(); } } @@ -3799,19 +3881,19 @@ BeginSweepPhase(JSRuntime *rt, bool lastGC) /* * Sweep phase. * - * Finalize as we sweep, outside of rt->gcLock but with rt->isHeapBusy() + * Finalize as we sweep, outside of rt->gc.lock but with rt->isHeapBusy() * true so that any attempt to allocate a GC-thing from a finalizer will * fail, rather than nest badly and leave the unmarked newborn to be swept. */ - JS_ASSERT(!rt->gcAbortSweepAfterCurrentGroup); + JS_ASSERT(!rt->gc.abortSweepAfterCurrentGroup); ComputeNonIncrementalMarkingForValidation(rt); - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP); #ifdef JS_THREADSAFE - rt->gcSweepOnBackgroundThread = !lastGC && rt->useHelperThreads(); + rt->gc.sweepOnBackgroundThread = !lastGC && rt->useHelperThreads(); #endif #ifdef DEBUG @@ -3844,15 +3926,15 @@ static bool DrainMarkStack(JSRuntime *rt, SliceBudget &sliceBudget, gcstats::Phase phase) { /* Run a marking slice and return whether the stack is now empty. */ - gcstats::AutoPhase ap(rt->gcStats, phase); - return rt->gcMarker.drainMarkStack(sliceBudget); + gcstats::AutoPhase ap(rt->gc.stats, phase); + return rt->gc.marker.drainMarkStack(sliceBudget); } static bool SweepPhase(JSRuntime *rt, SliceBudget &sliceBudget) { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP); - FreeOp fop(rt, rt->gcSweepOnBackgroundThread); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP); + FreeOp fop(rt, rt->gc.sweepOnBackgroundThread); bool finished = DrainMarkStack(rt, sliceBudget, gcstats::PHASE_SWEEP_MARK); if (!finished) @@ -3860,33 +3942,33 @@ SweepPhase(JSRuntime *rt, SliceBudget &sliceBudget) for (;;) { /* Finalize foreground finalized things. */ - for (; rt->gcSweepPhase < FinalizePhaseCount ; ++rt->gcSweepPhase) { - gcstats::AutoPhase ap(rt->gcStats, FinalizePhaseStatsPhase[rt->gcSweepPhase]); + for (; rt->gc.sweepPhase < FinalizePhaseCount ; ++rt->gc.sweepPhase) { + gcstats::AutoPhase ap(rt->gc.stats, FinalizePhaseStatsPhase[rt->gc.sweepPhase]); - for (; rt->gcSweepZone; rt->gcSweepZone = rt->gcSweepZone->nextNodeInGroup()) { - Zone *zone = rt->gcSweepZone; + for (; rt->gc.sweepZone; rt->gc.sweepZone = rt->gc.sweepZone->nextNodeInGroup()) { + Zone *zone = rt->gc.sweepZone; - while (rt->gcSweepKindIndex < FinalizePhaseLength[rt->gcSweepPhase]) { - AllocKind kind = FinalizePhases[rt->gcSweepPhase][rt->gcSweepKindIndex]; + while (rt->gc.sweepKindIndex < FinalizePhaseLength[rt->gc.sweepPhase]) { + AllocKind kind = FinalizePhases[rt->gc.sweepPhase][rt->gc.sweepKindIndex]; if (!zone->allocator.arenas.foregroundFinalize(&fop, kind, sliceBudget)) return false; /* Yield to the mutator. */ - ++rt->gcSweepKindIndex; + ++rt->gc.sweepKindIndex; } - rt->gcSweepKindIndex = 0; + rt->gc.sweepKindIndex = 0; } - rt->gcSweepZone = rt->gcCurrentZoneGroup; + rt->gc.sweepZone = rt->gc.currentZoneGroup; } /* Remove dead shapes from the shape tree, but don't finalize them yet. */ { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_SHAPE); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP_SHAPE); - for (; rt->gcSweepZone; rt->gcSweepZone = rt->gcSweepZone->nextNodeInGroup()) { - Zone *zone = rt->gcSweepZone; + for (; rt->gc.sweepZone; rt->gc.sweepZone = rt->gc.sweepZone->nextNodeInGroup()) { + Zone *zone = rt->gc.sweepZone; while (ArenaHeader *arena = zone->allocator.arenas.gcShapeArenasToSweep) { - for (CellIterUnderGC i(arena); !i.done(); i.next()) { + for (ArenaCellIterUnderGC i(arena); !i.done(); i.next()) { Shape *shape = i.get(); if (!shape->isMarked()) shape->sweep(); @@ -3902,7 +3984,7 @@ SweepPhase(JSRuntime *rt, SliceBudget &sliceBudget) EndSweepingZoneGroup(rt); GetNextZoneGroup(rt); - if (!rt->gcCurrentZoneGroup) + if (!rt->gc.currentZoneGroup) return true; /* We're finished. */ EndMarkingZoneGroup(rt); BeginSweepingZoneGroup(rt); @@ -3912,22 +3994,22 @@ SweepPhase(JSRuntime *rt, SliceBudget &sliceBudget) static void EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC) { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP); - FreeOp fop(rt, rt->gcSweepOnBackgroundThread); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_SWEEP); + FreeOp fop(rt, rt->gc.sweepOnBackgroundThread); - JS_ASSERT_IF(lastGC, !rt->gcSweepOnBackgroundThread); + JS_ASSERT_IF(lastGC, !rt->gc.sweepOnBackgroundThread); - JS_ASSERT(rt->gcMarker.isDrained()); - rt->gcMarker.stop(); + JS_ASSERT(rt->gc.marker.isDrained()); + rt->gc.marker.stop(); /* * Recalculate whether GC was full or not as this may have changed due to * newly created zones. Can only change from full to not full. */ - if (rt->gcIsFull) { + if (rt->gc.isFull) { for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { if (!zone->isCollecting()) { - rt->gcIsFull = false; + rt->gc.isFull = false; break; } } @@ -3939,7 +4021,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC) * will no longer be collected. This is safe, although it may * prevent the cycle collector from collecting some dead objects. */ - if (rt->gcFoundBlackGrayEdges) { + if (rt->gc.foundBlackGrayEdges) { for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { if (!zone->isCollecting()) zone->allocator.arenas.unmarkAll(); @@ -3947,7 +4029,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC) } { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DESTROY); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_DESTROY); /* * Sweep script filenames after sweeping functions in the generic loop @@ -3955,7 +4037,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC) * script and calls rt->destroyScriptHook, the hook can still access the * script's filename. See bug 323267. */ - if (rt->gcIsFull) + if (rt->gc.isFull) SweepScriptData(rt); /* Clear out any small pools that we're hanging on to. */ @@ -3969,7 +4051,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC) if (!lastGC) SweepZones(&fop, lastGC); - if (!rt->gcSweepOnBackgroundThread) { + if (!rt->gc.sweepOnBackgroundThread) { /* * Destroy arenas after we finished the sweeping so finalizers can * safely use IsAboutToBeFinalized(). This is done on the @@ -3982,26 +4064,26 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC) } { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_FINALIZE_END); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_FINALIZE_END); - if (rt->gcFinalizeCallback) - rt->gcFinalizeCallback(&fop, JSFINALIZE_COLLECTION_END, !rt->gcIsFull); + if (rt->gc.finalizeCallback) + rt->gc.finalizeCallback(&fop, JSFINALIZE_COLLECTION_END, !rt->gc.isFull); /* If we finished a full GC, then the gray bits are correct. */ - if (rt->gcIsFull) - rt->gcGrayBitsValid = true; + if (rt->gc.isFull) + rt->gc.grayBitsValid = true; } /* Set up list of zones for sweeping of background things. */ - JS_ASSERT(!rt->gcSweepingZones); + JS_ASSERT(!rt->gc.sweepingZones); for (GCZonesIter zone(rt); !zone.done(); zone.next()) { - zone->gcNextGraphNode = rt->gcSweepingZones; - rt->gcSweepingZones = zone; + zone->gcNextGraphNode = rt->gc.sweepingZones; + rt->gc.sweepingZones = zone; } /* If not sweeping on background thread then we must do it here. */ - if (!rt->gcSweepOnBackgroundThread) { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DESTROY); + if (!rt->gc.sweepOnBackgroundThread) { + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_DESTROY); SweepBackgroundThings(rt, false); @@ -4025,7 +4107,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC) for (unsigned i = 0 ; i < FINALIZE_LIMIT ; ++i) { JS_ASSERT_IF(!IsBackgroundFinalized(AllocKind(i)) || - !rt->gcSweepOnBackgroundThread, + !rt->gc.sweepOnBackgroundThread, !zone->allocator.arenas.arenaListsToSweep[i]); } #endif @@ -4045,7 +4127,7 @@ EndSweepPhase(JSRuntime *rt, JSGCInvocationKind gckind, bool lastGC) FinishMarkingValidation(rt); - rt->gcLastGCTime = PRMJ_Now(); + rt->gc.lastGCTime = PRMJ_Now(); } namespace { @@ -4070,13 +4152,13 @@ class AutoGCSession AutoTraceSession::AutoTraceSession(JSRuntime *rt, js::HeapState heapState) : lock(rt), runtime(rt), - prevState(rt->heapState) + prevState(rt->gc.heapState) { - JS_ASSERT(!rt->noGCOrAllocationCheck); + JS_ASSERT(!rt->gc.noGCOrAllocationCheck); JS_ASSERT(!rt->isHeapBusy()); JS_ASSERT(heapState != Idle); #ifdef JSGC_GENERATIONAL - JS_ASSERT_IF(heapState == MajorCollecting, rt->gcNursery.isEmpty()); + JS_ASSERT_IF(heapState == MajorCollecting, rt->gc.nursery.isEmpty()); #endif // Threads with an exclusive context can hit refillFreeList while holding @@ -4090,12 +4172,12 @@ AutoTraceSession::AutoTraceSession(JSRuntime *rt, js::HeapState heapState) // presence of exclusive threads, to avoid racing with refillFreeList. #ifdef JS_THREADSAFE AutoLockWorkerThreadState lock; - rt->heapState = heapState; + rt->gc.heapState = heapState; #else MOZ_CRASH(); #endif } else { - rt->heapState = heapState; + rt->gc.heapState = heapState; } } @@ -4106,7 +4188,7 @@ AutoTraceSession::~AutoTraceSession() if (runtime->exclusiveThreadsPresent()) { #ifdef JS_THREADSAFE AutoLockWorkerThreadState lock; - runtime->heapState = prevState; + runtime->gc.heapState = prevState; // Notify any worker threads waiting for the trace session to end. WorkerThreadState().notifyAll(GlobalWorkerThreadState::PRODUCER); @@ -4114,7 +4196,7 @@ AutoTraceSession::~AutoTraceSession() MOZ_CRASH(); #endif } else { - runtime->heapState = prevState; + runtime->gc.heapState = prevState; } } @@ -4123,10 +4205,10 @@ AutoGCSession::AutoGCSession(JSRuntime *rt) session(rt, MajorCollecting), canceled(false) { - runtime->gcIsNeeded = false; - runtime->gcInterFrameGC = true; + runtime->gc.isNeeded = false; + runtime->gc.interFrameGC = true; - runtime->gcNumber++; + runtime->gc.number++; // It's ok if threads other than the main thread have suppressGC set, as // they are operating on zones which will not be collected from here. @@ -4139,14 +4221,14 @@ AutoGCSession::~AutoGCSession() return; #ifndef JS_MORE_DETERMINISTIC - runtime->gcNextFullGCTime = PRMJ_Now() + GC_IDLE_FULL_SPAN; + runtime->gc.nextFullGCTime = PRMJ_Now() + GC_IDLE_FULL_SPAN; #endif - runtime->gcChunkAllocationSinceLastGC = false; + runtime->gc.chunkAllocationSinceLastGC = false; #ifdef JS_GC_ZEAL /* Keeping these around after a GC is dangerous. */ - runtime->gcSelectedForMarking.clearAndFree(); + runtime->gc.selectedForMarking.clearAndFree(); #endif /* Clear gcMallocBytes for all compartments */ @@ -4197,7 +4279,7 @@ IncrementalCollectSlice(JSRuntime *rt, static void ResetIncrementalGC(JSRuntime *rt, const char *reason) { - switch (rt->gcIncrementalState) { + switch (rt->gc.incrementalState) { case NO_INCREMENTAL: return; @@ -4205,8 +4287,8 @@ ResetIncrementalGC(JSRuntime *rt, const char *reason) /* Cancel any ongoing marking. */ AutoCopyFreeListToArenasForGC copy(rt); - rt->gcMarker.reset(); - rt->gcMarker.stop(); + rt->gc.marker.reset(); + rt->gc.marker.stop(); for (GCCompartmentsIter c(rt); !c.done(); c.next()) { ArrayBufferObject::resetArrayBufferList(c); @@ -4221,26 +4303,26 @@ ResetIncrementalGC(JSRuntime *rt, const char *reason) rt->setNeedsBarrier(false); AssertNeedsBarrierFlagsConsistent(rt); - rt->gcIncrementalState = NO_INCREMENTAL; + rt->gc.incrementalState = NO_INCREMENTAL; - JS_ASSERT(!rt->gcStrictCompartmentChecking); + JS_ASSERT(!rt->gc.strictCompartmentChecking); break; } case SWEEP: - rt->gcMarker.reset(); + rt->gc.marker.reset(); for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) zone->scheduledForDestruction = false; /* Finish sweeping the current zone group, then abort. */ - rt->gcAbortSweepAfterCurrentGroup = true; + rt->gc.abortSweepAfterCurrentGroup = true; IncrementalCollectSlice(rt, SliceBudget::Unlimited, JS::gcreason::RESET, GC_NORMAL); { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); - rt->gcHelperThread.waitBackgroundSweepOrAllocEnd(); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); + rt->gc.helperThread.waitBackgroundSweepOrAllocEnd(); } break; @@ -4248,7 +4330,7 @@ ResetIncrementalGC(JSRuntime *rt, const char *reason) MOZ_ASSUME_UNREACHABLE("Invalid incremental GC state"); } - rt->gcStats.reset(reason); + rt->gc.stats.reset(reason); #ifdef DEBUG for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) @@ -4327,10 +4409,10 @@ PushZealSelectedObjects(JSRuntime *rt) { #ifdef JS_GC_ZEAL /* Push selected objects onto the mark stack and clear the list. */ - for (JSObject **obj = rt->gcSelectedForMarking.begin(); - obj != rt->gcSelectedForMarking.end(); obj++) + for (JSObject **obj = rt->gc.selectedForMarking.begin(); + obj != rt->gc.selectedForMarking.end(); obj++) { - MarkObjectUnbarriered(&rt->gcMarker, obj, "selected obj"); + MarkObjectUnbarriered(&rt->gc.marker, obj, "selected obj"); } #endif } @@ -4348,7 +4430,7 @@ IncrementalCollectSlice(JSRuntime *rt, bool lastGC = (reason == JS::gcreason::DESTROY_RUNTIME); - gc::State initialState = rt->gcIncrementalState; + gc::State initialState = rt->gc.incrementalState; int zeal = 0; #ifdef JS_GC_ZEAL @@ -4362,8 +4444,8 @@ IncrementalCollectSlice(JSRuntime *rt, } #endif - JS_ASSERT_IF(rt->gcIncrementalState != NO_INCREMENTAL, rt->gcIsIncremental); - rt->gcIsIncremental = budget != SliceBudget::Unlimited; + JS_ASSERT_IF(rt->gc.incrementalState != NO_INCREMENTAL, rt->gc.isIncremental); + rt->gc.isIncremental = budget != SliceBudget::Unlimited; if (zeal == ZealIncrementalRootsThenFinish || zeal == ZealIncrementalMarkAllThenFinish) { /* @@ -4375,46 +4457,46 @@ IncrementalCollectSlice(JSRuntime *rt, SliceBudget sliceBudget(budget); - if (rt->gcIncrementalState == NO_INCREMENTAL) { - rt->gcIncrementalState = MARK_ROOTS; - rt->gcLastMarkSlice = false; + if (rt->gc.incrementalState == NO_INCREMENTAL) { + rt->gc.incrementalState = MARK_ROOTS; + rt->gc.lastMarkSlice = false; } - if (rt->gcIncrementalState == MARK) - AutoGCRooter::traceAllWrappers(&rt->gcMarker); + if (rt->gc.incrementalState == MARK) + AutoGCRooter::traceAllWrappers(&rt->gc.marker); - switch (rt->gcIncrementalState) { + switch (rt->gc.incrementalState) { case MARK_ROOTS: if (!BeginMarkPhase(rt)) { - rt->gcIncrementalState = NO_INCREMENTAL; + rt->gc.incrementalState = NO_INCREMENTAL; return; } if (!lastGC) PushZealSelectedObjects(rt); - rt->gcIncrementalState = MARK; + rt->gc.incrementalState = MARK; - if (rt->gcIsIncremental && zeal == ZealIncrementalRootsThenFinish) + if (rt->gc.isIncremental && zeal == ZealIncrementalRootsThenFinish) break; /* fall through */ case MARK: { /* If we needed delayed marking for gray roots, then collect until done. */ - if (!rt->gcMarker.hasBufferedGrayRoots()) { + if (!rt->gc.marker.hasBufferedGrayRoots()) { sliceBudget.reset(); - rt->gcIsIncremental = false; + rt->gc.isIncremental = false; } bool finished = DrainMarkStack(rt, sliceBudget, gcstats::PHASE_MARK); if (!finished) break; - JS_ASSERT(rt->gcMarker.isDrained()); + JS_ASSERT(rt->gc.marker.isDrained()); - if (!rt->gcLastMarkSlice && rt->gcIsIncremental && + if (!rt->gc.lastMarkSlice && rt->gc.isIncremental && ((initialState == MARK && zeal != ZealIncrementalRootsThenFinish) || zeal == ZealIncrementalMarkAllThenFinish)) { @@ -4423,11 +4505,11 @@ IncrementalCollectSlice(JSRuntime *rt, * slice. We will need to mark anything new on the stack * when we resume, so we stay in MARK state. */ - rt->gcLastMarkSlice = true; + rt->gc.lastMarkSlice = true; break; } - rt->gcIncrementalState = SWEEP; + rt->gc.incrementalState = SWEEP; /* * This runs to completion, but we don't continue if the budget is @@ -4441,7 +4523,7 @@ IncrementalCollectSlice(JSRuntime *rt, * Always yield here when running in incremental multi-slice zeal * mode, so RunDebugGC can reset the slice buget. */ - if (rt->gcIsIncremental && zeal == ZealIncrementalMultipleSlices) + if (rt->gc.isIncremental && zeal == ZealIncrementalMultipleSlices) break; /* fall through */ @@ -4454,10 +4536,10 @@ IncrementalCollectSlice(JSRuntime *rt, EndSweepPhase(rt, gckind, lastGC); - if (rt->gcSweepOnBackgroundThread) - rt->gcHelperThread.startBackgroundSweep(gckind == GC_SHRINK); + if (rt->gc.sweepOnBackgroundThread) + rt->gc.helperThread.startBackgroundSweep(gckind == GC_SHRINK); - rt->gcIncrementalState = NO_INCREMENTAL; + rt->gc.incrementalState = NO_INCREMENTAL; break; } @@ -4474,7 +4556,7 @@ gc::IsIncrementalGCSafe(JSRuntime *rt) if (rt->keepAtoms()) return IncrementalSafety::Unsafe("keepAtoms set"); - if (!rt->gcIncrementalEnabled) + if (!rt->gc.incrementalEnabled) return IncrementalSafety::Unsafe("incremental permanently disabled"); return IncrementalSafety::Safe(); @@ -4487,30 +4569,30 @@ BudgetIncrementalGC(JSRuntime *rt, int64_t *budget) if (!safe) { ResetIncrementalGC(rt, safe.reason()); *budget = SliceBudget::Unlimited; - rt->gcStats.nonincremental(safe.reason()); + rt->gc.stats.nonincremental(safe.reason()); return; } if (rt->gcMode() != JSGC_MODE_INCREMENTAL) { ResetIncrementalGC(rt, "GC mode change"); *budget = SliceBudget::Unlimited; - rt->gcStats.nonincremental("GC mode"); + rt->gc.stats.nonincremental("GC mode"); return; } if (rt->isTooMuchMalloc()) { *budget = SliceBudget::Unlimited; - rt->gcStats.nonincremental("malloc bytes trigger"); + rt->gc.stats.nonincremental("malloc bytes trigger"); } bool reset = false; for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) { if (zone->gcBytes >= zone->gcTriggerBytes) { *budget = SliceBudget::Unlimited; - rt->gcStats.nonincremental("allocation trigger"); + rt->gc.stats.nonincremental("allocation trigger"); } - if (rt->gcIncrementalState != NO_INCREMENTAL && + if (rt->gc.incrementalState != NO_INCREMENTAL && zone->isGCScheduled() != zone->wasGCStarted()) { reset = true; @@ -4518,7 +4600,7 @@ BudgetIncrementalGC(JSRuntime *rt, int64_t *budget) if (zone->isTooMuchMalloc()) { *budget = SliceBudget::Unlimited; - rt->gcStats.nonincremental("malloc bytes trigger"); + rt->gc.stats.nonincremental("malloc bytes trigger"); } } @@ -4548,23 +4630,23 @@ GCCycle(JSRuntime *rt, bool incremental, int64_t budget, * when manipulating the chunks during the GC. */ { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); - rt->gcHelperThread.waitBackgroundSweepOrAllocEnd(); + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_WAIT_BACKGROUND_THREAD); + rt->gc.helperThread.waitBackgroundSweepOrAllocEnd(); } - State prevState = rt->gcIncrementalState; + State prevState = rt->gc.incrementalState; if (!incremental) { /* If non-incremental GC was requested, reset incremental GC. */ ResetIncrementalGC(rt, "requested"); - rt->gcStats.nonincremental("requested"); + rt->gc.stats.nonincremental("requested"); budget = SliceBudget::Unlimited; } else { BudgetIncrementalGC(rt, &budget); } /* The GC was reset, so we need a do-over. */ - if (prevState != NO_INCREMENTAL && rt->gcIncrementalState == NO_INCREMENTAL) { + if (prevState != NO_INCREMENTAL && rt->gc.incrementalState == NO_INCREMENTAL) { gcsession.cancel(); return true; } @@ -4611,12 +4693,12 @@ class AutoDisableStoreBuffer public: AutoDisableStoreBuffer(JSRuntime *rt) : runtime(rt) { - prior = rt->gcStoreBuffer.isEnabled(); - rt->gcStoreBuffer.disable(); + prior = rt->gc.storeBuffer.isEnabled(); + rt->gc.storeBuffer.disable(); } ~AutoDisableStoreBuffer() { if (prior) - runtime->gcStoreBuffer.enable(); + runtime->gc.storeBuffer.enable(); } }; #else @@ -4647,7 +4729,7 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, AutoTraceLog logGC(logger, TraceLogger::GC); #ifdef JS_GC_ZEAL - if (rt->gcDeterministicOnly && !IsDeterministicGCReason(reason)) + if (rt->gc.deterministicOnly && !IsDeterministicGCReason(reason)) return; #endif @@ -4666,7 +4748,7 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, zone->scheduleGC(); /* This is a heuristic to avoid resets. */ - if (rt->gcIncrementalState != NO_INCREMENTAL && zone->needsBarrier()) + if (rt->gc.incrementalState != NO_INCREMENTAL && zone->needsBarrier()) zone->scheduleGC(); zoneCount++; @@ -4677,7 +4759,7 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, for (CompartmentsIter c(rt, WithAtoms); !c.done(); c.next()) compartmentCount++; - rt->gcShouldCleanUpEverything = ShouldCleanUpEverything(rt, reason, gckind); + rt->gc.shouldCleanUpEverything = ShouldCleanUpEverything(rt, reason, gckind); bool repeat = false; do { @@ -4689,29 +4771,29 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, */ AutoDisableStoreBuffer adsb(rt); - gcstats::AutoGCSlice agc(rt->gcStats, collectedCount, zoneCount, compartmentCount, reason); + gcstats::AutoGCSlice agc(rt->gc.stats, collectedCount, zoneCount, compartmentCount, reason); /* * Let the API user decide to defer a GC if it wants to (unless this * is the last context). Invoke the callback regardless. */ - if (rt->gcIncrementalState == NO_INCREMENTAL) { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_GC_BEGIN); - if (JSGCCallback callback = rt->gcCallback) - callback(rt, JSGC_BEGIN, rt->gcCallbackData); + if (rt->gc.incrementalState == NO_INCREMENTAL) { + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_GC_BEGIN); + if (JSGCCallback callback = rt->gc.callback) + callback(rt, JSGC_BEGIN, rt->gc.callbackData); } - rt->gcPoke = false; + rt->gc.poke = false; bool wasReset = GCCycle(rt, incremental, budget, gckind, reason); - if (rt->gcIncrementalState == NO_INCREMENTAL) { - gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_GC_END); - if (JSGCCallback callback = rt->gcCallback) - callback(rt, JSGC_END, rt->gcCallbackData); + if (rt->gc.incrementalState == NO_INCREMENTAL) { + gcstats::AutoPhase ap(rt->gc.stats, gcstats::PHASE_GC_END); + if (JSGCCallback callback = rt->gc.callback) + callback(rt, JSGC_END, rt->gc.callbackData); } /* Need to re-schedule all zones for GC. */ - if (rt->gcPoke && rt->gcShouldCleanUpEverything) + if (rt->gc.poke && rt->gc.shouldCleanUpEverything) JS::PrepareForFullGC(rt); /* @@ -4720,10 +4802,10 @@ Collect(JSRuntime *rt, bool incremental, int64_t budget, * case) until we can be sure that no additional garbage is created * (which typically happens if roots are dropped during finalizers). */ - repeat = (rt->gcPoke && rt->gcShouldCleanUpEverything) || wasReset; + repeat = (rt->gc.poke && rt->gc.shouldCleanUpEverything) || wasReset; } while (repeat); - if (rt->gcIncrementalState == NO_INCREMENTAL) { + if (rt->gc.incrementalState == NO_INCREMENTAL) { #ifdef JS_THREADSAFE EnqueuePendingParseTasksAfterGC(rt); #endif @@ -4742,10 +4824,10 @@ js::GCSlice(JSRuntime *rt, JSGCInvocationKind gckind, JS::gcreason::Reason reaso int64_t sliceBudget; if (millis) sliceBudget = SliceBudget::TimeBudget(millis); - else if (rt->gcHighFrequencyGC && rt->gcDynamicMarkSlice) - sliceBudget = rt->gcSliceBudget * IGC_MARK_SLICE_MULTIPLIER; + else if (rt->gc.highFrequencyGC && rt->gc.dynamicMarkSlice) + sliceBudget = rt->gc.sliceBudget * IGC_MARK_SLICE_MULTIPLIER; else - sliceBudget = rt->gcSliceBudget; + sliceBudget = rt->gc.sliceBudget; Collect(rt, true, sliceBudget, gckind, reason); } @@ -4796,7 +4878,7 @@ JS::ShrinkGCBuffers(JSRuntime *rt) if (!rt->useHelperThreads()) ExpireChunksAndArenas(rt, true); else - rt->gcHelperThread.startBackgroundShrink(); + rt->gc.helperThread.startBackgroundShrink(); } void @@ -4805,8 +4887,8 @@ js::MinorGC(JSRuntime *rt, JS::gcreason::Reason reason) #ifdef JSGC_GENERATIONAL TraceLogger *logger = TraceLoggerForMainThread(rt); AutoTraceLog logMinorGC(logger, TraceLogger::MinorGC); - rt->gcNursery.collect(rt, reason, nullptr); - JS_ASSERT_IF(!rt->mainThread.suppressGC, rt->gcNursery.isEmpty()); + rt->gc.nursery.collect(rt, reason, nullptr); + JS_ASSERT_IF(!rt->mainThread.suppressGC, rt->gc.nursery.isEmpty()); #endif } @@ -4821,12 +4903,12 @@ js::MinorGC(JSContext *cx, JS::gcreason::Reason reason) Nursery::TypeObjectList pretenureTypes; JSRuntime *rt = cx->runtime(); - rt->gcNursery.collect(cx->runtime(), reason, &pretenureTypes); + rt->gc.nursery.collect(cx->runtime(), reason, &pretenureTypes); for (size_t i = 0; i < pretenureTypes.length(); i++) { if (pretenureTypes[i]->canPreTenure()) pretenureTypes[i]->setShouldPreTenure(cx); } - JS_ASSERT_IF(!rt->mainThread.suppressGC, rt->gcNursery.isEmpty()); + JS_ASSERT_IF(!rt->mainThread.suppressGC, rt->gc.nursery.isEmpty()); #endif } @@ -4840,18 +4922,18 @@ js::gc::GCIfNeeded(JSContext *cx) * In case of store buffer overflow perform minor GC first so that the * correct reason is seen in the logs. */ - if (rt->gcStoreBuffer.isAboutToOverflow()) + if (rt->gc.storeBuffer.isAboutToOverflow()) MinorGC(cx, JS::gcreason::FULL_STORE_BUFFER); #endif - if (rt->gcIsNeeded) - GCSlice(rt, GC_NORMAL, rt->gcTriggerReason); + if (rt->gc.isNeeded) + GCSlice(rt, GC_NORMAL, rt->gc.triggerReason); } void js::gc::FinishBackgroundFinalize(JSRuntime *rt) { - rt->gcHelperThread.waitBackgroundSweepEnd(); + rt->gc.helperThread.waitBackgroundSweepEnd(); } AutoFinishGC::AutoFinishGC(JSRuntime *rt) @@ -4907,7 +4989,7 @@ js::NewCompartment(JSContext *cx, Zone *zone, JSPrincipals *principals, return nullptr; } - if (zoneHolder && !rt->zones.append(zone)) { + if (zoneHolder && !rt->gc.zones.append(zone)) { js_ReportOutOfMemory(cx); return nullptr; } @@ -4934,13 +5016,13 @@ gc::MergeCompartments(JSCompartment *source, JSCompartment *target) // Fixup compartment pointers in source to refer to target. - for (CellIter iter(source->zone(), FINALIZE_SCRIPT); !iter.done(); iter.next()) { + for (ZoneCellIter iter(source->zone(), FINALIZE_SCRIPT); !iter.done(); iter.next()) { JSScript *script = iter.get(); JS_ASSERT(script->compartment() == source); script->compartment_ = target; } - for (CellIter iter(source->zone(), FINALIZE_BASE_SHAPE); !iter.done(); iter.next()) { + for (ZoneCellIter iter(source->zone(), FINALIZE_BASE_SHAPE); !iter.done(); iter.next()) { BaseShape *base = iter.get(); JS_ASSERT(base->compartment() == source); base->compartment_ = target; @@ -4987,7 +5069,7 @@ gc::RunDebugGC(JSContext *cx) type == ZealIncrementalMarkAllThenFinish || type == ZealIncrementalMultipleSlices) { - js::gc::State initialState = rt->gcIncrementalState; + js::gc::State initialState = rt->gc.incrementalState; int64_t budget; if (type == ZealIncrementalMultipleSlices) { /* @@ -4996,10 +5078,10 @@ gc::RunDebugGC(JSContext *cx) * completion. */ if (initialState == NO_INCREMENTAL) - rt->gcIncrementalLimit = rt->gcZealFrequency / 2; + rt->gc.incrementalLimit = rt->gc.zealFrequency / 2; else - rt->gcIncrementalLimit *= 2; - budget = SliceBudget::WorkBudget(rt->gcIncrementalLimit); + rt->gc.incrementalLimit *= 2; + budget = SliceBudget::WorkBudget(rt->gc.incrementalLimit); } else { // This triggers incremental GC but is actually ignored by IncrementalMarkSlice. budget = SliceBudget::WorkBudget(1); @@ -5012,9 +5094,9 @@ gc::RunDebugGC(JSContext *cx) * phase. */ if (type == ZealIncrementalMultipleSlices && - initialState == MARK && rt->gcIncrementalState == SWEEP) + initialState == MARK && rt->gc.incrementalState == SWEEP) { - rt->gcIncrementalLimit = rt->gcZealFrequency / 2; + rt->gc.incrementalLimit = rt->gc.zealFrequency / 2; } } else { Collect(rt, false, SliceBudget::Unlimited, GC_NORMAL, JS::gcreason::DEBUG_GC); @@ -5028,7 +5110,7 @@ gc::SetDeterministicGC(JSContext *cx, bool enabled) { #ifdef JS_GC_ZEAL JSRuntime *rt = cx->runtime(); - rt->gcDeterministicOnly = enabled; + rt->gc.deterministicOnly = enabled; #endif } @@ -5036,14 +5118,14 @@ void gc::SetValidateGC(JSContext *cx, bool enabled) { JSRuntime *rt = cx->runtime(); - rt->gcValidate = enabled; + rt->gc.validate = enabled; } void gc::SetFullCompartmentChecks(JSContext *cx, bool enabled) { JSRuntime *rt = cx->runtime(); - rt->gcFullCompartmentChecks = enabled; + rt->gc.fullCompartmentChecks = enabled; } #ifdef DEBUG @@ -5075,7 +5157,7 @@ js::ReleaseAllJITCode(FreeOp *fop) # ifdef DEBUG /* Assert no baseline scripts are marked as active. */ - for (CellIter i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIter i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); JS_ASSERT_IF(script->hasBaselineScript(), !script->baselineScript()->active()); } @@ -5086,7 +5168,7 @@ js::ReleaseAllJITCode(FreeOp *fop) jit::InvalidateAll(fop, zone); - for (CellIter i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIter i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); jit::FinishInvalidation(fop, script); jit::FinishInvalidation(fop, script); @@ -5131,15 +5213,15 @@ static void ReleaseScriptCounts(FreeOp *fop) { JSRuntime *rt = fop->runtime(); - JS_ASSERT(rt->scriptAndCountsVector); + JS_ASSERT(rt->gc.scriptAndCountsVector); - ScriptAndCountsVector &vec = *rt->scriptAndCountsVector; + ScriptAndCountsVector &vec = *rt->gc.scriptAndCountsVector; for (size_t i = 0; i < vec.length(); i++) vec[i].scriptCounts.destroy(fop); - fop->delete_(rt->scriptAndCountsVector); - rt->scriptAndCountsVector = nullptr; + fop->delete_(rt->gc.scriptAndCountsVector); + rt->gc.scriptAndCountsVector = nullptr; } JS_FRIEND_API(void) @@ -5150,7 +5232,7 @@ js::StartPCCountProfiling(JSContext *cx) if (rt->profilingScripts) return; - if (rt->scriptAndCountsVector) + if (rt->gc.scriptAndCountsVector) ReleaseScriptCounts(rt->defaultFreeOp()); ReleaseAllJITCode(rt->defaultFreeOp()); @@ -5165,7 +5247,7 @@ js::StopPCCountProfiling(JSContext *cx) if (!rt->profilingScripts) return; - JS_ASSERT(!rt->scriptAndCountsVector); + JS_ASSERT(!rt->gc.scriptAndCountsVector); ReleaseAllJITCode(rt->defaultFreeOp()); @@ -5174,7 +5256,7 @@ js::StopPCCountProfiling(JSContext *cx) return; for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) { - for (CellIter i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIter i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->hasScriptCounts() && script->types) { ScriptAndCounts sac; @@ -5187,7 +5269,7 @@ js::StopPCCountProfiling(JSContext *cx) } rt->profilingScripts = false; - rt->scriptAndCountsVector = vec; + rt->gc.scriptAndCountsVector = vec; } JS_FRIEND_API(void) @@ -5195,7 +5277,7 @@ js::PurgePCCounts(JSContext *cx) { JSRuntime *rt = cx->runtime(); - if (!rt->scriptAndCountsVector) + if (!rt->gc.scriptAndCountsVector) return; JS_ASSERT(!rt->profilingScripts); @@ -5206,7 +5288,7 @@ void js::PurgeJITCaches(Zone *zone) { #ifdef JS_ION - for (CellIterUnderGC i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIterUnderGC i(zone, FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); /* Discard Ion caches. */ @@ -5290,27 +5372,27 @@ ArenaLists::containsArena(JSRuntime *rt, ArenaHeader *needle) AutoMaybeTouchDeadZones::AutoMaybeTouchDeadZones(JSContext *cx) : runtime(cx->runtime()), - markCount(runtime->gcObjectsMarkedInDeadZones), + markCount(runtime->gc.objectsMarkedInDeadZones), inIncremental(JS::IsIncrementalGCInProgress(runtime)), - manipulatingDeadZones(runtime->gcManipulatingDeadZones) + manipulatingDeadZones(runtime->gc.manipulatingDeadZones) { - runtime->gcManipulatingDeadZones = true; + runtime->gc.manipulatingDeadZones = true; } AutoMaybeTouchDeadZones::AutoMaybeTouchDeadZones(JSObject *obj) : runtime(obj->compartment()->runtimeFromMainThread()), - markCount(runtime->gcObjectsMarkedInDeadZones), + markCount(runtime->gc.objectsMarkedInDeadZones), inIncremental(JS::IsIncrementalGCInProgress(runtime)), - manipulatingDeadZones(runtime->gcManipulatingDeadZones) + manipulatingDeadZones(runtime->gc.manipulatingDeadZones) { - runtime->gcManipulatingDeadZones = true; + runtime->gc.manipulatingDeadZones = true; } AutoMaybeTouchDeadZones::~AutoMaybeTouchDeadZones() { - runtime->gcManipulatingDeadZones = manipulatingDeadZones; + runtime->gc.manipulatingDeadZones = manipulatingDeadZones; - if (inIncremental && runtime->gcObjectsMarkedInDeadZones != markCount) { + if (inIncremental && runtime->gc.objectsMarkedInDeadZones != markCount) { JS::PrepareForFullGC(runtime); js::GC(runtime, GC_NORMAL, JS::gcreason::TRANSPLANT); } @@ -5343,7 +5425,7 @@ js::UninlinedIsInsideNursery(JSRuntime *rt, const void *thing) #ifdef DEBUG AutoDisableProxyCheck::AutoDisableProxyCheck(JSRuntime *rt MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) - : count(rt->gcDisableStrictProxyCheckingCount) + : count(rt->gc.disableStrictProxyCheckingCount) { MOZ_GUARD_OBJECT_NOTIFIER_INIT; count++; @@ -5362,7 +5444,7 @@ JS::GetGCNumber() JSRuntime *rt = js::TlsPerThreadData.get()->runtimeFromMainThread(); if (!rt) return 0; - return rt->gcNumber; + return rt->gc.number; } JS::AutoAssertNoGC::AutoAssertNoGC() @@ -5378,18 +5460,18 @@ JS::AutoAssertNoGC::AutoAssertNoGC() */ runtime = data->runtimeIfOnOwnerThread(); if (runtime) - gcNumber = runtime->gcNumber; + gcNumber = runtime->gc.number; } } JS::AutoAssertNoGC::AutoAssertNoGC(JSRuntime *rt) - : runtime(rt), gcNumber(rt->gcNumber) + : runtime(rt), gcNumber(rt->gc.number) { } JS::AutoAssertNoGC::~AutoAssertNoGC() { if (runtime) - MOZ_ASSERT(gcNumber == runtime->gcNumber, "GC ran inside an AutoAssertNoGC scope."); + MOZ_ASSERT(gcNumber == runtime->gc.number, "GC ran inside an AutoAssertNoGC scope."); } #endif diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 34f4b424883c..96e6ab1c5259 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -50,6 +50,18 @@ enum HeapState { MinorCollecting // doing a GC of the minor heap (nursery) }; +struct ExtraTracer { + JSTraceDataOp op; + void *data; + + ExtraTracer() + : op(nullptr), data(nullptr) + {} + ExtraTracer(JSTraceDataOp op, void *data) + : op(op), data(data) + {} +}; + namespace jit { class JitCode; } diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index d24f429a0fb8..3b6a47882420 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -27,8 +27,8 @@ struct AutoMarkInDeadZone scheduled(zone->scheduledForDestruction) { JSRuntime *rt = zone->runtimeFromMainThread(); - if (rt->gcManipulatingDeadZones && zone->scheduledForDestruction) { - rt->gcObjectsMarkedInDeadZones++; + if (rt->gc.manipulatingDeadZones && zone->scheduledForDestruction) { + rt->gc.objectsMarkedInDeadZones++; zone->scheduledForDestruction = false; } } @@ -106,12 +106,12 @@ GetGCThingTraceKind(const void *thing) static inline void GCPoke(JSRuntime *rt) { - rt->gcPoke = true; + rt->gc.poke = true; #ifdef JS_GC_ZEAL /* Schedule a GC to happen "soon" after a GC poke. */ if (rt->gcZeal() == js::gc::ZealPokeValue) - rt->gcNextScheduled = 1; + rt->gc.nextScheduled = 1; #endif } @@ -122,21 +122,12 @@ class ArenaIter public: ArenaIter() { - init(); - } - - ArenaIter(JS::Zone *zone, AllocKind kind) { - init(zone, kind); - } - - void init() { aheader = nullptr; remainingHeader = nullptr; } - void init(ArenaHeader *aheaderArg) { - aheader = aheaderArg; - remainingHeader = nullptr; + ArenaIter(JS::Zone *zone, AllocKind kind) { + init(zone, kind); } void init(JS::Zone *zone, AllocKind kind) { @@ -148,15 +139,16 @@ class ArenaIter } } - bool done() { + bool done() const { return !aheader; } - ArenaHeader *get() { + ArenaHeader *get() const { return aheader; } void next() { + JS_ASSERT(!done()); aheader = aheader->next; if (!aheader) { aheader = remainingHeader; @@ -165,99 +157,160 @@ class ArenaIter } }; -class CellIterImpl +class ArenaCellIterImpl { + // These three are set in initUnsynchronized(). size_t firstThingOffset; size_t thingSize; - ArenaIter aiter; - FreeSpan firstSpan; - const FreeSpan *span; +#ifdef DEBUG + bool isInited; +#endif + + // These three are set in reset() (which is called by init()). + FreeSpan span; uintptr_t thing; - Cell *cell; + uintptr_t limit; - protected: - CellIterImpl() { - } - - void initSpan(JS::Zone *zone, AllocKind kind) { - JS_ASSERT(zone->allocator.arenas.isSynchronizedFreeList(kind)); - firstThingOffset = Arena::firstThingOffset(kind); - thingSize = Arena::thingSize(kind); - firstSpan.initAsEmpty(); - span = &firstSpan; - thing = span->first; - } - - void init(ArenaHeader *singleAheader) { - initSpan(singleAheader->zone, singleAheader->getAllocKind()); - aiter.init(singleAheader); - next(); - aiter.init(); - } - - void init(JS::Zone *zone, AllocKind kind) { - initSpan(zone, kind); - aiter.init(zone, kind); - next(); + // Upon entry, |thing| points to any thing (free or used) and finds the + // first used thing, which may be |thing|. + void moveForwardIfFree() { + JS_ASSERT(!done()); + if (thing == span.first) { + if (span.hasNext()) { + thing = span.last + thingSize; + span = *span.nextSpan(); + } else { + thing = limit; + } + } } public: - bool done() const { - return !cell; + ArenaCellIterImpl() {} + + void initUnsynchronized(ArenaHeader *aheader) { + AllocKind kind = aheader->getAllocKind(); +#ifdef DEBUG + isInited = true; +#endif + firstThingOffset = Arena::firstThingOffset(kind); + thingSize = Arena::thingSize(kind); + reset(aheader); } - template T *get() const { - JS_ASSERT(!done()); - return static_cast(cell); + void init(ArenaHeader *aheader) { +#ifdef DEBUG + AllocKind kind = aheader->getAllocKind(); + JS_ASSERT(aheader->zone->allocator.arenas.isSynchronizedFreeList(kind)); +#endif + initUnsynchronized(aheader); + } + + // Use this to move from an Arena of a particular kind to another Arena of + // the same kind. + void reset(ArenaHeader *aheader) { + JS_ASSERT(isInited); + span = aheader->getFirstFreeSpan(); + uintptr_t arenaAddr = aheader->arenaAddress(); + thing = arenaAddr + firstThingOffset; + limit = arenaAddr + ArenaSize; + moveForwardIfFree(); + } + + bool done() const { + return thing == limit; } Cell *getCell() const { JS_ASSERT(!done()); - return cell; + return reinterpret_cast(thing); + } + + template T *get() const { + JS_ASSERT(!done()); + return static_cast(getCell()); } void next() { - for (;;) { - if (thing != span->first) - break; - if (MOZ_LIKELY(span->hasNext())) { - thing = span->last + thingSize; - span = span->nextSpan(); - break; - } - if (aiter.done()) { - cell = nullptr; - return; - } - ArenaHeader *aheader = aiter.get(); - firstSpan = aheader->getFirstFreeSpan(); - span = &firstSpan; - thing = aheader->arenaAddress() | firstThingOffset; - aiter.next(); - } - cell = reinterpret_cast(thing); + MOZ_ASSERT(!done()); thing += thingSize; + if (thing < limit) + moveForwardIfFree(); } }; -class CellIterUnderGC : public CellIterImpl +class ArenaCellIterUnderGC : public ArenaCellIterImpl { public: - CellIterUnderGC(JS::Zone *zone, AllocKind kind) { -#ifdef JSGC_GENERATIONAL - JS_ASSERT(zone->runtimeFromAnyThread()->gcNursery.isEmpty()); -#endif - JS_ASSERT(zone->runtimeFromAnyThread()->isHeapBusy()); - init(zone, kind); - } - - CellIterUnderGC(ArenaHeader *aheader) { + ArenaCellIterUnderGC(ArenaHeader *aheader) { JS_ASSERT(aheader->zone->runtimeFromAnyThread()->isHeapBusy()); init(aheader); } }; -class CellIter : public CellIterImpl +class ArenaCellIterUnderFinalize : public ArenaCellIterImpl +{ + public: + ArenaCellIterUnderFinalize(ArenaHeader *aheader) { + initUnsynchronized(aheader); + } +}; + +class ZoneCellIterImpl +{ + ArenaIter arenaIter; + ArenaCellIterImpl cellIter; + + protected: + ZoneCellIterImpl() {} + + void init(JS::Zone *zone, AllocKind kind) { + JS_ASSERT(zone->allocator.arenas.isSynchronizedFreeList(kind)); + arenaIter.init(zone, kind); + if (!arenaIter.done()) + cellIter.init(arenaIter.get()); + } + + public: + bool done() const { + return arenaIter.done(); + } + + template T *get() const { + JS_ASSERT(!done()); + return cellIter.get(); + } + + Cell *getCell() const { + JS_ASSERT(!done()); + return cellIter.getCell(); + } + + void next() { + JS_ASSERT(!done()); + cellIter.next(); + if (cellIter.done()) { + JS_ASSERT(!arenaIter.done()); + arenaIter.next(); + if (!arenaIter.done()) + cellIter.reset(arenaIter.get()); + } + } +}; + +class ZoneCellIterUnderGC : public ZoneCellIterImpl +{ + public: + ZoneCellIterUnderGC(JS::Zone *zone, AllocKind kind) { +#ifdef JSGC_GENERATIONAL + JS_ASSERT(zone->runtimeFromAnyThread()->gc.nursery.isEmpty()); +#endif + JS_ASSERT(zone->runtimeFromAnyThread()->isHeapBusy()); + init(zone, kind); + } +}; + +class ZoneCellIter : public ZoneCellIterImpl { ArenaLists *lists; AllocKind kind; @@ -265,7 +318,7 @@ class CellIter : public CellIterImpl size_t *counter; #endif public: - CellIter(JS::Zone *zone, AllocKind kind) + ZoneCellIter(JS::Zone *zone, AllocKind kind) : lists(&zone->allocator.arenas), kind(kind) { @@ -284,7 +337,7 @@ class CellIter : public CellIterImpl #ifdef JSGC_GENERATIONAL /* Evict the nursery before iterating so we can see all things. */ JSRuntime *rt = zone->runtimeFromMainThread(); - if (!rt->gcNursery.isEmpty()) + if (!rt->gc.nursery.isEmpty()) MinorGC(rt, JS::gcreason::EVICT_NURSERY); #endif @@ -296,15 +349,15 @@ class CellIter : public CellIterImpl } #ifdef DEBUG - /* Assert that no GCs can occur while a CellIter is live. */ - counter = &zone->runtimeFromAnyThread()->noGCOrAllocationCheck; + /* Assert that no GCs can occur while a ZoneCellIter is live. */ + counter = &zone->runtimeFromAnyThread()->gc.noGCOrAllocationCheck; ++*counter; #endif init(zone, kind); } - ~CellIter() { + ~ZoneCellIter() { #ifdef DEBUG JS_ASSERT(*counter > 0); --*counter; @@ -353,7 +406,7 @@ class GCZoneGroupIter { public: GCZoneGroupIter(JSRuntime *rt) { JS_ASSERT(rt->isHeapBusy()); - current = rt->gcCurrentZoneGroup; + current = rt->gc.currentZoneGroup; } bool done() const { return !current; } @@ -387,7 +440,7 @@ TryNewNurseryObject(ThreadSafeContext *cxArg, size_t thingSize, size_t nDynamicS JS_ASSERT(!IsAtomsCompartment(cx->compartment())); JSRuntime *rt = cx->runtime(); - Nursery &nursery = rt->gcNursery; + Nursery &nursery = rt->gc.nursery; JSObject *obj = nursery.allocateObject(cx, thingSize, nDynamicSlots); if (obj) return obj; @@ -427,7 +480,7 @@ CheckAllocatorState(ThreadSafeContext *cx, AllocKind kind) kind == FINALIZE_FAT_INLINE_STRING || kind == FINALIZE_JITCODE); JS_ASSERT(!rt->isHeapBusy()); - JS_ASSERT(!rt->noGCOrAllocationCheck); + JS_ASSERT(!rt->gc.noGCOrAllocationCheck); #endif // For testing out of memory conditions diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 367738bff321..fbdae80705af 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -2321,7 +2321,7 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target) /* Mark type sets which contain obj as having a generic object types. */ - for (gc::CellIter i(cx->zone(), gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) { + for (gc::ZoneCellIter i(cx->zone(), gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) { TypeObject *object = i.get(); unsigned count = object->getPropertyCount(); for (unsigned i = 0; i < count; i++) { @@ -2331,7 +2331,7 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target) } } - for (gc::CellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (gc::ZoneCellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { RootedScript script(cx, i.get()); if (script->types) { unsigned count = TypeScript::NumTypeSets(script); @@ -2358,7 +2358,7 @@ TypeCompartment::print(JSContext *cx, bool force) if (!force && !InferSpewActive(ISpewResult)) return; - for (gc::CellIter i(compartment->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (gc::ZoneCellIter i(compartment->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { // Note: use cx->runtime() instead of cx to work around IsInRequest(cx) // assertion failures when we're called from DestroyContext. RootedScript script(cx->runtime(), i.get()); @@ -2366,7 +2366,7 @@ TypeCompartment::print(JSContext *cx, bool force) script->types->printTypes(cx, script); } - for (gc::CellIter i(compartment->zone(), gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) { + for (gc::ZoneCellIter i(compartment->zone(), gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) { TypeObject *object = i.get(); object->print(); } @@ -3917,7 +3917,7 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction * #ifdef JSGC_GENERATIONAL if (proto.isObject() && hasNursery() && nursery().isInside(proto.toObject())) { - asJSContext()->runtime()->gcStoreBuffer.putGeneric( + asJSContext()->runtime()->gc.storeBuffer.putGeneric( NewTypeObjectsSetRef(&newTypeObjects, clasp, proto.toObject(), fun)); } #endif @@ -4255,7 +4255,7 @@ TypeCompartment::sweep(FreeOp *fop) void JSCompartment::sweepNewTypeObjectTable(TypeObjectWithNewScriptSet &table) { - gcstats::AutoPhase ap(runtimeFromMainThread()->gcStats, + gcstats::AutoPhase ap(runtimeFromMainThread()->gc.stats, gcstats::PHASE_SWEEP_TABLES_TYPE_OBJECT); JS_ASSERT(zone()->isGCSweeping()); @@ -4400,9 +4400,9 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom) #endif { - gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_DISCARD_TI); + gcstats::AutoPhase ap2(rt->gc.stats, gcstats::PHASE_DISCARD_TI); - for (CellIterUnderGC i(zone(), FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIterUnderGC i(zone(), FINALIZE_SCRIPT); !i.done(); i.next()) { JSScript *script = i.get(); if (script->types) { types::TypeScript::Sweep(fop, script, oom); @@ -4442,9 +4442,9 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom) } { - gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_SWEEP_TYPES); + gcstats::AutoPhase ap2(rt->gc.stats, gcstats::PHASE_SWEEP_TYPES); - for (gc::CellIterUnderGC iter(zone(), gc::FINALIZE_TYPE_OBJECT); + for (gc::ZoneCellIterUnderGC iter(zone(), gc::FINALIZE_TYPE_OBJECT); !iter.done(); iter.next()) { TypeObject *object = iter.get(); @@ -4470,7 +4470,7 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom) } { - gcstats::AutoPhase ap2(rt->gcStats, gcstats::PHASE_FREE_TI_ARENA); + gcstats::AutoPhase ap2(rt->gc.stats, gcstats::PHASE_FREE_TI_ARENA); rt->freeLifoAlloc.transferFrom(&oldAlloc); } } @@ -4478,7 +4478,7 @@ TypeZone::sweep(FreeOp *fop, bool releaseTypes, bool *oom) void TypeZone::clearAllNewScriptAddendumsOnOOM() { - for (gc::CellIterUnderGC iter(zone(), gc::FINALIZE_TYPE_OBJECT); + for (gc::ZoneCellIterUnderGC iter(zone(), gc::FINALIZE_TYPE_OBJECT); !iter.done(); iter.next()) { TypeObject *object = iter.get(); diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 4d046f54e906..e3ce922a9558 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1503,7 +1503,7 @@ static void GeneratorWriteBarrierPost(JSContext *cx, JSGenerator *gen) { #ifdef JSGC_GENERATIONAL - cx->runtime()->gcStoreBuffer.putWholeCell(gen->obj); + cx->runtime()->gc.storeBuffer.putWholeCell(gen->obj); #endif } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index c9f52631478b..35c2ffba164f 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -507,7 +507,7 @@ Reject(JSContext *cx, HandleId id, unsigned errorNumber, bool throwError, bool * // JS_FRIEND_API(bool) js::CheckDefineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value, - PropertyOp getter, StrictPropertyOp setter, unsigned attrs) + unsigned attrs, PropertyOp getter, StrictPropertyOp setter) { if (!obj->isNative()) return true; @@ -1290,7 +1290,7 @@ NewObject(ExclusiveContext *cx, types::TypeObject *type_, JSObject *parent, gc:: if (!cx->shouldBeJSContext()) return nullptr; JSRuntime *rt = cx->asJSContext()->runtime(); - rt->gcIncrementalEnabled = false; + rt->gc.incrementalEnabled = false; #ifdef DEBUG if (rt->gcMode() == JSGC_MODE_INCREMENTAL) { @@ -2710,7 +2710,7 @@ AllocateSlots(ThreadSafeContext *cx, JSObject *obj, uint32_t nslots) { #ifdef JSGC_GENERATIONAL if (cx->isJSContext()) - return cx->asJSContext()->runtime()->gcNursery.allocateSlots(cx->asJSContext(), obj, nslots); + return cx->asJSContext()->runtime()->gc.nursery.allocateSlots(cx->asJSContext(), obj, nslots); #endif return cx->pod_malloc(nslots); } @@ -2721,9 +2721,9 @@ ReallocateSlots(ThreadSafeContext *cx, JSObject *obj, HeapSlot *oldSlots, { #ifdef JSGC_GENERATIONAL if (cx->isJSContext()) { - return cx->asJSContext()->runtime()->gcNursery.reallocateSlots(cx->asJSContext(), - obj, oldSlots, - oldCount, newCount); + return cx->asJSContext()->runtime()->gc.nursery.reallocateSlots(cx->asJSContext(), + obj, oldSlots, + oldCount, newCount); } #endif return (HeapSlot *)cx->realloc_(oldSlots, oldCount * sizeof(HeapSlot), @@ -2798,7 +2798,7 @@ FreeSlots(ThreadSafeContext *cx, HeapSlot *slots) // Note: threads without a JSContext do not have access to nursery allocated things. #ifdef JSGC_GENERATIONAL if (cx->isJSContext()) - return cx->asJSContext()->runtime()->gcNursery.freeSlots(cx->asJSContext(), slots); + return cx->asJSContext()->runtime()->gc.nursery.freeSlots(cx->asJSContext(), slots); #endif js_free(slots); } @@ -3020,7 +3020,7 @@ AllocateElements(ThreadSafeContext *cx, JSObject *obj, uint32_t nelems) { #ifdef JSGC_GENERATIONAL if (cx->isJSContext()) - return cx->asJSContext()->runtime()->gcNursery.allocateElements(cx->asJSContext(), obj, nelems); + return cx->asJSContext()->runtime()->gc.nursery.allocateElements(cx->asJSContext(), obj, nelems); #endif return static_cast(cx->malloc_(nelems * sizeof(HeapValue))); @@ -3032,9 +3032,9 @@ ReallocateElements(ThreadSafeContext *cx, JSObject *obj, ObjectElements *oldHead { #ifdef JSGC_GENERATIONAL if (cx->isJSContext()) { - return cx->asJSContext()->runtime()->gcNursery.reallocateElements(cx->asJSContext(), obj, - oldHeader, oldCount, - newCount); + return cx->asJSContext()->runtime()->gc.nursery.reallocateElements(cx->asJSContext(), obj, + oldHeader, oldCount, + newCount); } #endif diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 152a11538142..5709b10dad03 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -517,7 +517,7 @@ JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::Initi if (extantSlots) { #ifdef JSGC_GENERATIONAL if (cx->isJSContext()) - cx->asJSContext()->runtime()->gcNursery.notifyInitialSlots(obj, extantSlots); + cx->asJSContext()->runtime()->gc.nursery.notifyInitialSlots(obj, extantSlots); #endif obj->slots = extantSlots; } diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index fc150726decd..b5e4e167340c 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -814,7 +814,7 @@ ToDisassemblySource(JSContext *cx, HandleValue v, JSAutoByteString *bytes) return true; } - if (cx->runtime()->isHeapBusy() || cx->runtime()->noGCOrAllocationCheck) { + if (cx->runtime()->isHeapBusy() || cx->runtime()->gc.noGCOrAllocationCheck) { char *source = JS_sprintf_append(nullptr, ""); if (!source) return false; @@ -1936,10 +1936,10 @@ js::GetPCCountScriptCount(JSContext *cx) { JSRuntime *rt = cx->runtime(); - if (!rt->scriptAndCountsVector) + if (!rt->gc.scriptAndCountsVector) return 0; - return rt->scriptAndCountsVector->length(); + return rt->gc.scriptAndCountsVector->length(); } enum MaybeComma {NO_COMMA, COMMA}; @@ -1974,12 +1974,12 @@ js::GetPCCountScriptSummary(JSContext *cx, size_t index) { JSRuntime *rt = cx->runtime(); - if (!rt->scriptAndCountsVector || index >= rt->scriptAndCountsVector->length()) { + if (!rt->gc.scriptAndCountsVector || index >= rt->gc.scriptAndCountsVector->length()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL); return nullptr; } - const ScriptAndCounts &sac = (*rt->scriptAndCountsVector)[index]; + const ScriptAndCounts &sac = (*rt->gc.scriptAndCountsVector)[index]; RootedScript script(cx, sac.script); /* @@ -2234,12 +2234,12 @@ js::GetPCCountScriptContents(JSContext *cx, size_t index) { JSRuntime *rt = cx->runtime(); - if (!rt->scriptAndCountsVector || index >= rt->scriptAndCountsVector->length()) { + if (!rt->gc.scriptAndCountsVector || index >= rt->gc.scriptAndCountsVector->length()) { JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL); return nullptr; } - const ScriptAndCounts &sac = (*rt->scriptAndCountsVector)[index]; + const ScriptAndCounts &sac = (*rt->gc.scriptAndCountsVector)[index]; JSScript *script = sac.script; StringBuffer buf(cx); diff --git a/js/src/jsproxy.cpp b/js/src/jsproxy.cpp index 56925dff9759..423a3f9a89ee 100644 --- a/js/src/jsproxy.cpp +++ b/js/src/jsproxy.cpp @@ -409,8 +409,8 @@ DirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId i assertEnteredPolicy(cx, proxy, id, SET); RootedObject target(cx, proxy->as().target()); RootedValue v(cx, desc.value()); - return CheckDefineProperty(cx, target, id, v, desc.getter(), desc.setter(), desc.attributes()) && - JS_DefinePropertyById(cx, target, id, v, desc.getter(), desc.setter(), desc.attributes()); + return CheckDefineProperty(cx, target, id, v, desc.attributes(), desc.getter(), desc.setter()) && + JS_DefinePropertyById(cx, target, id, v, desc.attributes(), desc.getter(), desc.setter()); } bool @@ -1477,8 +1477,8 @@ TrapDefineOwnProperty(JSContext *cx, HandleObject proxy, HandleId id, MutableHan Rooted desc(cx); if (!ParsePropertyDescriptorObject(cx, proxy, vp, &desc)) return false; - return JS_DefinePropertyById(cx, target, id, desc.value(), desc.getter(), desc.setter(), - desc.attributes()); + return JS_DefinePropertyById(cx, target, id, desc.value(), desc.attributes(), + desc.getter(), desc.setter()); } // step 5 @@ -2987,7 +2987,7 @@ ProxyObject::trace(JSTracer *trc, JSObject *obj) ProxyObject *proxy = &obj->as(); #ifdef DEBUG - if (!trc->runtime()->gcDisableStrictProxyCheckingCount && proxy->is()) { + if (!trc->runtime()->gc.disableStrictProxyCheckingCount && proxy->is()) { JSObject *referent = &proxy->private_().toObject(); if (referent->compartment() != proxy->compartment()) { /* diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index a70b591f35fd..f04c4ee4a0da 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -2063,7 +2063,7 @@ SaveSharedScriptData(ExclusiveContext *cx, Handle script, SharedScri */ if (cx->isJSContext()) { JSRuntime *rt = cx->asJSContext()->runtime(); - if (JS::IsIncrementalGCInProgress(rt) && rt->gcIsFull) + if (JS::IsIncrementalGCInProgress(rt) && rt->gc.isFull) ssd->marked = true; } #endif @@ -2081,14 +2081,14 @@ MarkScriptData(JSRuntime *rt, const jsbytecode *bytecode) * a GC. Since SweepScriptBytecodes is only called during a full gc, * to preserve this invariant, only mark during a full gc. */ - if (rt->gcIsFull) + if (rt->gc.isFull) SharedScriptData::fromBytecode(bytecode)->marked = true; } void js::UnmarkScriptData(JSRuntime *rt) { - JS_ASSERT(rt->gcIsFull); + JS_ASSERT(rt->gc.isFull); ScriptDataTable &table = rt->scriptDataTable(); for (ScriptDataTable::Enum e(table); !e.empty(); e.popFront()) { SharedScriptData *entry = e.front(); @@ -2099,7 +2099,7 @@ js::UnmarkScriptData(JSRuntime *rt) void js::SweepScriptData(JSRuntime *rt) { - JS_ASSERT(rt->gcIsFull); + JS_ASSERT(rt->gc.isFull); ScriptDataTable &table = rt->scriptDataTable(); if (rt->keepAtoms()) @@ -3304,7 +3304,7 @@ JSScript::markChildren(JSTracer *trc) // JSScript::Create(), but not yet finished initializing it with // fullyInitFromEmitter() or fullyInitTrivial(). - JS_ASSERT_IF(trc->runtime()->gcStrictCompartmentChecking, zone()->isCollecting()); + JS_ASSERT_IF(trc->runtime()->gc.strictCompartmentChecking, zone()->isCollecting()); for (uint32_t i = 0; i < natoms(); ++i) { if (atoms[i]) diff --git a/js/src/jsscript.h b/js/src/jsscript.h index ed7d7b6b72a7..b7e2ea4b0a41 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -1916,21 +1916,6 @@ SweepScriptData(JSRuntime *rt); extern void FreeScriptData(JSRuntime *rt); -struct ScriptAndCounts -{ - /* This structure is stored and marked from the JSRuntime. */ - JSScript *script; - ScriptCounts scriptCounts; - - PCCounts &getPCCounts(jsbytecode *pc) const { - return scriptCounts.pcCountsVector[script->pcToOffset(pc)]; - } - - jit::IonScriptCounts *getIonCounts() const { - return scriptCounts.ionCounts; - } -}; - struct GSNCache; jssrcnote * diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index a50b845fc0a0..4521e7699b42 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -288,7 +288,7 @@ WeakMapPostWriteBarrier(JSRuntime *rt, ObjectValueMap *weakMap, JSObject *key) typedef gc::HashKeyRef Ref; if (key && IsInsideNursery(rt, key)) - rt->gcStoreBuffer.putGeneric(Ref((unbarrieredMap), key)); + rt->gc.storeBuffer.putGeneric(Ref((unbarrieredMap), key)); #endif } diff --git a/js/src/jsworkers.cpp b/js/src/jsworkers.cpp index 834326ac6cea..2f91655d3819 100644 --- a/js/src/jsworkers.cpp +++ b/js/src/jsworkers.cpp @@ -650,7 +650,7 @@ GlobalWorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void // to the corresponding prototype in the new compartment. This will briefly // create cross compartment pointers, which will be fixed by the // MergeCompartments call below. - for (gc::CellIter iter(parseTask->cx->zone(), gc::FINALIZE_TYPE_OBJECT); + for (gc::ZoneCellIter iter(parseTask->cx->zone(), gc::FINALIZE_TYPE_OBJECT); !iter.done(); iter.next()) { diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index ed184920df32..52570c24e424 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -5779,10 +5779,10 @@ BindScriptArgs(JSContext *cx, JSObject *obj_, OptionParser *op) for (size_t i = 0; !msr.empty(); msr.popFront(), ++i) { const char *scriptArg = msr.front(); - JSString *str = JS_NewStringCopyZ(cx, scriptArg); + JS::RootedString str(cx, JS_NewStringCopyZ(cx, scriptArg)); if (!str || - !JS_DefineElement(cx, scriptArgs, i, STRING_TO_JSVAL(str), nullptr, nullptr, - JSPROP_ENUMERATE)) { + !JS_DefineElement(cx, scriptArgs, i, str, JSPROP_ENUMERATE)) + { return false; } } @@ -6040,7 +6040,7 @@ Shell(JSContext *cx, OptionParser *op, char **envp) JSAutoCompartment ac(cx, glob); js::SetDefaultObjectForContext(cx, glob); - JSObject *envobj = JS_DefineObject(cx, glob, "environment", &env_class, nullptr, 0); + JSObject *envobj = JS_DefineObject(cx, glob, "environment", &env_class); if (!envobj) return 1; JS_SetPrivate(envobj, envp); diff --git a/js/src/tests/js1_8_5/extensions/sps-generators.js b/js/src/tests/js1_8_5/extensions/sps-generators.js index dc8a7b3a3367..d99e93c5bf9c 100644 --- a/js/src/tests/js1_8_5/extensions/sps-generators.js +++ b/js/src/tests/js1_8_5/extensions/sps-generators.js @@ -23,7 +23,10 @@ function turnoff() { for (var slowAsserts of [ true, false ]) { // The slowAssertions setting is not expected to matter - enableSPSProfilingAssertions(slowAsserts); + if (slowAsserts) + enableSPSProfilingWithSlowAssertions(); + else + enableSPSProfiling(); g = gen(); assertEq(g.next(), 'hi'); diff --git a/js/src/tests/js1_8_5/regress/regress-yarr-regexp.js b/js/src/tests/js1_8_5/regress/regress-yarr-regexp.js index 9738aa4e89b5..1b31f3c53af1 100644 --- a/js/src/tests/js1_8_5/regress/regress-yarr-regexp.js +++ b/js/src/tests/js1_8_5/regress/regress-yarr-regexp.js @@ -12,9 +12,9 @@ reportCompare(["a", ""].toSource(), toSource(/a((?:.)*)/.exec("a"))); reportCompare(["B", "B"].toSource(), toSource(/([A-Z])/.exec("fooBar"))); // These just mustn't crash. See bug 872971 -reportCompare(/x{2147483648}x/.test('1'), false); -reportCompare(/x{2147483648,}x/.test('1'), false); -reportCompare(/x{2147483647,2147483648}x/.test('1'), false); +try { reportCompare(/x{2147483648}x/.test('1'), false); } catch (e) {} +try { reportCompare(/x{2147483648,}x/.test('1'), false); } catch (e) {} +try { reportCompare(/x{2147483647,2147483648}x/.test('1'), false); } catch (e) {} // Same for these. See bug 813366 -reportCompare("".match(/.{2147483647}11/), null); -reportCompare("".match(/(?:(?=g)).{2147483648,}/ + ""), null); +try { reportCompare("".match(/.{2147483647}11/), null); } catch (e) {} +try { reportCompare("".match(/(?:(?=g)).{2147483648,}/ + ""), null); } catch (e) {} diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 94b210a5098d..5306d15e9c23 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -535,7 +535,7 @@ ArrayBufferObject::canNeuterAsmJSArrayBuffer(JSContext *cx, ArrayBufferObject &b void * ArrayBufferObject::createMappedContents(int fd, size_t offset, size_t length) { - return AllocateMappedContent(fd, offset, length, ARRAY_BUFFER_ALIGNMENT); + return SystemPageAllocator::AllocateMappedContent(fd, offset, length, ARRAY_BUFFER_ALIGNMENT); } void @@ -544,7 +544,7 @@ ArrayBufferObject::releaseMappedArray() if(!isMappedArrayBuffer() || isNeutered()) return; - DeallocateMappedContent(dataPointer(), byteLength()); + SystemPageAllocator::DeallocateMappedContent(dataPointer(), byteLength()); } void @@ -1107,7 +1107,7 @@ JS_CreateMappedArrayBufferContents(int fd, size_t offset, size_t length) JS_PUBLIC_API(void) JS_ReleaseMappedArrayBufferContents(void *contents, size_t length) { - DeallocateMappedContent(contents, length); + SystemPageAllocator::DeallocateMappedContent(contents, length); } JS_FRIEND_API(bool) @@ -1133,9 +1133,9 @@ JS_GetArrayBufferViewData(JSObject *obj) } JS_FRIEND_API(JSObject *) -JS_GetArrayBufferViewBuffer(JSContext *cx, JSObject *obj) +JS_GetArrayBufferViewBuffer(JSContext *cx, HandleObject objArg) { - obj = CheckedUnwrap(obj); + JSObject *obj = CheckedUnwrap(objArg); if (!obj) return nullptr; Rooted viewObject(cx, &obj->as()); diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index 646c1ccc7f49..b81caa0cbc91 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -276,7 +276,7 @@ PostBarrierTypedArrayObject(JSObject *obj) JS_ASSERT(obj); JSRuntime *rt = obj->runtimeFromMainThread(); if (!rt->isHeapBusy() && !IsInsideNursery(rt, obj)) - rt->gcStoreBuffer.putWholeCell(obj); + rt->gc.storeBuffer.putWholeCell(obj); #endif } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 3f5e3760c148..74bec13e62e2 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -2021,7 +2021,7 @@ Debugger::addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp) { THIS_DEBUGGER(cx, argc, vp, "addAllGlobalsAsDebuggees", args, dbg); for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) { - // Invalidate a zone at a time to avoid doing a zone-wide CellIter + // Invalidate a zone at a time to avoid doing a ZoneCellIter // per compartment. AutoDebugModeInvalidation invalidate(zone); @@ -2113,7 +2113,7 @@ Debugger::getNewestFrame(JSContext *cx, unsigned argc, Value *vp) if (dbg->observesFrame(i)) { // Ensure that Ion frames are rematerialized. Only rematerialized // Ion frames may be used as AbstractFramePtrs. - if (i.isIon() && !i.ensureHasRematerializedFrame()) + if (i.isIon() && !i.ensureHasRematerializedFrame(cx)) return false; AbstractFramePtr frame = i.abstractFramePtr(); ScriptFrameIter iter(i.activation()->cx(), ScriptFrameIter::GO_THROUGH_SAVED); @@ -4118,7 +4118,7 @@ UpdateFrameIterPc(FrameIter &iter) jit::IonJSFrameLayout *jsFrame = (jit::IonJSFrameLayout *)frame->top(); jit::JitActivation *activation = iter.activation()->asJit(); - ActivationIterator activationIter(activation->cx()->runtime()); + ActivationIterator activationIter(activation->cx()->perThreadData); while (activationIter.activation() != activation) ++activationIter; @@ -4370,7 +4370,7 @@ DebuggerFrame_getOlder(JSContext *cx, unsigned argc, Value *vp) for (++iter; !iter.done(); ++iter) { if (dbg->observesFrame(iter)) { - if (iter.isIon() && !iter.ensureHasRematerializedFrame()) + if (iter.isIon() && !iter.ensureHasRematerializedFrame(cx)) return false; return dbg->getScriptFrame(cx, iter, args.rval()); } diff --git a/js/src/vm/ForkJoin.cpp b/js/src/vm/ForkJoin.cpp index 459c9a3edef7..6720861a6ae1 100644 --- a/js/src/vm/ForkJoin.cpp +++ b/js/src/vm/ForkJoin.cpp @@ -462,7 +462,7 @@ class AutoSetForkJoinContext ForkJoinActivation::ForkJoinActivation(JSContext *cx) : Activation(cx, ForkJoin), - prevIonTop_(cx->mainThread().ionTop), + prevJitTop_(cx->mainThread().jitTop), av_(cx->runtime(), false) { // Note: we do not allow GC during parallel sections. @@ -479,7 +479,7 @@ ForkJoinActivation::ForkJoinActivation(JSContext *cx) MinorGC(cx->runtime(), JS::gcreason::API); - cx->runtime()->gcHelperThread.waitBackgroundSweepEnd(); + cx->runtime()->gc.helperThread.waitBackgroundSweepEnd(); JS_ASSERT(!cx->runtime()->needsBarrier()); JS_ASSERT(!cx->zone()->needsBarrier()); @@ -487,7 +487,7 @@ ForkJoinActivation::ForkJoinActivation(JSContext *cx) ForkJoinActivation::~ForkJoinActivation() { - cx_->mainThread().ionTop = prevIonTop_; + cx_->perThreadData->jitTop = prevJitTop_; } /////////////////////////////////////////////////////////////////////////// @@ -1331,10 +1331,11 @@ class ParallelIonInvoke calleeToken_ = CalleeToToken(callee); } - bool invoke(PerThreadData *perThread) { - RootedValue result(perThread); + bool invoke(ForkJoinContext *cx) { + JitActivation activation(cx); + Value result; CALL_GENERATED_CODE(enter_, jitcode_, argc_ + 1, argv_ + 1, nullptr, calleeToken_, - nullptr, 0, result.address()); + nullptr, 0, &result); return !result.isMagic(); } }; @@ -1535,13 +1536,13 @@ ForkJoinShared::executePortion(PerThreadData *perThread, ThreadPoolWorker *worke cx.bailoutRecord->setCause(ParallelBailoutMainScriptNotPresent); setAbortFlagAndRequestInterrupt(false); } else { - ParallelIonInvoke<3> fii(cx_->runtime(), fun_, 3); + ParallelIonInvoke<3> fii(runtime(), fun_, 3); fii.args[0] = Int32Value(worker->id()); fii.args[1] = Int32Value(sliceStart_); fii.args[2] = Int32Value(sliceEnd_); - bool ok = fii.invoke(perThread); + bool ok = fii.invoke(&cx); JS_ASSERT(ok == !cx.bailoutRecord->topScript); if (!ok) setAbortFlagAndRequestInterrupt(false); @@ -1557,7 +1558,7 @@ ForkJoinShared::setAbortFlagDueToInterrupt(ForkJoinContext &cx) // The GC Needed flag should not be set during parallel // execution. Instead, one of the requestGC() or // requestZoneGC() methods should be invoked. - JS_ASSERT(!cx_->runtime()->gcIsNeeded); + JS_ASSERT(!cx_->runtime()->gc.isNeeded); if (!abort_) { cx.bailoutRecord->setCause(ParallelBailoutInterrupt); diff --git a/js/src/vm/ForkJoin.h b/js/src/vm/ForkJoin.h index f8c41ab18f74..58d379b531b6 100644 --- a/js/src/vm/ForkJoin.h +++ b/js/src/vm/ForkJoin.h @@ -216,7 +216,7 @@ namespace js { class ForkJoinActivation : public Activation { - uint8_t *prevIonTop_; + uint8_t *prevJitTop_; // We ensure that incremental GC be finished before we enter into a fork // join section, but the runtime/zone might still be marked as needing diff --git a/js/src/vm/MemoryMetrics.cpp b/js/src/vm/MemoryMetrics.cpp index 5862324c46c1..ea6793dea24a 100644 --- a/js/src/vm/MemoryMetrics.cpp +++ b/js/src/vm/MemoryMetrics.cpp @@ -537,7 +537,7 @@ JS::CollectRuntimeStats(JSRuntime *rt, RuntimeStats *rtStats, ObjectPrivateVisit if (!rtStats->compartmentStatsVector.reserve(rt->numCompartments)) return false; - if (!rtStats->zoneStatsVector.reserve(rt->zones.length())) + if (!rtStats->zoneStatsVector.reserve(rt->gc.zones.length())) return false; rtStats->gcHeapChunkTotal = diff --git a/js/src/vm/OldDebugAPI.cpp b/js/src/vm/OldDebugAPI.cpp index ed06e953d2fc..92c0380b9d89 100644 --- a/js/src/vm/OldDebugAPI.cpp +++ b/js/src/vm/OldDebugAPI.cpp @@ -173,7 +173,7 @@ JS_FRIEND_API(bool) JS_SetDebugModeForAllCompartments(JSContext *cx, bool debug) { for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) { - // Invalidate a zone at a time to avoid doing a zone-wide CellIter + // Invalidate a zone at a time to avoid doing a ZoneCellIter // per compartment. AutoDebugModeInvalidation invalidate(zone); for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) { @@ -835,7 +835,7 @@ JS_DumpPCCounts(JSContext *cx, HandleScript script) JS_PUBLIC_API(void) JS_DumpCompartmentPCCounts(JSContext *cx) { - for (CellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { + for (ZoneCellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) { RootedScript script(cx, i.get()); if (script->compartment() != cx->compartment()) continue; diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index cf47cb0d9e04..5e4af96641c6 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -731,7 +731,7 @@ RegExpCompartment::sweep(JSRuntime *rt) for (PendingSet::Enum e(inUse_); !e.empty(); e.popFront()) { RegExpShared *shared = e.front(); - if (shared->activeUseCount == 0 && shared->gcNumberWhenUsed < rt->gcStartNumber) { + if (shared->activeUseCount == 0 && shared->gcNumberWhenUsed < rt->gc.startNumber) { js_delete(shared); e.removeFront(); } diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp index 8072a182f5b9..d3b02f785ea0 100644 --- a/js/src/vm/Runtime.cpp +++ b/js/src/vm/Runtime.cpp @@ -69,7 +69,7 @@ const JSSecurityCallbacks js::NullSecurityCallbacks = { }; PerThreadData::PerThreadData(JSRuntime *runtime) : PerThreadDataFriendFields(), runtime_(runtime), - ionTop(nullptr), + jitTop(nullptr), jitJSContext(nullptr), jitStackLimit(0), #ifdef JS_TRACE_LOGGING @@ -114,7 +114,7 @@ static const JSWrapObjectCallbacks DefaultWrapObjectCallbacks = { JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThreads) : JS::shadow::Runtime( #ifdef JSGC_GENERATIONAL - &gcStoreBuffer + &gc.storeBuffer #endif ), mainThread(this), @@ -135,7 +135,6 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThrea #else interruptLockTaken(false), #endif - systemZone(nullptr), numCompartments(0), localeCallbacks(nullptr), defaultLocale(nullptr), @@ -166,89 +165,11 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThrea #ifdef DEBUG activeContext(nullptr), #endif + gc(thisFromCtor()), gcInitialized(false), - gcSystemAvailableChunkListHead(nullptr), - gcUserAvailableChunkListHead(nullptr), - gcBytes(0), - gcMaxBytes(0), - gcMaxMallocBytes(0), - gcNumArenasFreeCommitted(0), - gcMarker(this), - gcVerifyPreData(nullptr), - gcVerifyPostData(nullptr), - gcChunkAllocationSinceLastGC(false), - gcNextFullGCTime(0), - gcLastGCTime(0), - gcJitReleaseTime(0), - gcAllocationThreshold(30 * 1024 * 1024), - gcHighFrequencyGC(false), - gcHighFrequencyTimeThreshold(1000), - gcHighFrequencyLowLimitBytes(100 * 1024 * 1024), - gcHighFrequencyHighLimitBytes(500 * 1024 * 1024), - gcHighFrequencyHeapGrowthMax(3.0), - gcHighFrequencyHeapGrowthMin(1.5), - gcLowFrequencyHeapGrowth(1.5), - gcDynamicHeapGrowth(false), - gcDynamicMarkSlice(false), - gcDecommitThreshold(32 * 1024 * 1024), - gcShouldCleanUpEverything(false), - gcGrayBitsValid(false), - gcIsNeeded(0), - gcStats(thisFromCtor()), - gcNumber(0), - gcStartNumber(0), - gcIsFull(false), - gcTriggerReason(JS::gcreason::NO_REASON), - gcStrictCompartmentChecking(false), -#ifdef DEBUG - gcDisableStrictProxyCheckingCount(0), -#endif - gcIncrementalState(gc::NO_INCREMENTAL), - gcLastMarkSlice(false), - gcSweepOnBackgroundThread(false), - gcFoundBlackGrayEdges(false), - gcSweepingZones(nullptr), - gcZoneGroupIndex(0), - gcZoneGroups(nullptr), - gcCurrentZoneGroup(nullptr), - gcSweepPhase(0), - gcSweepZone(nullptr), - gcSweepKindIndex(0), - gcAbortSweepAfterCurrentGroup(false), - gcArenasAllocatedDuringSweep(nullptr), -#ifdef DEBUG - gcMarkingValidator(nullptr), -#endif - gcInterFrameGC(0), - gcSliceBudget(SliceBudget::Unlimited), - gcIncrementalEnabled(true), - gcGenerationalDisabled(0), - gcManipulatingDeadZones(false), - gcObjectsMarkedInDeadZones(0), - gcPoke(false), - heapState(Idle), -#ifdef JSGC_GENERATIONAL - gcNursery(thisFromCtor()), - gcStoreBuffer(thisFromCtor(), gcNursery), -#endif -#ifdef JS_GC_ZEAL - gcZeal_(0), - gcZealFrequency(0), - gcNextScheduled(0), - gcDeterministicOnly(false), - gcIncrementalLimit(0), -#endif - gcValidate(true), - gcFullCompartmentChecks(false), - gcCallback(nullptr), - gcSliceCallback(nullptr), - gcFinalizeCallback(nullptr), - gcMallocBytes(0), - gcMallocGCTriggered(false), #ifdef JS_ARM_SIMULATOR simulatorRuntime_(nullptr), #endif - scriptAndCountsVector(nullptr), NaNValue(DoubleNaNValue()), negativeInfinityValue(DoubleValue(NegativeInfinity())), positiveInfinityValue(DoubleValue(PositiveInfinity())), @@ -256,13 +177,9 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThrea debugMode(false), spsProfiler(thisFromCtor()), profilingScripts(false), - alwaysPreserveCode(false), hadOutOfMemory(false), haveCreatedContext(false), data(nullptr), - gcLock(nullptr), - gcLockOwner(nullptr), - gcHelperThread(thisFromCtor()), signalHandlersInstalled_(false), defaultFreeOp_(thisFromCtor(), false), debuggerMutations(0), @@ -289,16 +206,12 @@ JSRuntime::JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThrea permanentAtoms(nullptr), wrapObjectCallbacks(&DefaultWrapObjectCallbacks), preserveWrapperCallback(nullptr), -#ifdef DEBUG - noGCOrAllocationCheck(0), -#endif jitSupportsFloatingPoint(false), ionPcScriptCache(nullptr), threadPool(this), defaultJSContextCallback(nullptr), ctypesActivityCallback(nullptr), forkJoinWarmup(0), - ionReturnOverride_(MagicValue(JS_ARG_POISON)), useHelperThreads_(useHelperThreads), parallelIonCompilationEnabled_(true), parallelParsingEnabled_(true), @@ -353,8 +266,8 @@ JSRuntime::init(uint32_t maxbytes) if (!interruptLock) return false; - gcLock = PR_NewLock(); - if (!gcLock) + gc.lock = PR_NewLock(); + if (!gc.lock) return false; exclusiveAccessLock = PR_NewLock(); @@ -373,7 +286,7 @@ JSRuntime::init(uint32_t maxbytes) if (!js_InitGC(this, maxbytes)) return false; - if (!gcMarker.init(gcMode())) + if (!gc.marker.init(gcMode())) return false; const char *size = getenv("JSGC_MARK_STACK_LIMIT"); @@ -389,7 +302,7 @@ JSRuntime::init(uint32_t maxbytes) if (!atomsCompartment || !atomsCompartment->init(nullptr)) return false; - zones.append(atomsZone.get()); + gc.zones.append(atomsZone.get()); atomsZone->compartments.append(atomsCompartment.get()); atomsCompartment->isSystem = true; @@ -524,8 +437,8 @@ JSRuntime::~JSRuntime() atomsCompartment_ = nullptr; #ifdef JS_THREADSAFE - if (gcLock) - PR_DestroyLock(gcLock); + if (gc.lock) + PR_DestroyLock(gc.lock); #endif js_free(defaultLocale); @@ -539,8 +452,8 @@ JSRuntime::~JSRuntime() js_delete(ionPcScriptCache); #ifdef JSGC_GENERATIONAL - gcStoreBuffer.disable(); - gcNursery.disable(); + gc.storeBuffer.disable(); + gc.nursery.disable(); #endif #ifdef JS_ARM_SIMULATOR @@ -628,12 +541,12 @@ JSRuntime::addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf, JS::Runtim } #endif - rtSizes->gc.marker += gcMarker.sizeOfExcludingThis(mallocSizeOf); + rtSizes->gc.marker += gc.marker.sizeOfExcludingThis(mallocSizeOf); #ifdef JSGC_GENERATIONAL - rtSizes->gc.nurseryCommitted += gcNursery.sizeOfHeapCommitted(); - rtSizes->gc.nurseryDecommitted += gcNursery.sizeOfHeapDecommitted(); - rtSizes->gc.nurseryHugeSlots += gcNursery.sizeOfHugeSlots(mallocSizeOf); - gcStoreBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc); + rtSizes->gc.nurseryCommitted += gc.nursery.sizeOfHeapCommitted(); + rtSizes->gc.nurseryDecommitted += gc.nursery.sizeOfHeapDecommitted(); + rtSizes->gc.nurseryHugeSlots += gc.nursery.sizeOfHugeSlots(mallocSizeOf); + gc.storeBuffer.addSizeOfExcludingThis(mallocSizeOf, &rtSizes->gc); #endif } @@ -785,7 +698,7 @@ JSRuntime::setGCMaxMallocBytes(size_t value) * For compatibility treat any value that exceeds PTRDIFF_T_MAX to * mean that value. */ - gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1; + gc.maxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1; resetGCMallocBytes(); for (ZonesIter zone(this, WithAtoms); !zone.done(); zone.next()) zone->setGCMaxMallocBytes(value); @@ -801,8 +714,8 @@ void JSRuntime::updateMallocCounter(JS::Zone *zone, size_t nbytes) { /* We tolerate any thread races when updating gcMallocBytes. */ - gcMallocBytes -= ptrdiff_t(nbytes); - if (MOZ_UNLIKELY(gcMallocBytes <= 0)) + gc.mallocBytes -= ptrdiff_t(nbytes); + if (MOZ_UNLIKELY(gc.mallocBytes <= 0)) onTooMuchMalloc(); else if (zone) zone->updateMallocCounter(nbytes); @@ -814,8 +727,8 @@ JSRuntime::onTooMuchMalloc() if (!CurrentThreadCanAccessRuntime(this)) return; - if (!gcMallocGCTriggered) - gcMallocGCTriggered = TriggerGC(this, JS::gcreason::TOO_MUCH_MALLOC); + if (!gc.mallocGCTriggered) + gc.mallocGCTriggered = TriggerGC(this, JS::gcreason::TOO_MUCH_MALLOC); } JS_FRIEND_API(void *) @@ -835,7 +748,7 @@ JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx) * all the allocations and released the empty GC chunks. */ JS::ShrinkGCBuffers(this); - gcHelperThread.waitBackgroundSweepOrAllocEnd(); + gc.helperThread.waitBackgroundSweepOrAllocEnd(); if (!p) p = js_malloc(nbytes); else if (p == reinterpret_cast(1)) @@ -930,7 +843,7 @@ JSRuntime::assertCanLock(RuntimeLock which) case InterruptLock: JS_ASSERT(!currentThreadOwnsInterruptLock()); case GCLock: - JS_ASSERT(gcLockOwner != PR_GetCurrentThread()); + JS_ASSERT(gc.lockOwner != PR_GetCurrentThread()); break; default: MOZ_CRASH(); diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 12c45f973e7b..d639082008f1 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -19,7 +19,6 @@ #include "jsatom.h" #include "jsclist.h" -#include "jsgc.h" #ifdef DEBUG # include "jsproxy.h" #endif @@ -27,13 +26,7 @@ #include "ds/FixedSizeHash.h" #include "frontend/ParseMaps.h" -#ifdef JSGC_GENERATIONAL -# include "gc/Nursery.h" -#endif -#include "gc/Statistics.h" -#ifdef JSGC_GENERATIONAL -# include "gc/StoreBuffer.h" -#endif +#include "gc/GCRuntime.h" #include "gc/Tracer.h" #ifdef XP_MACOSX # include "jit/AsmJSSignalHandlers.h" @@ -135,48 +128,6 @@ struct ScopeCoordinateNameCache { void purge(); }; -typedef Vector ScriptAndCountsVector; - -struct ConservativeGCData -{ - /* - * The GC scans conservatively between ThreadData::nativeStackBase and - * nativeStackTop unless the latter is nullptr. - */ - uintptr_t *nativeStackTop; - - union { - jmp_buf jmpbuf; - uintptr_t words[JS_HOWMANY(sizeof(jmp_buf), sizeof(uintptr_t))]; - } registerSnapshot; - - ConservativeGCData() { - mozilla::PodZero(this); - } - - ~ConservativeGCData() { -#ifdef JS_THREADSAFE - /* - * The conservative GC scanner should be disabled when the thread leaves - * the last request. - */ - JS_ASSERT(!hasStackToScan()); -#endif - } - - MOZ_NEVER_INLINE void recordStackTop(); - -#ifdef JS_THREADSAFE - void updateForRequestEnd() { - nativeStackTop = nullptr; - } -#endif - - bool hasStackToScan() const { - return !!nativeStackTop; - } -}; - struct EvalCacheEntry { JSScript *script; @@ -522,10 +473,10 @@ class PerThreadData : public PerThreadDataFriendFields #endif /* - * If Ion code is on the stack, and has called into C++, this will be - * aligned to an Ion exit frame. + * If Baseline or Ion code is on the stack, and has called into C++, this + * will be aligned to an exit frame. */ - uint8_t *ionTop; + uint8_t *jitTop; /* * The current JSContext when entering JIT code. This field may only be used @@ -655,12 +606,6 @@ class PerThreadData : public PerThreadDataFriendFields #endif }; -namespace gc { -class MarkingValidator; -} // namespace gc - -typedef Vector ZoneVector; - class AutoLockForExclusiveAccess; void RecomputeStackLimit(JSRuntime *rt, StackKind kind); @@ -806,12 +751,6 @@ struct JSRuntime : public JS::shadow::Runtime, #endif } - /* Embedders can use this zone however they wish. */ - JS::Zone *systemZone; - - /* List of compartments and zones (protected by the GC lock). */ - js::ZoneVector zones; - /* How many compartments there are across all zones. */ size_t numCompartments; @@ -975,259 +914,37 @@ struct JSRuntime : public JS::shadow::Runtime, #endif /* Garbage collector state, used by jsgc.c. */ + js::gc::GCRuntime gc; /* Garbase collector state has been sucessfully initialized. */ bool gcInitialized; - /* - * Set of all GC chunks with at least one allocated thing. The - * conservative GC uses it to quickly check if a possible GC thing points - * into an allocated chunk. - */ - js::GCChunkSet gcChunkSet; - - /* - * Doubly-linked lists of chunks from user and system compartments. The GC - * allocates its arenas from the corresponding list and when all arenas - * in the list head are taken, then the chunk is removed from the list. - * During the GC when all arenas in a chunk become free, that chunk is - * removed from the list and scheduled for release. - */ - js::gc::Chunk *gcSystemAvailableChunkListHead; - js::gc::Chunk *gcUserAvailableChunkListHead; - js::gc::ChunkPool gcChunkPool; - - js::RootedValueMap gcRootsHash; - - /* This is updated by both the main and GC helper threads. */ - mozilla::Atomic gcBytes; - - size_t gcMaxBytes; - size_t gcMaxMallocBytes; - - /* - * Number of the committed arenas in all GC chunks including empty chunks. - */ - mozilla::Atomic gcNumArenasFreeCommitted; - js::GCMarker gcMarker; - void *gcVerifyPreData; - void *gcVerifyPostData; - bool gcChunkAllocationSinceLastGC; - int64_t gcNextFullGCTime; - int64_t gcLastGCTime; - int64_t gcJitReleaseTime; - private: - JSGCMode gcMode_; - - public: - JSGCMode gcMode() const { return gcMode_; } + JSGCMode gcMode() const { return gc.mode; } void setGCMode(JSGCMode mode) { - gcMode_ = mode; - gcMarker.setGCMode(mode); + gc.mode = mode; + gc.marker.setGCMode(mode); } - size_t gcAllocationThreshold; - bool gcHighFrequencyGC; - uint64_t gcHighFrequencyTimeThreshold; - uint64_t gcHighFrequencyLowLimitBytes; - uint64_t gcHighFrequencyHighLimitBytes; - double gcHighFrequencyHeapGrowthMax; - double gcHighFrequencyHeapGrowthMin; - double gcLowFrequencyHeapGrowth; - bool gcDynamicHeapGrowth; - bool gcDynamicMarkSlice; - uint64_t gcDecommitThreshold; - - /* During shutdown, the GC needs to clean up every possible object. */ - bool gcShouldCleanUpEverything; - - /* - * The gray bits can become invalid if UnmarkGray overflows the stack. A - * full GC will reset this bit, since it fills in all the gray bits. - */ - bool gcGrayBitsValid; - - /* - * These flags must be kept separate so that a thread requesting a - * compartment GC doesn't cancel another thread's concurrent request for a - * full GC. - */ - volatile uintptr_t gcIsNeeded; - - js::gcstats::Statistics gcStats; - - /* Incremented on every GC slice. */ - uint64_t gcNumber; - - /* The gcNumber at the time of the most recent GC's first slice. */ - uint64_t gcStartNumber; - - /* Whether the currently running GC can finish in multiple slices. */ - bool gcIsIncremental; - - /* Whether all compartments are being collected in first GC slice. */ - bool gcIsFull; - - /* The reason that an interrupt-triggered GC should be called. */ - JS::gcreason::Reason gcTriggerReason; - - /* - * If this is true, all marked objects must belong to a compartment being - * GCed. This is used to look for compartment bugs. - */ - bool gcStrictCompartmentChecking; - -#ifdef DEBUG - /* - * If this is 0, all cross-compartment proxies must be registered in the - * wrapper map. This checking must be disabled temporarily while creating - * new wrappers. When non-zero, this records the recursion depth of wrapper - * creation. - */ - uintptr_t gcDisableStrictProxyCheckingCount; -#else - uintptr_t unused1; -#endif - - /* - * The current incremental GC phase. This is also used internally in - * non-incremental GC. - */ - js::gc::State gcIncrementalState; - - /* Indicates that the last incremental slice exhausted the mark stack. */ - bool gcLastMarkSlice; - - /* Whether any sweeping will take place in the separate GC helper thread. */ - bool gcSweepOnBackgroundThread; - - /* Whether any black->gray edges were found during marking. */ - bool gcFoundBlackGrayEdges; - - /* List head of zones to be swept in the background. */ - JS::Zone *gcSweepingZones; - - /* Index of current zone group (for stats). */ - unsigned gcZoneGroupIndex; - - /* - * Incremental sweep state. - */ - JS::Zone *gcZoneGroups; - JS::Zone *gcCurrentZoneGroup; - int gcSweepPhase; - JS::Zone *gcSweepZone; - int gcSweepKindIndex; - bool gcAbortSweepAfterCurrentGroup; - - /* - * List head of arenas allocated during the sweep phase. - */ - js::gc::ArenaHeader *gcArenasAllocatedDuringSweep; - -#ifdef DEBUG - js::gc::MarkingValidator *gcMarkingValidator; -#endif - - /* - * Indicates that a GC slice has taken place in the middle of an animation - * frame, rather than at the beginning. In this case, the next slice will be - * delayed so that we don't get back-to-back slices. - */ - volatile uintptr_t gcInterFrameGC; - - /* Default budget for incremental GC slice. See SliceBudget in jsgc.h. */ - int64_t gcSliceBudget; - - /* - * We disable incremental GC if we encounter a js::Class with a trace hook - * that does not implement write barriers. - */ - bool gcIncrementalEnabled; - - /* - * GGC can be enabled from the command line while testing. - */ - unsigned gcGenerationalDisabled; - - /* - * This is true if we are in the middle of a brain transplant (e.g., - * JS_TransplantObject) or some other operation that can manipulate - * dead zones. - */ - bool gcManipulatingDeadZones; - - /* - * This field is incremented each time we mark an object inside a - * zone with no incoming cross-compartment pointers. Typically if - * this happens it signals that an incremental GC is marking too much - * stuff. At various times we check this counter and, if it has changed, we - * run an immediate, non-incremental GC to clean up the dead - * zones. This should happen very rarely. - */ - unsigned gcObjectsMarkedInDeadZones; - - bool gcPoke; - - volatile js::HeapState heapState; - - bool isHeapBusy() { return heapState != js::Idle; } - bool isHeapMajorCollecting() { return heapState == js::MajorCollecting; } - bool isHeapMinorCollecting() { return heapState == js::MinorCollecting; } + bool isHeapBusy() { return gc.heapState != js::Idle; } + bool isHeapMajorCollecting() { return gc.heapState == js::MajorCollecting; } + bool isHeapMinorCollecting() { return gc.heapState == js::MinorCollecting; } bool isHeapCollecting() { return isHeapMajorCollecting() || isHeapMinorCollecting(); } -#ifdef JSGC_GENERATIONAL - js::Nursery gcNursery; - js::gc::StoreBuffer gcStoreBuffer; -#endif - - /* - * These options control the zealousness of the GC. The fundamental values - * are gcNextScheduled and gcDebugCompartmentGC. At every allocation, - * gcNextScheduled is decremented. When it reaches zero, we do either a - * full or a compartmental GC, based on gcDebugCompartmentGC. - * - * At this point, if gcZeal_ is one of the types that trigger periodic - * collection, then gcNextScheduled is reset to the value of - * gcZealFrequency. Otherwise, no additional GCs take place. - * - * You can control these values in several ways: - * - Pass the -Z flag to the shell (see the usage info for details) - * - Call gczeal() or schedulegc() from inside shell-executed JS code - * (see the help for details) - * - * If gzZeal_ == 1 then we perform GCs in select places (during MaybeGC and - * whenever a GC poke happens). This option is mainly useful to embedders. - * - * We use gcZeal_ == 4 to enable write barrier verification. See the comment - * in jsgc.cpp for more information about this. - * - * gcZeal_ values from 8 to 10 periodically run different types of - * incremental GC. - */ #ifdef JS_GC_ZEAL - int gcZeal_; - int gcZealFrequency; - int gcNextScheduled; - bool gcDeterministicOnly; - int gcIncrementalLimit; - - js::Vector gcSelectedForMarking; - - int gcZeal() { return gcZeal_; } + int gcZeal() { return gc.zealMode; } bool upcomingZealousGC() { - return gcNextScheduled == 1; + return gc.nextScheduled == 1; } bool needZealousGC() { - if (gcNextScheduled > 0 && --gcNextScheduled == 0) { + if (gc.nextScheduled > 0 && --gc.nextScheduled == 0) { if (gcZeal() == js::gc::ZealAllocValue || gcZeal() == js::gc::ZealGenerationalGCValue || (gcZeal() >= js::gc::ZealIncrementalRootsThenFinish && gcZeal() <= js::gc::ZealIncrementalMultipleSlices)) { - gcNextScheduled = gcZealFrequency; + gc.nextScheduled = gc.zealFrequency; } return true; } @@ -1239,27 +956,24 @@ struct JSRuntime : public JS::shadow::Runtime, bool needZealousGC() { return false; } #endif - bool gcValidate; - bool gcFullCompartmentChecks; + void lockGC() { +#ifdef JS_THREADSAFE + assertCanLock(js::GCLock); + PR_Lock(gc.lock); + JS_ASSERT(!gc.lockOwner); +#ifdef DEBUG + gc.lockOwner = PR_GetCurrentThread(); +#endif +#endif + } - JSGCCallback gcCallback; - JS::GCSliceCallback gcSliceCallback; - JSFinalizeCallback gcFinalizeCallback; - - void *gcCallbackData; - - private: - /* - * Malloc counter to measure memory pressure for GC scheduling. It runs - * from gcMaxMallocBytes down to zero. - */ - mozilla::Atomic gcMallocBytes; - - /* - * Whether a GC has been triggered as a result of gcMallocBytes falling - * below zero. - */ - mozilla::Atomic gcMallocGCTriggered; + void unlockGC() { +#ifdef JS_THREADSAFE + JS_ASSERT(gc.lockOwner == PR_GetCurrentThread()); + gc.lockOwner = nullptr; + PR_Unlock(gc.lock); +#endif + } #ifdef JS_ARM_SIMULATOR js::jit::SimulatorRuntime *simulatorRuntime_; @@ -1270,45 +984,11 @@ struct JSRuntime : public JS::shadow::Runtime, needsBarrier_ = needs; } - struct ExtraTracer { - JSTraceDataOp op; - void *data; - - ExtraTracer() - : op(nullptr), data(nullptr) - {} - ExtraTracer(JSTraceDataOp op, void *data) - : op(op), data(data) - {} - }; - #ifdef JS_ARM_SIMULATOR js::jit::SimulatorRuntime *simulatorRuntime() const; void setSimulatorRuntime(js::jit::SimulatorRuntime *srt); #endif - /* - * The trace operations to trace embedding-specific GC roots. One is for - * tracing through black roots and the other is for tracing through gray - * roots. The black/gray distinction is only relevant to the cycle - * collector. - */ - typedef js::Vector ExtraTracerVector; - ExtraTracerVector gcBlackRootTracers; - ExtraTracer gcGrayRootTracer; - - /* - * The GC can only safely decommit memory when the page size of the - * running process matches the compiled arena size. - */ - size_t gcSystemPageSize; - - /* The OS allocation granularity may not match the page size. */ - size_t gcSystemAllocGranularity; - - /* Strong references on scripts held for PCCount profiling API. */ - js::ScriptAndCountsVector *scriptAndCountsVector; - /* Well-known numbers held for use by this runtime's contexts. */ const js::Value NaNValue; const js::Value negativeInfinityValue; @@ -1337,9 +1017,6 @@ struct JSRuntime : public JS::shadow::Runtime, /* If true, new scripts must be created with PC counter information. */ bool profilingScripts; - /* Always preserve JIT code during GCs, for testing. */ - bool alwaysPreserveCode; - /* Had an out-of-memory error which did not populate an exception. */ bool hadOutOfMemory; @@ -1358,35 +1035,6 @@ struct JSRuntime : public JS::shadow::Runtime, /* Client opaque pointers */ void *data; - private: - /* Synchronize GC heap access between main thread and GCHelperThread. */ - PRLock *gcLock; - mozilla::DebugOnly gcLockOwner; - - friend class js::GCHelperThread; - public: - - void lockGC() { -#ifdef JS_THREADSAFE - assertCanLock(js::GCLock); - PR_Lock(gcLock); - JS_ASSERT(!gcLockOwner); -#ifdef DEBUG - gcLockOwner = PR_GetCurrentThread(); -#endif -#endif - } - - void unlockGC() { -#ifdef JS_THREADSAFE - JS_ASSERT(gcLockOwner == PR_GetCurrentThread()); - gcLockOwner = nullptr; - PR_Unlock(gcLock); -#endif - } - - js::GCHelperThread gcHelperThread; - #if defined(XP_MACOSX) && defined(JS_ION) js::AsmJSMachExceptionHandler asmJSMachExceptionHandler; #endif @@ -1458,8 +1106,6 @@ struct JSRuntime : public JS::shadow::Runtime, js::DateTimeInfo dateTimeInfo; - js::ConservativeGCData conservativeGC; - // Pool of maps used during parse/emit. This may be modified by threads // with an ExclusiveContext and requires a lock. Active compilations // prevent the pool from being purged during GCs. @@ -1579,10 +1225,6 @@ struct JSRuntime : public JS::shadow::Runtime, return scriptDataTable_; } -#ifdef DEBUG - size_t noGCOrAllocationCheck; -#endif - bool jitSupportsFloatingPoint; // Used to reset stack limit after a signaled interrupt (i.e. jitStackLimit_ = -1) @@ -1603,20 +1245,6 @@ struct JSRuntime : public JS::shadow::Runtime, uint32_t forkJoinWarmup; private: - // In certain cases, we want to optimize certain opcodes to typed instructions, - // to avoid carrying an extra register to feed into an unbox. Unfortunately, - // that's not always possible. For example, a GetPropertyCacheT could return a - // typed double, but if it takes its out-of-line path, it could return an - // object, and trigger invalidation. The invalidation bailout will consider the - // return value to be a double, and create a garbage Value. - // - // To allow the GetPropertyCacheT optimization, we allow the ability for - // GetPropertyCache to override the return value at the top of the stack - the - // value that will be temporarily corrupt. This special override value is set - // only in callVM() targets that are about to return *and* have invalidated - // their callee. - js::Value ionReturnOverride_; - #ifdef JS_THREADSAFE static mozilla::Atomic liveRuntimesCount; #else @@ -1628,19 +1256,6 @@ struct JSRuntime : public JS::shadow::Runtime, return liveRuntimesCount > 0; } - bool hasIonReturnOverride() const { - return !ionReturnOverride_.isMagic(); - } - js::Value takeIonReturnOverride() { - js::Value v = ionReturnOverride_; - ionReturnOverride_ = js::MagicValue(JS_ARG_POISON); - return v; - } - void setIonReturnOverride(const js::Value &v) { - JS_ASSERT(!hasIonReturnOverride()); - ionReturnOverride_ = v; - } - JSRuntime(JSRuntime *parentRuntime, JSUseHelperThreads useHelperThreads); ~JSRuntime(); @@ -1651,8 +1266,8 @@ struct JSRuntime : public JS::shadow::Runtime, void setGCMaxMallocBytes(size_t value); void resetGCMallocBytes() { - gcMallocBytes = ptrdiff_t(gcMaxMallocBytes); - gcMallocGCTriggered = false; + gc.mallocBytes = ptrdiff_t(gc.maxMallocBytes); + gc.mallocGCTriggered = false; } /* @@ -1669,7 +1284,7 @@ struct JSRuntime : public JS::shadow::Runtime, void reportAllocationOverflow() { js_ReportAllocationOverflow(nullptr); } bool isTooMuchMalloc() const { - return gcMallocBytes <= 0; + return gc.mallocBytes <= 0; } /* @@ -1856,7 +1471,7 @@ inline void FreeOp::free_(void *p) { if (shouldFreeLater()) { - runtime()->gcHelperThread.freeLater(p); + runtime()->gc.helperThread.freeLater(p); return; } js_free(p); diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 7051c2be4d72..1e8305525e54 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -1404,8 +1404,7 @@ class DebugScopeProxy : public BaseProxyHandler if (found) return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP); - return JS_DefinePropertyById(cx, scope, id, desc.value(), desc.getter(), desc.setter(), - desc.attributes()); + return JS_DefinePropertyById(cx, scope, id, desc.value(), desc.attributes(), desc.getter(), desc.setter()); } bool getScopePropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props, @@ -1582,7 +1581,7 @@ DebugScopes::proxiedScopesPostWriteBarrier(JSRuntime *rt, ObjectWeakMap *map, typedef gc::HashKeyRef Ref; if (key && IsInsideNursery(rt, key)) - rt->gcStoreBuffer.putGeneric(Ref(unbarrieredMap, key.get())); + rt->gc.storeBuffer.putGeneric(Ref(unbarrieredMap, key.get())); #endif } @@ -1613,7 +1612,7 @@ DebugScopes::missingScopesPostWriteBarrier(JSRuntime *rt, MissingScopeMap *map, { #ifdef JSGC_GENERATIONAL if (key.enclosingScope() && IsInsideNursery(rt, key.enclosingScope())) - rt->gcStoreBuffer.putGeneric(MissingScopesRef(map, key)); + rt->gc.storeBuffer.putGeneric(MissingScopesRef(map, key)); #endif } @@ -1629,7 +1628,7 @@ DebugScopes::liveScopesPostWriteBarrier(JSRuntime *rt, LiveScopeMap *map, ScopeO RuntimeAllocPolicy> UnbarrieredLiveScopeMap; typedef gc::HashKeyRef Ref; if (key && IsInsideNursery(rt, key)) - rt->gcStoreBuffer.putGeneric(Ref(reinterpret_cast(map), key)); + rt->gc.storeBuffer.putGeneric(Ref(reinterpret_cast(map), key)); #endif } diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index f446a98da3a0..be119523f00a 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -1085,7 +1085,7 @@ CloneProperties(JSContext *cx, HandleObject selfHostedObject, HandleObject clone if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue)) return false; if (!CloneValue(cx, selfHostedValue, &val) || - !JS_DefinePropertyById(cx, clone, id, val.get(), nullptr, nullptr, 0)) + !JS_DefinePropertyById(cx, clone, id, val, 0)) { return false; } diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index ceda6fa1b125..9a03cfb894f9 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1526,7 +1526,7 @@ BaseShape::assertConsistency() void JSCompartment::sweepBaseShapeTable() { - gcstats::AutoPhase ap(runtimeFromMainThread()->gcStats, + gcstats::AutoPhase ap(runtimeFromMainThread()->gc.stats, gcstats::PHASE_SWEEP_TABLES_BASE_SHAPE); if (baseShapes.initialized()) { @@ -1736,7 +1736,7 @@ EmptyShape::getInitialShape(ExclusiveContext *cx, const Class *clasp, TaggedProt { InitialShapeSetRef ref( &table, clasp, protoRoot, parentRoot, metadataRoot, nfixed, objectFlags); - cx->asJSContext()->runtime()->gcStoreBuffer.putGeneric(ref); + cx->asJSContext()->runtime()->gc.storeBuffer.putGeneric(ref); } } #endif @@ -1814,7 +1814,7 @@ EmptyShape::insertInitialShape(ExclusiveContext *cx, HandleShape shape, HandleOb void JSCompartment::sweepInitialShapeTable() { - gcstats::AutoPhase ap(runtimeFromMainThread()->gcStats, + gcstats::AutoPhase ap(runtimeFromMainThread()->gc.stats, gcstats::PHASE_SWEEP_TABLES_INITIAL_SHAPE); if (initialShapes.initialized()) { diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 2e71604d8de0..eff936197531 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -890,22 +890,22 @@ AbstractFramePtr::popWith(JSContext *cx) const #endif } -Activation::Activation(JSContext *cx, Kind kind) +Activation::Activation(ThreadSafeContext *cx, Kind kind) : cx_(cx), - compartment_(cx->compartment()), - prev_(cx->mainThread().activation_), + compartment_(cx->compartment_), + prev_(cx->perThreadData->activation_), savedFrameChain_(0), hideScriptedCallerCount_(0), kind_(kind) { - cx->mainThread().activation_ = this; + cx->perThreadData->activation_ = this; } Activation::~Activation() { - JS_ASSERT(cx_->mainThread().activation_ == this); + JS_ASSERT(cx_->perThreadData->activation_ == this); JS_ASSERT(hideScriptedCallerCount_ == 0); - cx_->mainThread().activation_ = prev_; + cx_->perThreadData->activation_ = prev_; } InterpreterActivation::InterpreterActivation(RunState &state, JSContext *cx, @@ -915,7 +915,7 @@ InterpreterActivation::InterpreterActivation(RunState &state, JSContext *cx, entryFrame_(entryFrame), opMask_(0) #ifdef DEBUG - , oldFrameCount_(cx_->runtime()->interpreterStack().frameCount_) + , oldFrameCount_(cx->runtime()->interpreterStack().frameCount_) #endif { if (!state.isGenerator()) { @@ -934,8 +934,9 @@ InterpreterActivation::~InterpreterActivation() while (regs_.fp() != entryFrame_) popInlineFrame(regs_.fp()); - JS_ASSERT(oldFrameCount_ == cx_->runtime()->interpreterStack().frameCount_); - JS_ASSERT_IF(oldFrameCount_ == 0, cx_->runtime()->interpreterStack().allocator_.used() == 0); + JSContext *cx = cx_->asJSContext(); + JS_ASSERT(oldFrameCount_ == cx->runtime()->interpreterStack().frameCount_); + JS_ASSERT_IF(oldFrameCount_ == 0, cx->runtime()->interpreterStack().allocator_.used() == 0); if (state_.isGenerator()) { JSGenerator *gen = state_.asGenerator()->gen(); @@ -945,16 +946,17 @@ InterpreterActivation::~InterpreterActivation() } if (entryFrame_) - cx_->runtime()->interpreterStack().releaseFrame(entryFrame_); + cx->runtime()->interpreterStack().releaseFrame(entryFrame_); } inline bool InterpreterActivation::pushInlineFrame(const CallArgs &args, HandleScript script, InitialFrameFlags initial) { - if (!cx_->runtime()->interpreterStack().pushInlineFrame(cx_, regs_, args, script, initial)) + JSContext *cx = cx_->asJSContext(); + if (!cx->runtime()->interpreterStack().pushInlineFrame(cx, regs_, args, script, initial)) return false; - JS_ASSERT(regs_.fp()->script()->compartment() == compartment_); + JS_ASSERT(regs_.fp()->script()->compartment() == compartment()); return true; } @@ -965,7 +967,13 @@ InterpreterActivation::popInlineFrame(InterpreterFrame *frame) JS_ASSERT(regs_.fp() == frame); JS_ASSERT(regs_.fp() != entryFrame_); - cx_->runtime()->interpreterStack().popInlineFrame(regs_); + cx_->asJSContext()->runtime()->interpreterStack().popInlineFrame(regs_); +} + +inline JSContext * +AsmJSActivation::cx() +{ + return cx_->asJSContext(); } } /* namespace js */ diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp index e6739dab3d04..922aa315a824 100644 --- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -557,7 +557,8 @@ FrameIter::settleOnActivation() // If the caller supplied principals, only show activations which are subsumed (of the same // origin or of an origin accessible) by these principals. if (data_.principals_) { - if (JSSubsumesOp subsumes = data_.cx_->runtime()->securityCallbacks->subsumes) { + JSContext *cx = data_.cx_->asJSContext(); + if (JSSubsumesOp subsumes = cx->runtime()->securityCallbacks->subsumes) { JS::AutoAssertNoGC nogc; if (!subsumes(data_.principals_, activation->compartment()->principals)) { ++data_.activations_; @@ -627,15 +628,15 @@ FrameIter::settleOnActivation() } } -FrameIter::Data::Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption, - JSPrincipals *principals) +FrameIter::Data::Data(ThreadSafeContext *cx, SavedOption savedOption, + ContextOption contextOption, JSPrincipals *principals) : cx_(cx), savedOption_(savedOption), contextOption_(contextOption), principals_(principals), pc_(nullptr), interpFrames_(nullptr), - activations_(cx->runtime()) + activations_(cx->perThreadData) #ifdef JS_ION , jitFrames_((uint8_t *)nullptr, SequentialExecution) , ionInlineFrameNo_(0) @@ -661,7 +662,7 @@ FrameIter::Data::Data(const FrameIter::Data &other) { } -FrameIter::FrameIter(JSContext *cx, SavedOption savedOption) +FrameIter::FrameIter(ThreadSafeContext *cx, SavedOption savedOption) : data_(cx, savedOption, CURRENT_CONTEXT, nullptr) #ifdef JS_ION , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr) @@ -670,6 +671,16 @@ FrameIter::FrameIter(JSContext *cx, SavedOption savedOption) settleOnActivation(); } +FrameIter::FrameIter(ThreadSafeContext *cx, ContextOption contextOption, + SavedOption savedOption) + : data_(cx, savedOption, contextOption, nullptr) +#ifdef JS_ION + , ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr) +#endif +{ + settleOnActivation(); +} + FrameIter::FrameIter(JSContext *cx, ContextOption contextOption, SavedOption savedOption, JSPrincipals *principals) : data_(cx, savedOption, contextOption, principals) @@ -1070,11 +1081,11 @@ FrameIter::isConstructing() const } bool -FrameIter::ensureHasRematerializedFrame() +FrameIter::ensureHasRematerializedFrame(ThreadSafeContext *cx) { #ifdef JS_ION MOZ_ASSERT(isIon()); - return !!activation()->asJit()->getRematerializedFrame(activation()->cx(), data_.jitFrames_); + return !!activation()->asJit()->getRematerializedFrame(cx, data_.jitFrames_); #else return true; #endif @@ -1156,9 +1167,9 @@ FrameIter::updatePcQuadratic() jit::BaselineFrame *frame = data_.jitFrames_.baselineFrame(); jit::JitActivation *activation = data_.activations_->asJit(); - // ActivationIterator::ionTop_ may be invalid, so create a new + // ActivationIterator::jitTop_ may be invalid, so create a new // activation iterator. - data_.activations_ = ActivationIterator(data_.cx_->runtime()); + data_.activations_ = ActivationIterator(data_.cx_->perThreadData); while (data_.activations_.activation() != activation) ++data_.activations_; @@ -1514,28 +1525,42 @@ jit::JitActivation::JitActivation(JSContext *cx, bool firstFrameIsConstructing, firstFrameIsConstructing_(firstFrameIsConstructing), active_(active) #ifdef JS_ION - , rematerializedFrames_(cx) + , rematerializedFrames_(nullptr) #endif { if (active) { - prevIonTop_ = cx->mainThread().ionTop; + prevJitTop_ = cx->mainThread().jitTop; prevJitJSContext_ = cx->mainThread().jitJSContext; cx->mainThread().jitJSContext = cx; } else { - prevIonTop_ = nullptr; + prevJitTop_ = nullptr; prevJitJSContext_ = nullptr; } } +jit::JitActivation::JitActivation(ForkJoinContext *cx) + : Activation(cx, Jit), + firstFrameIsConstructing_(false), + active_(true) +#ifdef JS_ION + , rematerializedFrames_(nullptr) +#endif +{ + prevJitTop_ = cx->perThreadData->jitTop; + prevJitJSContext_ = cx->perThreadData->jitJSContext; + cx->perThreadData->jitJSContext = nullptr; +} + jit::JitActivation::~JitActivation() { if (active_) { - cx_->mainThread().ionTop = prevIonTop_; - cx_->mainThread().jitJSContext = prevJitJSContext_; + cx_->perThreadData->jitTop = prevJitTop_; + cx_->perThreadData->jitJSContext = prevJitJSContext_; } #ifdef JS_ION clearRematerializedFrames(); + js_delete(rematerializedFrames_); #endif } @@ -1552,11 +1577,11 @@ jit::JitActivation::setActive(JSContext *cx, bool active) active_ = active; if (active) { - prevIonTop_ = cx->mainThread().ionTop; + prevJitTop_ = cx->mainThread().jitTop; prevJitJSContext_ = cx->mainThread().jitJSContext; cx->mainThread().jitJSContext = cx; } else { - cx->mainThread().ionTop = prevIonTop_; + cx->mainThread().jitTop = prevJitTop_; cx->mainThread().jitJSContext = prevJitJSContext_; } } @@ -1577,36 +1602,43 @@ jit::JitActivation::freeRematerializedFramesInVector(RematerializedFrameVector & void jit::JitActivation::removeRematerializedFrame(uint8_t *top) { - if (!rematerializedFrames_.initialized()) + if (!rematerializedFrames_) return; - if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top)) { + if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) { freeRematerializedFramesInVector(p->value()); - rematerializedFrames_.remove(p); + rematerializedFrames_->remove(p); } } void jit::JitActivation::clearRematerializedFrames() { - if (!rematerializedFrames_.initialized()) + if (!rematerializedFrames_) return; - for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) { + for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) { freeRematerializedFramesInVector(e.front().value()); e.removeFront(); } } jit::RematerializedFrame * -jit::JitActivation::getRematerializedFrame(JSContext *cx, JitFrameIterator &iter, +jit::JitActivation::getRematerializedFrame(ThreadSafeContext *cx, JitFrameIterator &iter, size_t inlineDepth) { + // Only allow rematerializing from the same thread. + MOZ_ASSERT(cx->perThreadData == cx_->perThreadData); MOZ_ASSERT(iter.activation() == this); MOZ_ASSERT(iter.isIonJS()); - if (!rematerializedFrames_.initialized() && !rematerializedFrames_.init()) - return nullptr; + if (!rematerializedFrames_) { + rematerializedFrames_ = cx->new_(cx); + if (!rematerializedFrames_ || !rematerializedFrames_->init()) { + rematerializedFrames_ = nullptr; + return nullptr; + } + } // The unit of rematerialization is an uninlined frame and its inlined // frames. Since inlined frames do not exist outside of snapshots, it is @@ -1615,10 +1647,10 @@ jit::JitActivation::getRematerializedFrame(JSContext *cx, JitFrameIterator &iter // its inlined frames at once. uint8_t *top = iter.fp(); - RematerializedFrameTable::AddPtr p = rematerializedFrames_.lookupForAdd(top); + RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top); if (!p) { RematerializedFrameVector empty(cx); - if (!rematerializedFrames_.add(p, top, Move(empty))) + if (!rematerializedFrames_->add(p, top, Move(empty))) return nullptr; InlineFrameIterator inlineIter(cx, &iter); @@ -1643,9 +1675,9 @@ jit::JitActivation::getRematerializedFrame(JSContext *cx, JitFrameIterator &iter jit::RematerializedFrame * jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth) { - if (!rematerializedFrames_.initialized()) + if (!rematerializedFrames_) return nullptr; - if (RematerializedFrameTable::Ptr p = rematerializedFrames_.lookup(top)) + if (RematerializedFrameTable::Ptr p = rematerializedFrames_->lookup(top)) return inlineDepth < p->value().length() ? p->value()[inlineDepth] : nullptr; return nullptr; } @@ -1653,9 +1685,9 @@ jit::JitActivation::lookupRematerializedFrame(uint8_t *top, size_t inlineDepth) void jit::JitActivation::markRematerializedFrames(JSTracer *trc) { - if (!rematerializedFrames_.initialized()) + if (!rematerializedFrames_) return; - for (RematerializedFrameTable::Enum e(rematerializedFrames_); !e.empty(); e.popFront()) { + for (RematerializedFrameTable::Enum e(*rematerializedFrames_); !e.empty(); e.popFront()) { RematerializedFrameVector &frames = e.front().value(); for (size_t i = 0; i < frames.length(); i++) frames[i]->mark(trc); @@ -1681,10 +1713,10 @@ AsmJSActivation::AsmJSActivation(JSContext *cx, AsmJSModule &module) profiler_->enterNative("asm.js code :0", this); } - prevAsmJS_ = cx_->runtime()->mainThread.asmJSActivationStack_; + prevAsmJS_ = cx->mainThread().asmJSActivationStack_; - JSRuntime::AutoLockForInterrupt lock(cx_->runtime()); - cx_->runtime()->mainThread.asmJSActivationStack_ = this; + JSRuntime::AutoLockForInterrupt lock(cx->runtime()); + cx->mainThread().asmJSActivationStack_ = this; (void) errorRejoinSP_; // squelch GCC warning } @@ -1694,10 +1726,11 @@ AsmJSActivation::~AsmJSActivation() if (profiler_) profiler_->exitNative(); - JS_ASSERT(cx_->runtime()->mainThread.asmJSActivationStack_ == this); + JSContext *cx = cx_->asJSContext(); + JS_ASSERT(cx->mainThread().asmJSActivationStack_ == this); - JSRuntime::AutoLockForInterrupt lock(cx_->runtime()); - cx_->runtime()->mainThread.asmJSActivationStack_ = prevAsmJS_; + JSRuntime::AutoLockForInterrupt lock(cx->runtime()); + cx->mainThread().asmJSActivationStack_ = prevAsmJS_; } InterpreterFrameIterator & @@ -1717,18 +1750,25 @@ InterpreterFrameIterator::operator++() } ActivationIterator::ActivationIterator(JSRuntime *rt) - : jitTop_(rt->mainThread.ionTop), + : jitTop_(rt->mainThread.jitTop), activation_(rt->mainThread.activation_) { settle(); } +ActivationIterator::ActivationIterator(PerThreadData *perThreadData) + : jitTop_(perThreadData->jitTop), + activation_(perThreadData->activation_) +{ + settle(); +} + ActivationIterator & ActivationIterator::operator++() { JS_ASSERT(activation_); if (activation_->isJit() && activation_->asJit()->isActive()) - jitTop_ = activation_->asJit()->prevIonTop(); + jitTop_ = activation_->asJit()->prevJitTop(); activation_ = activation_->prev(); settle(); return *this; diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 52259f6d2b47..a62fd378ba30 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1138,7 +1138,7 @@ namespace jit { class Activation { protected: - JSContext *cx_; + ThreadSafeContext *cx_; JSCompartment *compartment_; Activation *prev_; @@ -1158,11 +1158,11 @@ class Activation enum Kind { Interpreter, Jit, ForkJoin, AsmJS }; Kind kind_; - inline Activation(JSContext *cx, Kind kind_); + inline Activation(ThreadSafeContext *cx, Kind kind_); inline ~Activation(); public: - JSContext *cx() const { + ThreadSafeContext *cx() const { return cx_; } JSCompartment *compartment() const { @@ -1289,7 +1289,8 @@ class InterpreterActivation : public Activation } }; -// Iterates over a runtime's activation list. +// Iterates over a thread's activation list. If given a runtime, iterate over +// the runtime's main thread's activation list. class ActivationIterator { uint8_t *jitTop_; @@ -1302,6 +1303,7 @@ class ActivationIterator public: explicit ActivationIterator(JSRuntime *rt); + explicit ActivationIterator(PerThreadData *perThreadData); ActivationIterator &operator++(); @@ -1325,20 +1327,20 @@ namespace jit { // A JitActivation is used for frames running in Baseline or Ion. class JitActivation : public Activation { - uint8_t *prevIonTop_; + uint8_t *prevJitTop_; JSContext *prevJitJSContext_; bool firstFrameIsConstructing_; bool active_; #ifdef JS_ION // Rematerialized Ion frames which has info copied out of snapshots. Maps - // frame pointers (i.e. ionTop) to a vector of rematerializations of all + // frame pointers (i.e. jitTop) to a vector of rematerializations of all // inline frames associated with that frame. // // This table is lazily initialized by calling getRematerializedFrame. typedef Vector RematerializedFrameVector; typedef HashMap RematerializedFrameTable; - RematerializedFrameTable rematerializedFrames_; + RematerializedFrameTable *rematerializedFrames_; void freeRematerializedFramesInVector(RematerializedFrameVector &frames); void clearRematerializedFrames(); @@ -1354,6 +1356,7 @@ class JitActivation : public Activation public: JitActivation(JSContext *cx, bool firstFrameIsConstructing, bool active = true); + JitActivation(ForkJoinContext *cx); ~JitActivation(); bool isActive() const { @@ -1361,17 +1364,14 @@ class JitActivation : public Activation } void setActive(JSContext *cx, bool active = true); - uint8_t *prevIonTop() const { - return prevIonTop_; - } - JSCompartment *compartment() const { - return compartment_; + uint8_t *prevJitTop() const { + return prevJitTop_; } bool firstFrameIsConstructing() const { return firstFrameIsConstructing_; } - static size_t offsetOfPrevIonTop() { - return offsetof(JitActivation, prevIonTop_); + static size_t offsetOfPrevJitTop() { + return offsetof(JitActivation, prevJitTop_); } static size_t offsetOfPrevJitJSContext() { return offsetof(JitActivation, prevJitJSContext_); @@ -1400,7 +1400,7 @@ class JitActivation : public Activation // provided, as values need to be read out of snapshots. // // The inlineDepth must be within bounds of the frame pointed to by iter. - RematerializedFrame *getRematerializedFrame(JSContext *cx, JitFrameIterator &iter, + RematerializedFrame *getRematerializedFrame(ThreadSafeContext *cx, JitFrameIterator &iter, size_t inlineDepth = 0); // Look up a rematerialized frame by the fp. If inlineDepth is out of @@ -1433,6 +1433,12 @@ class JitActivationIterator : public ActivationIterator settle(); } + explicit JitActivationIterator(PerThreadData *perThreadData) + : ActivationIterator(perThreadData) + { + settle(); + } + JitActivationIterator &operator++() { ActivationIterator::operator++(); settle(); @@ -1511,7 +1517,7 @@ class AsmJSActivation : public Activation AsmJSActivation(JSContext *cx, AsmJSModule &module); ~AsmJSActivation(); - JSContext *cx() { return cx_; } + inline JSContext *cx(); AsmJSModule &module() const { return module_; } AsmJSActivation *prevAsmJS() const { return prevAsmJS_; } @@ -1566,14 +1572,14 @@ class FrameIter // the heap, so this structure should not contain any GC things. struct Data { - JSContext * cx_; - SavedOption savedOption_; - ContextOption contextOption_; - JSPrincipals * principals_; + ThreadSafeContext * cx_; + SavedOption savedOption_; + ContextOption contextOption_; + JSPrincipals * principals_; - State state_; + State state_; - jsbytecode * pc_; + jsbytecode * pc_; InterpreterFrameIterator interpFrames_; ActivationIterator activations_; @@ -1584,13 +1590,14 @@ class FrameIter AsmJSFrameIterator asmJSFrames_; #endif - Data(JSContext *cx, SavedOption savedOption, ContextOption contextOption, + Data(ThreadSafeContext *cx, SavedOption savedOption, ContextOption contextOption, JSPrincipals *principals); Data(const Data &other); }; - FrameIter(JSContext *cx, SavedOption = STOP_AT_SAVED); - FrameIter(JSContext *cx, ContextOption, SavedOption, JSPrincipals* = nullptr); + FrameIter(ThreadSafeContext *cx, SavedOption = STOP_AT_SAVED); + FrameIter(ThreadSafeContext *cx, ContextOption, SavedOption); + FrameIter(JSContext *cx, ContextOption, SavedOption, JSPrincipals *); FrameIter(const FrameIter &iter); FrameIter(const Data &data); FrameIter(AbstractFramePtr frame); @@ -1678,7 +1685,7 @@ class FrameIter // Ensures that we have rematerialized the top frame and its associated // inline frames. Can only be called when isIon(). - bool ensureHasRematerializedFrame(); + bool ensureHasRematerializedFrame(ThreadSafeContext *cx); // True when isInterp() or isBaseline(). True when isIon() if it // has a rematerialized frame. False otherwise false otherwise. @@ -1723,16 +1730,24 @@ class ScriptFrameIter : public FrameIter } public: - ScriptFrameIter(JSContext *cx, SavedOption savedOption = STOP_AT_SAVED) + ScriptFrameIter(ThreadSafeContext *cx, SavedOption savedOption = STOP_AT_SAVED) : FrameIter(cx, savedOption) { settle(); } + ScriptFrameIter(ThreadSafeContext *cx, + ContextOption cxOption, + SavedOption savedOption) + : FrameIter(cx, cxOption, savedOption) + { + settle(); + } + ScriptFrameIter(JSContext *cx, ContextOption cxOption, SavedOption savedOption, - JSPrincipals *prin = nullptr) + JSPrincipals *prin) : FrameIter(cx, cxOption, savedOption, prin) { settle(); @@ -1765,17 +1780,25 @@ class NonBuiltinFrameIter : public FrameIter void settle(); public: - NonBuiltinFrameIter(JSContext *cx, + NonBuiltinFrameIter(ThreadSafeContext *cx, FrameIter::SavedOption opt = FrameIter::STOP_AT_SAVED) : FrameIter(cx, opt) { settle(); } + NonBuiltinFrameIter(ThreadSafeContext *cx, + FrameIter::ContextOption contextOption, + FrameIter::SavedOption savedOption) + : FrameIter(cx, contextOption, savedOption) + { + settle(); + } + NonBuiltinFrameIter(JSContext *cx, FrameIter::ContextOption contextOption, FrameIter::SavedOption savedOption, - JSPrincipals *principals = nullptr) + JSPrincipals *principals) : FrameIter(cx, contextOption, savedOption, principals) { settle(); @@ -1798,17 +1821,25 @@ class NonBuiltinScriptFrameIter : public ScriptFrameIter void settle(); public: - NonBuiltinScriptFrameIter(JSContext *cx, + NonBuiltinScriptFrameIter(ThreadSafeContext *cx, ScriptFrameIter::SavedOption opt = ScriptFrameIter::STOP_AT_SAVED) : ScriptFrameIter(cx, opt) { settle(); } + NonBuiltinScriptFrameIter(ThreadSafeContext *cx, + ScriptFrameIter::ContextOption contextOption, + ScriptFrameIter::SavedOption savedOption) + : ScriptFrameIter(cx, contextOption, savedOption) + { + settle(); + } + NonBuiltinScriptFrameIter(JSContext *cx, ScriptFrameIter::ContextOption contextOption, ScriptFrameIter::SavedOption savedOption, - JSPrincipals *principals = nullptr) + JSPrincipals *principals) : ScriptFrameIter(cx, contextOption, savedOption, principals) { settle(); @@ -1832,7 +1863,7 @@ class NonBuiltinScriptFrameIter : public ScriptFrameIter class AllFramesIter : public ScriptFrameIter { public: - AllFramesIter(JSContext *cx) + AllFramesIter(ThreadSafeContext *cx) : ScriptFrameIter(cx, ScriptFrameIter::ALL_CONTEXTS, ScriptFrameIter::GO_THROUGH_SAVED) {} }; diff --git a/js/src/vm/TraceLogging.cpp b/js/src/vm/TraceLogging.cpp index 8236c98d2b0d..8cc5e6ce4809 100644 --- a/js/src/vm/TraceLogging.cpp +++ b/js/src/vm/TraceLogging.cpp @@ -835,6 +835,10 @@ TraceLogging::lazyInit() enabledTextIds[TraceLogger::EliminateDeadCode] = true; enabledTextIds[TraceLogger::EdgeCaseAnalysis] = true; enabledTextIds[TraceLogger::EliminateRedundantChecks] = true; + enabledTextIds[TraceLogger::GenerateLIR] = true; + enabledTextIds[TraceLogger::RegisterAllocation] = true; + enabledTextIds[TraceLogger::UnsplitEdges] = true; + enabledTextIds[TraceLogger::GenerateCode] = true; } const char *options = getenv("TLOPTIONS"); diff --git a/js/src/vm/TraceLogging.h b/js/src/vm/TraceLogging.h index df70ac4e5ccc..290a1b3209e8 100644 --- a/js/src/vm/TraceLogging.h +++ b/js/src/vm/TraceLogging.h @@ -145,7 +145,11 @@ namespace jit { _(EffectiveAddressAnalysis) \ _(EliminateDeadCode) \ _(EdgeCaseAnalysis) \ - _(EliminateRedundantChecks) + _(EliminateRedundantChecks) \ + _(GenerateLIR) \ + _(RegisterAllocation) \ + _(UnsplitEdges) \ + _(GenerateCode) \ class AutoTraceLog; diff --git a/js/src/vm/Value.cpp b/js/src/vm/Value.cpp index d88760b07600..a2e41efca55e 100644 --- a/js/src/vm/Value.cpp +++ b/js/src/vm/Value.cpp @@ -17,5 +17,7 @@ namespace JS { const HandleValue NullHandleValue = HandleValue::fromMarkedLocation(&JSVAL_NULL); const HandleValue UndefinedHandleValue = HandleValue::fromMarkedLocation(&JSVAL_VOID); +const HandleValue TrueHandleValue = HandleValue::fromMarkedLocation(&JSVAL_TRUE); +const HandleValue FalseHandleValue = HandleValue::fromMarkedLocation(&JSVAL_FALSE); } // namespace JS diff --git a/js/src/yarr/CheckedArithmetic.h b/js/src/yarr/CheckedArithmetic.h index 212caac5bca1..20fb23013115 100644 --- a/js/src/yarr/CheckedArithmetic.h +++ b/js/src/yarr/CheckedArithmetic.h @@ -110,7 +110,7 @@ private: unsigned char m_overflowed; }; -template class Checked; +template class Checked; template struct RemoveChecked; template struct RemoveChecked >; diff --git a/js/src/yarr/YarrJIT.cpp b/js/src/yarr/YarrJIT.cpp index 7191c1e5a7ae..a8a2d1e33abd 100644 --- a/js/src/yarr/YarrJIT.cpp +++ b/js/src/yarr/YarrJIT.cpp @@ -611,10 +611,11 @@ class YarrGenerator : private MacroAssembler { // to many terms; terms commonly jump out of the forwards matching path // on any failed conditions, and add these jumps to the m_jumps list. If // no special handling is required we can often just backtrack to m_jumps. - void backtrackTermDefault(size_t opIndex) + bool backtrackTermDefault(size_t opIndex) { YarrOp& op = m_ops[opIndex]; m_backtrackingState.append(op.m_jumps); + return true; } bool generateAssertionBOL(size_t opIndex) @@ -643,9 +644,9 @@ class YarrGenerator : private MacroAssembler { } return true; } - void backtrackAssertionBOL(size_t opIndex) + bool backtrackAssertionBOL(size_t opIndex) { - backtrackTermDefault(opIndex); + return backtrackTermDefault(opIndex); } bool generateAssertionEOL(size_t opIndex) @@ -674,9 +675,9 @@ class YarrGenerator : private MacroAssembler { } return true; } - void backtrackAssertionEOL(size_t opIndex) + bool backtrackAssertionEOL(size_t opIndex) { - backtrackTermDefault(opIndex); + return backtrackTermDefault(opIndex); } // Also falls though on nextIsNotWordChar. @@ -740,9 +741,9 @@ class YarrGenerator : private MacroAssembler { wordCharThenNonWordChar.link(this); return true; } - void backtrackAssertionWordBoundary(size_t opIndex) + bool backtrackAssertionWordBoundary(size_t opIndex) { - backtrackTermDefault(opIndex); + return backtrackTermDefault(opIndex); } bool generatePatternCharacterOnce(size_t opIndex) @@ -865,9 +866,9 @@ class YarrGenerator : private MacroAssembler { op.m_jumps.append(branch32(NotEqual, character, Imm32(allCharacters | ignoreCaseMask))); return true; } - void backtrackPatternCharacterOnce(size_t opIndex) + bool backtrackPatternCharacterOnce(size_t opIndex) { - backtrackTermDefault(opIndex); + return backtrackTermDefault(opIndex); } bool generatePatternCharacterFixed(size_t opIndex) @@ -880,10 +881,15 @@ class YarrGenerator : private MacroAssembler { const RegisterID countRegister = regT1; move(index, countRegister); + if (term->quantityCount.hasOverflowed()) + return false; sub32(Imm32(term->quantityCount.unsafeGet()), countRegister); Label loop(this); - BaseIndex address(input, countRegister, m_charScale, (Checked(term->inputPosition - m_checked + Checked(term->quantityCount)) * static_cast(m_charSize == Char8 ? sizeof(char) : sizeof(UChar))).unsafeGet()); + int offset; + if ((Checked(term->inputPosition - m_checked + Checked(term->quantityCount)) * static_cast(m_charSize == Char8 ? sizeof(char) : sizeof(UChar))).safeGet(offset)) + return false; + BaseIndex address(input, countRegister, m_charScale, offset); if (m_charSize == Char8) load8(address, character); @@ -904,9 +910,9 @@ class YarrGenerator : private MacroAssembler { return true; } - void backtrackPatternCharacterFixed(size_t opIndex) + bool backtrackPatternCharacterFixed(size_t opIndex) { - backtrackTermDefault(opIndex); + return backtrackTermDefault(opIndex); } bool generatePatternCharacterGreedy(size_t opIndex) @@ -929,10 +935,13 @@ class YarrGenerator : private MacroAssembler { add32(TrustedImm32(1), countRegister); add32(TrustedImm32(1), index); - if (term->quantityCount == quantifyInfinite) + if (term->quantityCount == quantifyInfinite) { jump(loop); - else + } else { + if (term->quantityCount.hasOverflowed()) + return false; branch32(NotEqual, countRegister, Imm32(term->quantityCount.unsafeGet())).linkTo(loop, this); + } failures.link(this); } @@ -941,7 +950,7 @@ class YarrGenerator : private MacroAssembler { storeToFrame(countRegister, term->frameLocation); return true; } - void backtrackPatternCharacterGreedy(size_t opIndex) + bool backtrackPatternCharacterGreedy(size_t opIndex) { YarrOp& op = m_ops[opIndex]; PatternTerm* term = op.m_term; @@ -955,6 +964,8 @@ class YarrGenerator : private MacroAssembler { sub32(TrustedImm32(1), countRegister); sub32(TrustedImm32(1), index); jump(op.m_reentry); + + return true; } bool generatePatternCharacterNonGreedy(size_t opIndex) @@ -969,7 +980,7 @@ class YarrGenerator : private MacroAssembler { storeToFrame(countRegister, term->frameLocation); return true; } - void backtrackPatternCharacterNonGreedy(size_t opIndex) + bool backtrackPatternCharacterNonGreedy(size_t opIndex) { YarrOp& op = m_ops[opIndex]; PatternTerm* term = op.m_term; @@ -986,8 +997,11 @@ class YarrGenerator : private MacroAssembler { if (!((ch > 0xff) && (m_charSize == Char8))) { JumpList nonGreedyFailures; nonGreedyFailures.append(atEndOfInput()); - if (term->quantityCount != quantifyInfinite) + if (term->quantityCount != quantifyInfinite) { + if (term->quantityCount.hasOverflowed()) + return false; nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount.unsafeGet()))); + } nonGreedyFailures.append(jumpIfCharNotEquals(ch, term->inputPosition - m_checked, character)); add32(TrustedImm32(1), countRegister); @@ -999,6 +1013,8 @@ class YarrGenerator : private MacroAssembler { sub32(countRegister, index); m_backtrackingState.fallthrough(); + + return true; } bool generateCharacterClassOnce(size_t opIndex) @@ -1020,9 +1036,9 @@ class YarrGenerator : private MacroAssembler { } return true; } - void backtrackCharacterClassOnce(size_t opIndex) + bool backtrackCharacterClassOnce(size_t opIndex) { - backtrackTermDefault(opIndex); + return backtrackTermDefault(opIndex); } bool generateCharacterClassFixed(size_t opIndex) @@ -1034,14 +1050,25 @@ class YarrGenerator : private MacroAssembler { const RegisterID countRegister = regT1; move(index, countRegister); + if (term->quantityCount.hasOverflowed()) + return false; sub32(Imm32(term->quantityCount.unsafeGet()), countRegister); Label loop(this); JumpList matchDest; - if (m_charSize == Char8) - load8(BaseIndex(input, countRegister, TimesOne, (Checked(term->inputPosition - m_checked + Checked(term->quantityCount)) * static_cast(sizeof(char))).unsafeGet()), character); - else - load16(BaseIndex(input, countRegister, TimesTwo, (Checked(term->inputPosition - m_checked + Checked(term->quantityCount)) * static_cast(sizeof(UChar))).unsafeGet()), character); + + int offset; + Checked checkedOffset(term->inputPosition - m_checked + Checked(term->quantityCount)); + + if (m_charSize == Char8) { + if ((Checked(checkedOffset) * static_cast(sizeof(char))).safeGet(offset)) + return false; + load8(BaseIndex(input, countRegister, TimesOne, offset), character); + } else { + if ((Checked(checkedOffset) * static_cast(sizeof(UChar))).safeGet(offset)) + return false; + load16(BaseIndex(input, countRegister, TimesTwo, offset), character); + } matchCharacterClass(character, matchDest, term->characterClass); if (term->invert()) @@ -1055,9 +1082,9 @@ class YarrGenerator : private MacroAssembler { branch32(NotEqual, countRegister, index).linkTo(loop, this); return true; } - void backtrackCharacterClassFixed(size_t opIndex) + bool backtrackCharacterClassFixed(size_t opIndex) { - backtrackTermDefault(opIndex); + return backtrackTermDefault(opIndex); } bool generateCharacterClassGreedy(size_t opIndex) @@ -1088,7 +1115,10 @@ class YarrGenerator : private MacroAssembler { add32(TrustedImm32(1), countRegister); add32(TrustedImm32(1), index); if (term->quantityCount != quantifyInfinite) { - branch32(NotEqual, countRegister, Imm32(term->quantityCount.unsafeGet())).linkTo(loop, this); + unsigned quantityCount; + if (term->quantityCount.safeGet(quantityCount)) + return false; + branch32(NotEqual, countRegister, Imm32(quantityCount)).linkTo(loop, this); failures.append(jump()); } else jump(loop); @@ -1099,7 +1129,7 @@ class YarrGenerator : private MacroAssembler { storeToFrame(countRegister, term->frameLocation); return true; } - void backtrackCharacterClassGreedy(size_t opIndex) + bool backtrackCharacterClassGreedy(size_t opIndex) { YarrOp& op = m_ops[opIndex]; PatternTerm* term = op.m_term; @@ -1113,6 +1143,8 @@ class YarrGenerator : private MacroAssembler { sub32(TrustedImm32(1), countRegister); sub32(TrustedImm32(1), index); jump(op.m_reentry); + + return true; } bool generateCharacterClassNonGreedy(size_t opIndex) @@ -1127,7 +1159,7 @@ class YarrGenerator : private MacroAssembler { storeToFrame(countRegister, term->frameLocation); return true; } - void backtrackCharacterClassNonGreedy(size_t opIndex) + bool backtrackCharacterClassNonGreedy(size_t opIndex) { YarrOp& op = m_ops[opIndex]; PatternTerm* term = op.m_term; @@ -1142,6 +1174,8 @@ class YarrGenerator : private MacroAssembler { loadFromFrame(term->frameLocation, countRegister); nonGreedyFailures.append(atEndOfInput()); + if (term->quantityCount.hasOverflowed()) + return false; nonGreedyFailures.append(branch32(Equal, countRegister, Imm32(term->quantityCount.unsafeGet()))); JumpList matchDest; @@ -1163,6 +1197,8 @@ class YarrGenerator : private MacroAssembler { nonGreedyFailures.link(this); sub32(countRegister, index); m_backtrackingState.fallthrough(); + + return true; } bool generateDotStarEnclosure(size_t opIndex) @@ -1222,9 +1258,9 @@ class YarrGenerator : private MacroAssembler { return true; } - void backtrackDotStarEnclosure(size_t opIndex) + bool backtrackDotStarEnclosure(size_t opIndex) { - backtrackTermDefault(opIndex); + return backtrackTermDefault(opIndex); } // Code generation/backtracking for simple terms @@ -1290,7 +1326,7 @@ class YarrGenerator : private MacroAssembler { return false; } - void backtrackTerm(size_t opIndex) + bool backtrackTerm(size_t opIndex) { YarrOp& op = m_ops[opIndex]; PatternTerm* term = op.m_term; @@ -1300,16 +1336,13 @@ class YarrGenerator : private MacroAssembler { switch (term->quantityType) { case QuantifierFixedCount: if (term->quantityCount == 1) - backtrackPatternCharacterOnce(opIndex); + return backtrackPatternCharacterOnce(opIndex); else - backtrackPatternCharacterFixed(opIndex); - break; + return backtrackPatternCharacterFixed(opIndex); case QuantifierGreedy: - backtrackPatternCharacterGreedy(opIndex); - break; + return backtrackPatternCharacterGreedy(opIndex); case QuantifierNonGreedy: - backtrackPatternCharacterNonGreedy(opIndex); - break; + return backtrackPatternCharacterNonGreedy(opIndex); } break; @@ -1317,46 +1350,40 @@ class YarrGenerator : private MacroAssembler { switch (term->quantityType) { case QuantifierFixedCount: if (term->quantityCount == 1) - backtrackCharacterClassOnce(opIndex); + return backtrackCharacterClassOnce(opIndex); else - backtrackCharacterClassFixed(opIndex); - break; + return backtrackCharacterClassFixed(opIndex); case QuantifierGreedy: - backtrackCharacterClassGreedy(opIndex); - break; + return backtrackCharacterClassGreedy(opIndex); case QuantifierNonGreedy: - backtrackCharacterClassNonGreedy(opIndex); - break; + return backtrackCharacterClassNonGreedy(opIndex); } break; case PatternTerm::TypeAssertionBOL: - backtrackAssertionBOL(opIndex); - break; + return backtrackAssertionBOL(opIndex); case PatternTerm::TypeAssertionEOL: - backtrackAssertionEOL(opIndex); - break; + return backtrackAssertionEOL(opIndex); case PatternTerm::TypeAssertionWordBoundary: - backtrackAssertionWordBoundary(opIndex); - break; + return backtrackAssertionWordBoundary(opIndex); case PatternTerm::TypeForwardReference: - break; + return true; case PatternTerm::TypeParenthesesSubpattern: case PatternTerm::TypeParentheticalAssertion: ASSERT_NOT_REACHED(); + return false; case PatternTerm::TypeDotStarEnclosure: - backtrackDotStarEnclosure(opIndex); - break; + return backtrackDotStarEnclosure(opIndex); case PatternTerm::TypeBackReference: - m_shouldFallBack = true; - break; + return false; } + return true; } bool generate() @@ -1779,7 +1806,7 @@ class YarrGenerator : private MacroAssembler { return true; } - void backtrack() + bool backtrack() { // Backwards generate the backtracking code. size_t opIndex = m_ops.size(); @@ -1791,7 +1818,8 @@ class YarrGenerator : private MacroAssembler { switch (op.m_op) { case OpTerm: - backtrackTerm(opIndex); + if (!backtrackTerm(opIndex)) + return false; break; // OpBodyAlternativeBegin/Next/End @@ -2310,6 +2338,8 @@ class YarrGenerator : private MacroAssembler { } } while (opIndex); + + return true; } // Compilation methods: @@ -2695,11 +2725,10 @@ public: return; } - if (!generate()) { + if (!generate() || !backtrack()) { jitObject.setFallBack(true); return; } - backtrack(); // Link & finalize the code. ExecutablePool *pool; diff --git a/js/src/yarr/YarrPattern.cpp b/js/src/yarr/YarrPattern.cpp index 60dca3f02ab6..380127d137e9 100644 --- a/js/src/yarr/YarrPattern.cpp +++ b/js/src/yarr/YarrPattern.cpp @@ -592,11 +592,13 @@ public: case PatternTerm::TypeAssertionBOL: case PatternTerm::TypeAssertionEOL: case PatternTerm::TypeAssertionWordBoundary: - term.inputPosition = currentInputPosition.unsafeGet(); + if (Checked(currentInputPosition).safeGet(term.inputPosition)) + return RuntimeError; break; case PatternTerm::TypeBackReference: - term.inputPosition = currentInputPosition.unsafeGet(); + if (Checked(currentInputPosition).safeGet(term.inputPosition)) + return RuntimeError; term.frameLocation = currentCallFrameSize; currentCallFrameSize += YarrStackSpaceForBackTrackInfoBackReference; alternative->m_hasFixedSize = false; @@ -606,7 +608,8 @@ public: break; case PatternTerm::TypePatternCharacter: - term.inputPosition = currentInputPosition.unsafeGet(); + if (Checked(currentInputPosition).safeGet(term.inputPosition)) + return RuntimeError; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; currentCallFrameSize += YarrStackSpaceForBackTrackInfoPatternCharacter; @@ -616,7 +619,8 @@ public: break; case PatternTerm::TypeCharacterClass: - term.inputPosition = currentInputPosition.unsafeGet(); + if (Checked(currentInputPosition).safeGet(term.inputPosition)) + return RuntimeError; if (term.quantityType != QuantifierFixedCount) { term.frameLocation = currentCallFrameSize; currentCallFrameSize += YarrStackSpaceForBackTrackInfoCharacterClass; @@ -628,24 +632,30 @@ public: case PatternTerm::TypeParenthesesSubpattern: // Note: for fixed once parentheses we will ensure at least the minimum is available; others are on their own. term.frameLocation = currentCallFrameSize; + unsigned position; + if (currentInputPosition.safeGet(position)) + return RuntimeError; if (term.quantityCount == 1 && !term.parentheses.isCopy) { if (term.quantityType != QuantifierFixedCount) currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesOnce; - if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition.unsafeGet(), ¤tCallFrameSize)) + if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, position, ¤tCallFrameSize)) return error; // If quantity is fixed, then pre-check its minimum size. if (term.quantityType == QuantifierFixedCount) currentInputPosition += term.parentheses.disjunction->m_minimumSize; - term.inputPosition = currentInputPosition.unsafeGet(); + if (Checked(currentInputPosition).safeGet(term.inputPosition)) + return RuntimeError; } else if (term.parentheses.isTerminal) { currentCallFrameSize += YarrStackSpaceForBackTrackInfoParenthesesTerminal; - if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, currentInputPosition.unsafeGet(), ¤tCallFrameSize)) + if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize, position, ¤tCallFrameSize)) return error; - term.inputPosition = currentInputPosition.unsafeGet(); + if (Checked(currentInputPosition).safeGet(term.inputPosition)) + return RuntimeError; } else { - term.inputPosition = currentInputPosition.unsafeGet(); + if (Checked(currentInputPosition).safeGet(term.inputPosition)) + return RuntimeError; unsigned dummy; - if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, BASE_FRAME_SIZE, currentInputPosition.unsafeGet(), &dummy)) + if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, BASE_FRAME_SIZE, position, &dummy)) return error; currentCallFrameSize += YarrStackSpaceForBackTrackInfoParentheses; } @@ -654,9 +664,10 @@ public: break; case PatternTerm::TypeParentheticalAssertion: - term.inputPosition = currentInputPosition.unsafeGet(); + if (Checked(currentInputPosition).safeGet(term.inputPosition)) + return RuntimeError; term.frameLocation = currentCallFrameSize; - if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, currentInputPosition.unsafeGet(), ¤tCallFrameSize)) + if (ErrorCode error = setupDisjunctionOffsets(term.parentheses.disjunction, currentCallFrameSize + YarrStackSpaceForBackTrackInfoParentheticalAssertion, term.inputPosition, ¤tCallFrameSize)) return error; break; @@ -667,7 +678,8 @@ public: } } - alternative->m_minimumSize = (currentInputPosition - initialInputPosition).unsafeGet(); + if ((currentInputPosition - initialInputPosition).safeGet(alternative->m_minimumSize)) + return RuntimeError; *callFrameSizeOut = currentCallFrameSize; return NoError; } diff --git a/js/xpconnect/loader/mozJSSubScriptLoader.cpp b/js/xpconnect/loader/mozJSSubScriptLoader.cpp index f7f3a3831334..fe7772f568ac 100644 --- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp +++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp @@ -74,9 +74,6 @@ public: mozJSSubScriptLoader::mozJSSubScriptLoader() : mSystemPrincipal(nullptr) { - // Force construction of the JS component loader. We may need it later. - nsCOMPtr componentLoader = - do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID); } mozJSSubScriptLoader::~mozJSSubScriptLoader() diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 640747228f4a..c6740607c3a6 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -321,9 +321,8 @@ ExportFunction(JSContext *cx, HandleValue vfunction, HandleValue vscope, HandleV // defineAs was set, we also need to define it as a property on // the target. if (!JSID_IS_VOID(options.defineAs)) { - if (!JS_DefinePropertyById(cx, targetScope, id, rval, - JS_PropertyStub, JS_StrictPropertyStub, - JSPROP_ENUMERATE)) { + if (!JS_DefinePropertyById(cx, targetScope, id, rval, JSPROP_ENUMERATE, + JS_PropertyStub, JS_StrictPropertyStub)) { return false; } } diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index 9390976e6766..52e5a7973295 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -323,9 +323,7 @@ nsXPCComponents_Interfaces::NewResolve(nsIXPConnectWrappedNative *wrapper, // Assign, not compare (idobj = holder->GetJSObject())) { *objp = obj; - *_retval = JS_DefinePropertyById(cx, obj, id, - OBJECT_TO_JSVAL(idobj), - nullptr, nullptr, + *_retval = JS_DefinePropertyById(cx, obj, id, idobj, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); @@ -579,9 +577,7 @@ nsXPCComponents_InterfacesByID::NewResolve(nsIXPConnectWrappedNative *wrapper, (idobj = holder->GetJSObject())) { *objp = obj; *_retval = - JS_DefinePropertyById(cx, obj, id, - OBJECT_TO_JSVAL(idobj), - nullptr, nullptr, + JS_DefinePropertyById(cx, obj, id, idobj, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); @@ -821,9 +817,7 @@ nsXPCComponents_Classes::NewResolve(nsIXPConnectWrappedNative *wrapper, // Assign, not compare (idobj = holder->GetJSObject())) { *objp = obj; - *_retval = JS_DefinePropertyById(cx, obj, id, - OBJECT_TO_JSVAL(idobj), - nullptr, nullptr, + *_retval = JS_DefinePropertyById(cx, obj, id, idobj, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); @@ -1082,9 +1076,7 @@ nsXPCComponents_ClassesByID::NewResolve(nsIXPConnectWrappedNative *wrapper, // Assign, not compare (idobj = holder->GetJSObject())) { *objp = obj; - *_retval = JS_DefinePropertyById(cx, obj, id, - ObjectValue(*idobj), - nullptr, nullptr, + *_retval = JS_DefinePropertyById(cx, obj, id, idobj, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); @@ -1303,11 +1295,8 @@ nsXPCComponents_Results::NewResolve(nsIXPConnectWrappedNative *wrapper, nsresult rv; while (nsXPCException::IterateNSResults(&rv, &rv_name, nullptr, &iter)) { if (!strcmp(name.ptr(), rv_name)) { - jsval val = JS_NumberValue((double)rv); - *objp = obj; - if (!JS_DefinePropertyById(cx, obj, id, val, - nullptr, nullptr, + if (!JS_DefinePropertyById(cx, obj, id, (uint32_t)rv, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) { @@ -2962,9 +2951,8 @@ xpc::CreateObjectIn(JSContext *cx, HandleValue vobj, CreateObjectInOptions &opti return false; if (define) { - if (!JS_DefinePropertyById(cx, scope, options.defineAs, ObjectValue(*obj), - JS_PropertyStub, JS_StrictPropertyStub, - JSPROP_ENUMERATE)) + if (!JS_DefinePropertyById(cx, scope, options.defineAs, obj, JSPROP_ENUMERATE, + JS_PropertyStub, JS_StrictPropertyStub)) return false; } } diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp index 7bf14f8575c9..3741438e1a8f 100644 --- a/js/xpconnect/src/XPCJSID.cpp +++ b/js/xpconnect/src/XPCJSID.cpp @@ -407,7 +407,7 @@ nsJSIID::NewResolve(nsIXPConnectWrappedNative *wrapper, return NS_ERROR_OUT_OF_MEMORY; *objp = obj; - *_retval = JS_DefinePropertyById(cx, obj, id, val, nullptr, nullptr, + *_retval = JS_DefinePropertyById(cx, obj, id, val, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT); } diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index b3a66480a50f..86ab45909c21 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -829,7 +829,7 @@ static bool env_resolve(JSContext *cx, HandleObject obj, HandleId id, JS::MutableHandleObject objp) { - JSString *idstr, *valstr; + JSString *idstr; RootedValue idval(cx); if (!JS_IdToValue(cx, id, &idval)) @@ -843,11 +843,10 @@ env_resolve(JSContext *cx, HandleObject obj, HandleId id, return false; const char *value = getenv(name.ptr()); if (value) { - valstr = JS_NewStringCopyZ(cx, value); + RootedString valstr(cx, JS_NewStringCopyZ(cx, value)); if (!valstr) return false; - if (!JS_DefinePropertyById(cx, obj, id, STRING_TO_JSVAL(valstr), - nullptr, nullptr, JSPROP_ENUMERATE)) { + if (!JS_DefinePropertyById(cx, obj, id, valstr, JSPROP_ENUMERATE)) { return false; } objp.set(obj); @@ -1094,11 +1093,9 @@ ProcessArgs(JSContext *cx, JS::Handle obj, char **argv, int argc, XPC return 1; for (size_t j = 0, length = argc - i; j < length; j++) { - JSString *str = JS_NewStringCopyZ(cx, argv[i++]); - if (!str) - return 1; - if (!JS_DefineElement(cx, argsObj, j, STRING_TO_JSVAL(str), - nullptr, nullptr, JSPROP_ENUMERATE)) { + RootedString str(cx, JS_NewStringCopyZ(cx, argv[i++])); + if (!str || + !JS_DefineElement(cx, argsObj, j, str, JSPROP_ENUMERATE)) { return 1; } } @@ -1572,7 +1569,7 @@ XRE_XPCShellMain(int argc, char **argv, char **envp) } JS::Rooted envobj(cx); - envobj = JS_DefineObject(cx, glob, "environment", &env_class, nullptr, 0); + envobj = JS_DefineObject(cx, glob, "environment", &env_class); if (!envobj) { JS_EndRequest(cx); return 1; diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 1af44ef5edd3..f17ec51bf67c 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -248,9 +248,8 @@ DefinePropertyIfFound(XPCCallContext& ccx, AutoResolveName arn(ccx, id); if (resolved) *resolved = true; - return JS_DefinePropertyById(ccx, obj, id, - OBJECT_TO_JSVAL(JS_GetFunctionObject(fun)), - nullptr, nullptr, + RootedObject value(ccx, JS_GetFunctionObject(fun)); + return JS_DefinePropertyById(ccx, obj, id, value, propFlags & ~JSPROP_ENUMERATE); } } @@ -277,8 +276,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, AutoResolveName arn(ccx, id); if (resolved) *resolved = true; - return JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), - nullptr, nullptr, + return JS_DefinePropertyById(ccx, obj, id, jso, propFlags & ~JSPROP_ENUMERATE); } else if (NS_FAILED(rv) && rv != NS_ERROR_NO_INTERFACE) { return Throw(rv, ccx); @@ -313,10 +311,9 @@ DefinePropertyIfFound(XPCCallContext& ccx, AutoResolveName arn(ccx, id); if (resolved) *resolved = true; - return JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, - JS_DATA_TO_FUNC_PTR(JSPropertyOp, - funobj.get()), - nullptr, propFlags); + return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags, + JS_DATA_TO_FUNC_PTR(JSPropertyOp, funobj.get()), + nullptr); } if (resolved) @@ -338,8 +335,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, AutoResolveName arn(ccx, id); if (resolved) *resolved = true; - return JS_DefinePropertyById(ccx, obj, id, OBJECT_TO_JSVAL(jso), - nullptr, nullptr, + return JS_DefinePropertyById(ccx, obj, id, jso, propFlags & ~JSPROP_ENUMERATE); } if (resolved) @@ -353,8 +349,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, if (resolved) *resolved = true; return member->GetConstantValue(ccx, iface, val.address()) && - JS_DefinePropertyById(ccx, obj, id, val, nullptr, nullptr, - propFlags); + JS_DefinePropertyById(ccx, obj, id, val, propFlags); } if (id == rt->GetStringID(XPCJSRuntime::IDX_TO_STRING) || @@ -372,8 +367,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, AutoResolveName arn(ccx, id); if (resolved) *resolved = true; - return JS_DefinePropertyById(ccx, obj, id, funval, nullptr, nullptr, - propFlags); + return JS_DefinePropertyById(ccx, obj, id, funval, propFlags); } // else... @@ -396,8 +390,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, if (resolved) *resolved = true; - return JS_DefinePropertyById(ccx, obj, id, JSVAL_VOID, getter, setter, - propFlags); + return JS_DefinePropertyById(ccx, obj, id, UndefinedHandleValue, propFlags, getter, setter); } /***************************************************************************/ diff --git a/js/xpconnect/src/XPCWrappedNativeScope.cpp b/js/xpconnect/src/XPCWrappedNativeScope.cpp index b4704e097955..3f15f30556f7 100644 --- a/js/xpconnect/src/XPCWrappedNativeScope.cpp +++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp @@ -183,8 +183,8 @@ XPCWrappedNativeScope::AttachComponentsObject(JSContext* aCx) MOZ_ASSERT(js::IsObjectInContextCompartment(global, aCx)); RootedId id(aCx, XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS)); - return JS_DefinePropertyById(aCx, global, id, ObjectValue(*components), - nullptr, nullptr, JSPROP_PERMANENT | JSPROP_READONLY); + return JS_DefinePropertyById(aCx, global, id, components, + JSPROP_PERMANENT | JSPROP_READONLY); } JSObject* diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index b3485a45845c..c2594d951803 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -475,9 +475,8 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, // This is broken, and will be fixed at some point, but for now we need to // cache the value explicitly. See the corresponding call to // JS_GetPropertyById at the top of this function. - return JS_DefinePropertyById(cx, holder, id, - ObjectValue(*JS_GetFunctionObject(fun)), - nullptr, nullptr, 0) && + RootedValue value(cx, ObjectValue(*JS_GetFunctionObject(fun))); + return JS_DefinePropertyById(cx, holder, id, value, 0) && JS_GetPropertyDescriptorById(cx, holder, id, desc); } @@ -1102,8 +1101,8 @@ XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext *cx, HandleObject wr desc.setSetterObject(&fval.toObject()); // Define the property. - return JS_DefinePropertyById(cx, holder, id, desc.value(), - desc.getter(), desc.setter(), desc.attributes()); + return JS_DefinePropertyById(cx, holder, id, desc.value(), desc.attributes(), + desc.getter(), desc.setter()); } static bool @@ -1174,9 +1173,9 @@ XrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, { if (!JS_AlreadyHasOwnPropertyById(cx, holder, id, &found)) return false; - if (!found && !JS_DefinePropertyById(cx, holder, id, UndefinedValue(), - wrappedJSObject_getter, nullptr, - JSPROP_ENUMERATE | JSPROP_SHARED)) { + if (!found && !JS_DefinePropertyById(cx, holder, id, UndefinedHandleValue, + JSPROP_ENUMERATE | JSPROP_SHARED, + wrappedJSObject_getter)) { return false; } if (!JS_GetPropertyDescriptorById(cx, holder, id, desc)) @@ -1284,7 +1283,7 @@ XPCWrappedNativeXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, Handle existingDesc, bool *defined) { *defined = false; - JSObject *holder = singleton.ensureHolder(cx, wrapper); + RootedObject holder(cx, singleton.ensureHolder(cx, wrapper)); if (isResolving(cx, holder, id)) { if (!desc.hasAttributes(JSPROP_GETTER | JSPROP_SETTER)) { if (!desc.getter()) @@ -1294,8 +1293,8 @@ XPCWrappedNativeXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, } *defined = true; - return JS_DefinePropertyById(cx, holder, id, desc.value(), desc.getter(), desc.setter(), - desc.attributes()); + return JS_DefinePropertyById(cx, holder, id, desc.value(), desc.attributes(), + desc.getter(), desc.setter()); } // Check for an indexed property on a Window. If that's happening, do @@ -1888,8 +1887,8 @@ XrayWrapper::getPropertyDescriptor(JSContext *cx, HandleObject wra if (!desc.object()) return true; - if (!JS_DefinePropertyById(cx, holder, id, desc.value(), desc.getter(), - desc.setter(), desc.attributes()) || + if (!JS_DefinePropertyById(cx, holder, id, desc.value(), desc.attributes(), + desc.getter(), desc.setter()) || !JS_GetPropertyDescriptorById(cx, holder, id, desc)) { return false; @@ -2021,8 +2020,8 @@ XrayWrapper::defineProperty(JSContext *cx, HandleObject wrapper, return false; return JS_DefinePropertyById(cx, expandoObject, id, wrappedDesc.value(), - wrappedDesc.getter(), wrappedDesc.setter(), - wrappedDesc.get().attrs); + wrappedDesc.get().attrs, + wrappedDesc.getter(), wrappedDesc.setter()); } template diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index dee051ce0fd8..e52a715374fd 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -2677,6 +2677,21 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram nsRect dirtyRect = visibleRegion.GetBounds(); builder.EnterPresShell(aFrame, dirtyRect); { + // If a scrollable container layer is created in nsDisplayList::PaintForFrame, + // it will be the scroll parent for display items that are built in the + // BuildDisplayListForStackingContext call below. We need to set the scroll + // parent on the display list builder while we build those items, so that they + // can pick up their scroll parent's id. + ViewID id = FrameMetrics::NULL_SCROLL_ID; + if (ignoreViewportScrolling && presContext->IsRootContentDocument()) { + if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) { + if (nsIContent* content = rootScrollFrame->GetContent()) { + id = nsLayoutUtils::FindOrCreateIDFor(content); + } + } + } + nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id); + PROFILER_LABEL("nsLayoutUtils","PaintFrame::BuildDisplayList"); aFrame->BuildDisplayListForStackingContext(&builder, dirtyRect, &list); } diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index bf9ac8db53ef..2e7624ccb2d4 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -239,7 +239,7 @@ nsSubDocumentFrame::PassPointerEventsToChildren() } nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (permMgr) { uint32_t permission = nsIPermissionManager::DENY_ACTION; permMgr->TestPermissionFromPrincipal(GetContent()->NodePrincipal(), diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 1f6993492fcd..8b9afcefb36b 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -289,7 +289,7 @@ nsComputedDOMStyle::Shutdown() } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsComputedDOMStyle, mContent) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsComputedDOMStyle, mContent) NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsComputedDOMStyle) return tmp->IsBlack(); diff --git a/layout/style/nsDOMCSSAttrDeclaration.cpp b/layout/style/nsDOMCSSAttrDeclaration.cpp index 400aea10a4ee..f193087a2a05 100644 --- a/layout/style/nsDOMCSSAttrDeclaration.cpp +++ b/layout/style/nsDOMCSSAttrDeclaration.cpp @@ -35,7 +35,7 @@ nsDOMCSSAttributeDeclaration::~nsDOMCSSAttributeDeclaration() MOZ_COUNT_DTOR(nsDOMCSSAttributeDeclaration); } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCSSAttributeDeclaration, mElement) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSAttributeDeclaration, mElement) // mElement holds a strong ref to us, so if it's going to be // skipped, the attribute declaration can't be part of a garbage diff --git a/layout/style/nsDOMCSSRGBColor.cpp b/layout/style/nsDOMCSSRGBColor.cpp index 5b4c3efde1e7..d683acb1f990 100644 --- a/layout/style/nsDOMCSSRGBColor.cpp +++ b/layout/style/nsDOMCSSRGBColor.cpp @@ -26,7 +26,7 @@ nsDOMCSSRGBColor::~nsDOMCSSRGBColor(void) { } -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(nsDOMCSSRGBColor, mAlpha, mBlue, mGreen, mRed) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSRGBColor, mAlpha, mBlue, mGreen, mRed) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsDOMCSSRGBColor, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsDOMCSSRGBColor, Release) diff --git a/layout/style/nsDOMCSSRect.cpp b/layout/style/nsDOMCSSRect.cpp index dfc73eda81f1..f80274249ea8 100644 --- a/layout/style/nsDOMCSSRect.cpp +++ b/layout/style/nsDOMCSSRect.cpp @@ -33,7 +33,7 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCSSRect) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCSSRect) -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(nsDOMCSSRect, mTop, mBottom, mLeft, mRight) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSRect, mTop, mBottom, mLeft, mRight) JSObject* nsDOMCSSRect::WrapObject(JSContext* cx) diff --git a/layout/style/nsDOMCSSValueList.cpp b/layout/style/nsDOMCSSValueList.cpp index abb8db6f88f0..cd8f3ed9910e 100644 --- a/layout/style/nsDOMCSSValueList.cpp +++ b/layout/style/nsDOMCSSValueList.cpp @@ -31,7 +31,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCSSValueList) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, CSSValue) NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCSSValueList, mCSSValues) +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsDOMCSSValueList, mCSSValues) JSObject* nsDOMCSSValueList::WrapObject(JSContext *cx) diff --git a/layout/style/nsFontFaceLoader.cpp b/layout/style/nsFontFaceLoader.cpp index 5db16bd38ed5..4fdd56762b05 100644 --- a/layout/style/nsFontFaceLoader.cpp +++ b/layout/style/nsFontFaceLoader.cpp @@ -1014,5 +1014,12 @@ nsUserFontSet::GetPrivateBrowsing() void nsUserFontSet::DoRebuildUserFontSet() { + if (!mPresContext) { + // AFAICS, this can only happen if someone has already called Destroy() on + // this font-set, which means it is in the process of being torn down -- + // so there's no point trying to update its rules. + return; + } + mPresContext->RebuildUserFontSet(); } diff --git a/media/mtransport/runnable_utils.h b/media/mtransport/runnable_utils.h index 5da3ff8aa52f..5eb41d9451b5 100644 --- a/media/mtransport/runnable_utils.h +++ b/media/mtransport/runnable_utils.h @@ -15,12 +15,43 @@ // Abstract base class for all of our templates namespace mozilla { +namespace detail { + +enum RunnableResult { + NoResult, + ReturnsResult +}; + +static inline nsresult +RunOnThreadInternal(nsIEventTarget *thread, nsIRunnable *runnable, uint32_t flags) +{ + nsCOMPtr runnable_ref(runnable); + if (thread) { + bool on; + nsresult rv; + rv = thread->IsOnCurrentThread(&on); + + // If the target thread has already shut down, we don't want to assert. + if (rv != NS_ERROR_NOT_INITIALIZED) { + MOZ_ASSERT(NS_SUCCEEDED(rv)); + } + + NS_ENSURE_SUCCESS(rv, rv); + if (!on) { + return thread->Dispatch(runnable_ref, flags); + } + } + return runnable_ref->Run(); +} + +template class runnable_args_base : public nsRunnable { public: NS_IMETHOD Run() = 0; - virtual bool returns_value() const { return false; } }; +} + // The generated file contains four major function templates // (in variants for arbitrary numbers of arguments up to 10, // which is why it is machine generated). The four templates @@ -38,34 +69,14 @@ class runnable_args_base : public nsRunnable { // to Dispatch(). #include "runnable_utils_generated.h" -// Temporary hack. Really we want to have a template which will do this -static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, nsIRunnable *runnable, uint32_t flags) { - RefPtr runnable_ref(runnable); - if (thread) { - bool on; - nsresult rv; - rv = thread->IsOnCurrentThread(&on); - - // If the target thread has already shut down, we don't want to assert. - if (rv != NS_ERROR_NOT_INITIALIZED) { - MOZ_ASSERT(NS_SUCCEEDED(rv)); - } - - NS_ENSURE_SUCCESS(rv, rv); - if(!on) { - return thread->Dispatch(runnable_ref, flags); - } - } - return runnable_ref->Run(); +static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, detail::runnable_args_base *runnable, uint32_t flags) { + return detail::RunOnThreadInternal(thread, static_cast(runnable), flags); } -static inline nsresult RUN_ON_THREAD(nsIEventTarget *thread, runnable_args_base *runnable, uint32_t flags) { - // Detect attempts to return a value when in async mode, since this - // most likely means someone is trying to assign to a heap variable - // which is now out of scope. - MOZ_ASSERT((!(runnable->returns_value()) || (flags != NS_DISPATCH_NORMAL))); - - return RUN_ON_THREAD(thread, static_cast(runnable), flags); +static inline nsresult +RUN_ON_THREAD(nsIEventTarget *thread, detail::runnable_args_base *runnable) +{ + return detail::RunOnThreadInternal(thread, static_cast(runnable), NS_DISPATCH_SYNC); } #ifdef DEBUG diff --git a/media/mtransport/runnable_utils.py b/media/mtransport/runnable_utils.py index 5680be453921..9ef23f11764d 100644 --- a/media/mtransport/runnable_utils.py +++ b/media/mtransport/runnable_utils.py @@ -69,27 +69,40 @@ def gen_types(args, member): return ", ".join(ret) -def generate_class_template(args, ret = False, member = True): - print "// %d arguments --"%args +def runnable_class_name(args, ret=False, member=True): if member: nm = "m" else: nm = "nm" - if not ret: - print "template<"+ gen_typenames(args, member) + "> class runnable_args_%s_%d : public runnable_args_base {"%(nm, args) + if ret: + class_suffix = "_ret" + enum_specializer = "detail::ReturnsResult" else: - print "template<"+ gen_typenames(args, member) + ", typename R> class runnable_args_%s_%d_ret : public runnable_args_base {"%(nm, args) + class_suffix = "" + enum_specializer = "detail::NoResult" + + return "runnable_args_%s_%d%s" % (nm, args, class_suffix), enum_specializer + +def generate_class_template(args, ret = False, member = True): + print "// %d arguments --"%args + + class_name, specializer = runnable_class_name(args, ret, member) + base_class = "detail::runnable_args_base<%s>" % specializer + + if not ret: + print "template<"+ gen_typenames(args, member) + "> class %s : public %s {" % (class_name, base_class) + else: + print "template<"+ gen_typenames(args, member) + ", typename R> class %s : public %s {" % (class_name, base_class) print " public:" if not ret: - print " runnable_args_%s_%d("%(nm, args) + gen_args_type(args, member) + ") :" + print " %s(" % class_name + gen_args_type(args, member) + ") :" print " " + gen_init(args, False, member) + " {}" else: - print " runnable_args_%s_%d_ret("%(nm, args) + gen_args_type(args, member) + ", R *r) :" + print " %s(" % class_name + gen_args_type(args, member) + ", R *r) :" print " " + gen_init(args, True, member) + " {}" - print " virtual bool returns_value() const { return true; }" print print " NS_IMETHOD Run() {" if ret: @@ -119,31 +132,32 @@ def generate_class_template(args, ret = False, member = True): def generate_function_template(args, member): if member: - nm = "m" NM = ""; else: - nm = "nm" NM = "NM"; - + + class_name, _ = runnable_class_name(args, False, member) + print "// %d arguments --"%args print "template<" + gen_typenames(args, member) + ">" - print "runnable_args_%s_%d<"%(nm, args) + gen_types(args, member) + ">* WrapRunnable%s("%NM + gen_args_type(args, member) + ") {" - print " return new runnable_args_%s_%d<"%(nm, args) + gen_types(args, member) + ">" + print "%s<" % class_name + gen_types(args, member) + ">* WrapRunnable%s("%NM + gen_args_type(args, member) + ") {" + print " return new %s<" % class_name + gen_types(args, member) + ">" print " (" + gen_args(args, member) + ");" print "}" print def generate_function_template_ret(args, member): if member: - nm = "m" NM = ""; else: - nm = "nm" NM = "NM"; + + class_name, _ = runnable_class_name(args, True, member) + print "// %d arguments --"%args print "template<" + gen_typenames(args, member) + ", typename R>" - print "runnable_args_%s_%d_ret<"%(nm, args) + gen_types(args, member) + ", R>* WrapRunnable%sRet("%NM + gen_args_type(args, member) + ", R* r) {" - print " return new runnable_args_%s_%d_ret<"%(nm, args) + gen_types(args, member) + ", R>" + print "%s<" % class_name + gen_types(args, member) + ", R>* WrapRunnable%sRet("%NM + gen_args_type(args, member) + ", R* r) {" + print " return new %s<" % class_name + gen_types(args, member) + ", R>" print " (" + gen_args(args, member) + ", r);" print "}" print diff --git a/media/mtransport/runnable_utils_generated.h b/media/mtransport/runnable_utils_generated.h index 544ba4b03847..5a45d82f4e35 100644 --- a/media/mtransport/runnable_utils_generated.h +++ b/media/mtransport/runnable_utils_generated.h @@ -4,7 +4,7 @@ // 0 arguments -- -template class runnable_args_nm_0 : public runnable_args_base { +template class runnable_args_nm_0 : public detail::runnable_args_base { public: runnable_args_nm_0(M m) : m_(m) {} @@ -21,11 +21,10 @@ template class runnable_args_nm_0 : public runnable_args_base { // 0 arguments -- -template class runnable_args_nm_0_ret : public runnable_args_base { +template class runnable_args_nm_0_ret : public detail::runnable_args_base { public: runnable_args_nm_0_ret(M m, R *r) : m_(m), r_(r) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(); @@ -40,7 +39,7 @@ template class runnable_args_nm_0_ret : public runnable_ // 0 arguments -- -template class runnable_args_m_0 : public runnable_args_base { +template class runnable_args_m_0 : public detail::runnable_args_base { public: runnable_args_m_0(C o, M m) : o_(o), m_(m) {} @@ -58,11 +57,10 @@ template class runnable_args_m_0 : public runnable_args_ // 0 arguments -- -template class runnable_args_m_0_ret : public runnable_args_base { +template class runnable_args_m_0_ret : public detail::runnable_args_base { public: runnable_args_m_0_ret(C o, M m, R *r) : o_(o), m_(m), r_(r) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(); @@ -78,7 +76,7 @@ template class runnable_args_m_0_ret : publi // 1 arguments -- -template class runnable_args_nm_1 : public runnable_args_base { +template class runnable_args_nm_1 : public detail::runnable_args_base { public: runnable_args_nm_1(M m, A0 a0) : m_(m), a0_(a0) {} @@ -96,11 +94,10 @@ template class runnable_args_nm_1 : public runnable_arg // 1 arguments -- -template class runnable_args_nm_1_ret : public runnable_args_base { +template class runnable_args_nm_1_ret : public detail::runnable_args_base { public: runnable_args_nm_1_ret(M m, A0 a0, R *r) : m_(m), r_(r), a0_(a0) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_); @@ -116,7 +113,7 @@ template class runnable_args_nm_1_ret : pub // 1 arguments -- -template class runnable_args_m_1 : public runnable_args_base { +template class runnable_args_m_1 : public detail::runnable_args_base { public: runnable_args_m_1(C o, M m, A0 a0) : o_(o), m_(m), a0_(a0) {} @@ -135,11 +132,10 @@ template class runnable_args_m_1 : public r // 1 arguments -- -template class runnable_args_m_1_ret : public runnable_args_base { +template class runnable_args_m_1_ret : public detail::runnable_args_base { public: runnable_args_m_1_ret(C o, M m, A0 a0, R *r) : o_(o), m_(m), r_(r), a0_(a0) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_); @@ -156,7 +152,7 @@ template class runnable_args_m_ // 2 arguments -- -template class runnable_args_nm_2 : public runnable_args_base { +template class runnable_args_nm_2 : public detail::runnable_args_base { public: runnable_args_nm_2(M m, A0 a0, A1 a1) : m_(m), a0_(a0), a1_(a1) {} @@ -175,11 +171,10 @@ template class runnable_args_nm_2 : public // 2 arguments -- -template class runnable_args_nm_2_ret : public runnable_args_base { +template class runnable_args_nm_2_ret : public detail::runnable_args_base { public: runnable_args_nm_2_ret(M m, A0 a0, A1 a1, R *r) : m_(m), r_(r), a0_(a0), a1_(a1) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_); @@ -196,7 +191,7 @@ template class runnable_args_n // 2 arguments -- -template class runnable_args_m_2 : public runnable_args_base { +template class runnable_args_m_2 : public detail::runnable_args_base { public: runnable_args_m_2(C o, M m, A0 a0, A1 a1) : o_(o), m_(m), a0_(a0), a1_(a1) {} @@ -216,11 +211,10 @@ template class runnable_args_m // 2 arguments -- -template class runnable_args_m_2_ret : public runnable_args_base { +template class runnable_args_m_2_ret : public detail::runnable_args_base { public: runnable_args_m_2_ret(C o, M m, A0 a0, A1 a1, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_); @@ -238,7 +232,7 @@ template class run // 3 arguments -- -template class runnable_args_nm_3 : public runnable_args_base { +template class runnable_args_nm_3 : public detail::runnable_args_base { public: runnable_args_nm_3(M m, A0 a0, A1 a1, A2 a2) : m_(m), a0_(a0), a1_(a1), a2_(a2) {} @@ -258,11 +252,10 @@ template class runnable_args_ // 3 arguments -- -template class runnable_args_nm_3_ret : public runnable_args_base { +template class runnable_args_nm_3_ret : public detail::runnable_args_base { public: runnable_args_nm_3_ret(M m, A0 a0, A1 a1, A2 a2, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_); @@ -280,7 +273,7 @@ template class ru // 3 arguments -- -template class runnable_args_m_3 : public runnable_args_base { +template class runnable_args_m_3 : public detail::runnable_args_base { public: runnable_args_m_3(C o, M m, A0 a0, A1 a1, A2 a2) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2) {} @@ -301,11 +294,10 @@ template class ru // 3 arguments -- -template class runnable_args_m_3_ret : public runnable_args_base { +template class runnable_args_m_3_ret : public detail::runnable_args_base { public: runnable_args_m_3_ret(C o, M m, A0 a0, A1 a1, A2 a2, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_); @@ -324,7 +316,7 @@ template class runnable_args_nm_4 : public runnable_args_base { +template class runnable_args_nm_4 : public detail::runnable_args_base { public: runnable_args_nm_4(M m, A0 a0, A1 a1, A2 a2, A3 a3) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} @@ -345,11 +337,10 @@ template class r // 4 arguments -- -template class runnable_args_nm_4_ret : public runnable_args_base { +template class runnable_args_nm_4_ret : public detail::runnable_args_base { public: runnable_args_nm_4_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_); @@ -368,7 +359,7 @@ template class runnable_args_m_4 : public runnable_args_base { +template class runnable_args_m_4 : public detail::runnable_args_base { public: runnable_args_m_4(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} @@ -390,11 +381,10 @@ template class runnable_args_m_4_ret : public runnable_args_base { +template class runnable_args_m_4_ret : public detail::runnable_args_base { public: runnable_args_m_4_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_); @@ -414,7 +404,7 @@ template class runnable_args_nm_5 : public runnable_args_base { +template class runnable_args_nm_5 : public detail::runnable_args_base { public: runnable_args_nm_5(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} @@ -436,11 +426,10 @@ template class runnable_args_nm_5_ret : public runnable_args_base { +template class runnable_args_nm_5_ret : public detail::runnable_args_base { public: runnable_args_nm_5_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_); @@ -460,7 +449,7 @@ template class runnable_args_m_5 : public runnable_args_base { +template class runnable_args_m_5 : public detail::runnable_args_base { public: runnable_args_m_5(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} @@ -483,11 +472,10 @@ template class runnable_args_m_5_ret : public runnable_args_base { +template class runnable_args_m_5_ret : public detail::runnable_args_base { public: runnable_args_m_5_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_); @@ -508,7 +496,7 @@ template class runnable_args_nm_6 : public runnable_args_base { +template class runnable_args_nm_6 : public detail::runnable_args_base { public: runnable_args_nm_6(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} @@ -531,11 +519,10 @@ template class runnable_args_nm_6_ret : public runnable_args_base { +template class runnable_args_nm_6_ret : public detail::runnable_args_base { public: runnable_args_nm_6_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_); @@ -556,7 +543,7 @@ template class runnable_args_m_6 : public runnable_args_base { +template class runnable_args_m_6 : public detail::runnable_args_base { public: runnable_args_m_6(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} @@ -580,11 +567,10 @@ template class runnable_args_m_6_ret : public runnable_args_base { +template class runnable_args_m_6_ret : public detail::runnable_args_base { public: runnable_args_m_6_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_); @@ -606,7 +592,7 @@ template class runnable_args_nm_7 : public runnable_args_base { +template class runnable_args_nm_7 : public detail::runnable_args_base { public: runnable_args_nm_7(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} @@ -630,11 +616,10 @@ template class runnable_args_nm_7_ret : public runnable_args_base { +template class runnable_args_nm_7_ret : public detail::runnable_args_base { public: runnable_args_nm_7_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_); @@ -656,7 +641,7 @@ template class runnable_args_m_7 : public runnable_args_base { +template class runnable_args_m_7 : public detail::runnable_args_base { public: runnable_args_m_7(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} @@ -681,11 +666,10 @@ template class runnable_args_m_7_ret : public runnable_args_base { +template class runnable_args_m_7_ret : public detail::runnable_args_base { public: runnable_args_m_7_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_); @@ -708,7 +692,7 @@ template class runnable_args_nm_8 : public runnable_args_base { +template class runnable_args_nm_8 : public detail::runnable_args_base { public: runnable_args_nm_8(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} @@ -733,11 +717,10 @@ template class runnable_args_nm_8_ret : public runnable_args_base { +template class runnable_args_nm_8_ret : public detail::runnable_args_base { public: runnable_args_nm_8_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); @@ -760,7 +743,7 @@ template class runnable_args_m_8 : public runnable_args_base { +template class runnable_args_m_8 : public detail::runnable_args_base { public: runnable_args_m_8(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} @@ -786,11 +769,10 @@ template class runnable_args_m_8_ret : public runnable_args_base { +template class runnable_args_m_8_ret : public detail::runnable_args_base { public: runnable_args_m_8_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_); @@ -814,7 +796,7 @@ template class runnable_args_nm_9 : public runnable_args_base { +template class runnable_args_nm_9 : public detail::runnable_args_base { public: runnable_args_nm_9(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} @@ -840,11 +822,10 @@ template class runnable_args_nm_9_ret : public runnable_args_base { +template class runnable_args_nm_9_ret : public detail::runnable_args_base { public: runnable_args_nm_9_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); @@ -868,7 +849,7 @@ template class runnable_args_m_9 : public runnable_args_base { +template class runnable_args_m_9 : public detail::runnable_args_base { public: runnable_args_m_9(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} @@ -895,11 +876,10 @@ template class runnable_args_m_9_ret : public runnable_args_base { +template class runnable_args_m_9_ret : public detail::runnable_args_base { public: runnable_args_m_9_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_); @@ -924,7 +904,7 @@ template class runnable_args_nm_10 : public runnable_args_base { +template class runnable_args_nm_10 : public detail::runnable_args_base { public: runnable_args_nm_10(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} @@ -951,11 +931,10 @@ template class runnable_args_nm_10_ret : public runnable_args_base { +template class runnable_args_nm_10_ret : public detail::runnable_args_base { public: runnable_args_nm_10_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); @@ -980,7 +959,7 @@ template class runnable_args_m_10 : public runnable_args_base { +template class runnable_args_m_10 : public detail::runnable_args_base { public: runnable_args_m_10(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} @@ -1008,11 +987,10 @@ template class runnable_args_m_10_ret : public runnable_args_base { +template class runnable_args_m_10_ret : public detail::runnable_args_base { public: runnable_args_m_10_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_); @@ -1038,7 +1016,7 @@ template class runnable_args_nm_11 : public runnable_args_base { +template class runnable_args_nm_11 : public detail::runnable_args_base { public: runnable_args_nm_11(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} @@ -1066,11 +1044,10 @@ template class runnable_args_nm_11_ret : public runnable_args_base { +template class runnable_args_nm_11_ret : public detail::runnable_args_base { public: runnable_args_nm_11_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); @@ -1096,7 +1073,7 @@ template class runnable_args_m_11 : public runnable_args_base { +template class runnable_args_m_11 : public detail::runnable_args_base { public: runnable_args_m_11(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} @@ -1125,11 +1102,10 @@ template class runnable_args_m_11_ret : public runnable_args_base { +template class runnable_args_m_11_ret : public detail::runnable_args_base { public: runnable_args_m_11_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_); @@ -1156,7 +1132,7 @@ template class runnable_args_nm_12 : public runnable_args_base { +template class runnable_args_nm_12 : public detail::runnable_args_base { public: runnable_args_nm_12(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} @@ -1185,11 +1161,10 @@ template class runnable_args_nm_12_ret : public runnable_args_base { +template class runnable_args_nm_12_ret : public detail::runnable_args_base { public: runnable_args_nm_12_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); @@ -1216,7 +1191,7 @@ template class runnable_args_m_12 : public runnable_args_base { +template class runnable_args_m_12 : public detail::runnable_args_base { public: runnable_args_m_12(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} @@ -1246,11 +1221,10 @@ template class runnable_args_m_12_ret : public runnable_args_base { +template class runnable_args_m_12_ret : public detail::runnable_args_base { public: runnable_args_m_12_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_); @@ -1278,7 +1252,7 @@ template class runnable_args_nm_13 : public runnable_args_base { +template class runnable_args_nm_13 : public detail::runnable_args_base { public: runnable_args_nm_13(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} @@ -1308,11 +1282,10 @@ template class runnable_args_nm_13_ret : public runnable_args_base { +template class runnable_args_nm_13_ret : public detail::runnable_args_base { public: runnable_args_nm_13_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); @@ -1340,7 +1313,7 @@ template class runnable_args_m_13 : public runnable_args_base { +template class runnable_args_m_13 : public detail::runnable_args_base { public: runnable_args_m_13(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} @@ -1371,11 +1344,10 @@ template class runnable_args_m_13_ret : public runnable_args_base { +template class runnable_args_m_13_ret : public detail::runnable_args_base { public: runnable_args_m_13_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_); @@ -1404,7 +1376,7 @@ template class runnable_args_nm_14 : public runnable_args_base { +template class runnable_args_nm_14 : public detail::runnable_args_base { public: runnable_args_nm_14(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) : m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} @@ -1435,11 +1407,10 @@ template class runnable_args_nm_14_ret : public runnable_args_base { +template class runnable_args_nm_14_ret : public detail::runnable_args_base { public: runnable_args_nm_14_ret(M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) : m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = m_(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); @@ -1468,7 +1439,7 @@ template class runnable_args_m_14 : public runnable_args_base { +template class runnable_args_m_14 : public detail::runnable_args_base { public: runnable_args_m_14(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13) : o_(o), m_(m), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} @@ -1500,11 +1471,10 @@ template class runnable_args_m_14_ret : public runnable_args_base { +template class runnable_args_m_14_ret : public detail::runnable_args_base { public: runnable_args_m_14_ret(C o, M m, A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 a12, A13 a13, R *r) : o_(o), m_(m), r_(r), a0_(a0), a1_(a1), a2_(a2), a3_(a3), a4_(a4), a5_(a5), a6_(a6), a7_(a7), a8_(a8), a9_(a9), a10_(a10), a11_(a11), a12_(a12), a13_(a13) {} - virtual bool returns_value() const { return true; } NS_IMETHOD Run() { *r_ = ((*o_).*m_)(a0_, a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_, a10_, a11_, a12_, a13_); diff --git a/media/mtransport/test/ice_unittest.cpp b/media/mtransport/test/ice_unittest.cpp index 90b051d32567..8ff366c168b1 100644 --- a/media/mtransport/test/ice_unittest.cpp +++ b/media/mtransport/test/ice_unittest.cpp @@ -248,8 +248,7 @@ class IceTestPeer : public sigslot::has_slots<> { RUN_ON_THREAD( test_utils->sts_target(), - WrapRunnableRet(this, &IceTestPeer::GetCandidates_s, stream, &v), - NS_DISPATCH_SYNC); + WrapRunnableRet(this, &IceTestPeer::GetCandidates_s, stream, &v)); return v; } diff --git a/media/mtransport/test/transport_unittests.cpp b/media/mtransport/test/transport_unittests.cpp index 4a026bbea8e0..33fcbe9fad04 100644 --- a/media/mtransport/test/transport_unittests.cpp +++ b/media/mtransport/test/transport_unittests.cpp @@ -366,8 +366,7 @@ class TransportTestPeer : public sigslot::has_slots<> { TransportLayer::State tstate; RUN_ON_THREAD(test_utils->sts_target(), - WrapRunnableRet(flow_, &TransportFlow::state, &tstate), - NS_DISPATCH_SYNC); + WrapRunnableRet(flow_, &TransportFlow::state, &tstate)); return tstate; } diff --git a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c index 23852fa8d909..ef4d07681b7b 100644 --- a/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c +++ b/media/webrtc/signaling/src/sipcc/core/gsm/gsm_sdp.c @@ -4545,7 +4545,7 @@ gsmsdp_add_rtcp_fb (int level, sdp_t *sdp_p, for (pt_index = 1; pt_index <= num_pts; pt_index++) { pt_codec = sdp_get_media_payload_type (sdp_p, level, pt_index, &indicator); - if ((pt_codec & 0xFF) == codec) { + if (codec == RTP_NONE || (pt_codec & 0xFF) == codec) { int pt = GET_DYN_PAYLOAD_TYPE_VALUE(pt_codec); /* Add requested a=rtcp-fb:nack attributes */ @@ -4665,7 +4665,11 @@ gsmsdp_negotiate_rtcp_fb (cc_sdp_t *cc_sdp_p, * Mask out the types that we do not support */ switch (codec) { + /* Really should be all video codecs... */ case RTP_VP8: + case RTP_H263: + case RTP_H264_P0: + case RTP_H264_P1: case RTP_I420: fb_types &= sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_BASIC) | @@ -4674,6 +4678,7 @@ gsmsdp_negotiate_rtcp_fb (cc_sdp_t *cc_sdp_p, break; default: fb_types = 0; + break; } /* @@ -5688,7 +5693,7 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb_p, const cc_media_cap_t *media_cap, } /* - * Setup the local soruce address. + * Setup the local source address. */ if (addr_type == CPR_IP_ADDR_IPV6) { gsmsdp_get_local_source_v6_address(media); @@ -5719,7 +5724,7 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb_p, const cc_media_cap_t *media_cap, /* Add supported rtcp-fb types */ if (media_cap->type == SDP_MEDIA_VIDEO) { - gsmsdp_add_rtcp_fb (level, dcb_p->sdp->src_sdp, RTP_VP8, + gsmsdp_add_rtcp_fb (level, dcb_p->sdp->src_sdp, RTP_NONE, /* RTP_NONE == all */ sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_BASIC) | sdp_rtcp_fb_nack_to_bitmap(SDP_RTCP_FB_NACK_PLI) | sdp_rtcp_fb_ccm_to_bitmap(SDP_RTCP_FB_CCM_FIR)); diff --git a/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h b/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h index 4327ab60652b..a2e48c7f85d9 100644 --- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h +++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp.h @@ -539,6 +539,7 @@ typedef enum sdp_srtp_crypto_suite_t_ { #define SDP_DEFAULT_PACKETIZATION_MODE_VALUE 0 /* max packetization mode for H.264 */ #define SDP_MAX_PACKETIZATION_MODE_VALUE 2 /* max packetization mode for H.264 */ +#define SDP_INVALID_PACKETIZATION_MODE_VALUE 255 #define SDP_MAX_LEVEL_ASYMMETRY_ALLOWED_VALUE 1 /* max level asymmetry allowed value for H.264 */ #define SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE 1 /* default level asymmetry allowed value for H.264 */ diff --git a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c index fa5ca2eab442..dd99ff529f3a 100644 --- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c +++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr.c @@ -492,7 +492,7 @@ sdp_result_e sdp_parse_attr_fmtp (sdp_t *sdp_p, sdp_attr_t *attr_p, * default value will be assumed for remote sdp. If remote sdp does specify * any value for these parameters, then default value will be overridden. */ - fmtp_p->packetization_mode = 0; + fmtp_p->packetization_mode = SDP_DEFAULT_PACKETIZATION_MODE_VALUE; fmtp_p->level_asymmetry_allowed = SDP_DEFAULT_LEVEL_ASYMMETRY_ALLOWED_VALUE; /* BEGIN - a typical macro fn to replace '/' with ';' from fmtp line*/ diff --git a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr_access.c b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr_access.c index f816920a2a70..c09a4eb2eea4 100644 --- a/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr_access.c +++ b/media/webrtc/signaling/src/sipcc/core/sdp/sdp_attr_access.c @@ -228,7 +228,7 @@ sdp_result_e sdp_add_new_attr (void *sdp_ptr, u16 level, u8 cap_num, fmtp_p = &(new_attr_p->attr.fmtp); fmtp_p->fmtp_format = SDP_FMTP_UNKNOWN_TYPE; // set to invalid value - fmtp_p->packetization_mode = 0xff; + fmtp_p->packetization_mode = SDP_INVALID_PACKETIZATION_MODE_VALUE; fmtp_p->level_asymmetry_allowed = SDP_INVALID_LEVEL_ASYMMETRY_ALLOWED_VALUE; fmtp_p->annexb_required = FALSE; fmtp_p->annexa_required = FALSE; @@ -7972,7 +7972,12 @@ sdp_result_e sdp_attr_get_fmtp_pack_mode (void *sdp_ptr, u16 level, sdp_p->conf_p->num_invalid_param++; return (SDP_INVALID_PARAMETER); } else { - *val = attr_p->attr.fmtp.packetization_mode; + if (SDP_INVALID_PACKETIZATION_MODE_VALUE == attr_p->attr.fmtp.packetization_mode) { + /* packetization mode unspecified (optional) */ + *val = SDP_DEFAULT_PACKETIZATION_MODE_VALUE; + } else { + *val = attr_p->attr.fmtp.packetization_mode; + } return (SDP_SUCCESS); } } diff --git a/mfbt/Assertions.h b/mfbt/Assertions.h index 7f9ccff2ccd7..ad5e55e2121e 100644 --- a/mfbt/Assertions.h +++ b/mfbt/Assertions.h @@ -280,9 +280,67 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {} * MOZ_RELEASE_ASSERT, which applies to non-debug builds as well. */ +/* + * Implement MOZ_VALIDATE_ASSERT_CONDITION_TYPE, which is used to guard against + * accidentally passing something unintended in lieu of an assertion condition. + */ + +#ifdef __cplusplus +# if defined(__clang__) +# define MOZ_SUPPORT_ASSERT_CONDITION_TYPE_VALIDATION +# elif defined(__GNUC__) +// B2G GCC 4.4 has insufficient decltype support. +# if MOZ_GCC_VERSION_AT_LEAST(4, 5, 0) +# define MOZ_SUPPORT_ASSERT_CONDITION_TYPE_VALIDATION +# endif +# elif defined(_MSC_VER) +// Disabled for now because of insufficient decltype support. Bug 1004028. +# endif +#endif + +#ifdef MOZ_SUPPORT_ASSERT_CONDITION_TYPE_VALIDATION +# include "mozilla/TypeTraits.h" +namespace mozilla { +namespace detail { + +template +struct IsFunction +{ + static const bool value = false; +}; + +template +struct IsFunction +{ + static const bool value = true; +}; + +template +void ValidateAssertConditionType() +{ + typedef typename RemoveReference::Type ValueT; + static_assert(!IsArray::value, + "Expected boolean assertion condition, got an array or a string!"); + static_assert(!IsFunction::value, + "Expected boolean assertion condition, got a function! Did you intend to call that function?"); + static_assert(!IsFloatingPoint::value, + "It's often a bad idea to assert that a floating-point number is nonzero, " + "because such assertions tend to intermittently fail. Shouldn't your code gracefully handle " + "this case instead of asserting? Anyway, if you really want to " + "do that, write an explicit boolean condition, like !!x or x!=0."); +} + +} // namespace detail +} // namespace mozilla +# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) mozilla::detail::ValidateAssertConditionType() +#else +# define MOZ_VALIDATE_ASSERT_CONDITION_TYPE(x) +#endif + /* First the single-argument form. */ #define MOZ_ASSERT_HELPER1(expr) \ do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ if (MOZ_UNLIKELY(!(expr))) { \ MOZ_ReportAssertionFailure(#expr, __FILE__, __LINE__); \ MOZ_REALLY_CRASH(); \ @@ -291,6 +349,7 @@ __declspec(noreturn) __inline void MOZ_NoReturn() {} /* Now the two-argument form. */ #define MOZ_ASSERT_HELPER2(expr, explain) \ do { \ + MOZ_VALIDATE_ASSERT_CONDITION_TYPE(expr); \ if (MOZ_UNLIKELY(!(expr))) { \ MOZ_ReportAssertionFailure(#expr " (" explain ")", __FILE__, __LINE__); \ MOZ_REALLY_CRASH(); \ diff --git a/mobile/android/base/AndroidGamepadManager.java b/mobile/android/base/AndroidGamepadManager.java new file mode 100644 index 000000000000..67373a216714 --- /dev/null +++ b/mobile/android/base/AndroidGamepadManager.java @@ -0,0 +1,395 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko; + +import org.mozilla.gecko.GeckoAppShell; +import org.mozilla.gecko.GeckoEvent; +import org.mozilla.gecko.util.GamepadUtils; +import org.mozilla.gecko.util.ThreadUtils; + +import android.content.Context; +import android.hardware.input.InputManager; +import android.os.Build; +import android.view.InputDevice; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import java.lang.Math; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + + +public class AndroidGamepadManager { + // This is completely arbitrary. + private static final float TRIGGER_PRESSED_THRESHOLD = 0.25f; + private static final long POLL_TIMER_PERIOD = 1000; // milliseconds + + private static enum Axis { + X(MotionEvent.AXIS_X), + Y(MotionEvent.AXIS_Y), + Z(MotionEvent.AXIS_Z), + RZ(MotionEvent.AXIS_RZ); + + public final int axis; + + private Axis(int axis) { + this.axis = axis; + } + }; + + // A list of gamepad button mappings. Axes are determined at + // runtime, as they vary by Android version. + private static enum Trigger { + Left(6), + Right(7); + + public final int button; + + private Trigger(int button) { + this.button = button; + } + }; + + private static final int FIRST_DPAD_BUTTON = 12; + // A list of axis number, gamepad button mappings for negative, positive. + // Button mappings are added to FIRST_DPAD_BUTTON. + private static enum DpadAxis { + UpDown(MotionEvent.AXIS_HAT_Y, 0, 1), + LeftRight(MotionEvent.AXIS_HAT_X, 2, 3); + + public final int axis; + public final int negativeButton; + public final int positiveButton; + + private DpadAxis(int axis, int negativeButton, int positiveButton) { + this.axis = axis; + this.negativeButton = negativeButton; + this.positiveButton = positiveButton; + } + }; + + private static enum Button { + A(KeyEvent.KEYCODE_BUTTON_A), + B(KeyEvent.KEYCODE_BUTTON_B), + X(KeyEvent.KEYCODE_BUTTON_X), + Y(KeyEvent.KEYCODE_BUTTON_Y), + L1(KeyEvent.KEYCODE_BUTTON_L1), + R1(KeyEvent.KEYCODE_BUTTON_R1), + L2(KeyEvent.KEYCODE_BUTTON_L2), + R2(KeyEvent.KEYCODE_BUTTON_R2), + SELECT(KeyEvent.KEYCODE_BUTTON_SELECT), + START(KeyEvent.KEYCODE_BUTTON_START), + THUMBL(KeyEvent.KEYCODE_BUTTON_THUMBL), + THUMBR(KeyEvent.KEYCODE_BUTTON_THUMBR), + DPAD_UP(KeyEvent.KEYCODE_DPAD_UP), + DPAD_DOWN(KeyEvent.KEYCODE_DPAD_DOWN), + DPAD_LEFT(KeyEvent.KEYCODE_DPAD_LEFT), + DPAD_RIGHT(KeyEvent.KEYCODE_DPAD_RIGHT); + + public final int button; + + private Button(int button) { + this.button = button; + } + }; + + private static class Gamepad { + // ID from GamepadService + public int id; + // Retain axis state so we can determine changes. + public float axes[]; + public boolean dpad[]; + public int triggerAxes[]; + public float triggers[]; + + public Gamepad(int serviceId, int deviceId) { + id = serviceId; + axes = new float[Axis.values().length]; + dpad = new boolean[4]; + triggers = new float[2]; + + InputDevice device = InputDevice.getDevice(deviceId); + if (device != null) { + // LTRIGGER/RTRIGGER don't seem to be exposed on older + // versions of Android. + if (device.getMotionRange(MotionEvent.AXIS_LTRIGGER) != null && device.getMotionRange(MotionEvent.AXIS_RTRIGGER) != null) { + triggerAxes = new int[]{MotionEvent.AXIS_LTRIGGER, + MotionEvent.AXIS_RTRIGGER}; + } else if (device.getMotionRange(MotionEvent.AXIS_BRAKE) != null && device.getMotionRange(MotionEvent.AXIS_GAS) != null) { + triggerAxes = new int[]{MotionEvent.AXIS_BRAKE, + MotionEvent.AXIS_GAS}; + } else { + triggerAxes = null; + } + } + } + } + + private static boolean sStarted = false; + private static HashMap sGamepads = null; + private static HashMap> sPendingGamepads = null; + private static InputManager.InputDeviceListener sListener = null; + private static Timer sPollTimer = null; + + private AndroidGamepadManager() { + } + + public static void startup() { + ThreadUtils.assertOnUiThread(); + if (!sStarted) { + sGamepads = new HashMap(); + sPendingGamepads = new HashMap>(); + scanForGamepads(); + addDeviceListener(); + sStarted = true; + } + } + + public static void shutdown() { + ThreadUtils.assertOnUiThread(); + if (sStarted) { + removeDeviceListener(); + sPendingGamepads = null; + sGamepads = null; + sStarted = false; + } + } + + public static void gamepadAdded(int deviceId, int serviceId) { + ThreadUtils.assertOnUiThread(); + if (!sStarted) { + return; + } + if (!sPendingGamepads.containsKey(deviceId)) { + removeGamepad(deviceId); + return; + } + + List pending = sPendingGamepads.get(deviceId); + sPendingGamepads.remove(deviceId); + sGamepads.put(deviceId, new Gamepad(serviceId, deviceId)); + // Handle queued KeyEvents + for (KeyEvent ev : pending) { + handleKeyEvent(ev); + } + } + + private static float deadZone(MotionEvent ev, int axis) { + if (GamepadUtils.isValueInDeadZone(ev, axis)) { + return 0.0f; + } + return ev.getAxisValue(axis); + } + + private static void mapDpadAxis(Gamepad gamepad, + boolean pressed, + float value, + int which) { + if (pressed != gamepad.dpad[which]) { + gamepad.dpad[which] = pressed; + GeckoAppShell.sendEventToGecko(GeckoEvent.createGamepadButtonEvent(gamepad.id, FIRST_DPAD_BUTTON + which, pressed, Math.abs(value))); + } + } + + public static boolean handleMotionEvent(MotionEvent ev) { + ThreadUtils.assertOnUiThread(); + if (!sStarted) { + return false; + } + + if (!sGamepads.containsKey(ev.getDeviceId())) { + // Not a device we care about. + return false; + } + + Gamepad gamepad = sGamepads.get(ev.getDeviceId()); + // First check the analog stick axes + boolean[] valid = new boolean[Axis.values().length]; + float[] axes = new float[Axis.values().length]; + boolean anyValidAxes = false; + for (Axis axis : Axis.values()) { + float value = deadZone(ev, axis.axis); + int i = axis.ordinal(); + if (value != gamepad.axes[i]) { + axes[i] = value; + gamepad.axes[i] = value; + valid[i] = true; + anyValidAxes = true; + } + } + if (anyValidAxes) { + // Send an axismove event. + GeckoAppShell.sendEventToGecko(GeckoEvent.createGamepadAxisEvent(gamepad.id, valid, axes)); + } + + // Map triggers to buttons. + if (gamepad.triggerAxes != null) { + for (Trigger trigger : Trigger.values()) { + int i = trigger.ordinal(); + int axis = gamepad.triggerAxes[i]; + float value = deadZone(ev, axis); + if (value != gamepad.triggers[i]) { + gamepad.triggers[i] = value; + boolean pressed = value > TRIGGER_PRESSED_THRESHOLD; + GeckoAppShell.sendEventToGecko(GeckoEvent.createGamepadButtonEvent(gamepad.id, trigger.button, pressed, value)); + } + } + } + // Map d-pad to buttons. + for (DpadAxis dpadaxis : DpadAxis.values()) { + float value = deadZone(ev, dpadaxis.axis); + mapDpadAxis(gamepad, value < 0.0f, value, dpadaxis.negativeButton); + mapDpadAxis(gamepad, value > 0.0f, value, dpadaxis.positiveButton); + } + return true; + } + + public static boolean handleKeyEvent(KeyEvent ev) { + ThreadUtils.assertOnUiThread(); + if (!sStarted) { + return false; + } + + int deviceId = ev.getDeviceId(); + if (sPendingGamepads.containsKey(deviceId)) { + // Queue up key events for pending devices. + sPendingGamepads.get(deviceId).add(ev); + return true; + } else if (!sGamepads.containsKey(deviceId)) { + InputDevice device = ev.getDevice(); + if (device != null && + (device.getSources() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { + // This is a gamepad we haven't seen yet. + addGamepad(device); + sPendingGamepads.get(deviceId).add(ev); + return true; + } + // Not a device we care about. + return false; + } + + int key = -1; + for (Button button : Button.values()) { + if (button.button == ev.getKeyCode()) { + key = button.ordinal(); + break; + } + } + if (key == -1) { + // Not a key we know how to handle. + return false; + } + if (ev.getRepeatCount() > 0) { + // We would handle this key, but we're not interested in + // repeats. Eat it. + return true; + } + + Gamepad gamepad = sGamepads.get(deviceId); + boolean pressed = ev.getAction() == KeyEvent.ACTION_DOWN; + GeckoAppShell.sendEventToGecko(GeckoEvent.createGamepadButtonEvent(gamepad.id, key, pressed, pressed ? 1.0f : 0.0f)); + return true; + } + + private static void scanForGamepads() { + if (Build.VERSION.SDK_INT < 9) { + return; + } + + int[] deviceIds = InputDevice.getDeviceIds(); + if (deviceIds == null) { + return; + } + for (int i=0; i < deviceIds.length; i++) { + InputDevice device = InputDevice.getDevice(deviceIds[i]); + if (device == null) { + continue; + } + if ((device.getSources() & InputDevice.SOURCE_GAMEPAD) != InputDevice.SOURCE_GAMEPAD) { + continue; + } + addGamepad(device); + } + } + + private static void addGamepad(InputDevice device) { + //TODO: when we're using a newer SDK version, use these. + //if (Build.VERSION.SDK_INT >= 12) { + //int vid = device.getVendorId(); + //int pid = device.getProductId(); + //} + sPendingGamepads.put(device.getId(), new ArrayList()); + GeckoAppShell.sendEventToGecko(GeckoEvent.createGamepadAddRemoveEvent(device.getId(), true)); + } + + private static void removeGamepad(int deviceId) { + Gamepad gamepad = sGamepads.get(deviceId); + GeckoAppShell.sendEventToGecko(GeckoEvent.createGamepadAddRemoveEvent(gamepad.id, false)); + sGamepads.remove(deviceId); + } + + private static void addDeviceListener() { + if (Build.VERSION.SDK_INT < 16) { + // Poll known gamepads to see if they've disappeared. + sPollTimer = new Timer(); + sPollTimer.scheduleAtFixedRate(new TimerTask() { + public void run() { + for (Integer deviceId : sGamepads.keySet()) { + if (InputDevice.getDevice(deviceId) == null) { + removeGamepad(deviceId); + } + } + } + }, POLL_TIMER_PERIOD, POLL_TIMER_PERIOD); + return; + } + sListener = new InputManager.InputDeviceListener() { + public void onInputDeviceAdded(int deviceId) { + InputDevice device = InputDevice.getDevice(deviceId); + if (device == null) { + return; + } + if ((device.getSources() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) { + addGamepad(device); + } + } + + public void onInputDeviceRemoved(int deviceId) { + if (sPendingGamepads.containsKey(deviceId)) { + // Got removed before Gecko's ack reached us. + // gamepadAdded will deal with it. + sPendingGamepads.remove(deviceId); + return; + } + if (sGamepads.containsKey(deviceId)) { + removeGamepad(deviceId); + } + } + + public void onInputDeviceChanged(int deviceId) { + } + }; + ((InputManager)GeckoAppShell.getContext().getSystemService(Context.INPUT_SERVICE)).registerInputDeviceListener(sListener, ThreadUtils.getUiHandler()); + } + + private static void removeDeviceListener() { + if (Build.VERSION.SDK_INT < 16) { + if (sPollTimer != null) { + sPollTimer.cancel(); + sPollTimer = null; + } + return; + } + ((InputManager)GeckoAppShell.getContext().getSystemService(Context.INPUT_SERVICE)).unregisterInputDeviceListener(sListener); + sListener = null; + } +} diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java index 6d9f0ed2b731..701ea5323b30 100644 --- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -14,6 +14,7 @@ import java.util.Vector; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.gecko.AndroidGamepadManager; import org.mozilla.gecko.DynamicToolbar.PinReason; import org.mozilla.gecko.DynamicToolbar.VisibilityTransition; import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException; @@ -268,6 +269,10 @@ abstract public class BrowserApp extends GeckoApp @Override public boolean onKey(View v, int keyCode, KeyEvent event) { + if (AndroidGamepadManager.handleKeyEvent(event)) { + return true; + } + // Global onKey handler. This is called if the focused UI doesn't // handle the key event, and before Gecko swallows the events. if (event.getAction() != KeyEvent.ACTION_DOWN) { @@ -357,6 +362,14 @@ abstract public class BrowserApp extends GeckoApp return super.onKeyDown(keyCode, event); } + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (AndroidGamepadManager.handleKeyEvent(event)) { + return true; + } + return super.onKeyUp(keyCode, event); + } + void handleReaderListStatusRequest(final String url) { ThreadUtils.postToBackgroundThread(new Runnable() { @Override diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index ffeb465720d7..10c2abf351c7 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -698,6 +698,43 @@ public class GeckoAppShell } } + @WrapElementForJNI + public static void startMonitoringGamepad() { + if (Build.VERSION.SDK_INT < 9) { + return; + } + ThreadUtils.postToUiThread(new Runnable() { + @Override + public void run() { + AndroidGamepadManager.startup(); + } + }); + } + + @WrapElementForJNI + public static void stopMonitoringGamepad() { + if (Build.VERSION.SDK_INT < 9) { + return; + } + + ThreadUtils.postToUiThread(new Runnable() { + @Override + public void run() { + AndroidGamepadManager.shutdown(); + } + }); + } + + @WrapElementForJNI + public static void gamepadAdded(final int device_id, final int service_id) { + ThreadUtils.postToUiThread(new Runnable() { + @Override + public void run() { + AndroidGamepadManager.gamepadAdded(device_id, service_id); + } + }); + } + @WrapElementForJNI public static void moveTaskToBack() { if (getGeckoInterface() != null) diff --git a/mobile/android/base/GeckoEvent.java b/mobile/android/base/GeckoEvent.java index 94093d642a1a..5c772a9a27e1 100644 --- a/mobile/android/base/GeckoEvent.java +++ b/mobile/android/base/GeckoEvent.java @@ -109,7 +109,9 @@ public class GeckoEvent { PREFERENCES_REMOVE_OBSERVERS(41), TELEMETRY_UI_SESSION_START(42), TELEMETRY_UI_SESSION_STOP(43), - TELEMETRY_UI_EVENT(44); + TELEMETRY_UI_EVENT(44), + GAMEPAD_ADDREMOVE(45), + GAMEPAD_DATA(46); public final int value; @@ -179,6 +181,12 @@ public class GeckoEvent { public static final int ACTION_MAGNIFY = 12; public static final int ACTION_MAGNIFY_END = 13; + public static final int ACTION_GAMEPAD_ADDED = 1; + public static final int ACTION_GAMEPAD_REMOVED = 2; + + public static final int ACTION_GAMEPAD_BUTTON = 1; + public static final int ACTION_GAMEPAD_AXES = 2; + private final int mType; private int mAction; private boolean mAckNeeded; @@ -231,6 +239,12 @@ public class GeckoEvent { private int mWidth; private int mHeight; + private int mID; + private int mGamepadButton; + private boolean mGamepadButtonPressed; + private float mGamepadButtonValue; + private float[] mGamepadValues; + private String[] mPrefNames; private GeckoEvent(NativeGeckoEvent event) { @@ -813,6 +827,47 @@ public class GeckoEvent { return event; } + public static GeckoEvent createGamepadAddRemoveEvent(int id, boolean added) { + GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.GAMEPAD_ADDREMOVE); + event.mID = id; + event.mAction = added ? ACTION_GAMEPAD_ADDED : ACTION_GAMEPAD_REMOVED; + return event; + } + + private static int boolArrayToBitfield(boolean[] array) { + int bits = 0; + for (int i = 0; i < array.length; i++) { + if (array[i]) { + bits |= 1< permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (!permMgr) return; @@ -1180,7 +1180,7 @@ nsHttpChannel::ProcessSSLInformation() // use via RetrieveSSLOptions(() nsCOMPtr permMgr = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (!permMgr) return; diff --git a/netwerk/protocol/http/nsHttpConnectionMgr.cpp b/netwerk/protocol/http/nsHttpConnectionMgr.cpp index b414f80b4a2b..9ad868a06491 100644 --- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp +++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp @@ -2366,6 +2366,13 @@ nsHttpConnectionMgr::OnMsgReclaimConnection(int32_t, void *param) ConditionallyStopTimeoutTick(); } + // a connection that still holds a reference to a transaction was + // not closed naturally (i.e. it was reset or aborted) and is + // therefore not something that should be reused. + if (conn->Transaction()) { + conn->DontReuse(); + } + if (conn->CanReuse()) { LOG((" adding connection to idle list\n")); // Keep The idle connection list sorted with the connections that diff --git a/netwerk/protocol/http/nsHttpTransaction.cpp b/netwerk/protocol/http/nsHttpTransaction.cpp index 6867c0569b96..190558bd3257 100644 --- a/netwerk/protocol/http/nsHttpTransaction.cpp +++ b/netwerk/protocol/http/nsHttpTransaction.cpp @@ -1066,7 +1066,10 @@ nsHttpTransaction::Restart() // clear old connection state... mSecurityInfo = 0; - NS_IF_RELEASE(mConnection); + if (mConnection) { + mConnection->DontReuse(); + NS_RELEASE(mConnection); + } // disable pipelining for the next attempt in case pipelining caused the // reset. this is being overly cautious since we don't know if pipelining diff --git a/netwerk/streamconv/src/nsStreamConverterService.cpp b/netwerk/streamconv/src/nsStreamConverterService.cpp index f549990b63ac..afe7611ef77b 100644 --- a/netwerk/streamconv/src/nsStreamConverterService.cpp +++ b/netwerk/streamconv/src/nsStreamConverterService.cpp @@ -38,27 +38,17 @@ /////////////////////////////////////////////////////////////////// // Breadth-First-Search (BFS) algorithm state classes and types. -// Adjacency list data class. -typedef nsCOMArray SCTableData; - -// Delete all the entries in the adjacency list -static bool DeleteAdjacencyEntry(nsHashKey *aKey, void *aData, void* closure) { - SCTableData *entry = (SCTableData*)aData; - delete entry; - return true; -} - // Used to establish discovered verticies. enum BFScolors {white, gray, black}; // BFS hashtable data class. struct BFSTableData { - nsCStringKey *key; + nsCString key; BFScolors color; int32_t distance; - nsAutoPtr predecessor; + nsAutoPtr predecessor; - explicit BFSTableData(nsCStringKey* aKey) + explicit BFSTableData(const nsACString& aKey) : key(aKey), color(white), distance(-1) { } @@ -75,7 +65,6 @@ NS_IMPL_ISUPPORTS(nsStreamConverterService, nsIStreamConverterService) //////////////////////////////////////////////////////////// // nsStreamConverterService methods nsStreamConverterService::nsStreamConverterService() - : mAdjacencyList(nullptr, nullptr, DeleteAdjacencyEntry, nullptr) { } @@ -151,18 +140,16 @@ nsStreamConverterService::AddAdjacency(const char *aContractID) { // Each MIME-type is a vertex in the graph, so first lets make sure // each MIME-type is represented as a key in our hashtable. - nsCStringKey fromKey(fromStr); - SCTableData *fromEdges = (SCTableData*)mAdjacencyList.Get(&fromKey); + nsCOMArray *fromEdges = mAdjacencyList.Get(fromStr); if (!fromEdges) { // There is no fromStr vertex, create one. - fromEdges = new SCTableData(); - mAdjacencyList.Put(&fromKey, fromEdges); + fromEdges = new nsCOMArray(); + mAdjacencyList.Put(fromStr, fromEdges); } - nsCStringKey toKey(toStr); - if (!mAdjacencyList.Get(&toKey)) { + if (!mAdjacencyList.Get(toStr)) { // There is no toStr vertex, create one. - mAdjacencyList.Put(&toKey, new SCTableData()); + mAdjacencyList.Put(toStr, new nsCOMArray()); } // Now we know the FROM and TO types are represented as keys in the hashtable. @@ -201,32 +188,29 @@ nsStreamConverterService::ParseFromTo(const char *aContractID, nsCString &aFromR return NS_OK; } +typedef nsClassHashtable BFSHashTable; + + // nsObjectHashtable enumerator functions. // Initializes the BFS state table. -static bool InitBFSTable(nsHashKey *aKey, void *aData, void* closure) { - NS_ASSERTION((SCTableData*)aData, "no data in the table enumeration"); +static PLDHashOperator +InitBFSTable(const nsACString &aKey, nsCOMArray *aData, void* aClosure) { + MOZ_ASSERT(aData, "no data in the table enumeration"); - nsHashtable *BFSTable = (nsHashtable*)closure; - if (!BFSTable) return false; + BFSHashTable *bfsTable = static_cast(aClosure); + if (!bfsTable) return PL_DHASH_STOP; - BFSTable->Put(aKey, new BFSTableData(static_cast(aKey))); - return true; -} - -// cleans up the BFS state table -static bool DeleteBFSEntry(nsHashKey *aKey, void *aData, void *closure) { - BFSTableData *data = (BFSTableData*)aData; - data->key = nullptr; - delete data; - return true; + BFSTableData *data = new BFSTableData(aKey); + bfsTable->Put(aKey, data); + return PL_DHASH_NEXT; } class CStreamConvDeallocator : public nsDequeFunctor { public: virtual void* operator()(void* anObject) { - nsCStringKey *key = (nsCStringKey*)anObject; - delete key; + nsCString *string = (nsCString*)anObject; + delete string; return 0; } }; @@ -244,12 +228,12 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsTArray= vertexCount) return NS_ERROR_FAILURE; // Create a corresponding color table for each vertex in the graph. - nsObjectHashtable lBFSTable(nullptr, nullptr, DeleteBFSEntry, nullptr); - mAdjacencyList.Enumerate(InitBFSTable, &lBFSTable); + BFSHashTable lBFSTable; + mAdjacencyList.EnumerateRead(InitBFSTable, &lBFSTable); NS_ASSERTION(lBFSTable.Count() == vertexCount, "strmconv BFS table init problem"); @@ -258,11 +242,8 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsTArray *data2 = mAdjacencyList.Get(*currentHead); if (!data2) return NS_ERROR_FAILURE; // Get the state of the current head to calculate the distance of each // reachable vertex in the loop. - BFSTableData *headVertexState = (BFSTableData*)lBFSTable.Get(currentHead); + BFSTableData *headVertexState = lBFSTable.Get(*currentHead); if (!headVertexState) return NS_ERROR_FAILURE; int32_t edgeCount = data2->Count(); @@ -290,10 +271,10 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsTArrayObjectAt(i); nsAutoString curVertexStr; curVertexAtom->ToString(curVertexStr); - nsCStringKey *curVertex = new nsCStringKey(ToNewCString(curVertexStr), - curVertexStr.Length(), nsCStringKey::OWN); + nsCString *curVertex = nullptr; + CopyUTF16toUTF8(curVertexStr, *curVertex); - BFSTableData *curVertexState = (BFSTableData*)lBFSTable.Get(curVertex); + BFSTableData *curVertexState = lBFSTable.Get(*curVertex); if (!curVertexState) { delete curVertex; return NS_ERROR_FAILURE; @@ -302,11 +283,7 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsTArraycolor) { curVertexState->color = gray; curVertexState->distance = headVertexState->distance + 1; - curVertexState->predecessor = (nsCStringKey*)currentHead->Clone(); - if (!curVertexState->predecessor) { - delete curVertex; - return NS_ERROR_OUT_OF_MEMORY; - } + curVertexState->predecessor = new nsCString(*currentHead); grayQ.Push(curVertex); } else { delete curVertex; // if this vertex has already been discovered, we don't want @@ -315,7 +292,7 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsTArraycolor = black; - nsCStringKey *cur = (nsCStringKey*)grayQ.PopFront(); + nsCString *cur = (nsCString*)grayQ.PopFront(); delete cur; cur = nullptr; } @@ -324,16 +301,15 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsTArray *shortestPath = new nsTArray(); - nsCStringKey toMIMEType(toStr); - data = (BFSTableData*)lBFSTable.Get(&toMIMEType); + data = lBFSTable.Get(toMIMEType); if (!data) { // If this vertex isn't in the BFSTable, then no-one has registered for it, // therefore we can't do the conversion. @@ -342,9 +318,7 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsTArraykey; - - if (fromStr.Equals(key->GetString())) { + if (fromStr.Equals(data->key)) { // found it. We're done here. *aEdgeList = shortestPath; return NS_OK; @@ -353,7 +327,7 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsTArraypredecessor) break; // no predecessor - BFSTableData *predecessorData = (BFSTableData*)lBFSTable.Get(data->predecessor); + BFSTableData *predecessorData = lBFSTable.Get(*data->predecessor); if (!predecessorData) break; // no predecessor, chain doesn't exist. @@ -361,11 +335,10 @@ nsStreamConverterService::FindConverter(const char *aContractID, nsTArray> mAdjacencyList; }; #endif // __nsstreamconverterservice__h___ diff --git a/security/apps/AppTrustDomain.h b/security/apps/AppTrustDomain.h index 875c1db34105..d7e4734fca2b 100644 --- a/security/apps/AppTrustDomain.h +++ b/security/apps/AppTrustDomain.h @@ -35,6 +35,8 @@ public: /*const*/ CERTCertificate* issuerCertToDup, PRTime time, /*optional*/ const SECItem* stapledOCSPresponse); + SECStatus IsChainValid(const CERTCertList* certChain) { return SECSuccess; } + private: void* mPinArg; // non-owning! mozilla::pkix::ScopedCERTCertificate mTrustedRoot; diff --git a/security/certverifier/CertVerifier.cpp b/security/certverifier/CertVerifier.cpp index 53de1779f1f7..f250fd9210ff 100644 --- a/security/certverifier/CertVerifier.cpp +++ b/security/certverifier/CertVerifier.cpp @@ -11,9 +11,11 @@ #include "pkix/pkix.h" #include "ExtendedValidation.h" #include "NSSCertDBTrustDomain.h" +#include "PublicKeyPinningService.h" #include "cert.h" #include "ocsp.h" #include "secerr.h" +#include "pk11pub.h" #include "prerror.h" #include "sslerr.h" @@ -38,7 +40,8 @@ CertVerifier::CertVerifier(implementation_config ic, #endif ocsp_download_config odc, ocsp_strict_config osc, - ocsp_get_config ogc) + ocsp_get_config ogc, + pinning_enforcement_config pel) : mImplementation(ic) #ifndef NSS_NO_LIBPKIX , mMissingCertDownloadEnabled(mcdc == missing_cert_download_on) @@ -47,6 +50,7 @@ CertVerifier::CertVerifier(implementation_config ic, , mOCSPDownloadEnabled(odc == ocsp_on) , mOCSPStrict(osc == ocsp_strict) , mOCSPGETEnabled(ogc == ocsp_get_enabled) + , mPinningEnforcementLevel(pel) { } @@ -64,7 +68,6 @@ InitCertVerifierLog() #endif } -#if 0 // Once we migrate to mozilla::pkix or change the overridable error // logic this will become unnecesary. static SECStatus @@ -95,23 +98,100 @@ insertErrorIntoVerifyLog(CERTCertificate* cert, const PRErrorCode err, return SECSuccess; } -#endif + +SECStatus +IsCertBuiltInRoot(CERTCertificate* cert, bool& result) { + result = false; + ScopedPtr slots; + slots = PK11_GetAllSlotsForCert(cert, nullptr); + if (!slots) { + if (PORT_GetError() == SEC_ERROR_NO_TOKEN) { + // no list + return SECSuccess; + } + return SECFailure; + } + for (PK11SlotListElement* le = slots->head; le; le = le->next) { + char* token = PK11_GetTokenName(le->slot); + PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, + ("BuiltInRoot? subject=%s token=%s",cert->subjectName, token)); + if (strcmp("Builtin Object Token", token) == 0) { + result = true; + return SECSuccess; + } + } + return SECSuccess; +} + +struct ChainValidationCallbackState +{ + const char* hostname; + const CertVerifier::pinning_enforcement_config pinningEnforcementLevel; + const SECCertificateUsage usage; + const PRTime time; +}; SECStatus chainValidationCallback(void* state, const CERTCertList* certList, PRBool* chainOK) { + ChainValidationCallbackState* callbackState = + reinterpret_cast(state); + *chainOK = PR_FALSE; - PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("verifycert: Inside the Callback \n")); + PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, + ("verifycert: Inside the Callback \n")); // On sanity failure we fail closed. if (!certList) { - PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("verifycert: Short circuit, callback, " - "sanity check failed \n")); + PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, + ("verifycert: Short circuit, callback, sanity check failed \n")); PR_SetError(PR_INVALID_STATE_ERROR, 0); return SECFailure; } - *chainOK = PR_TRUE; + if (!callbackState) { + PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, + ("verifycert: Short circuit, callback, no state! \n")); + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return SECFailure; + } + + if (callbackState->usage != certificateUsageSSLServer || + callbackState->pinningEnforcementLevel == CertVerifier::pinningDisabled) { + PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, + ("verifycert: Callback shortcut pel=%d \n", + callbackState->pinningEnforcementLevel)); + *chainOK = PR_TRUE; + return SECSuccess; + } + + for (CERTCertListNode* node = CERT_LIST_HEAD(certList); + !CERT_LIST_END(node, certList); + node = CERT_LIST_NEXT(node)) { + CERTCertificate* currentCert = node->cert; + if (CERT_LIST_END(CERT_LIST_NEXT(node), certList)) { + bool isBuiltInRoot = false; + SECStatus srv = IsCertBuiltInRoot(currentCert, isBuiltInRoot); + if (srv != SECSuccess) { + PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("Is BuiltInRoot failure")); + return srv; + } + // If desired, the user can enable "allow user CA MITM mode", in which + // case key pinning is not enforced for certificates that chain to trust + // anchors that are not in Mozilla's root program + if (!isBuiltInRoot && + (callbackState->pinningEnforcementLevel == + CertVerifier::pinningAllowUserCAMITM)) { + *chainOK = PR_TRUE; + return SECSuccess; + } + } + } + + *chainOK = PublicKeyPinningService:: + ChainHasValidPins(certList, callbackState->hostname, + callbackState->time); + return SECSuccess; } @@ -120,42 +200,41 @@ ClassicVerifyCert(CERTCertificate* cert, const SECCertificateUsage usage, const PRTime time, void* pinArg, + ChainValidationCallbackState* callbackState, /*optional out*/ ScopedCERTCertList* validationChain, /*optional out*/ CERTVerifyLog* verifyLog) { SECStatus rv; SECCertUsage enumUsage; - if (validationChain) { - switch(usage){ - case certificateUsageSSLClient: - enumUsage = certUsageSSLClient; - break; - case certificateUsageSSLServer: - enumUsage = certUsageSSLServer; - break; - case certificateUsageSSLCA: - enumUsage = certUsageSSLCA; - break; - case certificateUsageEmailSigner: - enumUsage = certUsageEmailSigner; - break; - case certificateUsageEmailRecipient: - enumUsage = certUsageEmailRecipient; - break; - case certificateUsageObjectSigner: - enumUsage = certUsageObjectSigner; - break; - case certificateUsageVerifyCA: - enumUsage = certUsageVerifyCA; - break; - case certificateUsageStatusResponder: - enumUsage = certUsageStatusResponder; - break; - default: - PR_NOT_REACHED("unexpected usage"); - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } + switch (usage) { + case certificateUsageSSLClient: + enumUsage = certUsageSSLClient; + break; + case certificateUsageSSLServer: + enumUsage = certUsageSSLServer; + break; + case certificateUsageSSLCA: + enumUsage = certUsageSSLCA; + break; + case certificateUsageEmailSigner: + enumUsage = certUsageEmailSigner; + break; + case certificateUsageEmailRecipient: + enumUsage = certUsageEmailRecipient; + break; + case certificateUsageObjectSigner: + enumUsage = certUsageObjectSigner; + break; + case certificateUsageVerifyCA: + enumUsage = certUsageVerifyCA; + break; + case certificateUsageStatusResponder: + enumUsage = certUsageStatusResponder; + break; + default: + PR_NOT_REACHED("unexpected usage"); + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; } if (usage == certificateUsageSSLServer) { // SSL server cert verification has always used CERT_VerifyCert, so we @@ -168,13 +247,38 @@ ClassicVerifyCert(CERTCertificate* cert, rv = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), cert, true, usage, time, pinArg, verifyLog, nullptr); } - if (rv == SECSuccess && validationChain) { - PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("VerifyCert: getting chain in 'classic' \n")); - *validationChain = CERT_GetCertChainFromCert(cert, time, enumUsage); - if (!*validationChain) { - rv = SECFailure; + + if (rv == SECSuccess && + (validationChain || usage == certificateUsageSSLServer)) { + PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, + ("VerifyCert: getting chain in 'classic' \n")); + ScopedCERTCertList certChain(CERT_GetCertChainFromCert(cert, time, + enumUsage)); + if (!certChain) { + return SECFailure; + } + if (usage == certificateUsageSSLServer) { + PRBool chainOK = PR_FALSE; + SECStatus srv = chainValidationCallback(callbackState, certChain.get(), + &chainOK); + if (srv != SECSuccess) { + return srv; + } + if (chainOK != PR_TRUE) { + if (verifyLog) { + insertErrorIntoVerifyLog(cert, + SEC_ERROR_APPLICATION_CALLBACK_ERROR, + verifyLog); + } + PR_SetError(SEC_ERROR_APPLICATION_CALLBACK_ERROR, 0); // same as libpkix + return SECFailure; + } + } + if (rv == SECSuccess && validationChain) { + *validationChain = certChain.release(); } } + return rv; } @@ -232,6 +336,7 @@ CertVerifier::MozillaPKIXVerifyCert( const PRTime time, void* pinArg, const Flags flags, + ChainValidationCallbackState* callbackState, /*optional*/ const SECItem* stapledOCSPResponse, /*optional out*/ mozilla::pkix::ScopedCERTCertList* validationChain, /*optional out*/ SECOidTag* evOidPolicy) @@ -254,6 +359,10 @@ CertVerifier::MozillaPKIXVerifyCert( return SECFailure; } + CERTChainVerifyCallback callbackContainer; + callbackContainer.isChainValid = chainValidationCallback; + callbackContainer.isChainValidArg = callbackState; + NSSCertDBTrustDomain::OCSPFetching ocspFetching = !mOCSPDownloadEnabled || (flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::NeverFetchOCSP @@ -300,7 +409,7 @@ CertVerifier::MozillaPKIXVerifyCert( ocspFetching == NSSCertDBTrustDomain::NeverFetchOCSP ? NSSCertDBTrustDomain::LocalOnlyOCSPForEV : NSSCertDBTrustDomain::FetchOCSPForEV, - mOCSPCache, pinArg); + mOCSPCache, pinArg, &callbackContainer); rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time, KU_DIGITAL_SIGNATURE, // ECDHE/DHE KU_KEY_ENCIPHERMENT, // RSA @@ -326,7 +435,7 @@ CertVerifier::MozillaPKIXVerifyCert( // Now try non-EV. NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache, - pinArg); + pinArg, &callbackContainer); rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time, KU_DIGITAL_SIGNATURE, // ECDHE/DHE KU_KEY_ENCIPHERMENT, // RSA @@ -443,19 +552,25 @@ CertVerifier::MozillaPKIXVerifyCert( SECStatus CertVerifier::VerifyCert(CERTCertificate* cert, - /*optional*/ const SECItem* stapledOCSPResponse, const SECCertificateUsage usage, const PRTime time, void* pinArg, + const char* hostname, const Flags flags, + /*optional in*/ const SECItem* stapledOCSPResponse, /*optional out*/ ScopedCERTCertList* validationChain, /*optional out*/ SECOidTag* evOidPolicy, /*optional out*/ CERTVerifyLog* verifyLog) { + ChainValidationCallbackState callbackState = { hostname, + mPinningEnforcementLevel, + usage, + time }; + if (mImplementation == mozillapkix) { return MozillaPKIXVerifyCert(cert, usage, time, pinArg, flags, - stapledOCSPResponse, validationChain, - evOidPolicy); + &callbackState, stapledOCSPResponse, + validationChain, evOidPolicy); } if (!cert) @@ -581,7 +696,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, CERTChainVerifyCallback callbackContainer; if (usage == certificateUsageSSLServer) { callbackContainer.isChainValid = chainValidationCallback; - callbackContainer.isChainValidArg = nullptr; + callbackContainer.isChainValidArg = &callbackState; cvin[i].type = cert_pi_chainVerifyCallback; cvin[i].value.pointer.chainVerifyCallback = &callbackContainer; ++i; @@ -685,8 +800,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, if (mImplementation == classic) { // XXX: we do not care about the localOnly flag (currently) as the // caller that wants localOnly should disable and reenable the fetching. - return ClassicVerifyCert(cert, usage, time, pinArg, validationChain, - verifyLog); + return ClassicVerifyCert(cert, usage, time, pinArg, &callbackState, + validationChain, verifyLog); } #ifdef NSS_NO_LIBPKIX @@ -826,9 +941,9 @@ CertVerifier::VerifySSLServerCert(CERTCertificate* peerCert, // CreateCertErrorRunnable assumes that CERT_VerifyCertName is only called // if VerifyCert succeeded. ScopedCERTCertList validationChain; - SECStatus rv = VerifyCert(peerCert, stapledOCSPResponse, - certificateUsageSSLServer, time, - pinarg, 0, &validationChain, evOidPolicy); + SECStatus rv = VerifyCert(peerCert, certificateUsageSSLServer, time, pinarg, + hostname, 0, stapledOCSPResponse, &validationChain, + evOidPolicy, nullptr); if (rv != SECSuccess) { return rv; } diff --git a/security/certverifier/CertVerifier.h b/security/certverifier/CertVerifier.h index 09ed4b040ccb..ac4cd0c58f15 100644 --- a/security/certverifier/CertVerifier.h +++ b/security/certverifier/CertVerifier.h @@ -12,6 +12,8 @@ namespace mozilla { namespace psm { +struct ChainValidationCallbackState; + class CertVerifier { public: @@ -24,11 +26,12 @@ public: // *evOidPolicy == SEC_OID_UNKNOWN means the cert is NOT EV // Only one usage per verification is supported. SECStatus VerifyCert(CERTCertificate* cert, - /*optional*/ const SECItem* stapledOCSPResponse, const SECCertificateUsage usage, const PRTime time, void* pinArg, + const char* hostname, const Flags flags = 0, + /*optional in*/ const SECItem* stapledOCSPResponse = nullptr, /*optional out*/ mozilla::pkix::ScopedCERTCertList* validationChain = nullptr, /*optional out*/ SECOidTag* evOidPolicy = nullptr , /*optional out*/ CERTVerifyLog* verifyLog = nullptr); @@ -52,6 +55,12 @@ public: mozillapkix = 2 }; + enum pinning_enforcement_config { + pinningDisabled = 0, + pinningAllowUserCAMITM = 1, + pinningStrict = 2 + }; + enum missing_cert_download_config { missing_cert_download_off = 0, missing_cert_download_on }; enum crl_download_config { crl_local_only = 0, crl_download_allowed }; enum ocsp_download_config { ocsp_off = 0, ocsp_on }; @@ -65,7 +74,8 @@ public: missing_cert_download_config ac, crl_download_config cdc, #endif ocsp_download_config odc, ocsp_strict_config osc, - ocsp_get_config ogc); + ocsp_get_config ogc, + pinning_enforcement_config pinningEnforcementLevel); ~CertVerifier(); void ClearOCSPCache() { mOCSPCache.Clear(); } @@ -78,6 +88,7 @@ public: const bool mOCSPDownloadEnabled; const bool mOCSPStrict; const bool mOCSPGETEnabled; + const pinning_enforcement_config mPinningEnforcementLevel; private: SECStatus MozillaPKIXVerifyCert(CERTCertificate* cert, @@ -85,6 +96,7 @@ private: const PRTime time, void* pinArg, const Flags flags, + ChainValidationCallbackState* callbackState, /*optional*/ const SECItem* stapledOCSPResponse, /*optional out*/ mozilla::pkix::ScopedCERTCertList* validationChain, /*optional out*/ SECOidTag* evOidPolicy); diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index 443f6d34ea96..aeaa1cd94899 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -42,11 +42,13 @@ typedef ScopedPtr ScopedSECMODModule; NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType, OCSPFetching ocspFetching, OCSPCache& ocspCache, - void* pinArg) + void* pinArg, + CERTChainVerifyCallback* checkChainCallback) : mCertDBTrustType(certDBTrustType) , mOCSPFetching(ocspFetching) , mOCSPCache(ocspCache) , mPinArg(pinArg) + , mCheckChainCallback(checkChainCallback) { } @@ -405,6 +407,37 @@ NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse( return rv; } +SECStatus +NSSCertDBTrustDomain::IsChainValid(const CERTCertList* certChain) { + SECStatus rv = SECFailure; + + PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, + ("NSSCertDBTrustDomain: Top of IsChainValid mCheckCallback=%p", + mCheckChainCallback)); + + if (!mCheckChainCallback) { + return SECSuccess; + } + if (!mCheckChainCallback->isChainValid) { + PR_SetError(SEC_ERROR_INVALID_ARGS, 0); + return SECFailure; + } + PRBool chainOK; + rv = (mCheckChainCallback->isChainValid)(mCheckChainCallback->isChainValidArg, + certChain, &chainOK); + if (rv != SECSuccess) { + return rv; + } + // rv = SECSuccess only implies successful call, now is time + // to check the chain check status + // we should only return success if the chain is valid + if (chainOK) { + return SECSuccess; + } + PR_SetError(SEC_ERROR_APPLICATION_CALLBACK_ERROR, 0); + return SECFailure; +} + namespace { static char* diff --git a/security/certverifier/NSSCertDBTrustDomain.h b/security/certverifier/NSSCertDBTrustDomain.h index 443860da6388..b6b73062ef71 100644 --- a/security/certverifier/NSSCertDBTrustDomain.h +++ b/security/certverifier/NSSCertDBTrustDomain.h @@ -57,7 +57,8 @@ public: LocalOnlyOCSPForEV = 4, }; NSSCertDBTrustDomain(SECTrustType certDBTrustType, OCSPFetching ocspFetching, - OCSPCache& ocspCache, void* pinArg); + OCSPCache& ocspCache, void* pinArg, + CERTChainVerifyCallback* checkChainCallback = nullptr); virtual SECStatus FindPotentialIssuers( const SECItem* encodedIssuerName, @@ -78,6 +79,8 @@ public: PRTime time, /*optional*/ const SECItem* stapledOCSPResponse); + virtual SECStatus IsChainValid(const CERTCertList* certChain); + private: enum EncodedResponseSource { ResponseIsFromNetwork = 1, @@ -92,6 +95,7 @@ private: const OCSPFetching mOCSPFetching; OCSPCache& mOCSPCache; // non-owning! void* mPinArg; // non-owning! + CERTChainVerifyCallback* mCheckChainCallback; // non-owning! }; } } // namespace mozilla::psm diff --git a/security/certverifier/moz.build b/security/certverifier/moz.build index e755fb43c97d..d5e13f2e0e0c 100644 --- a/security/certverifier/moz.build +++ b/security/certverifier/moz.build @@ -16,6 +16,7 @@ if not CONFIG['NSS_NO_EV_CERTS']: ] LOCAL_INCLUDES += [ + '../manager/boot/src', '../pkix/include', ] diff --git a/security/manager/boot/src/PreloadedHPKPins.json b/security/manager/boot/src/PreloadedHPKPins.json index 68c90c2b083b..5c151a2a7021 100644 --- a/security/manager/boot/src/PreloadedHPKPins.json +++ b/security/manager/boot/src/PreloadedHPKPins.json @@ -11,7 +11,7 @@ // name: (string) the name of the pinset // static_spki_hashes: (list of strings) the set of allowed SPKIs hashes // -// For a given pinset, a certifiacte is accepted if at least one of the +// For a given pinset, a certificate is accepted if at least one of the // "static_spki_hashes" SPKIs is found in the chain. // SPKIs are specified as names, which must match up with the name given // in the Mozilla root store. @@ -81,6 +81,14 @@ "thawte Primary Root CA - G3", "Baltimore CyberTrust Root" ] + }, + // For pinning tests on pinning.example.com, the certificate must be 'End + // Entity Test Cert' + { + "name": "mozilla_test", + "static_spki_hashes": [ + "End Entity Test Cert" + ] } ], @@ -90,6 +98,7 @@ { "name": "cdn.mozilla.net", "include_subdomains": true, "pins": "mozilla_cdn" }, { "name": "cdn.mozilla.org", "include_subdomains": true, "pins": "mozilla_cdn" }, { "name": "media.mozilla.com", "include_subdomains": true, "pins": "mozilla_cdn" }, - { "name": "getpersonas.org", "include_subdomains": true, "pins": "mozilla_cdn" } + { "name": "include-subdomains.pinning.example.com", "include_subdomains": true, "pins": "mozilla_test" }, + { "name": "exclude-subdomains.pinning.example.com", "include_subdomains": false, "pins": "mozilla_test" } ] } diff --git a/security/manager/boot/src/StaticHPKPins.h b/security/manager/boot/src/StaticHPKPins.h index a8229b758b38..cee2881d4b8d 100644 --- a/security/manager/boot/src/StaticHPKPins.h +++ b/security/manager/boot/src/StaticHPKPins.h @@ -23,6 +23,10 @@ static const char kDigiCert_Global_Root_CAFingerprint[]= static const char kDigiCert_High_Assurance_EV_Root_CAFingerprint[]= "WoiWRyIOVNa9ihaBciRSC7XHjliYS9VwUGOIud4PB18="; +/* End Entity Test Cert */ +static const char kEnd_Entity_Test_CertFingerprint[]= + "sEIYDccDj1ULE64YxhvqV7ASqc2qfIofVyArzg+62hU="; + /* Equifax Secure CA */ static const char kEquifax_Secure_CAFingerprint[]= "/1aAzXOlcD2gSBegdf1GJQanNQbEuBoVg+9UlHjSZHY="; @@ -174,6 +178,11 @@ static const char* const kPinSet_mozilla_cdn_Data[] = { }; const StaticPinset kPinSet_mozilla_cdn = { 28, kPinSet_mozilla_cdn_Data}; +static const char* const kPinSet_mozilla_test_Data[] = { + kEnd_Entity_Test_CertFingerprint, +}; +const StaticPinset kPinSet_mozilla_test = { 1, kPinSet_mozilla_test_Data}; + /*Domainlist*/ typedef struct { const char *mHost; @@ -186,10 +195,11 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = { { "addons.mozilla.org", true, &kPinSet_mozilla }, { "cdn.mozilla.net", true, &kPinSet_mozilla_cdn }, { "cdn.mozilla.org", true, &kPinSet_mozilla_cdn }, - { "getpersonas.org", true, &kPinSet_mozilla_cdn }, + { "exclude-subdomains.pinning.example.com", false, &kPinSet_mozilla_test }, + { "include-subdomains.pinning.example.com", true, &kPinSet_mozilla_test }, { "media.mozilla.com", true, &kPinSet_mozilla_cdn }, }; -static const int kPublicKeyPinningPreloadListLength = 6; +static const int kPublicKeyPinningPreloadListLength = 7; -const PRTime kPreloadPKPinsExpirationTime = INT64_C(1409688371834000); +const PRTime kPreloadPKPinsExpirationTime = INT64_C(1409782406553000); diff --git a/security/manager/boot/src/default-ee.der b/security/manager/boot/src/default-ee.der new file mode 100644 index 000000000000..6874346226ed Binary files /dev/null and b/security/manager/boot/src/default-ee.der differ diff --git a/security/manager/boot/src/genHPKPStaticPins.js b/security/manager/boot/src/genHPKPStaticPins.js index 5781829f527d..ba5809affe17 100644 --- a/security/manager/boot/src/genHPKPStaticPins.js +++ b/security/manager/boot/src/genHPKPStaticPins.js @@ -7,13 +7,14 @@ // 2. [build/obtain firefox binaries] // 3. run `[path to]/run-mozilla.sh [path to]/xpcshell \ // [path to]/genHPKPStaticpins.js +// Files PreloadedHPKPins.json and default-ee.der must be in the current +// working directory. const { 'classes': Cc, 'interfaces': Ci, 'utils': Cu, 'results': Cr } = Components; let { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {}); let { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm", {}); let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); -let { XPCOMUtils } = Cu.import("resource:///modules/XPCOMUtils.jsm", {}); const certdb2 = Cc["@mozilla.org/security/x509certdb;1"] .getService(Ci.nsIX509CertDB2); @@ -48,8 +49,7 @@ function writeTo(string, fos) { fos.write(string, string.length); } -function readFile(filename) { - print("filename =" + filename) +function readFileToString(filename) { let path = filename; let lf = Components.classes["@mozilla.org/file/directory_service;1"] @@ -67,26 +67,23 @@ function readFile(filename) { } } } - let file = lf; - let fstream = Cc["@mozilla.org/network/file-input-stream;1"] - .createInstance(Ci.nsIFileInputStream); - fstream.init(file, -1, 0, 0); - var line = {}; + let stream = Cc["@mozilla.org/network/file-input-stream;1"] + .createInstance(Ci.nsIFileInputStream); + stream.init(lf, -1, 0, 0); + let buf = NetUtil.readInputStreamToString(stream, stream.available()); + return buf; +} + +function stripComments(buf) { + var lines = buf.split("\n"); let entryRegex = /^\s*\/\//; let data = ""; - while(fstream.readLine(line)) { - let match = entryRegex.exec(line.value); + for (let i = 0; i < lines.length; ++i) { + let match = entryRegex.exec(lines[i]); if (!match) { - data = data + line.value; + data = data + lines[i]; } } - // The last line of the read is a false, but content can be there - // so: repeat the logic - let match = entryRegex.exec(line.value); - if (!match) { - data = data + line.value; - } - fstream.close(); return data; } @@ -124,11 +121,25 @@ function loadNSSCertinfo() { certNameToSKD[name] = SDK; certSDKToName[SDK] = name; } + { + // A certificate for *.example.com. + let der = readFileToString("default-ee.der"); + // XPCOM is too dumb to automatically query the parent interface of + // nsIX509CertDB2 without a hint. + let certdb = certdb2.QueryInterface(Ci.nsIX509CertDB); + let testCert = certdb.constructX509(der, der.length); + // We can't include this cert in the previous loop, because it skips + // non-builtin certs and the nickname is not built-in to the cert. + let name = "End Entity Test Cert"; + let SDK = testCert.sha256SubjectPublicKeyInfoDigest; + certNameToSKD[name] = SDK; + certSDKToName[SDK] = name; + } return [certNameToSKD, certSDKToName]; } function parseMozFile() { - mozFile = readFile(MOZINPUT); + mozFile = stripComments(readFileToString(MOZINPUT)); mozJSON = JSON.parse(mozFile); return mozJSON; } @@ -221,8 +232,7 @@ function writeFile(certNameToSDK, certSDKToName, jsonPins) { FileUtils.closeSafeFileOutputStream(fos); - } - catch (e) { + } catch (e) { dump("ERROR: problem writing output to '" + OUTPUT + "': " + e + "\n"); } } diff --git a/security/manager/ssl/src/SSLServerCertVerification.cpp b/security/manager/ssl/src/SSLServerCertVerification.cpp index 4640c94bb5c4..125da53bc565 100644 --- a/security/manager/ssl/src/SSLServerCertVerification.cpp +++ b/security/manager/ssl/src/SSLServerCertVerification.cpp @@ -634,8 +634,9 @@ NSSDetermineCertOverrideErrors(CertVerifier& certVerifier, // possible failure. // XXX TODO: convert to VerifySSLServerCert // XXX TODO: get rid of error log - certVerifier.VerifyCert(cert, stapledOCSPResponse, certificateUsageSSLServer, - now, infoObject, 0, nullptr, nullptr, verify_log); + certVerifier.VerifyCert(cert, certificateUsageSSLServer, + now, infoObject, infoObject->GetHostNameRaw(), + 0, stapledOCSPResponse, nullptr, nullptr, verify_log); // Check the name field against the desired hostname. if (CERT_VerifyCertName(cert, infoObject->GetHostNameRaw()) != SECSuccess) { diff --git a/security/manager/ssl/src/SharedCertVerifier.h b/security/manager/ssl/src/SharedCertVerifier.h index 32a92a3eb68f..c7c193611f23 100644 --- a/security/manager/ssl/src/SharedCertVerifier.h +++ b/security/manager/ssl/src/SharedCertVerifier.h @@ -24,12 +24,14 @@ public: missing_cert_download_config ac, crl_download_config cdc, #endif ocsp_download_config odc, ocsp_strict_config osc, - ocsp_get_config ogc) + ocsp_get_config ogc, + pinning_enforcement_config pinningEnforcementLevel) : mozilla::psm::CertVerifier(ic, #ifndef NSS_NO_LIBPKIX ac, cdc, #endif - odc, osc, ogc) + odc, osc, ogc, + pinningEnforcementLevel) { } }; diff --git a/security/manager/ssl/src/nsCMS.cpp b/security/manager/ssl/src/nsCMS.cpp index 70a3c49dc32b..ee76c07fa9b0 100644 --- a/security/manager/ssl/src/nsCMS.cpp +++ b/security/manager/ssl/src/nsCMS.cpp @@ -264,9 +264,10 @@ nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, uint32_ NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); { - SECStatus srv = certVerifier->VerifyCert(si->cert, nullptr, + SECStatus srv = certVerifier->VerifyCert(si->cert, certificateUsageEmailSigner, - PR_Now(), nullptr /*XXX pinarg*/); + PR_Now(), nullptr /*XXX pinarg*/, + nullptr /*hostname*/); if (srv != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted now\n")); diff --git a/security/manager/ssl/src/nsNSSCertificate.cpp b/security/manager/ssl/src/nsNSSCertificate.cpp index 976691d43b76..85a24f4a256d 100644 --- a/security/manager/ssl/src/nsNSSCertificate.cpp +++ b/security/manager/ssl/src/nsNSSCertificate.cpp @@ -829,10 +829,12 @@ nsNSSCertificate::GetChain(nsIArray** _rvChain) // We want to test all usages, but we start with server because most of the // time Firefox users care about server certs. - certVerifier->VerifyCert(mCert.get(), nullptr, + certVerifier->VerifyCert(mCert.get(), certificateUsageSSLServer, PR_Now(), nullptr, /*XXX fixme*/ + nullptr, /* hostname */ CertVerifier::FLAG_LOCAL_ONLY, + nullptr, /* stapledOCSPResponse */ &nssChain); // This is the whitelist of all non-SSLServer usages that are supported by // verifycert. @@ -851,10 +853,12 @@ nsNSSCertificate::GetChain(nsIArray** _rvChain) PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("pipnss: PKIX attempting chain(%d) for '%s'\n", usage, mCert->nickname)); - certVerifier->VerifyCert(mCert.get(), nullptr, + certVerifier->VerifyCert(mCert.get(), usage, PR_Now(), nullptr, /*XXX fixme*/ + nullptr, /*hostname*/ CertVerifier::FLAG_LOCAL_ONLY, + nullptr, /* stapledOCSPResponse */ &nssChain); } @@ -1467,10 +1471,11 @@ nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV) uint32_t flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY | mozilla::psm::CertVerifier::FLAG_MUST_BE_EV; - SECStatus rv = certVerifier->VerifyCert(mCert.get(), nullptr, + SECStatus rv = certVerifier->VerifyCert(mCert.get(), certificateUsageSSLServer, PR_Now(), nullptr /* XXX pinarg */, - flags, nullptr, &resultOidTag); + nullptr /* hostname */, + flags, nullptr /* stapledOCSPResponse */ , nullptr, &resultOidTag); if (rv != SECSuccess) { resultOidTag = SEC_OID_UNKNOWN; diff --git a/security/manager/ssl/src/nsNSSCertificateDB.cpp b/security/manager/ssl/src/nsNSSCertificateDB.cpp index 40b03c1d673b..c9fd8bad6657 100644 --- a/security/manager/ssl/src/nsNSSCertificateDB.cpp +++ b/security/manager/ssl/src/nsNSSCertificateDB.cpp @@ -634,9 +634,10 @@ nsNSSCertificateDB::ImportEmailCertificate(uint8_t * data, uint32_t length, mozilla::pkix::ScopedCERTCertList certChain; - SECStatus rv = certVerifier->VerifyCert(node->cert, nullptr, + SECStatus rv = certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient, - now, ctx, 0, &certChain); + now, ctx, nullptr, 0, + nullptr, &certChain); if (rv != SECSuccess) { nsCOMPtr certToShow = nsNSSCertificate::Create(node->cert); @@ -801,9 +802,10 @@ nsNSSCertificateDB::ImportValidCACertsInList(CERTCertList *certList, nsIInterfac !CERT_LIST_END(node,certList); node = CERT_LIST_NEXT(node)) { mozilla::pkix::ScopedCERTCertList certChain; - SECStatus rv = certVerifier->VerifyCert(node->cert, nullptr, + SECStatus rv = certVerifier->VerifyCert(node->cert, certificateUsageVerifyCA, - PR_Now(), ctx, 0, &certChain); + PR_Now(), ctx, nullptr, 0, nullptr, + &certChain); if (rv != SECSuccess) { nsCOMPtr certToShow = nsNSSCertificate::Create(node->cert); DisplayCertificateAlert(ctx, "NotImportingUnverifiedCert", certToShow, proofOfLock); @@ -1381,9 +1383,10 @@ nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEma !CERT_LIST_END(node, certlist); node = CERT_LIST_NEXT(node)) { - SECStatus srv = certVerifier->VerifyCert(node->cert, nullptr, + SECStatus srv = certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient, - PR_Now(), nullptr /*XXX pinarg*/); + PR_Now(), nullptr /*XXX pinarg*/, + nullptr /*hostname*/); if (srv == SECSuccess) { break; } @@ -1772,10 +1775,12 @@ nsNSSCertificateDB::VerifyCertNow(nsIX509Cert* aCert, SECOidTag evOidPolicy; SECStatus srv; - srv = certVerifier->VerifyCert(nssCert, nullptr, + srv = certVerifier->VerifyCert(nssCert, aUsage, PR_Now(), nullptr, // Assume no context + nullptr, // hostname aFlags, + nullptr, // stapledOCSPResponse &resultChain, &evOidPolicy); diff --git a/security/manager/ssl/src/nsNSSComponent.cpp b/security/manager/ssl/src/nsNSSComponent.cpp index 97dc8eb9a5cf..226d5b4d3c10 100644 --- a/security/manager/ssl/src/nsNSSComponent.cpp +++ b/security/manager/ssl/src/nsNSSComponent.cpp @@ -994,6 +994,24 @@ void nsNSSComponent::setValidationOptions(bool isInitialSetting, } } + CertVerifier::pinning_enforcement_config + pinningEnforcementLevel = CertVerifier::pinningAllowUserCAMITM; + int prefPinningEnforcementLevel = Preferences::GetInt("security.cert_pinning.enforcement_level", + pinningEnforcementLevel); + switch (prefPinningEnforcementLevel) { + case 0: + pinningEnforcementLevel = CertVerifier::pinningDisabled; + break; + case 1: + pinningEnforcementLevel = CertVerifier::pinningAllowUserCAMITM; + break; + case 2: + pinningEnforcementLevel = CertVerifier::pinningStrict; + break; + default: + pinningEnforcementLevel = CertVerifier::pinningAllowUserCAMITM; + } + CertVerifier::ocsp_download_config odc; CertVerifier::ocsp_strict_config osc; CertVerifier::ocsp_get_config ogc; @@ -1007,7 +1025,7 @@ void nsNSSComponent::setValidationOptions(bool isInitialSetting, crlDownloading ? CertVerifier::crl_download_allowed : CertVerifier::crl_local_only, #endif - odc, osc, ogc); + odc, osc, ogc, pinningEnforcementLevel); // mozilla::pkix has its own OCSP cache, so disable the NSS cache // if appropriate. @@ -1630,7 +1648,8 @@ nsNSSComponent::Observe(nsISupports* aSubject, const char* aTopic, || prefName.Equals("security.OCSP.GET.enabled") || prefName.Equals("security.ssl.enable_ocsp_stapling") || prefName.Equals("security.use_mozillapkix_verification") - || prefName.Equals("security.use_libpkix_verification")) { + || prefName.Equals("security.use_libpkix_verification") + || prefName.Equals("security.cert_pinning.enforcement_level")) { MutexAutoLock lock(mutex); setValidationOptions(false, lock); } else if (prefName.Equals("network.ntlm.send-lm-response")) { diff --git a/security/manager/ssl/src/nsUsageArrayHelper.cpp b/security/manager/ssl/src/nsUsageArrayHelper.cpp index 7f7249f7543b..dd65ae57b977 100644 --- a/security/manager/ssl/src/nsUsageArrayHelper.cpp +++ b/security/manager/ssl/src/nsUsageArrayHelper.cpp @@ -105,8 +105,9 @@ nsUsageArrayHelper::check(uint32_t previousCheckResult, MOZ_CRASH("unknown cert usage passed to check()"); } - SECStatus rv = certVerifier->VerifyCert(mCert, nullptr, aCertUsage, - time, nullptr /*XXX:wincx*/, flags); + SECStatus rv = certVerifier->VerifyCert(mCert, aCertUsage, time, + nullptr /*XXX:wincx*/, + nullptr /*hostname*/, flags); if (rv == SECSuccess) { typestr.Append(suffix); diff --git a/security/manager/ssl/tests/unit/head_psm.js b/security/manager/ssl/tests/unit/head_psm.js index 4caf5a5d2ce4..e71b20b12660 100644 --- a/security/manager/ssl/tests/unit/head_psm.js +++ b/security/manager/ssl/tests/unit/head_psm.js @@ -51,6 +51,7 @@ const SEC_ERROR_OCSP_INVALID_SIGNING_CERT = SEC_ERROR_BASE + 144; const SEC_ERROR_POLICY_VALIDATION_FAILED = SEC_ERROR_BASE + 160; // -8032 const SEC_ERROR_OCSP_BAD_SIGNATURE = SEC_ERROR_BASE + 157; const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176; +const SEC_ERROR_APPLICATION_CALLBACK_ERROR = SEC_ERROR_BASE + 178; const SSL_ERROR_BAD_CERT_DOMAIN = SSL_ERROR_BASE + 12; diff --git a/security/manager/ssl/tests/unit/test_cert_overrides.js b/security/manager/ssl/tests/unit/test_cert_overrides.js index af3b519820b2..99b1b03d6680 100644 --- a/security/manager/ssl/tests/unit/test_cert_overrides.js +++ b/security/manager/ssl/tests/unit/test_cert_overrides.js @@ -230,7 +230,7 @@ function add_distrust_override_test(certFileName, hostName, let certToDistrust = constructCertFromFile(certFileName); add_test(function () { - // "pu" means the cert is actively distrusted. + // Add an entry to the NSS certDB that says to distrust the cert setCertTrust(certToDistrust, "pu,,"); clearSessionCache(); run_next_test(); diff --git a/security/manager/ssl/tests/unit/test_pinning.js b/security/manager/ssl/tests/unit/test_pinning.js new file mode 100644 index 000000000000..e70563ab9247 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_pinning.js @@ -0,0 +1,96 @@ +// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. +// +// For all cases, the acceptable pinset includes only certificates pinned to +// Test End Entity Cert (signed by issuer testCA). Other certificates +// are issued by otherCA, which is never in the pinset but is a user-specified +// trust anchor. This test covers multiple cases: +// +// Pinned domain include-subdomains.pinning.example.com includes subdomains +// - PASS: include-subdomains.pinning.example.com serves a correct cert +// - PASS: good.include-subdomains.pinning.example.com serves a correct cert +// - FAIL (strict): bad.include-subdomains.pinning.example.com serves a cert +// not in the pinset +// - PASS (mitm): bad.include-subdomains.pinning.example.com serves a cert not +// in the pinset, but issued by a user-specified trust domain +// +// Pinned domain exclude-subdomains.pinning.example.com excludes subdomains +// - PASS: exclude-subdomains.pinning.example.com serves a correct cert +// - FAIL: exclude-subdomains.pinning.example.com services an incorrect cert +// (TODO: test using verifyCertnow) +// - PASS: sub.exclude-subdomains.pinning.example.com serves an incorrect cert + +"use strict"; + +do_get_profile(); // must be called before getting nsIX509CertDB +const certdb = Cc["@mozilla.org/security/x509certdb;1"] + .getService(Ci.nsIX509CertDB); + +function test_strict() { + // In strict mode, we always evaluate pinning data, regardless of whether the + // issuer is a built-in trust anchor. + add_test(function() { + Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2); + run_next_test(); + }); + + // Issued by otherCA, which is not in the pinset for pinning.example.com. + add_connection_test("bad.include-subdomains.pinning.example.com", + getXPCOMStatusFromNSS(SEC_ERROR_APPLICATION_CALLBACK_ERROR)); + + // These domains serve certs that match the pinset. + add_connection_test("include-subdomains.pinning.example.com", Cr.NS_OK); + add_connection_test("good.include-subdomains.pinning.example.com", Cr.NS_OK); + add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK); + + // This domain serves a cert that doesn't match the pinset, but subdomains + // are excluded. + add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK); +}; + +function test_mitm() { + // In MITM mode, we allow pinning to pass if the chain resolves to any + // user-specified trust anchor, even if it is not in the pinset. + add_test(function() { + Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1); + run_next_test(); + }); + + add_connection_test("include-subdomains.pinning.example.com", Cr.NS_OK); + add_connection_test("good.include-subdomains.pinning.example.com", Cr.NS_OK); + + // In this case, even though otherCA is not in the pinset, it is a + // user-specified trust anchor and the pinning check succeeds. + add_connection_test("bad.include-subdomains.pinning.example.com", Cr.NS_OK); + + add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK); + add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK); +}; + +function test_disabled() { + // Disable pinning. + add_test(function() { + Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 0); + run_next_test(); + }); + + add_connection_test("include-subdomains.pinning.example.com", Cr.NS_OK); + add_connection_test("good.include-subdomains.pinning.example.com", Cr.NS_OK); + add_connection_test("bad.include-subdomains.pinning.example.com", Cr.NS_OK); + add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK); + add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK); +}; + +function run_test() { + add_tls_server_setup("BadCertServer"); + + // Add a user-specified trust anchor. + addCertFromFile(certdb, "tlsserver/other-test-ca.der", "CTu,u,u"); + + test_strict(); + test_mitm(); + test_disabled(); + run_next_test(); +} diff --git a/security/manager/ssl/tests/unit/tlsserver/cert8.db b/security/manager/ssl/tests/unit/tlsserver/cert8.db index 13c101f2a27d..7da5d7f0aeff 100644 Binary files a/security/manager/ssl/tests/unit/tlsserver/cert8.db and b/security/manager/ssl/tests/unit/tlsserver/cert8.db differ diff --git a/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp index a4c59a4c1a7d..5c220bbcc003 100644 --- a/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp +++ b/security/manager/ssl/tests/unit/tlsserver/cmd/BadCertServer.cpp @@ -24,6 +24,7 @@ struct BadCertHost const char *mCertName; }; +// Hostname, cert nickname pairs. const BadCertHost sBadCertHosts[] = { { "expired.example.com", "expired" }, @@ -42,6 +43,15 @@ const BadCertHost sBadCertHosts[] = { "inadequatekeyusage.example.com", "inadequatekeyusage" }, { "selfsigned-inadequateEKU.example.com", "selfsigned-inadequateEKU" }, { "self-signed-end-entity-with-cA-true.example.com", "self-signed-EE-with-cA-true" }, + // All of include-subdomains.pinning.example.com is pinned to End Entity Test + // Cert with nick localhostAndExampleCom. Any other nick will only pass + // pinning when security.cert_pinning.enforcement.level != strict and otherCA + // is added as a user-specified trust anchor. See StaticHPKPins.h. + { "include-subdomains.pinning.example.com", "localhostAndExampleCom" }, + { "good.include-subdomains.pinning.example.com", "localhostAndExampleCom" }, + { "bad.include-subdomains.pinning.example.com", "otherIssuerEE" }, + { "exclude-subdomains.pinning.example.com", "localhostAndExampleCom" }, + { "sub.exclude-subdomains.pinning.example.com", "otherIssuerEE" }, { nullptr, nullptr } }; diff --git a/security/manager/ssl/tests/unit/tlsserver/default-ee.der b/security/manager/ssl/tests/unit/tlsserver/default-ee.der index ac98037be14f..6874346226ed 100644 Binary files a/security/manager/ssl/tests/unit/tlsserver/default-ee.der and b/security/manager/ssl/tests/unit/tlsserver/default-ee.der differ diff --git a/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh b/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh index ef388bbdda77..549cd692cee9 100755 --- a/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh +++ b/security/manager/ssl/tests/unit/tlsserver/generate_certs.sh @@ -12,7 +12,10 @@ # # NB: This will cause the following files to be overwritten if they are in # the output directory: -# cert8.db, key3.db, secmod.db, ocsp-ca.der, ocsp-other-ca.der +# cert8.db, key3.db, secmod.db, ocsp-ca.der, ocsp-other-ca.der, default-ee.der +# NB: You must run genHPKPStaticPins.js after running this file, since its +# output (StaticHPKPins.h) depends on default-ee.der + set -x set -e @@ -25,11 +28,13 @@ OBJDIR=${1} OUTPUT_DIR=${2} RUN_MOZILLA="$OBJDIR/dist/bin/run-mozilla.sh" CERTUTIL="$OBJDIR/dist/bin/certutil" +# On BSD, mktemp requires either a template or a prefix. +MKTEMP="mktemp temp.XXXX" -NOISE_FILE=`mktemp` +NOISE_FILE=`$MKTEMP` # Make a good effort at putting something unique in the noise file. date +%s%N > "$NOISE_FILE" -PASSWORD_FILE=`mktemp` +PASSWORD_FILE=`$MKTEMP` function cleanup { rm -f "$NOISE_FILE" "$PASSWORD_FILE" @@ -134,7 +139,11 @@ function make_delegated { make_CA testCA 'CN=Test CA' test-ca.der make_CA otherCA 'CN=Other test CA' other-test-ca.der -make_EE localhostAndExampleCom 'CN=Test End-entity' testCA "localhost,*.example.com" + +make_EE localhostAndExampleCom 'CN=Test End-entity' testCA "localhost,*.example.com,*.pinning.example.com,*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com" +# Make an EE cert issued by otherCA +make_EE otherIssuerEE 'CN=Wrong CA Pin Test End-Entity' otherCA "*.include-subdomains.pinning.example.com,*.exclude-subdomains.pinning.example.com" + $RUN_MOZILLA $CERTUTIL -d $OUTPUT_DIR -L -n localhostAndExampleCom -r > $OUTPUT_DIR/default-ee.der # A cert that is like localhostAndExampleCom, but with a different serial number for # testing the "OCSP response is from the right issuer, but it is for the wrong cert" diff --git a/security/manager/ssl/tests/unit/tlsserver/key3.db b/security/manager/ssl/tests/unit/tlsserver/key3.db index 283e8fbf695d..2d4dd2947a9c 100644 Binary files a/security/manager/ssl/tests/unit/tlsserver/key3.db and b/security/manager/ssl/tests/unit/tlsserver/key3.db differ diff --git a/security/manager/ssl/tests/unit/tlsserver/other-test-ca.der b/security/manager/ssl/tests/unit/tlsserver/other-test-ca.der index 794fb9cec9b1..369e7acca831 100644 Binary files a/security/manager/ssl/tests/unit/tlsserver/other-test-ca.der and b/security/manager/ssl/tests/unit/tlsserver/other-test-ca.der differ diff --git a/security/manager/ssl/tests/unit/tlsserver/secmod.db b/security/manager/ssl/tests/unit/tlsserver/secmod.db index a5f2f603a728..7a0e2b57d29b 100644 Binary files a/security/manager/ssl/tests/unit/tlsserver/secmod.db and b/security/manager/ssl/tests/unit/tlsserver/secmod.db differ diff --git a/security/manager/ssl/tests/unit/tlsserver/test-ca.der b/security/manager/ssl/tests/unit/tlsserver/test-ca.der index f4c4863a5bba..7fc8feda6c62 100644 Binary files a/security/manager/ssl/tests/unit/tlsserver/test-ca.der and b/security/manager/ssl/tests/unit/tlsserver/test-ca.der differ diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini index 8e510dd53bdd..f66d3fa3d88d 100644 --- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -66,3 +66,7 @@ fail-if = os == "android" || buildapp == "b2g" # Bug 989485 : this test this fails on slow devices skip-if = os == "android" || (buildapp == "b2g" && processor == "arm") requesttimeoutfactor = 4 +[test_pinning.js] +run-sequentially = hardcoded ports +# Bug 676972: test fails consistently on Android and B2G +fail-if = os == "android" || buildapp == "b2g" diff --git a/security/pkix/include/pkix/pkixtypes.h b/security/pkix/include/pkix/pkixtypes.h index da00ad25e2c9..ee374b60bd37 100644 --- a/security/pkix/include/pkix/pkixtypes.h +++ b/security/pkix/include/pkix/pkixtypes.h @@ -100,6 +100,11 @@ public: PRTime time, /*optional*/ const SECItem* stapledOCSPresponse) = 0; + // Called as soon as we think we have a valid chain but before revocation + // checks are done. Called to compute additional chain level checks, by the + // TrustDomain. + virtual SECStatus IsChainValid(const CERTCertList* certChain) = 0; + protected: TrustDomain() { } diff --git a/security/pkix/lib/pkixbuild.cpp b/security/pkix/lib/pkixbuild.cpp index 1f7693b89334..d0d28c4c75b8 100644 --- a/security/pkix/lib/pkixbuild.cpp +++ b/security/pkix/lib/pkixbuild.cpp @@ -224,6 +224,30 @@ BuildForward(TrustDomain& trustDomain, } if (trustLevel == TrustDomain::TrustAnchor) { + ScopedCERTCertList certChain(CERT_NewCertList()); + if (!certChain) { + PR_SetError(SEC_ERROR_NO_MEMORY, 0); + return MapSECStatus(SECFailure); + } + + rv = subject.PrependNSSCertToList(certChain.get()); + if (rv != Success) { + return rv; + } + BackCert* child = subject.childCert; + while (child) { + rv = child->PrependNSSCertToList(certChain.get()); + if (rv != Success) { + return rv; + } + child = child->childCert; + } + + SECStatus srv = trustDomain.IsChainValid(certChain.get()); + if (srv != SECSuccess) { + return MapSECStatus(srv); + } + // End of the recursion. Create the result list and add the trust anchor to // it. results = CERT_NewCertList(); diff --git a/storage/src/mozStorageAsyncStatementExecution.cpp b/storage/src/mozStorageAsyncStatementExecution.cpp index f4c7660df679..ee8228accdaf 100644 --- a/storage/src/mozStorageAsyncStatementExecution.cpp +++ b/storage/src/mozStorageAsyncStatementExecution.cpp @@ -19,6 +19,7 @@ #include "mozStorageStatementData.h" #include "mozStorageAsyncStatementExecution.h" +#include "mozilla/DebugOnly.h" #include "mozilla/Telemetry.h" namespace mozilla { @@ -453,7 +454,9 @@ AsyncExecuteStatements::notifyComplete() } } else { - NS_WARN_IF(NS_FAILED(mConnection->rollbackTransactionInternal(mNativeConnection))); + DebugOnly rv = + mConnection->rollbackTransactionInternal(mNativeConnection); + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Transaction failed to rollback"); } mHasTransaction = false; } @@ -584,7 +587,6 @@ AsyncExecuteStatements::Run() return notifyComplete(); if (statementsNeedTransaction()) { - Connection* rawConnection = static_cast(mConnection.get()); if (NS_SUCCEEDED(mConnection->beginTransactionInternal(mNativeConnection, mozIStorageConnection::TRANSACTION_IMMEDIATE))) { mHasTransaction = true; diff --git a/storage/src/mozStorageAsyncStatementParams.cpp b/storage/src/mozStorageAsyncStatementParams.cpp index 7e7f19a7b64b..882f1d062b51 100644 --- a/storage/src/mozStorageAsyncStatementParams.cpp +++ b/storage/src/mozStorageAsyncStatementParams.cpp @@ -104,16 +104,15 @@ AsyncStatementParams::NewResolve( uint32_t idx = JSID_TO_INT(aId); // All indexes are good because we don't know how many parameters there // really are. - ok = ::JS_DefineElement(aCtx, scopeObj, idx, JSVAL_VOID, nullptr, - nullptr, 0); + ok = ::JS_DefineElement(aCtx, scopeObj, idx, JS::UndefinedHandleValue, 0); resolved = true; } else if (JSID_IS_STRING(aId)) { // We are unable to tell if there's a parameter with this name and so // we must assume that there is. This screws the rest of the prototype // chain, but people really shouldn't be depending on this anyways. - ok = ::JS_DefinePropertyById(aCtx, scopeObj, aId, JSVAL_VOID, nullptr, - nullptr, 0); + JS::Rooted id(aCtx, aId); + ok = ::JS_DefinePropertyById(aCtx, scopeObj, id, JS::UndefinedHandleValue, 0); resolved = true; } diff --git a/storage/src/mozStorageStatementParams.cpp b/storage/src/mozStorageStatementParams.cpp index 6344b05a685b..d661733323aa 100644 --- a/storage/src/mozStorageStatementParams.cpp +++ b/storage/src/mozStorageStatementParams.cpp @@ -177,8 +177,7 @@ StatementParams::NewResolve(nsIXPConnectWrappedNative *aWrapper, if (idx >= mParamCount) return NS_ERROR_INVALID_ARG; - ok = ::JS_DefineElement(aCtx, scope, idx, JSVAL_VOID, nullptr, - nullptr, JSPROP_ENUMERATE); + ok = ::JS_DefineElement(aCtx, scope, idx, JS::UndefinedHandleValue, JSPROP_ENUMERATE); resolved = true; } else if (JSID_IS_STRING(id)) { @@ -193,8 +192,7 @@ StatementParams::NewResolve(nsIXPConnectWrappedNative *aWrapper, uint32_t idx; nsresult rv = mStatement->GetParameterIndex(name, &idx); if (NS_SUCCEEDED(rv)) { - ok = ::JS_DefinePropertyById(aCtx, scope, id, JSVAL_VOID, nullptr, - nullptr, JSPROP_ENUMERATE); + ok = ::JS_DefinePropertyById(aCtx, scope, id, JS::UndefinedHandleValue, JSPROP_ENUMERATE); resolved = true; } } diff --git a/storage/src/mozStorageStatementRow.cpp b/storage/src/mozStorageStatementRow.cpp index 77433a4bfe81..935b9d269062 100644 --- a/storage/src/mozStorageStatementRow.cpp +++ b/storage/src/mozStorageStatementRow.cpp @@ -141,8 +141,8 @@ StatementRow::NewResolve(nsIXPConnectWrappedNative *aWrapper, return NS_OK; } - *_retval = ::JS_DefinePropertyById(aCtx, scopeObj, aId, JSVAL_VOID, - nullptr, nullptr, 0); + JS::Rooted id(aCtx, aId); + *_retval = ::JS_DefinePropertyById(aCtx, scopeObj, id, JS::UndefinedHandleValue, 0); *_objp = scopeObj; return NS_OK; } diff --git a/testing/marionette/client/marionette/__init__.py b/testing/marionette/client/marionette/__init__.py index fabb1d04220e..a4e35abc976b 100644 --- a/testing/marionette/client/marionette/__init__.py +++ b/testing/marionette/client/marionette/__init__.py @@ -2,13 +2,25 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from gestures import * +from gestures import smooth_scroll, pinch from by import By from marionette import Marionette, HTMLElement, Actions, MultiActions from marionette_test import MarionetteTestCase, MarionetteJSTestCase, CommonTestCase, expectedFailure, skip, SkipTest from emulator import Emulator -from errors import * -from runner import * +from errors import ( + ErrorCodes, MarionetteException, InstallGeckoError, TimeoutException, InvalidResponseException, + JavascriptException, NoSuchElementException, XPathLookupException, NoSuchWindowException, + StaleElementException, ScriptTimeoutException, ElementNotVisibleException, + NoSuchFrameException, InvalidElementStateException, NoAlertPresentException, + InvalidCookieDomainException, UnableToSetCookieException, InvalidSelectorException, + MoveTargetOutOfBoundsException, FrameSendNotInitializedError, FrameSendFailureError + ) +from runner import ( + B2GTestCaseMixin, B2GTestResultMixin, BaseMarionetteOptions, BaseMarionetteTestRunner, EnduranceOptionsMixin, + EnduranceTestCaseMixin, HTMLReportingOptionsMixin, HTMLReportingTestResultMixin, HTMLReportingTestRunnerMixin, + Marionette, MarionetteTest, MarionetteTestResult, MarionetteTextTestRunner, MemoryEnduranceTestCaseMixin, + MozHttpd, OptionParser, TestManifest, TestResult, TestResultCollection + ) from wait import Wait from date_time_value import DateTimeValue import decorators diff --git a/testing/marionette/client/marionette/marionette.py b/testing/marionette/client/marionette/marionette.py index ae06ad330ce9..8ca36972f115 100644 --- a/testing/marionette/client/marionette/marionette.py +++ b/testing/marionette/client/marionette/marionette.py @@ -14,7 +14,14 @@ from application_cache import ApplicationCache from decorators import do_crash_check from emulator import Emulator from emulator_screen import EmulatorScreen -from errors import * +from errors import ( + ErrorCodes, MarionetteException, InstallGeckoError, TimeoutException, InvalidResponseException, + JavascriptException, NoSuchElementException, XPathLookupException, NoSuchWindowException, + StaleElementException, ScriptTimeoutException, ElementNotVisibleException, + NoSuchFrameException, InvalidElementStateException, NoAlertPresentException, + InvalidCookieDomainException, UnableToSetCookieException, InvalidSelectorException, + MoveTargetOutOfBoundsException, FrameSendNotInitializedError, FrameSendFailureError + ) from keys import Keys from marionette_transport import MarionetteTransport diff --git a/testing/marionette/client/marionette/marionette_test.py b/testing/marionette/client/marionette/marionette_test.py index 6c4a2aeedefd..80c9008a9aca 100644 --- a/testing/marionette/client/marionette/marionette_test.py +++ b/testing/marionette/client/marionette/marionette_test.py @@ -14,7 +14,14 @@ import unittest import weakref import warnings -from errors import * +from errors import ( + ErrorCodes, MarionetteException, InstallGeckoError, TimeoutException, InvalidResponseException, + JavascriptException, NoSuchElementException, XPathLookupException, NoSuchWindowException, + StaleElementException, ScriptTimeoutException, ElementNotVisibleException, + NoSuchFrameException, InvalidElementStateException, NoAlertPresentException, + InvalidCookieDomainException, UnableToSetCookieException, InvalidSelectorException, + MoveTargetOutOfBoundsException, FrameSendNotInitializedError, FrameSendFailureError + ) from marionette import Marionette class SkipTest(Exception): diff --git a/testing/marionette/client/marionette/runner/__init__.py b/testing/marionette/client/marionette/runner/__init__.py index ee34308330d4..c0ba0a7d487a 100644 --- a/testing/marionette/client/marionette/runner/__init__.py +++ b/testing/marionette/client/marionette/runner/__init__.py @@ -2,5 +2,13 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from base import * -from mixins import * +from base import ( + B2GTestResultMixin, BaseMarionetteOptions, BaseMarionetteTestRunner, + Marionette, MarionetteTest, MarionetteTestResult, MarionetteTextTestRunner, + MozHttpd, OptionParser, TestManifest, TestResult, TestResultCollection + ) +from mixins import ( + B2GTestCaseMixin, B2GTestResultMixin, EnduranceOptionsMixin, + EnduranceTestCaseMixin, HTMLReportingOptionsMixin, HTMLReportingTestResultMixin, + HTMLReportingTestRunnerMixin, MemoryEnduranceTestCaseMixin + ) diff --git a/testing/marionette/client/marionette/runner/mixins/__init__.py b/testing/marionette/client/marionette/runner/mixins/__init__.py index a3d8714c1f0b..6c69c65851b5 100644 --- a/testing/marionette/client/marionette/runner/mixins/__init__.py +++ b/testing/marionette/client/marionette/runner/mixins/__init__.py @@ -2,6 +2,11 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from endurance import * -from reporting import * -from b2g import * +from endurance import ( + EnduranceOptionsMixin, EnduranceTestCaseMixin, MemoryEnduranceTestCaseMixin + ) +from reporting import ( + HTMLReportingOptionsMixin, HTMLReportingTestResultMixin, + HTMLReportingTestRunnerMixin + ) +from b2g import B2GTestCaseMixin, B2GTestResultMixin diff --git a/testing/marionette/client/marionette/tests/unit/test_single_finger.py b/testing/marionette/client/marionette/tests/unit/test_single_finger.py index 4897f06b28cd..98db76b2d6fb 100644 --- a/testing/marionette/client/marionette/tests/unit/test_single_finger.py +++ b/testing/marionette/client/marionette/tests/unit/test_single_finger.py @@ -9,7 +9,12 @@ from marionette import MarionetteException import os import sys sys.path.append(os.path.dirname(__file__)) -from single_finger_functions import * +from single_finger_functions import ( + chain, chain_flick, context_menu, double_tap, long_press_action, + move_element, move_element_offset, press_release, single_tap, wait, + wait_with_value + ) + class testSingleFinger(MarionetteTestCase): def test_press_release(self): diff --git a/testing/marionette/client/marionette/tests/unit/test_single_finger_desktop.py b/testing/marionette/client/marionette/tests/unit/test_single_finger_desktop.py index e45c45fa761a..35404d592940 100644 --- a/testing/marionette/client/marionette/tests/unit/test_single_finger_desktop.py +++ b/testing/marionette/client/marionette/tests/unit/test_single_finger_desktop.py @@ -5,7 +5,11 @@ from marionette import MarionetteException import os import sys sys.path.append(os.path.dirname(__file__)) -from single_finger_functions import * +from single_finger_functions import ( + chain, chain_flick, context_menu, double_tap, long_press_action, + move_element, move_element_offset, press_release, single_tap, wait, + wait_with_value + ) class testSingleFingerMouse(MarionetteTestCase): def setUp(self): diff --git a/testing/marionette/client/marionette/tests/unit/test_switch_remote_frame.py b/testing/marionette/client/marionette/tests/unit/test_switch_remote_frame.py index 64d6a8bd1f73..0c2fb6cddffe 100644 --- a/testing/marionette/client/marionette/tests/unit/test_switch_remote_frame.py +++ b/testing/marionette/client/marionette/tests/unit/test_switch_remote_frame.py @@ -79,6 +79,36 @@ class TestSwitchRemoteFrame(MarionetteTestCase): """) self.assertFalse(main_process) + def test_we_can_switch_to_a_remote_frame_by_index(self): + # test if we can revisit a remote frame (this takes a different codepath) + self.marionette.navigate(self.marionette.absolute_url("test.html")) + self.marionette.execute_script("SpecialPowers.addPermission('browser', true, document)") + self.marionette.execute_script(""" + let iframe = document.createElement("iframe"); + SpecialPowers.wrap(iframe).mozbrowser = true; + SpecialPowers.wrap(iframe).remote = true; + iframe.id = "remote_iframe"; + iframe.style.height = "100px"; + iframe.style.width = "100%%"; + iframe.src = "%s"; + document.body.appendChild(iframe); + """ % self.marionette.absolute_url("test.html")) + self.marionette.switch_to_frame(0) + main_process = self.marionette.execute_script(""" + return SpecialPowers.isMainProcess(); + """) + self.assertFalse(main_process) + self.marionette.switch_to_frame() + main_process = self.marionette.execute_script(""" + return SpecialPowers.isMainProcess(); + """) + self.assertTrue(main_process) + self.marionette.switch_to_frame(0) + main_process = self.marionette.execute_script(""" + return SpecialPowers.isMainProcess(); + """) + self.assertFalse(main_process) + def tearDown(self): if self.oop_by_default is None: self.marionette.execute_script(""" diff --git a/testing/marionette/client/marionette/tests/unit/unit-tests.ini b/testing/marionette/client/marionette/tests/unit/unit-tests.ini index fcbcc9f46f2c..1bf4c06ba7ac 100644 --- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini +++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini @@ -85,7 +85,6 @@ browser = false [test_switch_frame.py] [test_switch_frame_chrome.py] [test_switch_remote_frame.py] -browser = false [test_pagesource.py] b2g = false diff --git a/testing/marionette/marionette-listener.js b/testing/marionette/marionette-listener.js index cf52b184c308..0527f6a8439f 100644 --- a/testing/marionette/marionette-listener.js +++ b/testing/marionette/marionette-listener.js @@ -116,7 +116,7 @@ function emitTouchEventForIFrame(message) { let message = message.json; let frames = curFrame.document.getElementsByTagName("iframe"); let iframe = frames[message.index]; - let identifier = touchId = nextTouchId++; + let identifier = nextTouchId; let tabParent = iframe.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.tabParent; tabParent.injectTouchEvent(message.type, [identifier], [message.clientX], [message.clientY], @@ -1871,9 +1871,18 @@ function switchToFrame(msg) { } if (foundFrame == null) { if (typeof(msg.json.id) === 'number') { - foundFrame = frames[msg.json.id].frameElement; - curFrame = foundFrame; - foundFrame = elementManager.addToKnownElements(curFrame); + try { + foundFrame = frames[msg.json.id].frameElement; + curFrame = foundFrame; + foundFrame = elementManager.addToKnownElements(curFrame); + } catch (e) { + // Since window.frames does not return OOP frames it will throw + // and we land up here. Let's not give up and check if there are + // iframes and switch to the indexed frame there + let iframes = curFrame.document.getElementsByTagName("iframe"); + curFrame = iframes[msg.json.id]; + foundFrame = msg.json.id + } } } if (foundFrame == null) { diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js index 1c9f3b4e8115..ff5e96594d76 100644 --- a/testing/specialpowers/content/specialpowersAPI.js +++ b/testing/specialpowers/content/specialpowersAPI.js @@ -802,9 +802,7 @@ SpecialPowersAPI.prototype = { if (aTopic == "perm-changed") { var permission = aSubject.QueryInterface(Ci.nsIPermission); if (permission.type == this._lastPermission.type) { - var os = Components.classes["@mozilla.org/observer-service;1"] - .getService(Components.interfaces.nsIObserverService); - os.removeObserver(this, "perm-changed"); + Services.obs.removeObserver(this, "perm-changed"); content.window.setTimeout(this._callback, 0); content.window.setTimeout(this._nextCallback, 0); } @@ -829,7 +827,6 @@ SpecialPowersAPI.prototype = { var lastPermission = pendingActions[pendingActions.length-1]; var self = this; - var os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); this._permissionObserver._lastPermission = lastPermission; this._permissionObserver._callback = callback; this._permissionObserver._nextCallback = function () { @@ -838,7 +835,7 @@ SpecialPowersAPI.prototype = { self._applyPermissions(); } - os.addObserver(this._permissionObserver, "perm-changed", false); + Services.obs.addObserver(this._permissionObserver, "perm-changed", false); for (var idx in pendingActions) { var perm = pendingActions[idx]; @@ -876,8 +873,7 @@ SpecialPowersAPI.prototype = { * */ pushPrefEnv: function(inPrefs, callback) { - var prefs = Components.classes["@mozilla.org/preferences-service;1"]. - getService(Components.interfaces.nsIPrefBranch); + var prefs = Services.prefs; var pref_string = []; pref_string[prefs.PREF_INT] = "INT"; @@ -997,7 +993,7 @@ SpecialPowersAPI.prototype = { var lastPref = pendingActions[pendingActions.length-1]; - var pb = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch); + var pb = Services.prefs; var self = this; pb.addObserver(lastPref.name, function prefObs(subject, topic, data) { pb.removeObserver(lastPref.name, prefObs); @@ -1068,20 +1064,14 @@ SpecialPowersAPI.prototype = { this._addObserverProxy(notification); if (typeof obs == 'object' && obs.observe.name != 'SpecialPowersCallbackWrapper') obs.observe = wrapCallback(obs.observe); - var obsvc = Cc['@mozilla.org/observer-service;1'] - .getService(Ci.nsIObserverService); - obsvc.addObserver(obs, notification, weak); + Services.obs.addObserver(obs, notification, weak); }, removeObserver: function(obs, notification) { this._removeObserverProxy(notification); - var obsvc = Cc['@mozilla.org/observer-service;1'] - .getService(Ci.nsIObserverService); - obsvc.removeObserver(obs, notification); + Services.obs.removeObserver(obs, notification); }, notifyObservers: function(subject, topic, data) { - var obsvc = Cc['@mozilla.org/observer-service;1'] - .getService(Ci.nsIObserverService); - obsvc.notifyObservers(subject, topic, data); + Services.obs.notifyObservers(subject, topic, data); }, can_QI: function(obj) { @@ -1418,8 +1408,7 @@ SpecialPowersAPI.prototype = { }, getDOMRequestService: function() { - var serv = Cc["@mozilla.org/dom/dom-request-service;1"]. - getService(Ci.nsIDOMRequestService); + var serv = Services.DOMRequest; var res = { __exposedProps__: {} }; var props = ["createRequest", "createCursor", "fireError", "fireSuccess", "fireDone", "fireDetailedError"]; @@ -1607,16 +1596,13 @@ SpecialPowersAPI.prototype = { }, setFullscreenAllowed: function(document) { - var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager); - pm.addFromPrincipal(document.nodePrincipal, "fullscreen", Ci.nsIPermissionManager.ALLOW_ACTION); - var obsvc = Cc['@mozilla.org/observer-service;1'] - .getService(Ci.nsIObserverService); - obsvc.notifyObservers(document, "fullscreen-approved", null); + Services.perms.addFromPrincipal(document.nodePrincipal, "fullscreen", + Ci.nsIPermissionManager.ALLOW_ACTION); + Services.obs.notifyObservers(document, "fullscreen-approved", null); }, removeFullscreenAllowed: function(document) { - var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager); - pm.removeFromPrincipal(document.nodePrincipal, "fullscreen"); + Services.perms.removeFromPrincipal(document.nodePrincipal, "fullscreen"); }, _getInfoFromPermissionArg: function(arg) { diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index 3765e37468f1..63ca50f0f872 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -20,7 +20,6 @@ #include "nsDownloadManager.h" #include "DownloadPlatform.h" #include "nsDownloadProxy.h" -#include "nsCharsetMenu.h" #include "rdf.h" #include "nsTypeAheadFind.h" @@ -111,7 +110,6 @@ NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERSTREAMUPDATER_CID); NS_DEFINE_NAMED_CID(NS_URLCLASSIFIERUTILS_CID); #endif NS_DEFINE_NAMED_CID(NS_BROWSERSTATUSFILTER_CID); -NS_DEFINE_NAMED_CID(NS_CHARSETMENU_CID); #if defined(USE_MOZ_UPDATER) NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_CID); #endif @@ -138,7 +136,6 @@ static const Module::CIDEntry kToolkitCIDs[] = { { &kNS_URLCLASSIFIERUTILS_CID, false, nullptr, nsUrlClassifierUtilsConstructor }, #endif { &kNS_BROWSERSTATUSFILTER_CID, false, nullptr, nsBrowserStatusFilterConstructor }, - { &kNS_CHARSETMENU_CID, false, nullptr, NS_NewCharsetMenu }, #if defined(USE_MOZ_UPDATER) { &kNS_UPDATEPROCESSOR_CID, false, nullptr, nsUpdateProcessorConstructor }, #endif @@ -168,7 +165,6 @@ static const Module::ContractIDEntry kToolkitContracts[] = { { NS_URLCLASSIFIERUTILS_CONTRACTID, &kNS_URLCLASSIFIERUTILS_CID }, #endif { NS_BROWSERSTATUSFILTER_CONTRACTID, &kNS_BROWSERSTATUSFILTER_CID }, - { NS_RDF_DATASOURCE_CONTRACTID_PREFIX NS_CHARSETMENU_PID, &kNS_CHARSETMENU_CID }, #if defined(USE_MOZ_UPDATER) { NS_UPDATEPROCESSOR_CONTRACTID, &kNS_UPDATEPROCESSOR_CID }, #endif diff --git a/toolkit/components/intl/moz.build b/toolkit/components/intl/moz.build deleted file mode 100644 index 34a4c18193e2..000000000000 --- a/toolkit/components/intl/moz.build +++ /dev/null @@ -1,11 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -SOURCES += [ - 'nsCharsetMenu.cpp', -] - -FINAL_LIBRARY = 'toolkitcomps' diff --git a/toolkit/components/intl/nsCharsetMenu.cpp b/toolkit/components/intl/nsCharsetMenu.cpp deleted file mode 100644 index 647307d95ee9..000000000000 --- a/toolkit/components/intl/nsCharsetMenu.cpp +++ /dev/null @@ -1,1797 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIServiceManager.h" -#include "nsIComponentManager.h" -#include "rdf.h" -#include "nsIRDFDataSource.h" -#include "nsIRDFService.h" -#include "nsIRDFContainerUtils.h" -#include "nsRDFCID.h" -#include "nsXPIDLString.h" -#include "nsCharsetMenu.h" -#include "nsICharsetConverterManager.h" -#include "nsICollation.h" -#include "nsCollationCID.h" -#include "nsILocaleService.h" -#include "nsIPrefService.h" -#include "nsIPrefBranch.h" -#include "nsIPrefLocalizedString.h" -#include "nsICurrentCharsetListener.h" -#include "nsQuickSort.h" -#include "nsIObserver.h" -#include "nsStringEnumerator.h" -#include "nsTArray.h" -#include "nsIObserverService.h" -#include "nsIRequestObserver.h" -#include "nsCRT.h" -#include "prmem.h" -#include "mozilla/ModuleUtils.h" -#include "nsCycleCollectionParticipant.h" - -//---------------------------------------------------------------------------- -// Global functions and data [declaration] - -static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); -static NS_DEFINE_CID(kRDFInMemoryDataSourceCID, NS_RDFINMEMORYDATASOURCE_CID); -static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); -static NS_DEFINE_CID(kRDFContainerCID, NS_RDFCONTAINER_CID); - -static const char kURINC_BrowserAutodetMenuRoot[] = "NC:BrowserAutodetMenuRoot"; -static const char kURINC_BrowserCharsetMenuRoot[] = "NC:BrowserCharsetMenuRoot"; -static const char kURINC_BrowserMoreCharsetMenuRoot[] = "NC:BrowserMoreCharsetMenuRoot"; -static const char kURINC_BrowserMore1CharsetMenuRoot[] = "NC:BrowserMore1CharsetMenuRoot"; -static const char kURINC_BrowserMore2CharsetMenuRoot[] = "NC:BrowserMore2CharsetMenuRoot"; -static const char kURINC_BrowserMore3CharsetMenuRoot[] = "NC:BrowserMore3CharsetMenuRoot"; -static const char kURINC_BrowserMore4CharsetMenuRoot[] = "NC:BrowserMore4CharsetMenuRoot"; -static const char kURINC_BrowserMore5CharsetMenuRoot[] = "NC:BrowserMore5CharsetMenuRoot"; -static const char kURINC_MaileditCharsetMenuRoot[] = "NC:MaileditCharsetMenuRoot"; -static const char kURINC_MailviewCharsetMenuRoot[] = "NC:MailviewCharsetMenuRoot"; -static const char kURINC_ComposerCharsetMenuRoot[] = "NC:ComposerCharsetMenuRoot"; -static const char kURINC_DecodersRoot[] = "NC:DecodersRoot"; -static const char kURINC_EncodersRoot[] = "NC:EncodersRoot"; -DEFINE_RDF_VOCAB(NC_NAMESPACE_URI, NC, Name); -DEFINE_RDF_VOCAB(NC_NAMESPACE_URI, NC, BookmarkSeparator); -DEFINE_RDF_VOCAB(NC_NAMESPACE_URI, NC, CharsetDetector); -DEFINE_RDF_VOCAB(RDF_NAMESPACE_URI, NC, type); - -// Note here that browser and mailview have the same static area and cache -// size but the cache itself is separate. - -#define kBrowserStaticPrefKey "intl.charsetmenu.browser.static" -#define kBrowserCachePrefKey "intl.charsetmenu.browser.cache" -#define kBrowserCacheSizePrefKey "intl.charsetmenu.browser.cache.size" - -#define kMailviewStaticPrefKey "intl.charsetmenu.browser.static" -#define kMailviewCachePrefKey "intl.charsetmenu.mailview.cache" -#define kMailviewCacheSizePrefKey "intl.charsetmenu.browser.cache.size" - -#define kComposerStaticPrefKey "intl.charsetmenu.browser.static" -#define kComposerCachePrefKey "intl.charsetmenu.composer.cache" -#define kComposerCacheSizePrefKey "intl.charsetmenu.browser.cache.size" - -#define kMaileditPrefKey "intl.charsetmenu.mailedit" - -//---------------------------------------------------------------------------- -// Class nsMenuEntry [declaration] - -/** - * A little class holding all data needed for a menu item. - * - * @created 18/Apr/2000 - * @author Catalin Rotaru [CATA] - */ -class nsMenuEntry -{ -public: - // memory & ref counting & leak prevention stuff - nsMenuEntry() { MOZ_COUNT_CTOR(nsMenuEntry); } - ~nsMenuEntry() { MOZ_COUNT_DTOR(nsMenuEntry); } - - nsAutoCString mCharset; - nsAutoString mTitle; -}; - -//---------------------------------------------------------------------------- -// Class nsCharsetMenu [declaration] - -/** - * The Charset Converter menu. - * - * God, our GUI programming disgusts me. - * - * @created 23/Nov/1999 - * @author Catalin Rotaru [CATA] - */ -class nsCharsetMenu : public nsIRDFDataSource, public nsICurrentCharsetListener -{ - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsCharsetMenu, nsIRDFDataSource) - -private: - static nsIRDFResource * kNC_BrowserAutodetMenuRoot; - static nsIRDFResource * kNC_BrowserCharsetMenuRoot; - static nsIRDFResource * kNC_BrowserMoreCharsetMenuRoot; - static nsIRDFResource * kNC_BrowserMore1CharsetMenuRoot; - static nsIRDFResource * kNC_BrowserMore2CharsetMenuRoot; - static nsIRDFResource * kNC_BrowserMore3CharsetMenuRoot; - static nsIRDFResource * kNC_BrowserMore4CharsetMenuRoot; - static nsIRDFResource * kNC_BrowserMore5CharsetMenuRoot; - static nsIRDFResource * kNC_MaileditCharsetMenuRoot; - static nsIRDFResource * kNC_MailviewCharsetMenuRoot; - static nsIRDFResource * kNC_ComposerCharsetMenuRoot; - static nsIRDFResource * kNC_DecodersRoot; - static nsIRDFResource * kNC_EncodersRoot; - static nsIRDFResource * kNC_Name; - static nsIRDFResource * kNC_CharsetDetector; - static nsIRDFResource * kNC_BookmarkSeparator; - static nsIRDFResource * kRDF_type; - - static nsIRDFDataSource * mInner; - - bool mInitialized; - bool mMailviewMenuInitialized; - bool mComposerMenuInitialized; - bool mMaileditMenuInitialized; - bool mSecondaryTiersInitialized; - bool mAutoDetectInitialized; - bool mOthersInitialized; - - nsTArray mMailviewMenu; - int32_t mMailviewCacheStart; - int32_t mMailviewCacheSize; - int32_t mMailviewMenuRDFPosition; - - nsTArray mComposerMenu; - int32_t mComposerCacheStart; - int32_t mComposerCacheSize; - int32_t mComposerMenuRDFPosition; - - nsCOMPtr mRDFService; - nsCOMPtr mCCManager; - nsCOMPtr mPrefs; - nsCOMPtr mCharsetMenuObserver; - nsTArray mDecoderList; - - nsresult Done(); - - nsresult FreeResources(); - - nsresult InitStaticMenu(nsTArray& aDecs, - nsIRDFResource * aResource, - const char * aKey, - nsTArray * aArray); - nsresult InitCacheMenu(nsTArray& aDecs, - nsIRDFResource * aResource, - const char * aKey, - nsTArray * aArray); - - nsresult InitMoreMenu(nsTArray& aDecs, - nsIRDFResource * aResource, - const char * aFlag); - - nsresult InitMoreSubmenus(nsTArray& aDecs); - - static nsresult SetArrayFromEnumerator(nsIUTF8StringEnumerator* aEnumerator, - nsTArray& aArray); - - nsresult AddCharsetToItemArray(nsTArray* aArray, - const nsAFlatCString& aCharset, - nsMenuEntry ** aResult, - int32_t aPlace); - nsresult AddCharsetArrayToItemArray(nsTArray &aArray, - const nsTArray& aCharsets); - nsresult AddMenuItemToContainer(nsIRDFContainer * aContainer, - nsMenuEntry * aItem, nsIRDFResource * aType, const char * aIDPrefix, - int32_t aPlace); - nsresult AddMenuItemArrayToContainer(nsIRDFContainer * aContainer, - nsTArray * aArray, nsIRDFResource * aType); - nsresult AddCharsetToContainer(nsTArray * aArray, - nsIRDFContainer * aContainer, - const nsAFlatCString& aCharset, - const char * aIDPrefix, - int32_t aPlace, int32_t aRDFPlace); - - nsresult AddFromPrefsToMenu(nsTArray * aArray, - nsIRDFContainer * aContainer, - const char * aKey, - nsTArray& aDecs, - const char * aIDPrefix); - nsresult AddFromNolocPrefsToMenu(nsTArray * aArray, - nsIRDFContainer * aContainer, - const char * aKey, - nsTArray& aDecs, - const char * aIDPrefix); - nsresult AddFromStringToMenu(char * aCharsetList, - nsTArray * aArray, - nsIRDFContainer * aContainer, - nsTArray& aDecs, - const char * aIDPrefix); - - nsresult AddSeparatorToContainer(nsIRDFContainer * aContainer); - nsresult AddCharsetToCache(const nsAFlatCString& aCharset, - nsTArray * aArray, - nsIRDFResource * aRDFResource, - uint32_t aCacheStart, uint32_t aCacheSize, - int32_t aRDFPlace); - - nsresult WriteCacheToPrefs(nsTArray * aArray, int32_t aCacheStart, - const char * aKey); - nsresult UpdateCachePrefs(const char * aCacheKey, const char * aCacheSizeKey, - const char * aStaticKey, const char16_t * aCharset); - - nsresult ClearMenu(nsIRDFContainer * aContainer, nsTArray * aArray); - nsresult RemoveLastMenuItem(nsIRDFContainer * aContainer, - nsTArray * aArray); - - nsresult RemoveFlaggedCharsets(nsTArray& aList, const nsString& aProp); - nsresult NewRDFContainer(nsIRDFDataSource * aDataSource, - nsIRDFResource * aResource, nsIRDFContainer ** aResult); - void FreeMenuItemArray(nsTArray * aArray); - int32_t FindMenuItemInArray(const nsTArray* aArray, - const nsAFlatCString& aCharset, - nsMenuEntry ** aResult); - nsresult ReorderMenuItemArray(nsTArray * aArray); - nsresult GetCollation(nsICollation ** aCollation); - -public: - nsCharsetMenu(); - virtual ~nsCharsetMenu(); - - nsresult Init(); - nsresult InitMaileditMenu(); - nsresult InitMailviewMenu(); - nsresult InitComposerMenu(); - nsresult InitOthers(); - nsresult InitSecondaryTiers(); - nsresult InitAutodetMenu(); - nsresult RefreshMailviewMenu(); - nsresult RefreshMaileditMenu(); - nsresult RefreshComposerMenu(); - - //-------------------------------------------------------------------------- - // Interface nsICurrentCharsetListener [declaration] - - NS_IMETHOD SetCurrentCharset(const char16_t * aCharset); - NS_IMETHOD SetCurrentMailCharset(const char16_t * aCharset); - NS_IMETHOD SetCurrentComposerCharset(const char16_t * aCharset); - - //-------------------------------------------------------------------------- - // Interface nsIRDFDataSource [declaration] - - NS_DECL_NSIRDFDATASOURCE -}; - -//---------------------------------------------------------------------------- -// Global functions and data [implementation] - -nsresult -NS_NewCharsetMenu(nsISupports * aOuter, const nsIID & aIID, - void ** aResult) -{ - if (!aResult) { - return NS_ERROR_NULL_POINTER; - } - if (aOuter) { - *aResult = nullptr; - return NS_ERROR_NO_AGGREGATION; - } - nsCharsetMenu* inst = new nsCharsetMenu(); - if (!inst) { - *aResult = nullptr; - return NS_ERROR_OUT_OF_MEMORY; - } - nsresult res = inst->QueryInterface(aIID, aResult); - if (NS_FAILED(res)) { - *aResult = nullptr; - delete inst; - } - return res; -} - -struct charsetMenuSortRecord { - nsMenuEntry* item; - uint8_t* key; - uint32_t len; - -}; - -static int CompareMenuItems(const void* aArg1, const void* aArg2, void *data) -{ - int32_t res; - nsICollation * collation = (nsICollation *) data; - charsetMenuSortRecord *rec1 = (charsetMenuSortRecord *) aArg1; - charsetMenuSortRecord *rec2 = (charsetMenuSortRecord *) aArg2; - - collation->CompareRawSortKey(rec1->key, rec1->len, rec2->key, rec2->len, &res); - - return res; -} - -nsresult -nsCharsetMenu::SetArrayFromEnumerator(nsIUTF8StringEnumerator* aEnumerator, - nsTArray& aArray) -{ - nsresult rv; - - bool hasMore; - rv = aEnumerator->HasMore(&hasMore); - - nsAutoCString value; - while (NS_SUCCEEDED(rv) && hasMore) { - rv = aEnumerator->GetNext(value); - if (NS_SUCCEEDED(rv)) - aArray.AppendElement(value); - - rv = aEnumerator->HasMore(&hasMore); - } - - return rv; -} - - -class nsIgnoreCaseCStringComparator -{ - public: - bool Equals(const nsACString& a, const nsACString& b) const - { - return nsCString(a).Equals(b, nsCaseInsensitiveCStringComparator()); - } - - bool LessThan(const nsACString& a, const nsACString& b) const - { - return a < b; - } -}; - -//---------------------------------------------------------------------------- -// Class nsCharsetMenuObserver - -class nsCharsetMenuObserver : public nsIObserver { - -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - nsCharsetMenuObserver(nsCharsetMenu * menu) - : mCharsetMenu(menu) - { - } - - virtual ~nsCharsetMenuObserver() {} - -private: - nsCharsetMenu* mCharsetMenu; -}; - -NS_IMPL_ISUPPORTS(nsCharsetMenuObserver, nsIObserver) - -NS_IMETHODIMP nsCharsetMenuObserver::Observe(nsISupports *aSubject, const char *aTopic, const char16_t *someData) -{ - nsresult rv = NS_OK; - - //XUL event handler - if (!nsCRT::strcmp(aTopic, "charsetmenu-selected")) { - nsDependentString nodeName(someData); - rv = mCharsetMenu->Init(); - if (nodeName.EqualsLiteral("composer")) { - rv = mCharsetMenu->InitComposerMenu(); - } - if (nodeName.EqualsLiteral("mailview")) { - rv = mCharsetMenu->InitMailviewMenu(); - } - if (nodeName.EqualsLiteral("mailedit")) { - rv = mCharsetMenu->InitMaileditMenu(); - rv = mCharsetMenu->InitOthers(); - } - if (nodeName.EqualsLiteral("more-menu")) { - rv = mCharsetMenu->InitSecondaryTiers(); - rv = mCharsetMenu->InitAutodetMenu(); - } - if (nodeName.EqualsLiteral("other")) { - rv = mCharsetMenu->InitOthers(); - rv = mCharsetMenu->InitMaileditMenu(); - } - } - - //pref event handler - if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { - nsDependentString prefName(someData); - - if (prefName.EqualsLiteral(kBrowserStaticPrefKey)) { - // refresh menus which share this pref - rv = mCharsetMenu->RefreshMailviewMenu(); - NS_ENSURE_SUCCESS(rv, rv); - rv = mCharsetMenu->RefreshComposerMenu(); - } - else if (prefName.EqualsLiteral(kMaileditPrefKey)) { - rv = mCharsetMenu->RefreshMaileditMenu(); - } - } - - return rv; -} - -//---------------------------------------------------------------------------- -// Class nsCharsetMenu [implementation] - -NS_IMPL_CYCLE_COLLECTION_CLASS(nsCharsetMenu) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsCharsetMenu) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCharsetMenu) - cb.NoteXPCOMChild(nsCharsetMenu::mInner); -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCharsetMenu) -NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCharsetMenu) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCharsetMenu) - NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource) - NS_INTERFACE_MAP_ENTRY(nsICurrentCharsetListener) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRDFDataSource) -NS_INTERFACE_MAP_END - -nsIRDFDataSource * nsCharsetMenu::mInner = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_BrowserAutodetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_BrowserCharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_BrowserMoreCharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_BrowserMore1CharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_BrowserMore2CharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_BrowserMore3CharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_BrowserMore4CharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_BrowserMore5CharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_MaileditCharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_MailviewCharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_ComposerCharsetMenuRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_DecodersRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_EncodersRoot = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_Name = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_CharsetDetector = nullptr; -nsIRDFResource * nsCharsetMenu::kNC_BookmarkSeparator = nullptr; -nsIRDFResource * nsCharsetMenu::kRDF_type = nullptr; - -nsCharsetMenu::nsCharsetMenu() -: mInitialized(false), - mMailviewMenuInitialized(false), - mComposerMenuInitialized(false), - mMaileditMenuInitialized(false), - mSecondaryTiersInitialized(false), - mAutoDetectInitialized(false), - mOthersInitialized(false) -{ - nsresult res = NS_OK; - - //get charset manager - mCCManager = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &res); - - //initialize skeleton RDF source - mRDFService = do_GetService(kRDFServiceCID, &res); - - if (NS_SUCCEEDED(res)) { - mRDFService->RegisterDataSource(this, false); - - CallCreateInstance(kRDFInMemoryDataSourceCID, &mInner); - - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserCharsetMenuRoot), - &kNC_BrowserCharsetMenuRoot); - } - - //get pref service - nsCOMPtr PrefService = do_GetService(NS_PREFSERVICE_CONTRACTID, &res); - if (NS_SUCCEEDED(res)) - res = PrefService->GetBranch(nullptr, getter_AddRefs(mPrefs)); - - //register event listener - mCharsetMenuObserver = new nsCharsetMenuObserver(this); - - if (mCharsetMenuObserver) { - nsCOMPtr observerService = - do_GetService("@mozilla.org/observer-service;1", &res); - - if (NS_SUCCEEDED(res)) - res = observerService->AddObserver(mCharsetMenuObserver, - "charsetmenu-selected", - false); - } - - NS_ASSERTION(NS_SUCCEEDED(res), "Failed to initialize nsCharsetMenu"); -} - -nsCharsetMenu::~nsCharsetMenu() -{ - Done(); - - FreeMenuItemArray(&mMailviewMenu); - FreeMenuItemArray(&mComposerMenu); - - FreeResources(); -} - -nsresult nsCharsetMenu::RefreshMailviewMenu() -{ - nsresult res = NS_OK; - - nsCOMPtr container; - res = NewRDFContainer(mInner, kNC_MailviewCharsetMenuRoot, getter_AddRefs(container)); - if (NS_FAILED(res)) return res; - - // clean the menu - res = ClearMenu(container, &mMailviewMenu); - if (NS_FAILED(res)) return res; - - nsCOMPtr decoders; - res = mCCManager->GetDecoderList(getter_AddRefs(decoders)); - if (NS_FAILED(res)) return res; - - nsTArray decs; - SetArrayFromEnumerator(decoders, decs); - - res = AddFromPrefsToMenu(&mMailviewMenu, container, kMailviewStaticPrefKey, - decs, "charset."); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing static charset menu from prefs"); - - // mark the end of the static area, the rest is cache - mMailviewCacheStart = mMailviewMenu.Length(); - - res = InitCacheMenu(decs, kNC_MailviewCharsetMenuRoot, - kMailviewCachePrefKey, &mMailviewMenu); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailview cache charset menu"); - - return res; -} - -nsresult nsCharsetMenu::RefreshMaileditMenu() -{ - nsresult res; - - nsCOMPtr container; - res = NewRDFContainer(mInner, kNC_MaileditCharsetMenuRoot, getter_AddRefs(container)); - NS_ENSURE_SUCCESS(res, res); - - nsCOMPtr enumerator; - res = container->GetElements(getter_AddRefs(enumerator)); - NS_ENSURE_SUCCESS(res, res); - - // clear the menu - nsCOMPtr supports; - while (NS_SUCCEEDED(enumerator->GetNext(getter_AddRefs(supports)))) { - nsCOMPtr node = do_QueryInterface(supports); - - res = mInner->Unassert(kNC_MaileditCharsetMenuRoot, kNC_Name, node); - NS_ENSURE_SUCCESS(res, res); - - res = container->RemoveElement(node, false); - NS_ENSURE_SUCCESS(res, res); - } - - // get a list of available encoders - nsCOMPtr encoders; - res = mCCManager->GetEncoderList(getter_AddRefs(encoders)); - NS_ENSURE_SUCCESS(res, res); - - nsTArray encs; - SetArrayFromEnumerator(encoders, encs); - - // add menu items from pref - res = AddFromPrefsToMenu(nullptr, container, kMaileditPrefKey, encs, nullptr); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailedit charset menu from prefs"); - - return res; -} - -nsresult nsCharsetMenu::RefreshComposerMenu() -{ - nsresult res = NS_OK; - - nsCOMPtr container; - res = NewRDFContainer(mInner, kNC_ComposerCharsetMenuRoot, getter_AddRefs(container)); - if (NS_FAILED(res)) return res; - - // clean the menu - res = ClearMenu(container, &mComposerMenu); - if (NS_FAILED(res)) return res; - - nsCOMPtr decoders; - res = mCCManager->GetDecoderList(getter_AddRefs(decoders)); - if (NS_FAILED(res)) return res; - - nsTArray decs; - SetArrayFromEnumerator(decoders, decs); - - res = AddFromPrefsToMenu(&mComposerMenu, container, kComposerStaticPrefKey, - decs, "charset."); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing static charset menu from prefs"); - - // mark the end of the static area, the rest is cache - mComposerCacheStart = mComposerMenu.Length(); - - res = InitCacheMenu(decs, kNC_ComposerCharsetMenuRoot, - kComposerCachePrefKey, &mComposerMenu); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing composer cache charset menu"); - - return res; -} - -nsresult nsCharsetMenu::Init() -{ - nsresult res = NS_OK; - - if (!mInitialized) { - - //enumerate decoders - nsCOMPtr decoders; - res = mCCManager->GetDecoderList(getter_AddRefs(decoders)); - if (NS_FAILED(res)) return res; - - SetArrayFromEnumerator(decoders, mDecoderList); - - //initialize all remaining RDF template nodes - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserAutodetMenuRoot), - &kNC_BrowserAutodetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMoreCharsetMenuRoot), - &kNC_BrowserMoreCharsetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore1CharsetMenuRoot), - &kNC_BrowserMore1CharsetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore2CharsetMenuRoot), - &kNC_BrowserMore2CharsetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore3CharsetMenuRoot), - &kNC_BrowserMore3CharsetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore4CharsetMenuRoot), - &kNC_BrowserMore4CharsetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BrowserMore5CharsetMenuRoot), - &kNC_BrowserMore5CharsetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_MaileditCharsetMenuRoot), - &kNC_MaileditCharsetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_MailviewCharsetMenuRoot), - &kNC_MailviewCharsetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_ComposerCharsetMenuRoot), - &kNC_ComposerCharsetMenuRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_DecodersRoot), - &kNC_DecodersRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_EncodersRoot), - &kNC_EncodersRoot); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_Name), - &kNC_Name); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_CharsetDetector), - &kNC_CharsetDetector); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_BookmarkSeparator), - &kNC_BookmarkSeparator); - mRDFService->GetResource(NS_LITERAL_CSTRING(kURINC_type), &kRDF_type); - - nsIRDFContainerUtils * rdfUtil = nullptr; - res = CallGetService(kRDFContainerUtilsCID, &rdfUtil); - if (NS_FAILED(res)) goto done; - - res = rdfUtil->MakeSeq(mInner, kNC_BrowserAutodetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_BrowserCharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_BrowserMoreCharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore1CharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore2CharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore3CharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore4CharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_BrowserMore5CharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_MaileditCharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_MailviewCharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_ComposerCharsetMenuRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_DecodersRoot, nullptr); - if (NS_FAILED(res)) goto done; - res = rdfUtil->MakeSeq(mInner, kNC_EncodersRoot, nullptr); - if (NS_FAILED(res)) goto done; - - done: - NS_IF_RELEASE(rdfUtil); - if (NS_FAILED(res)) return res; - } - mInitialized = NS_SUCCEEDED(res); - return res; -} - -nsresult nsCharsetMenu::Done() -{ - nsresult res = NS_OK; - res = mRDFService->UnregisterDataSource(this); - - NS_IF_RELEASE(kNC_BrowserAutodetMenuRoot); - NS_IF_RELEASE(kNC_BrowserCharsetMenuRoot); - NS_IF_RELEASE(kNC_BrowserMoreCharsetMenuRoot); - NS_IF_RELEASE(kNC_BrowserMore1CharsetMenuRoot); - NS_IF_RELEASE(kNC_BrowserMore2CharsetMenuRoot); - NS_IF_RELEASE(kNC_BrowserMore3CharsetMenuRoot); - NS_IF_RELEASE(kNC_BrowserMore4CharsetMenuRoot); - NS_IF_RELEASE(kNC_BrowserMore5CharsetMenuRoot); - NS_IF_RELEASE(kNC_MaileditCharsetMenuRoot); - NS_IF_RELEASE(kNC_MailviewCharsetMenuRoot); - NS_IF_RELEASE(kNC_ComposerCharsetMenuRoot); - NS_IF_RELEASE(kNC_DecodersRoot); - NS_IF_RELEASE(kNC_EncodersRoot); - NS_IF_RELEASE(kNC_Name); - NS_IF_RELEASE(kNC_CharsetDetector); - NS_IF_RELEASE(kNC_BookmarkSeparator); - NS_IF_RELEASE(kRDF_type); - NS_IF_RELEASE(mInner); - - return res; -} - -/** - * Free the resources no longer needed by the component. - */ -nsresult nsCharsetMenu::FreeResources() -{ - nsresult res = NS_OK; - - if (mCharsetMenuObserver) { - mPrefs->RemoveObserver(kBrowserStaticPrefKey, mCharsetMenuObserver); - mPrefs->RemoveObserver(kMaileditPrefKey, mCharsetMenuObserver); - /* nsIObserverService has to have released nsCharsetMenu already */ - } - - mRDFService = nullptr; - mCCManager = nullptr; - mPrefs = nullptr; - - return res; -} - -nsresult nsCharsetMenu::InitMaileditMenu() -{ - nsresult res = NS_OK; - - if (!mMaileditMenuInitialized) { - nsCOMPtr container; - res = NewRDFContainer(mInner, kNC_MaileditCharsetMenuRoot, getter_AddRefs(container)); - if (NS_FAILED(res)) return res; - - //enumerate encoders - // this would bring in a whole bunch of 'font encoders' as well as genuine - // charset encoders, but it's safe because we rely on prefs to filter - // them out. Moreover, 'customize' menu lists only genuine charset - // encoders further guarding against 'font encoders' sneaking in. - nsCOMPtr encoders; - res = mCCManager->GetEncoderList(getter_AddRefs(encoders)); - if (NS_FAILED(res)) return res; - - nsTArray maileditEncoderList; - SetArrayFromEnumerator(encoders, maileditEncoderList); - - res = AddFromPrefsToMenu(nullptr, container, kMaileditPrefKey, - maileditEncoderList, nullptr); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailedit charset menu from prefs"); - - // register prefs callback - mPrefs->AddObserver(kMaileditPrefKey, mCharsetMenuObserver, false); - } - - mMaileditMenuInitialized = NS_SUCCEEDED(res); - - return res; -} - -nsresult nsCharsetMenu::InitMailviewMenu() -{ - nsresult res = NS_OK; - - if (!mMailviewMenuInitialized) { - nsCOMPtr container; - res = NewRDFContainer(mInner, kNC_MailviewCharsetMenuRoot, getter_AddRefs(container)); - if (NS_FAILED(res)) return res; - - nsTArray mailviewDecoderList(mDecoderList); - - res = InitStaticMenu(mailviewDecoderList, kNC_MailviewCharsetMenuRoot, - kMailviewStaticPrefKey, &mMailviewMenu); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailview static charset menu"); - - // mark the end of the static area, the rest is cache - mMailviewCacheStart = mMailviewMenu.Length(); - mPrefs->GetIntPref(kMailviewCacheSizePrefKey, &mMailviewCacheSize); - - // compute the position of the menu in the RDF container - res = container->GetCount(&mMailviewMenuRDFPosition); - if (NS_FAILED(res)) return res; - // this "1" here is a correction necessary because the RDF container - // elements are numbered from 1 (why god, WHY?!?!?!) - mMailviewMenuRDFPosition -= mMailviewCacheStart - 1; - - res = InitCacheMenu(mailviewDecoderList, kNC_MailviewCharsetMenuRoot, - kMailviewCachePrefKey, &mMailviewMenu); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing mailview cache charset menu"); - } - - mMailviewMenuInitialized = NS_SUCCEEDED(res); - - return res; -} - -nsresult nsCharsetMenu::InitComposerMenu() -{ - nsresult res = NS_OK; - - if (!mComposerMenuInitialized) { - nsCOMPtr container; - res = NewRDFContainer(mInner, kNC_ComposerCharsetMenuRoot, getter_AddRefs(container)); - if (NS_FAILED(res)) return res; - - nsTArray composerDecoderList(mDecoderList); - - // even if we fail, the show must go on - res = InitStaticMenu(composerDecoderList, kNC_ComposerCharsetMenuRoot, - kComposerStaticPrefKey, &mComposerMenu); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing composer static charset menu"); - - // mark the end of the static area, the rest is cache - mComposerCacheStart = mComposerMenu.Length(); - mPrefs->GetIntPref(kComposerCacheSizePrefKey, &mComposerCacheSize); - - // compute the position of the menu in the RDF container - res = container->GetCount(&mComposerMenuRDFPosition); - if (NS_FAILED(res)) return res; - // this "1" here is a correction necessary because the RDF container - // elements are numbered from 1 (why god, WHY?!?!?!) - mComposerMenuRDFPosition -= mComposerCacheStart - 1; - - res = InitCacheMenu(composerDecoderList, kNC_ComposerCharsetMenuRoot, - kComposerCachePrefKey, &mComposerMenu); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing composer cache charset menu"); - } - - mComposerMenuInitialized = NS_SUCCEEDED(res); - - return res; -} - -nsresult nsCharsetMenu::InitOthers() -{ - nsresult res = NS_OK; - - if (!mOthersInitialized) { - nsTArray othersDecoderList(mDecoderList); - - res = InitMoreMenu(othersDecoderList, kNC_DecodersRoot, ".notForBrowser"); - if (NS_FAILED(res)) return res; - - // Using mDecoderList instead of GetEncoderList(), we can avoid having to - // tag a whole bunch of 'font encoders' with '.notForOutgoing' in - // charsetData.properties file. - nsTArray othersEncoderList(mDecoderList); - - res = InitMoreMenu(othersEncoderList, kNC_EncodersRoot, ".notForOutgoing"); - if (NS_FAILED(res)) return res; - } - - mOthersInitialized = NS_SUCCEEDED(res); - - return res; -} - -/** - * Inits the secondary tiers of the charset menu. Because currently all the CS - * menus are sharing the secondary tiers, one should call this method only - * once for all of them. - */ -nsresult nsCharsetMenu::InitSecondaryTiers() -{ - nsresult res = NS_OK; - - if (!mSecondaryTiersInitialized) { - nsTArray secondaryTiersDecoderList(mDecoderList); - - res = InitMoreSubmenus(secondaryTiersDecoderList); - NS_ASSERTION(NS_SUCCEEDED(res), "err init browser charset more submenus"); - - res = InitMoreMenu(secondaryTiersDecoderList, kNC_BrowserMoreCharsetMenuRoot, ".notForBrowser"); - NS_ASSERTION(NS_SUCCEEDED(res), "err init browser charset more menu"); - } - - mSecondaryTiersInitialized = NS_SUCCEEDED(res); - - return res; -} - -nsresult nsCharsetMenu::InitStaticMenu(nsTArray& aDecs, - nsIRDFResource * aResource, - const char * aKey, - nsTArray * aArray) -{ - nsresult res = NS_OK; - nsCOMPtr container; - - res = NewRDFContainer(mInner, aResource, getter_AddRefs(container)); - if (NS_FAILED(res)) return res; - - // XXX work around bug that causes the submenus to be first instead of last - res = AddSeparatorToContainer(container); - NS_ASSERTION(NS_SUCCEEDED(res), "error adding separator to container"); - - res = AddFromPrefsToMenu(aArray, container, aKey, aDecs, "charset."); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing static charset menu from prefs"); - - return res; -} - -nsresult nsCharsetMenu::InitCacheMenu( - nsTArray& aDecs, - nsIRDFResource * aResource, - const char * aKey, - nsTArray * aArray) -{ - nsresult res = NS_OK; - nsCOMPtr container; - - res = NewRDFContainer(mInner, aResource, getter_AddRefs(container)); - if (NS_FAILED(res)) return res; - - res = AddFromNolocPrefsToMenu(aArray, container, aKey, aDecs, "charset."); - NS_ASSERTION(NS_SUCCEEDED(res), "error initializing cache charset menu from prefs"); - - return res; -} - -nsresult nsCharsetMenu::InitAutodetMenu() -{ - nsresult res = NS_OK; - - if (!mAutoDetectInitialized) { - nsTArray chardetArray; - nsCOMPtr container; - nsTArray detectorArray; - - res = NewRDFContainer(mInner, kNC_BrowserAutodetMenuRoot, getter_AddRefs(container)); - if (NS_FAILED(res)) return res; - - nsCOMPtr detectors; - res = mCCManager->GetCharsetDetectorList(getter_AddRefs(detectors)); - if (NS_FAILED(res)) goto done; - - res = SetArrayFromEnumerator(detectors, detectorArray); - if (NS_FAILED(res)) goto done; - - res = AddCharsetArrayToItemArray(chardetArray, detectorArray); - if (NS_FAILED(res)) goto done; - - // reorder the array - res = ReorderMenuItemArray(&chardetArray); - if (NS_FAILED(res)) goto done; - - res = AddMenuItemArrayToContainer(container, &chardetArray, - kNC_CharsetDetector); - if (NS_FAILED(res)) goto done; - - done: - // free the elements in the nsTArray - FreeMenuItemArray(&chardetArray); - } - - mAutoDetectInitialized = NS_SUCCEEDED(res); - - return res; -} - -nsresult nsCharsetMenu::InitMoreMenu(nsTArray& aDecs, - nsIRDFResource * aResource, - const char * aFlag) -{ - nsresult res = NS_OK; - nsCOMPtr container; - nsTArray moreMenu; - - res = NewRDFContainer(mInner, aResource, getter_AddRefs(container)); - if (NS_FAILED(res)) goto done; - - // remove charsets "not for browser" - res = RemoveFlaggedCharsets(aDecs, NS_ConvertASCIItoUTF16(aFlag)); - if (NS_FAILED(res)) goto done; - - res = AddCharsetArrayToItemArray(moreMenu, aDecs); - if (NS_FAILED(res)) goto done; - - // reorder the array - res = ReorderMenuItemArray(&moreMenu); - if (NS_FAILED(res)) goto done; - - res = AddMenuItemArrayToContainer(container, &moreMenu, nullptr); - if (NS_FAILED(res)) goto done; - -done: - // free the elements in the nsTArray - FreeMenuItemArray(&moreMenu); - - return res; -} - -// XXX please make this method more general; the cut&pasted code is laughable -nsresult nsCharsetMenu::InitMoreSubmenus(nsTArray& aDecs) -{ - nsresult res = NS_OK; - - nsCOMPtr container1; - nsCOMPtr container2; - nsCOMPtr container3; - nsCOMPtr container4; - nsCOMPtr container5; - const char key1[] = "intl.charsetmenu.browser.more1"; - const char key2[] = "intl.charsetmenu.browser.more2"; - const char key3[] = "intl.charsetmenu.browser.more3"; - const char key4[] = "intl.charsetmenu.browser.more4"; - const char key5[] = "intl.charsetmenu.browser.more5"; - - res = NewRDFContainer(mInner, kNC_BrowserMore1CharsetMenuRoot, - getter_AddRefs(container1)); - if (NS_FAILED(res)) return res; - AddFromNolocPrefsToMenu(nullptr, container1, key1, aDecs, nullptr); - - res = NewRDFContainer(mInner, kNC_BrowserMore2CharsetMenuRoot, - getter_AddRefs(container2)); - if (NS_FAILED(res)) return res; - AddFromNolocPrefsToMenu(nullptr, container2, key2, aDecs, nullptr); - - res = NewRDFContainer(mInner, kNC_BrowserMore3CharsetMenuRoot, - getter_AddRefs(container3)); - if (NS_FAILED(res)) return res; - AddFromNolocPrefsToMenu(nullptr, container3, key3, aDecs, nullptr); - - res = NewRDFContainer(mInner, kNC_BrowserMore4CharsetMenuRoot, - getter_AddRefs(container4)); - if (NS_FAILED(res)) return res; - AddFromNolocPrefsToMenu(nullptr, container4, key4, aDecs, nullptr); - - res = NewRDFContainer(mInner, kNC_BrowserMore5CharsetMenuRoot, - getter_AddRefs(container5)); - if (NS_FAILED(res)) return res; - AddFromNolocPrefsToMenu(nullptr, container5, key5, aDecs, nullptr); - - return res; -} - -nsresult nsCharsetMenu::AddCharsetToItemArray(nsTArray *aArray, - const nsAFlatCString& aCharset, - nsMenuEntry ** aResult, - int32_t aPlace) -{ - nsresult res = NS_OK; - nsMenuEntry * item = nullptr; - - if (aResult != nullptr) *aResult = nullptr; - - item = new nsMenuEntry(); - if (item == nullptr) { - res = NS_ERROR_OUT_OF_MEMORY; - goto done; - } - - item->mCharset = aCharset; - - if (NS_FAILED(mCCManager->GetCharsetTitle(aCharset.get(), item->mTitle))) { - item->mTitle.AssignWithConversion(aCharset.get()); - } - - if (aArray != nullptr) { - if (aPlace < 0) { - aArray->AppendElement(item); - } else { - aArray->InsertElementsAt(aPlace, 1, item); - } - } - - if (aResult != nullptr) *aResult = item; - - // if we have made another reference to "item", do not delete it - if ((aArray != nullptr) || (aResult != nullptr)) item = nullptr; - -done: - if (item != nullptr) delete item; - - return res; -} - -nsresult -nsCharsetMenu::AddCharsetArrayToItemArray(nsTArray& aArray, - const nsTArray& aCharsets) -{ - uint32_t count = aCharsets.Length(); - - for (uint32_t i = 0; i < count; i++) { - - const nsCString& str = aCharsets[i]; - nsresult res = AddCharsetToItemArray(&aArray, str, nullptr, -1); - - if (NS_FAILED(res)) - return res; - } - - return NS_OK; -} - -// aPlace < -1 for Remove -// aPlace < 0 for Append -nsresult nsCharsetMenu::AddMenuItemToContainer( - nsIRDFContainer * aContainer, - nsMenuEntry * aItem, - nsIRDFResource * aType, - const char * aIDPrefix, - int32_t aPlace) -{ - nsresult res = NS_OK; - nsCOMPtr node; - - nsAutoCString id; - if (aIDPrefix != nullptr) id.Assign(aIDPrefix); - id.Append(aItem->mCharset); - - // Make up a unique ID and create the RDF NODE - res = mRDFService->GetResource(id, getter_AddRefs(node)); - if (NS_FAILED(res)) return res; - - const char16_t * title = aItem->mTitle.get(); - - // set node's title - nsCOMPtr titleLiteral; - res = mRDFService->GetLiteral(title, getter_AddRefs(titleLiteral)); - if (NS_FAILED(res)) return res; - - if (aPlace < -1) { - res = Unassert(node, kNC_Name, titleLiteral); - if (NS_FAILED(res)) return res; - } else { - res = Assert(node, kNC_Name, titleLiteral, true); - if (NS_FAILED(res)) return res; - } - - if (aType != nullptr) { - if (aPlace < -1) { - res = Unassert(node, kRDF_type, aType); - if (NS_FAILED(res)) return res; - } else { - res = Assert(node, kRDF_type, aType, true); - if (NS_FAILED(res)) return res; - } - } - - // Add the element to the container - if (aPlace < -1) { - res = aContainer->RemoveElement(node, true); - if (NS_FAILED(res)) return res; - } else if (aPlace < 0) { - res = aContainer->AppendElement(node); - if (NS_FAILED(res)) return res; - } else { - res = aContainer->InsertElementAt(node, aPlace, true); - if (NS_FAILED(res)) return res; - } - - return res; -} - -nsresult nsCharsetMenu::AddMenuItemArrayToContainer( - nsIRDFContainer * aContainer, - nsTArray * aArray, - nsIRDFResource * aType) -{ - uint32_t count = aArray->Length(); - nsresult res = NS_OK; - - for (uint32_t i = 0; i < count; i++) { - nsMenuEntry * item = aArray->ElementAt(i); - if (item == nullptr) return NS_ERROR_UNEXPECTED; - - res = AddMenuItemToContainer(aContainer, item, aType, nullptr, -1); - if (NS_FAILED(res)) return res; - } - - return NS_OK; -} - -nsresult nsCharsetMenu::AddCharsetToContainer(nsTArray *aArray, - nsIRDFContainer * aContainer, - const nsAFlatCString& aCharset, - const char * aIDPrefix, - int32_t aPlace, - int32_t aRDFPlace) -{ - nsresult res = NS_OK; - nsMenuEntry * item = nullptr; - - res = AddCharsetToItemArray(aArray, aCharset, &item, aPlace); - if (NS_FAILED(res)) goto done; - - res = AddMenuItemToContainer(aContainer, item, nullptr, aIDPrefix, - aPlace + aRDFPlace); - if (NS_FAILED(res)) goto done; - - // if we have made another reference to "item", do not delete it - if (aArray != nullptr) item = nullptr; - -done: - if (item != nullptr) delete item; - - return res; -} - -nsresult nsCharsetMenu::AddFromPrefsToMenu( - nsTArray * aArray, - nsIRDFContainer * aContainer, - const char * aKey, - nsTArray& aDecs, - const char * aIDPrefix) -{ - nsresult res = NS_OK; - - nsCOMPtr pls; - res = mPrefs->GetComplexValue(aKey, NS_GET_IID(nsIPrefLocalizedString), getter_AddRefs(pls)); - if (NS_FAILED(res)) return res; - - if (pls) { - nsXPIDLString ucsval; - pls->ToString(getter_Copies(ucsval)); - NS_ConvertUTF16toUTF8 utf8val(ucsval); - if (ucsval) - res = AddFromStringToMenu(utf8val.BeginWriting(), aArray, - aContainer, aDecs, aIDPrefix); - } - - return res; -} - -nsresult -nsCharsetMenu::AddFromNolocPrefsToMenu(nsTArray * aArray, - nsIRDFContainer * aContainer, - const char * aKey, - nsTArray& aDecs, - const char * aIDPrefix) -{ - nsresult res = NS_OK; - - char * value = nullptr; - res = mPrefs->GetCharPref(aKey, &value); - if (NS_FAILED(res)) return res; - - if (value != nullptr) { - res = AddFromStringToMenu(value, aArray, aContainer, aDecs, aIDPrefix); - nsMemory::Free(value); - } - - return res; -} - -nsresult nsCharsetMenu::AddFromStringToMenu( - char * aCharsetList, - nsTArray * aArray, - nsIRDFContainer * aContainer, - nsTArray& aDecs, - const char * aIDPrefix) -{ - nsresult res = NS_OK; - char * p = aCharsetList; - char * q = p; - while (*p != 0) { - for (; (*q != ',') && (*q != ' ') && (*q != 0); q++) {;} - char temp = *q; - *q = 0; - - // if this charset is not on the accepted list of charsets, ignore it - int32_t index; - index = aDecs.IndexOf(nsAutoCString(p), 0, nsIgnoreCaseCStringComparator()); - if (index >= 0) { - - // else, add it to the menu - res = AddCharsetToContainer(aArray, aContainer, nsDependentCString(p), - aIDPrefix, -1, 0); - NS_ASSERTION(NS_SUCCEEDED(res), "cannot add charset to menu"); - if (NS_FAILED(res)) break; - - aDecs.RemoveElementAt(index); - } - - *q = temp; - for (; (*q == ',') || (*q == ' '); q++) {;} - p=q; - } - - return NS_OK; -} - -nsresult nsCharsetMenu::AddSeparatorToContainer(nsIRDFContainer * aContainer) -{ - nsAutoCString str; - str.AssignLiteral("----"); - - // hack to generate unique id's for separators - static int32_t u = 0; - u++; - str.AppendInt(u); - - nsMenuEntry item; - item.mCharset = str; - item.mTitle.AssignWithConversion(str.get()); - - return AddMenuItemToContainer(aContainer, &item, kNC_BookmarkSeparator, - nullptr, -1); -} - -nsresult -nsCharsetMenu::AddCharsetToCache(const nsAFlatCString& aCharset, - nsTArray * aArray, - nsIRDFResource * aRDFResource, - uint32_t aCacheStart, - uint32_t aCacheSize, - int32_t aRDFPlace) -{ - int32_t i; - nsresult res = NS_OK; - - i = FindMenuItemInArray(aArray, aCharset, nullptr); - if (i >= 0) return res; - - nsCOMPtr container; - res = NewRDFContainer(mInner, aRDFResource, getter_AddRefs(container)); - if (NS_FAILED(res)) return res; - - // if too many items, remove last one - if (aArray->Length() - aCacheStart >= aCacheSize){ - res = RemoveLastMenuItem(container, aArray); - if (NS_FAILED(res)) return res; - } - - res = AddCharsetToContainer(aArray, container, aCharset, "charset.", - aCacheStart, aRDFPlace); - - return res; -} - -nsresult nsCharsetMenu::WriteCacheToPrefs(nsTArray * aArray, - int32_t aCacheStart, - const char * aKey) -{ - nsresult res = NS_OK; - - // create together the cache string - nsAutoCString cache; - nsAutoCString sep(NS_LITERAL_CSTRING(", ")); - uint32_t count = aArray->Length(); - - for (uint32_t i = aCacheStart; i < count; i++) { - nsMenuEntry * item = aArray->ElementAt(i); - if (item != nullptr) { - cache.Append(item->mCharset); - if (i < count - 1) { - cache.Append(sep); - } - } - } - - // write the pref - res = mPrefs->SetCharPref(aKey, cache.get()); - - return res; -} - -nsresult nsCharsetMenu::UpdateCachePrefs(const char * aCacheKey, - const char * aCacheSizeKey, - const char * aStaticKey, - const char16_t * aCharset) -{ - nsresult rv = NS_OK; - nsXPIDLCString cachePrefValue; - nsXPIDLCString staticPrefValue; - NS_LossyConvertUTF16toASCII currentCharset(aCharset); - int32_t cacheSize = 0; - - mPrefs->GetCharPref(aCacheKey, getter_Copies(cachePrefValue)); - mPrefs->GetCharPref(aStaticKey, getter_Copies(staticPrefValue)); - rv = mPrefs->GetIntPref(aCacheSizeKey, &cacheSize); - - if (NS_FAILED(rv) || cacheSize <= 0) - return NS_ERROR_UNEXPECTED; - - if ((cachePrefValue.Find(currentCharset) == kNotFound) && - (staticPrefValue.Find(currentCharset) == kNotFound)) { - - if (!cachePrefValue.IsEmpty()) - cachePrefValue.Insert(", ", 0); - - cachePrefValue.Insert(currentCharset, 0); - if (cacheSize < (int32_t) cachePrefValue.CountChar(',') + 1) - cachePrefValue.Truncate(cachePrefValue.RFindChar(',')); - - rv = mPrefs->SetCharPref(aCacheKey, cachePrefValue); - } - - return rv; -} - -nsresult nsCharsetMenu::ClearMenu(nsIRDFContainer * aContainer, - nsTArray * aArray) -{ - nsresult res = NS_OK; - - // clean the RDF data source - uint32_t count = aArray->Length(); - for (uint32_t i = 0; i < count; i++) { - nsMenuEntry * item = aArray->ElementAt(i); - if (item != nullptr) { - res = AddMenuItemToContainer(aContainer, item, nullptr, "charset.", -2); - if (NS_FAILED(res)) return res; - } - } - - // clean the internal data structures - FreeMenuItemArray(aArray); - - return res; -} - -nsresult nsCharsetMenu::RemoveLastMenuItem(nsIRDFContainer * aContainer, - nsTArray * aArray) -{ - nsresult res = NS_OK; - - int32_t last = aArray->Length() - 1; - if (last >= 0) { - nsMenuEntry * item = aArray->ElementAt(last); - if (item != nullptr) { - res = AddMenuItemToContainer(aContainer, item, nullptr, "charset.", -2); - if (NS_FAILED(res)) return res; - - aArray->RemoveElementAt(last); - } - } - - return res; -} - -nsresult nsCharsetMenu::RemoveFlaggedCharsets(nsTArray& aList, - const nsString& aProp) -{ - nsresult res = NS_OK; - uint32_t count; - - count = aList.Length(); - if (NS_FAILED(res)) return res; - - nsAutoString str; - for (uint32_t i = 0; i < count; i++) { - - res = mCCManager->GetCharsetData(aList[i].get(), aProp.get(), str); - if (NS_FAILED(res)) continue; - - aList.RemoveElementAt(i); - - i--; - count--; - } - - return NS_OK; -} - -nsresult nsCharsetMenu::NewRDFContainer(nsIRDFDataSource * aDataSource, - nsIRDFResource * aResource, - nsIRDFContainer ** aResult) -{ - nsresult res = CallCreateInstance(kRDFContainerCID, aResult); - if (NS_FAILED(res)) return res; - - res = (*aResult)->Init(aDataSource, aResource); - if (NS_FAILED(res)) NS_RELEASE(*aResult); - - return res; -} - -void nsCharsetMenu::FreeMenuItemArray(nsTArray * aArray) -{ - uint32_t count = aArray->Length(); - for (uint32_t i = 0; i < count; i++) { - nsMenuEntry * item = aArray->ElementAt(i); - if (item != nullptr) { - delete item; - } - } - aArray->Clear(); -} - -int32_t nsCharsetMenu::FindMenuItemInArray(const nsTArray* aArray, - const nsAFlatCString& aCharset, - nsMenuEntry ** aResult) -{ - uint32_t count = aArray->Length(); - - for (uint32_t i=0; i < count; i++) { - nsMenuEntry * item = aArray->ElementAt(i); - if (item->mCharset == aCharset) { - if (aResult != nullptr) *aResult = item; - return i; - } - } - - if (aResult != nullptr) *aResult = nullptr; - return -1; -} - -nsresult nsCharsetMenu::ReorderMenuItemArray(nsTArray * aArray) -{ - nsresult res = NS_OK; - nsCOMPtr collation; - uint32_t count = aArray->Length(); - uint32_t i; - - // we need to use a temporary array - charsetMenuSortRecord *array = new charsetMenuSortRecord [count]; - NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY); - for (i = 0; i < count; i++) - array[i].key = nullptr; - - res = GetCollation(getter_AddRefs(collation)); - if (NS_FAILED(res)) - goto done; - - for (i = 0; i < count && NS_SUCCEEDED(res); i++) { - array[i].item = aArray->ElementAt(i); - - res = collation->AllocateRawSortKey(nsICollation::kCollationCaseInSensitive, - (array[i].item)->mTitle, &array[i].key, &array[i].len); - } - - // reorder the array - if (NS_SUCCEEDED(res)) { - NS_QuickSort(array, count, sizeof(*array), CompareMenuItems, collation); - - // move the elements from the temporary array into the the real one - aArray->Clear(); - for (i = 0; i < count; i++) { - aArray->AppendElement(array[i].item); - } - } - -done: - for (i = 0; i < count; i++) { - PR_FREEIF(array[i].key); - } - delete [] array; - return res; -} - -nsresult nsCharsetMenu::GetCollation(nsICollation ** aCollation) -{ - nsresult res = NS_OK; - nsCOMPtr locale = nullptr; - nsICollationFactory * collationFactory = nullptr; - - nsCOMPtr localeServ = - do_GetService(NS_LOCALESERVICE_CONTRACTID, &res); - if (NS_FAILED(res)) return res; - - res = localeServ->GetApplicationLocale(getter_AddRefs(locale)); - if (NS_FAILED(res)) return res; - - res = CallCreateInstance(NS_COLLATIONFACTORY_CONTRACTID, &collationFactory); - if (NS_FAILED(res)) return res; - - res = collationFactory->CreateCollation(locale, aCollation); - NS_RELEASE(collationFactory); - return res; -} - -//---------------------------------------------------------------------------- -// Interface nsICurrentCharsetListener [implementation] - -NS_IMETHODIMP nsCharsetMenu::SetCurrentCharset(const char16_t * aCharset) -{ - return NS_OK; -} - -NS_IMETHODIMP nsCharsetMenu::SetCurrentMailCharset(const char16_t * aCharset) -{ - nsresult res = NS_OK; - - if (mMailviewMenuInitialized) { - res = AddCharsetToCache(NS_LossyConvertUTF16toASCII(aCharset), - &mMailviewMenu, kNC_MailviewCharsetMenuRoot, - mMailviewCacheStart, mMailviewCacheSize, - mMailviewMenuRDFPosition); - if (NS_FAILED(res)) return res; - - res = WriteCacheToPrefs(&mMailviewMenu, mMailviewCacheStart, - kMailviewCachePrefKey); - } else { - res = UpdateCachePrefs(kMailviewCachePrefKey, kMailviewCacheSizePrefKey, - kMailviewStaticPrefKey, aCharset); - } - return res; -} - -NS_IMETHODIMP nsCharsetMenu::SetCurrentComposerCharset(const char16_t * aCharset) -{ - nsresult res = NS_OK; - - if (mComposerMenuInitialized) { - - res = AddCharsetToCache(NS_LossyConvertUTF16toASCII(aCharset), - &mComposerMenu, kNC_ComposerCharsetMenuRoot, - mComposerCacheStart, mComposerCacheSize, - mComposerMenuRDFPosition); - if (NS_FAILED(res)) return res; - - res = WriteCacheToPrefs(&mComposerMenu, mComposerCacheStart, - kComposerCachePrefKey); - } else { - res = UpdateCachePrefs(kComposerCachePrefKey, kComposerCacheSizePrefKey, - kComposerStaticPrefKey, aCharset); - } - return res; -} - -//---------------------------------------------------------------------------- -// Interface nsIRDFDataSource [implementation] - -NS_IMETHODIMP nsCharsetMenu::GetURI(char ** uri) -{ - if (!uri) return NS_ERROR_NULL_POINTER; - - *uri = NS_strdup("rdf:charset-menu"); - if (!(*uri)) return NS_ERROR_OUT_OF_MEMORY; - - return NS_OK; -} - -NS_IMETHODIMP nsCharsetMenu::GetSource(nsIRDFResource* property, - nsIRDFNode* target, - bool tv, - nsIRDFResource** source) -{ - return mInner->GetSource(property, target, tv, source); -} - -NS_IMETHODIMP nsCharsetMenu::GetSources(nsIRDFResource* property, - nsIRDFNode* target, - bool tv, - nsISimpleEnumerator** sources) -{ - return mInner->GetSources(property, target, tv, sources); -} - -NS_IMETHODIMP nsCharsetMenu::GetTarget(nsIRDFResource* source, - nsIRDFResource* property, - bool tv, - nsIRDFNode** target) -{ - return mInner->GetTarget(source, property, tv, target); -} - -NS_IMETHODIMP nsCharsetMenu::GetTargets(nsIRDFResource* source, - nsIRDFResource* property, - bool tv, - nsISimpleEnumerator** targets) -{ - return mInner->GetTargets(source, property, tv, targets); -} - -NS_IMETHODIMP nsCharsetMenu::Assert(nsIRDFResource* aSource, - nsIRDFResource* aProperty, - nsIRDFNode* aTarget, - bool aTruthValue) -{ - // TODO: filter out asserts we don't care about - return mInner->Assert(aSource, aProperty, aTarget, aTruthValue); -} - -NS_IMETHODIMP nsCharsetMenu::Unassert(nsIRDFResource* aSource, - nsIRDFResource* aProperty, - nsIRDFNode* aTarget) -{ - // TODO: filter out unasserts we don't care about - return mInner->Unassert(aSource, aProperty, aTarget); -} - - -NS_IMETHODIMP nsCharsetMenu::Change(nsIRDFResource* aSource, - nsIRDFResource* aProperty, - nsIRDFNode* aOldTarget, - nsIRDFNode* aNewTarget) -{ - // TODO: filter out changes we don't care about - return mInner->Change(aSource, aProperty, aOldTarget, aNewTarget); -} - -NS_IMETHODIMP nsCharsetMenu::Move(nsIRDFResource* aOldSource, - nsIRDFResource* aNewSource, - nsIRDFResource* aProperty, - nsIRDFNode* aTarget) -{ - // TODO: filter out changes we don't care about - return mInner->Move(aOldSource, aNewSource, aProperty, aTarget); -} - - -NS_IMETHODIMP nsCharsetMenu::HasAssertion(nsIRDFResource* source, - nsIRDFResource* property, - nsIRDFNode* target, bool tv, - bool* hasAssertion) -{ - return mInner->HasAssertion(source, property, target, tv, hasAssertion); -} - -NS_IMETHODIMP nsCharsetMenu::AddObserver(nsIRDFObserver* n) -{ - return mInner->AddObserver(n); -} - -NS_IMETHODIMP nsCharsetMenu::RemoveObserver(nsIRDFObserver* n) -{ - return mInner->RemoveObserver(n); -} - -NS_IMETHODIMP -nsCharsetMenu::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result) -{ - return mInner->HasArcIn(aNode, aArc, result); -} - -NS_IMETHODIMP -nsCharsetMenu::HasArcOut(nsIRDFResource *source, nsIRDFResource *aArc, bool *result) -{ - return mInner->HasArcOut(source, aArc, result); -} - -NS_IMETHODIMP nsCharsetMenu::ArcLabelsIn(nsIRDFNode* node, - nsISimpleEnumerator** labels) -{ - return mInner->ArcLabelsIn(node, labels); -} - -NS_IMETHODIMP nsCharsetMenu::ArcLabelsOut(nsIRDFResource* source, - nsISimpleEnumerator** labels) -{ - return mInner->ArcLabelsOut(source, labels); -} - -NS_IMETHODIMP nsCharsetMenu::GetAllResources(nsISimpleEnumerator** aCursor) -{ - return mInner->GetAllResources(aCursor); -} - -NS_IMETHODIMP nsCharsetMenu::GetAllCmds( - nsIRDFResource* source, - nsISimpleEnumerator/**/** commands) -{ - NS_NOTYETIMPLEMENTED("nsCharsetMenu::GetAllCmds"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP nsCharsetMenu::IsCommandEnabled( - nsISupportsArray/**/* aSources, - nsIRDFResource* aCommand, - nsISupportsArray/**/* aArguments, - bool* aResult) -{ - NS_NOTYETIMPLEMENTED("nsCharsetMenu::IsCommandEnabled"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP nsCharsetMenu::DoCommand(nsISupportsArray* aSources, - nsIRDFResource* aCommand, - nsISupportsArray* aArguments) -{ - NS_NOTYETIMPLEMENTED("nsCharsetMenu::DoCommand"); - return NS_ERROR_NOT_IMPLEMENTED; -} - -NS_IMETHODIMP nsCharsetMenu::BeginUpdateBatch() -{ - return mInner->BeginUpdateBatch(); -} - -NS_IMETHODIMP nsCharsetMenu::EndUpdateBatch() -{ - return mInner->EndUpdateBatch(); -} diff --git a/toolkit/components/intl/nsCharsetMenu.h b/toolkit/components/intl/nsCharsetMenu.h deleted file mode 100644 index 286b4975fd68..000000000000 --- a/toolkit/components/intl/nsCharsetMenu.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsCharsetMenu_h___ -#define nsCharsetMenu_h___ - -#define NS_CHARSETMENU_CID \ - {0x42c52b81, 0xa200, 0x11d3, { 0x9d, 0xb, 0x0, 0x50, 0x4, 0x0, 0x7, 0xb2}} - -#define NS_CHARSETMENU_PID "charset-menu" - -nsresult -NS_NewCharsetMenu(nsISupports* aOuter, const nsIID& aIID, - void** aResult); - -#endif /* nsCharsetMenu_h___ */ diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index 62b69a9d59f1..f417052987fd 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -23,7 +23,6 @@ PARALLEL_DIRS += [ 'filepicker', 'finalizationwitness', 'find', - 'intl', 'jsdownloads', 'mediasniffer', 'microformats', diff --git a/toolkit/components/places/History.cpp b/toolkit/components/places/History.cpp index e35feacabb78..99fb84cf8988 100644 --- a/toolkit/components/places/History.cpp +++ b/toolkit/components/places/History.cpp @@ -251,7 +251,7 @@ GetJSArrayFromJSValue(JS::Handle aValue, _array.set(JS_NewArrayObject(aCtx, 0)); NS_ENSURE_TRUE(_array, NS_ERROR_OUT_OF_MEMORY); - bool rc = JS_DefineElement(aCtx, _array, 0, aValue, nullptr, nullptr, 0); + bool rc = JS_DefineElement(aCtx, _array, 0, aValue, 0); NS_ENSURE_TRUE(rc, NS_ERROR_UNEXPECTED); return NS_OK; } diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 069e7859923c..3d8d3d5ff8ce 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -516,7 +516,7 @@ bool TelemetryIOInterposeObserver::ReflectFileStats(FileIOEntryType* entry, stages[s].setObject(*jsStats); } - JS::RootedObject jsEntry(cx, JS_NewArrayObject(cx, stages)); + JS::Rooted jsEntry(cx, JS_NewArrayObject(cx, stages)); if (!jsEntry) { return false; } @@ -524,8 +524,7 @@ bool TelemetryIOInterposeObserver::ReflectFileStats(FileIOEntryType* entry, // Add jsEntry to top-level dictionary const nsAString& key = entry->GetKey(); return JS_DefineUCProperty(cx, obj, key.Data(), key.Length(), - OBJECT_TO_JSVAL(jsEntry), nullptr, nullptr, - JSPROP_ENUMERATE | JSPROP_READONLY); + jsEntry, JSPROP_ENUMERATE | JSPROP_READONLY); } bool TelemetryIOInterposeObserver::ReflectIntoJS(JSContext *cx, @@ -806,7 +805,7 @@ FillRanges(JSContext *cx, JS::Handle array, Histogram *h) JS::Rooted range(cx); for (size_t i = 0; i < h->bucket_count(); i++) { range = INT_TO_JSVAL(h->ranges(i)); - if (!JS_DefineElement(cx, array, i, range, nullptr, nullptr, JSPROP_ENUMERATE)) + if (!JS_DefineElement(cx, array, i, range, JSPROP_ENUMERATE)) return false; } return true; @@ -870,8 +869,7 @@ ReflectHistogramAndSamples(JSContext *cx, JS::Handle obj, Histogram * return REFLECT_FAILURE; } for (size_t i = 0; i < count; i++) { - if (!JS_DefineElement(cx, counts_array, i, INT_TO_JSVAL(ss.counts(i)), - nullptr, nullptr, JSPROP_ENUMERATE)) { + if (!JS_DefineElement(cx, counts_array, i, ss.counts(i), JSPROP_ENUMERATE)) { return REFLECT_FAILURE; } } diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index 50582345c074..727ae660ce5d 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -1270,7 +1270,7 @@ nsUrlClassifierDBService::LookupURI(nsIPrincipal* aPrincipal, if (!clean) { nsCOMPtr permissionManager = - do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + services::GetPermissionManager(); if (permissionManager) { uint32_t perm; diff --git a/toolkit/content/charsetOverlay.js b/toolkit/content/charsetOverlay.js deleted file mode 100644 index 60961e663604..000000000000 --- a/toolkit/content/charsetOverlay.js +++ /dev/null @@ -1,267 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -function MultiplexHandler(aEvent) -{ - MultiplexHandlerEx( - aEvent, - function Browser_SelectDetector(event) { - BrowserCharsetReload(); - /* window.content.location.reload() will re-download everything */ - SelectDetector(event, null); - }, - function Browser_SetForcedCharset(charset, isPredefined) { - BrowserSetForcedCharacterSet(charset); - } - ); -} - -function MailMultiplexHandler(aEvent) -{ - MultiplexHandlerEx( - aEvent, - function Mail_SelectDetector(event) { - SelectDetector( - event, - function Mail_Reload() { - messenger.setDocumentCharset(msgWindow.mailCharacterSet); - } - ); - }, - function Mail_SetForcedCharset(charset, isPredefined) { - MessengerSetForcedCharacterSet(charset); - } - ); -} - -function ComposerMultiplexHandler(aEvent) -{ - MultiplexHandlerEx( - aEvent, - function Composer_SelectDetector(event) { - SelectDetector( - event, - function Composer_Reload() { - EditorLoadUrl(GetDocumentUrl()); - } - ); - }, - function Composer_SetForcedCharset(charset, isPredefined) { - if ((!isPredefined) && charset.length > 0) { - gCharsetMenu.SetCurrentComposerCharset(charset); - } - EditorSetDocumentCharacterSet(charset); - } - ); -} - -function MultiplexHandlerEx(aEvent, aSelectDetector, aSetForcedCharset) -{ - try { - var node = aEvent.target; - var name = node.getAttribute('name'); - - if (name == 'detectorGroup') { - aSelectDetector(aEvent); - } else if (name == 'charsetGroup') { - var charset = node.getAttribute('id'); - charset = charset.substring('charset.'.length, charset.length) - aSetForcedCharset(charset, true); - } else if (name == 'charsetCustomize') { - //do nothing - please remove this else statement, once the charset prefs moves to the pref window - } else { - aSetForcedCharset(node.getAttribute('id'), false); - } - } catch(ex) { - alert(ex); - } -} - -function SelectDetector(event, doReload) -{ - dump("Charset Detector menu item pressed: " + event.target.getAttribute('id') + "\n"); - - var uri = event.target.getAttribute("id"); - var prefvalue = uri.substring('chardet.'.length, uri.length); - if ("off" == prefvalue) { // "off" is special value to turn off the detectors - prefvalue = ""; - } - - try { - var pref = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefBranch); - var str = Components.classes["@mozilla.org/supports-string;1"] - .createInstance(Components.interfaces.nsISupportsString); - - str.data = prefvalue; - pref.setComplexValue("intl.charset.detector", - Components.interfaces.nsISupportsString, str); - if (typeof doReload == "function") doReload(); - } - catch (ex) { - dump("Failed to set the intl.charset.detector preference.\n"); - } -} - -var gPrevCharset = null; -function UpdateCurrentCharset() -{ - // extract the charset from DOM - var wnd = document.commandDispatcher.focusedWindow; - if ((window == wnd) || (wnd == null)) wnd = window.content; - - // Uncheck previous item - if (gPrevCharset) { - var pref_item = document.getElementById('charset.' + gPrevCharset); - if (pref_item) - pref_item.setAttribute('checked', 'false'); - } - - var menuitem = document.getElementById('charset.' + wnd.document.characterSet); - if (menuitem) { - menuitem.setAttribute('checked', 'true'); - } -} - -function UpdateCurrentMailCharset() -{ - var charset = msgWindow.mailCharacterSet; - var menuitem = document.getElementById('charset.' + charset); - - if (menuitem) { - menuitem.setAttribute('checked', 'true'); - } -} - -function UpdateCharsetDetector() -{ - var prefvalue; - - try { - var pref = Components.classes["@mozilla.org/preferences-service;1"] - .getService(Components.interfaces.nsIPrefBranch); - prefvalue = pref.getComplexValue("intl.charset.detector", - Components.interfaces.nsIPrefLocalizedString).data; - } - catch (ex) { - prefvalue = ""; - } - - if (prefvalue == "") prefvalue = "off"; - dump("intl.charset.detector = "+ prefvalue + "\n"); - - prefvalue = 'chardet.' + prefvalue; - var menuitem = document.getElementById(prefvalue); - - if (menuitem) { - menuitem.setAttribute('checked', 'true'); - } -} - -function UpdateMenus(event) -{ - // use setTimeout workaround to delay checkmark the menu - // when onmenucomplete is ready then use it instead of oncreate - // see bug 78290 for the detail - UpdateCurrentCharset(); - setTimeout(UpdateCurrentCharset, 0); - UpdateCharsetDetector(); - setTimeout(UpdateCharsetDetector, 0); -} - -function CreateMenu(node) -{ - var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService); - observerService.notifyObservers(null, "charsetmenu-selected", node); -} - -function UpdateMailMenus(event) -{ - // use setTimeout workaround to delay checkmark the menu - // when onmenucomplete is ready then use it instead of oncreate - // see bug 78290 for the detail - UpdateCurrentMailCharset(); - setTimeout(UpdateCurrentMailCharset, 0); - UpdateCharsetDetector(); - setTimeout(UpdateCharsetDetector, 0); -} - -var gCharsetMenu = Components.classes['@mozilla.org/rdf/datasource;1?name=charset-menu'].getService().QueryInterface(Components.interfaces.nsICurrentCharsetListener); -var gLastBrowserCharset = null; - -function charsetLoadListener (event) -{ - var charset = window.content.document.characterSet; - - if (charset.length > 0 && (charset != gLastBrowserCharset)) { - gCharsetMenu.SetCurrentCharset(charset); - gPrevCharset = gLastBrowserCharset; - gLastBrowserCharset = charset; - } -} - - -function composercharsetLoadListener (event) -{ - var charset = window.content.document.characterSet; - - - if (charset.length > 0 ) { - gCharsetMenu.SetCurrentComposerCharset(charset); - } - } - -function SetForcedEditorCharset(charset) -{ - if (charset.length > 0 ) { - gCharsetMenu.SetCurrentComposerCharset(charset); - } - EditorSetDocumentCharacterSet(charset); -} - - -var gLastMailCharset = null; - -function mailCharsetLoadListener (event) -{ - if (msgWindow) { - var charset = msgWindow.mailCharacterSet; - if (charset.length > 0 && (charset != gLastMailCharset)) { - gCharsetMenu.SetCurrentMailCharset(charset); - gLastMailCharset = charset; - } - } -} - -function InitCharsetMenu() -{ - removeEventListener("load", InitCharsetMenu, true); - - var wintype = document.documentElement.getAttribute('windowtype'); - if (window && (wintype == "navigator:browser")) - { - var contentArea = window.document.getElementById("appcontent"); - if (contentArea) - contentArea.addEventListener("pageshow", charsetLoadListener, true); - } - else - { - var arrayOfStrings = wintype.split(":"); - if (window && arrayOfStrings[0] == "mail") - { - var messageContent = window.document.getElementById("messagepane"); - if (messageContent) - messageContent.addEventListener("pageshow", mailCharsetLoadListener, true); - } - else - if (window && arrayOfStrings[0] == "composer") - { - contentArea = window.document.getElementById("appcontent"); - if (contentArea) - contentArea.addEventListener("pageshow", composercharsetLoadListener, true); - } - } -} - -addEventListener("load", InitCharsetMenu, true); diff --git a/toolkit/content/charsetOverlay.xul b/toolkit/content/charsetOverlay.xul deleted file mode 100644 index 6bea37b08659..000000000000 --- a/toolkit/content/charsetOverlay.xul +++ /dev/null @@ -1,325 +0,0 @@ - - - - - - - - - - - - - -