diff --git a/accessible/ipc/DocAccessibleParent.cpp b/accessible/ipc/DocAccessibleParent.cpp index d8d3180d2ecd..636f93b90b35 100644 --- a/accessible/ipc/DocAccessibleParent.cpp +++ b/accessible/ipc/DocAccessibleParent.cpp @@ -19,6 +19,8 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData) if (mShutdown) return true; + CheckDocTree(); + if (aData.NewTree().IsEmpty()) { NS_ERROR("no children being added"); return false; @@ -48,6 +50,8 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData) } #endif + CheckDocTree(); + return true; } @@ -118,6 +122,8 @@ DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID) parent->RemoveChild(root); root->Shutdown(); + CheckDocTree(); + return true; } @@ -190,9 +196,12 @@ DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uin if (!aID) return false; + CheckDocTree(); + auto childDoc = static_cast(aChildDoc); bool result = AddChildDoc(childDoc, aID, false); MOZ_ASSERT(result); + CheckDocTree(); return result; } diff --git a/b2g/app/b2g.js b/b2g/app/b2g.js index ce5181f642c8..a4b5d71f4eb2 100644 --- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -627,9 +627,7 @@ pref("app.update.socket.maxErrors", 20); pref("app.update.log", true); // SystemUpdate API -#ifdef MOZ_WIDGET_GONK pref("dom.system_update.active", "@mozilla.org/updates/update-prompt;1"); -#endif #else // Explicitly disable the shutdown watchdog. It's enabled by default. // When the updater is disabled, we want to know about shutdown hangs. diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index 4cddb93034d3..8d9a0d6bf7e1 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index c5ac83614114..fa99bc21bc38 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index 9fe1142f91a9..34f99c095685 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index d881cc07abb9..4c1c36f65ffc 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index 2a42bab14101..cc4b87a2c2ac 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index 7013870db80d..d603471c0099 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index 9fe1142f91a9..34f99c095685 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index b8f690c4fcc9..e69fc2e3035b 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index c4a0921249f5..e0d5e3063105 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "21256d7665f972255d198f8af81a8df4bd0e0fc4", + "git_revision": "088f350b39baf8f86c7c1161fd4be178ce822b7b", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "5ec7add1a5ed54e7c57e9fd24704624a9e84139a", + "revision": "97666dae0fe5da2a0da4f57f41fcb12e9c2fe709", "repo_path": "integration/gaia-central" } diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index 311c2ddaa029..2d21dc36efee 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,7 +17,7 @@ - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index 2414b8573463..ce7372256e2d 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + diff --git a/b2g/installer/package-manifest.in b/b2g/installer/package-manifest.in index 100973054c1d..51e85ef77eb0 100644 --- a/b2g/installer/package-manifest.in +++ b/b2g/installer/package-manifest.in @@ -709,9 +709,13 @@ @RESPATH@/components/nsUrlClassifierHashCompleter.js @RESPATH@/components/nsUrlClassifierListManager.js @RESPATH@/components/nsUrlClassifierLib.js -@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js @RESPATH@/components/url-classifier.xpt +; Private Browsing +@RESPATH@/components/privatebrowsing.xpt +@RESPATH@/components/PrivateBrowsing.manifest +@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js + ; GNOME hooks #ifdef MOZ_ENABLE_GNOME_COMPONENT @RESPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@ diff --git a/browser/config/mozconfigs/linux64/opt-tsan b/browser/config/mozconfigs/linux64/opt-tsan index d1673fd51cf9..872a0ca69f1e 100644 --- a/browser/config/mozconfigs/linux64/opt-tsan +++ b/browser/config/mozconfigs/linux64/opt-tsan @@ -2,6 +2,9 @@ ac_add_options --with-google-oauth-api-keyfile=/builds/google-oauth-api.key . $topsrcdir/build/unix/mozconfig.tsan +export PKG_CONFIG_LIBDIR=/usr/lib64/pkgconfig:/usr/share/pkgconfig +. $topsrcdir/build/unix/mozconfig.gtk + # Need this to prevent name conflicts with the normal nightly build packages export MOZ_PKG_SPECIAL=tsan diff --git a/browser/config/tooltool-manifests/linux64/tsan.manifest b/browser/config/tooltool-manifests/linux64/tsan.manifest index 11fbd9e68d90..80609e02c1a0 100644 --- a/browser/config/tooltool-manifests/linux64/tsan.manifest +++ b/browser/config/tooltool-manifests/linux64/tsan.manifest @@ -8,5 +8,12 @@ "algorithm": "sha512", "filename": "clang.tar.bz2", "unpack": true +}, +{ +"size": 4431740, +"digest": "68fc56b0fb0cdba629b95683d6649ff76b00dccf97af90960c3d7716f6108b2162ffd5ffcd5c3a60a21b28674df688fe4dabc67345e2da35ec5abeae3d48c8e3", +"algorithm": "sha512", +"filename": "gtk3.tar.xz", +"unpack": true } ] diff --git a/browser/config/tooltool-manifests/macosx64/cross-releng.manifest b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest new file mode 100644 index 000000000000..5e36a856df2d --- /dev/null +++ b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest @@ -0,0 +1,34 @@ +[ +{ +"clang_version": "r183744" +}, +{ +"size": 70350828, +"digest": "6cd04e8ec44c6fef159349c22bd0476891e4a2d46479f9586283eaf3305e42f79c720d40dfec0e78d8899c1651189b12e285de60862ffd0612b0dac7a0c336c6", +"algorithm": "sha512", +"unpack": true, +"filename": "clang.tar.bz2" +}, +{ +"size": 2581027, +"digest": "9b59abef2bd4ae3a5b792de96e1336d879c1c5b6b07382797ae1bcc299e74ddf805bc95b7bc813cf3b4586db5eb4d0f41d09b2f85f0629cf27e57a4de851129c", +"algorithm": "sha512", +"unpack": true, +"filename": "cctools.tar.gz" +}, +{ +"size": 35215976, +"visibility": "internal", +"digest": "8be736545ddab25ebded188458ce974d5c9a7e29f3c50d2ebfbcb878f6aff853dd2ff5a3528bdefc64396a10101a1b50fd2fe52000140df33643cebe1ea759da", +"algorithm": "sha512", +"unpack": true, +"filename": "MacOSX10.7.sdk.tar.bz2" +}, +{ +"size": 167175, +"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831", +"algorithm": "sha512", +"unpack": true, +"filename": "sccache.tar.bz2" +} +] diff --git a/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js b/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js index 14c51b24fc6a..c89eb47ce924 100644 --- a/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js +++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js @@ -42,7 +42,6 @@ const TESTS = [ file: "test-bug-595934-workers.html", category: "Web Worker", matchString: "fooBarWorker", - expectError: true, }, { // #4 diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index c142003a8952..e68059c1e7a6 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -638,10 +638,14 @@ @RESPATH@/components/nsUrlClassifierHashCompleter.js @RESPATH@/components/nsUrlClassifierListManager.js @RESPATH@/components/nsUrlClassifierLib.js -@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js @RESPATH@/components/url-classifier.xpt #endif +; Private Browsing +@RESPATH@/components/privatebrowsing.xpt +@RESPATH@/components/PrivateBrowsing.manifest +@RESPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js + ; ANGLE GLES-on-D3D rendering library #ifdef MOZ_ANGLE_RENDERER @BINPATH@/libEGL.dll diff --git a/build/autoconf/icu.m4 b/build/autoconf/icu.m4 index 838e977236d9..dd673c06e426 100644 --- a/build/autoconf/icu.m4 +++ b/build/autoconf/icu.m4 @@ -173,59 +173,59 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then ICU_CROSS_BUILD_OPT="" if test "$CROSS_COMPILE"; then - # Remove _DEPEND_CFLAGS from HOST_FLAGS to avoid configure error - HOST_ICU_CFLAGS="$HOST_CFLAGS" - HOST_ICU_CXXFLAGS="$HOST_CXXFLAGS" + # Remove _DEPEND_CFLAGS from HOST_FLAGS to avoid configure error + HOST_ICU_CFLAGS="$HOST_CFLAGS" + HOST_ICU_CXXFLAGS="$HOST_CXXFLAGS" - HOST_ICU_CFLAGS=`echo $HOST_ICU_CFLAGS | sed "s|$_DEPEND_CFLAGS||g"` - HOST_ICU_CXXFLAGS=`echo $HOST_ICU_CFXXLAGS | sed "s|$_DEPEND_CFLAGS||g"` + HOST_ICU_CFLAGS=`echo $HOST_ICU_CFLAGS | sed "s|$_DEPEND_CFLAGS||g"` + HOST_ICU_CXXFLAGS=`echo $HOST_ICU_CFXXLAGS | sed "s|$_DEPEND_CFLAGS||g"` - # ICU requires RTTI - if test "$GNU_CC"; then - HOST_ICU_CXXFLAGS=`echo $HOST_ICU_CXXFLAGS | sed 's|-fno-rtti|-frtti|g'` - elif test "$_MSC_VER"; then - HOST_ICU_CXXFLAGS=`echo $HOST_ICU_CXXFLAGS | sed 's|-GR-|-GR|g'` - fi + # ICU requires RTTI + if test "$GNU_CC"; then + HOST_ICU_CXXFLAGS=`echo $HOST_ICU_CXXFLAGS | sed 's|-fno-rtti|-frtti|g'` + elif test "$_MSC_VER"; then + HOST_ICU_CXXFLAGS=`echo $HOST_ICU_CXXFLAGS | sed 's|-GR-|-GR|g'` + fi - HOST_ICU_BUILD_OPTS="" - if test -n "$MOZ_DEBUG"; then - HOST_ICU_BUILD_OPTS="$HOST_ICU_BUILD_OPTS --enable-debug" - fi + HOST_ICU_BUILD_OPTS="" + if test -n "$MOZ_DEBUG"; then + HOST_ICU_BUILD_OPTS="$HOST_ICU_BUILD_OPTS --enable-debug" + fi - abs_srcdir=`(cd $srcdir; pwd)` - mkdir -p $_objdir/intl/icu/host - (export AR="$HOST_AR" - export RANLIB="$HOST_RANLIB" - export CC="$HOST_CC" - export CXX="$HOST_CXX" - export CPP="$HOST_CPP" - export LD="$HOST_LD" - export CFLAGS="$HOST_ICU_CFLAGS $HOST_OPTIMIZE_FLAGS" - export CPPFLAGS="$ICU_CPPFLAGS" - export CXXFLAGS="$HOST_ICU_CXXFLAGS $HOST_OPTIMIZE_FLAGS" - export LDFLAGS="$HOST_LDFLAGS" - ac_configure_args="$HOST_ICU_BUILD_OPTS" - ac_configure_args="$ac_configure_args --enable-static --disable-shared --enable-extras=no --enable-icuio=no --enable-layout=no --enable-tests=no --enable-samples=no" - AC_OUTPUT_SUBDIRS_NOW(intl/icu/source:intl/icu/host) - ) || exit 1 - # generate config/icucross.mk - $GMAKE -C $_objdir/intl/icu/host/ config/icucross.mk + abs_srcdir=`(cd $srcdir; pwd)` + mkdir -p $_objdir/intl/icu/host + (export AR="$HOST_AR" + export RANLIB="$HOST_RANLIB" + export CC="$HOST_CC" + export CXX="$HOST_CXX" + export CPP="$HOST_CPP" + export LD="$HOST_LD" + export CFLAGS="$HOST_ICU_CFLAGS $HOST_OPTIMIZE_FLAGS" + export CPPFLAGS="$ICU_CPPFLAGS" + export CXXFLAGS="$HOST_ICU_CXXFLAGS $HOST_OPTIMIZE_FLAGS" + export LDFLAGS="$HOST_LDFLAGS" + ac_configure_args="$HOST_ICU_BUILD_OPTS" + ac_configure_args="$ac_configure_args --enable-static --disable-shared --enable-extras=no --enable-icuio=no --enable-layout=no --enable-tests=no --enable-samples=no" + AC_OUTPUT_SUBDIRS_NOW(intl/icu/source:intl/icu/host) + ) || exit 1 + # generate config/icucross.mk + $GMAKE -C $_objdir/intl/icu/host/ config/icucross.mk - # --with-cross-build requires absolute path - ICU_HOST_PATH=`cd $_objdir/intl/icu/host && pwd` - ICU_CROSS_BUILD_OPT="--with-cross-build=$ICU_HOST_PATH --disable-tools" - ICU_TARGET_OPT="--build=$build --host=$target" + # --with-cross-build requires absolute path + ICU_HOST_PATH=`cd $_objdir/intl/icu/host && pwd` + ICU_CROSS_BUILD_OPT="--with-cross-build=$ICU_HOST_PATH --disable-tools" + ICU_TARGET_OPT="--build=$build --host=$target" else - # CROSS_COMPILE isn't set build and target are i386 and x86-64. - # So we must set target for --build and --host. - ICU_TARGET_OPT="--build=$target --host=$target" + # CROSS_COMPILE isn't set build and target are i386 and x86-64. + # So we must set target for --build and --host. + ICU_TARGET_OPT="--build=$target --host=$target" fi if test -z "$MOZ_SHARED_ICU"; then - # To reduce library size, use static linking - ICU_LINK_OPTS="--enable-static --disable-shared" + # To reduce library size, use static linking + ICU_LINK_OPTS="--enable-static --disable-shared" else - ICU_LINK_OPTS="--disable-static --enable-shared" + ICU_LINK_OPTS="--disable-static --enable-shared" fi # Force the ICU static libraries to be position independent code ICU_CFLAGS="$DSO_PIC_CFLAGS $CFLAGS" @@ -233,64 +233,64 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then ICU_BUILD_OPTS="" if test -n "$MOZ_DEBUG" -o "MOZ_DEBUG_SYMBOLS"; then - ICU_CFLAGS="$ICU_CFLAGS $MOZ_DEBUG_FLAGS" - ICU_CXXFLAGS="$ICU_CXXFLAGS $MOZ_DEBUG_FLAGS" - if test -n "$CROSS_COMPILE" -a "$OS_TARGET" = "Darwin" \ - -a "$HOST_OS_ARCH" != "Darwin" - then - # Bug 951758: Cross-OSX builds with non-Darwin hosts have issues - # with -g and friends (like -gdwarf and -gfull) because they try - # to run dsymutil - changequote(,) - ICU_CFLAGS=`echo $ICU_CFLAGS | sed 's|-g[^ \t]*||g'` - ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-g[^ \t]*||g'` - changequote([,]) - fi + ICU_CFLAGS="$ICU_CFLAGS $MOZ_DEBUG_FLAGS" + ICU_CXXFLAGS="$ICU_CXXFLAGS $MOZ_DEBUG_FLAGS" + if test -n "$CROSS_COMPILE" -a "$OS_TARGET" = "Darwin" \ + -a "$HOST_OS_ARCH" != "Darwin" + then + # Bug 951758: Cross-OSX builds with non-Darwin hosts have issues + # with -g and friends (like -gdwarf and -gfull) because they try + # to run dsymutil + changequote(,) + ICU_CFLAGS=`echo $ICU_CFLAGS | sed 's|-g[^ \t]*||g'` + ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-g[^ \t]*||g'` + changequote([,]) + fi - ICU_LDFLAGS="$MOZ_DEBUG_LDFLAGS" - if test -z "$MOZ_DEBUG"; then - # To generate debug symbols, it requires MOZ_DEBUG_FLAGS. - # But, not debug build. - ICU_CFLAGS="$ICU_CFLAGS -UDEBUG -DNDEBUG" - ICU_CXXFLAGS="$ICU_CXXFLAGS -UDEBUG -DNDEBUG" - elif test -z "$MOZ_NO_DEBUG_RTL"; then - ICU_BUILD_OPTS="$ICU_BUILD_OPTS --enable-debug" - fi + ICU_LDFLAGS="$MOZ_DEBUG_LDFLAGS" + if test -z "$MOZ_DEBUG"; then + # To generate debug symbols, it requires MOZ_DEBUG_FLAGS. + # But, not debug build. + ICU_CFLAGS="$ICU_CFLAGS -UDEBUG -DNDEBUG" + ICU_CXXFLAGS="$ICU_CXXFLAGS -UDEBUG -DNDEBUG" + elif test -z "$MOZ_NO_DEBUG_RTL"; then + ICU_BUILD_OPTS="$ICU_BUILD_OPTS --enable-debug" + fi fi if test -z "$MOZ_OPTIMIZE"; then - ICU_BUILD_OPTS="$ICU_BUILD_OPTS --disable-release" + ICU_BUILD_OPTS="$ICU_BUILD_OPTS --disable-release" else - ICU_CFLAGS="$ICU_CFLAGS $MOZ_OPTIMIZE_FLAGS" - ICU_CXXFLAGS="$ICU_CXXFLAGS $MOZ_OPTIMIZE_FLAGS" + ICU_CFLAGS="$ICU_CFLAGS $MOZ_OPTIMIZE_FLAGS" + ICU_CXXFLAGS="$ICU_CXXFLAGS $MOZ_OPTIMIZE_FLAGS" fi if test "$am_cv_langinfo_codeset" = "no"; then - # ex. Android - ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_HAVE_NL_LANGINFO_CODESET=0" + # ex. Android + ICU_CPPFLAGS="$ICU_CPPFLAGS -DU_HAVE_NL_LANGINFO_CODESET=0" fi # ICU requires RTTI if test "$GNU_CC"; then - ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-fno-rtti|-frtti|g'` + ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-fno-rtti|-frtti|g'` else - if test "$_MSC_VER"; then - ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-GR-|-GR|g'` - fi + if test "$_MSC_VER"; then + ICU_CXXFLAGS=`echo $ICU_CXXFLAGS | sed 's|-GR-|-GR|g'` + fi - # Add RTL flags for MSVCRT.DLL - if test -n "$MOZ_DEBUG" -a -z "$MOZ_NO_DEBUG_RTL"; then - ICU_CFLAGS="$ICU_CFLAGS -MDd" - ICU_CXXFLAGS="$ICU_CXXFLAGS -MDd" - else - ICU_CFLAGS="$ICU_CFLAGS -MD" - ICU_CXXFLAGS="$ICU_CXXFLAGS -MD" - fi + # Add RTL flags for MSVCRT.DLL + if test -n "$MOZ_DEBUG" -a -z "$MOZ_NO_DEBUG_RTL"; then + ICU_CFLAGS="$ICU_CFLAGS -MDd" + ICU_CXXFLAGS="$ICU_CXXFLAGS -MDd" + else + ICU_CFLAGS="$ICU_CFLAGS -MD" + ICU_CXXFLAGS="$ICU_CXXFLAGS -MD" + fi - # add disable optimize flag for workaround for bug 899948 - if test -z "$MOZ_OPTIMIZE"; then - ICU_CFLAGS="$ICU_CFLAGS -Od" - ICU_CXXFLAGS="$ICU_CXXFLAGS -Od" - fi + # add disable optimize flag for workaround for bug 899948 + if test -z "$MOZ_OPTIMIZE"; then + ICU_CFLAGS="$ICU_CFLAGS -Od" + ICU_CXXFLAGS="$ICU_CXXFLAGS -Od" + fi fi if test -n "$gonkdir"; then diff --git a/build/macosx/cross-mozconfig.common b/build/macosx/cross-mozconfig.common new file mode 100644 index 000000000000..311acde7a464 --- /dev/null +++ b/build/macosx/cross-mozconfig.common @@ -0,0 +1,50 @@ +# 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/. + +MOZ_AUTOMATION_L10N_CHECK=0 +#TODO: bug 935237 - fix packaging +MOZ_AUTOMATION_PACKAGE=0 +#TODO: bug 543111 - fix Breakpad +MOZ_AUTOMATION_BUILD_SYMBOLS=0 +MOZ_AUTOMATION_UPLOAD_SYMBOLS=0 + +if [ "x$IS_NIGHTLY" = "xyes" ]; then + # Some nightlies (eg: Mulet) don't want these set. + MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1} + MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1} +fi +. "$topsrcdir/build/mozconfig.common" +#TODO: bug 543111 - fix Breakpad +ac_add_options --disable-crashreporter + +# ld needs libLTO.so from llvm +mk_add_options "export LD_LIBRARY_PATH=$topsrcdir/clang/lib" + +CROSS_CCTOOLS_PATH=$topsrcdir/cctools +CROSS_SYSROOT=$topsrcdir/MacOSX10.7.sdk +CROSS_PRIVATE_FRAMEWORKS=$CROSS_SYSROOT/System/Library/PrivateFrameworks +FLAGS="-target x86_64-apple-darwin10 -mlinker-version=136 -B $CROSS_CCTOOLS_PATH/bin -isysroot $CROSS_SYSROOT" + +export CC="$topsrcdir/clang/bin/clang $FLAGS" +export CXX="$topsrcdir/clang/bin/clang++ $FLAGS" +export CPP="$topsrcdir/clang/bin/clang $FLAGS -E" +export LLVMCONFIG=$topsrcdir/clang/bin/llvm-config +export LDFLAGS="-Wl,-syslibroot,$CROSS_SYSROOT -Wl,-dead_strip" +export TOOLCHAIN_PREFIX=$CROSS_CCTOOLS_PATH/bin/x86_64-apple-darwin10- +#TODO: bug 1184202 - would be nice if these could be detected with TOOLCHAIN_PREFIX automatically +export AR=${TOOLCHAIN_PREFIX}ar +export RANLIB=${TOOLCHAIN_PREFIX}ranlib +export STRIP=${TOOLCHAIN_PREFIX}strip +export OTOOL=${TOOLCHAIN_PREFIX}otool + +export HOST_CC=gcc +export HOST_CXX=g++ +export HOST_LDFLAGS="-g" + +ac_add_options --target=x86_64-apple-darwin +ac_add_options --with-macos-private-frameworks=$CROSS_PRIVATE_FRAMEWORKS + +. "$topsrcdir/build/mozconfig.cache" + +export SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE=/builds/crash-stats-api.token diff --git a/build/macosx/local-mozconfig.common b/build/macosx/local-mozconfig.common new file mode 100644 index 000000000000..a36cf895d431 --- /dev/null +++ b/build/macosx/local-mozconfig.common @@ -0,0 +1,37 @@ +# 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/. + +MOZ_AUTOMATION_L10N_CHECK=0 + +if [ "x$IS_NIGHTLY" = "xyes" ]; then + # Some nightlies (eg: Mulet) don't want these set. + MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1} + MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1} + MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1} +fi +. "$topsrcdir/build/mozconfig.common" + +if [ -d "$topsrcdir/clang" ]; then + # mozilla-central based build + export CC=$topsrcdir/clang/bin/clang + export CXX=$topsrcdir/clang/bin/clang++ + export LLVMCONFIG=$topsrcdir/clang/bin/llvm-config +elif [ -d "$topsrcdir/../clang" ]; then + # comm-central based build + export CC=$topsrcdir/../clang/bin/clang + export CXX=$topsrcdir/../clang/bin/clang++ + export LLVMCONFIG=$topsrcdir/../clang/bin/llvm-config +fi + +# If not set use the system default clang +if [ -z "$CC" ]; then + export CC=clang +fi + +# If not set use the system default clang++ +if [ -z "$CXX" ]; then + export CXX=clang++ +fi + +export SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE=/builds/crash-stats-api.token diff --git a/build/macosx/mozconfig.common b/build/macosx/mozconfig.common index a36cf895d431..27634b7f3162 100644 --- a/build/macosx/mozconfig.common +++ b/build/macosx/mozconfig.common @@ -1,37 +1,5 @@ -# 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/. - -MOZ_AUTOMATION_L10N_CHECK=0 - -if [ "x$IS_NIGHTLY" = "xyes" ]; then - # Some nightlies (eg: Mulet) don't want these set. - MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1} - MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1} - MOZ_AUTOMATION_SDK=${MOZ_AUTOMATION_SDK-1} +if test `uname -s` = Linux; then + . $topsrcdir/build/macosx/cross-mozconfig.common +else + . $topsrcdir/build/macosx/local-mozconfig.common fi -. "$topsrcdir/build/mozconfig.common" - -if [ -d "$topsrcdir/clang" ]; then - # mozilla-central based build - export CC=$topsrcdir/clang/bin/clang - export CXX=$topsrcdir/clang/bin/clang++ - export LLVMCONFIG=$topsrcdir/clang/bin/llvm-config -elif [ -d "$topsrcdir/../clang" ]; then - # comm-central based build - export CC=$topsrcdir/../clang/bin/clang - export CXX=$topsrcdir/../clang/bin/clang++ - export LLVMCONFIG=$topsrcdir/../clang/bin/llvm-config -fi - -# If not set use the system default clang -if [ -z "$CC" ]; then - export CC=clang -fi - -# If not set use the system default clang++ -if [ -z "$CXX" ]; then - export CXX=clang++ -fi - -export SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE=/builds/crash-stats-api.token diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 407f2c864ca6..39e322357a31 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -761,16 +761,6 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal, // the methods that work on chains of nested URIs and they will only look // at the flags for our one URI. - // Special case: moz-extension has a whitelist of URIs that are loadable by - // anyone. - if (targetScheme.EqualsLiteral("moz-extension") && GetAddonPolicyService()) { - bool loadable = false; - rv = GetAddonPolicyService()->ExtensionURILoadableByAnyone(targetBaseURI, &loadable); - if (NS_SUCCEEDED(rv) && loadable) { - return NS_OK; - } - } - // Check for system target URI rv = DenyAccessIfURIHasFlags(targetBaseURI, nsIProtocolHandler::URI_DANGEROUS_TO_LOAD); diff --git a/caps/tests/mochitest/test_extensionURL.html b/caps/tests/mochitest/test_extensionURL.html index 6c1d7e09a0f0..7e05453f2986 100644 --- a/caps/tests/mochitest/test_extensionURL.html +++ b/caps/tests/mochitest/test_extensionURL.html @@ -89,10 +89,18 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1161831 ifr.onload = function() { ok(true, 'Loaded ' + url); var prin = SpecialPowers.wrap(ifr.contentWindow).document.nodePrincipal; - is(prin.originNoSuffix, url, 'Principal origin is correct: ' + url); + function stripTrailingSlash(s) { return s.replace(/\/$/, ''); }; + is(stripTrailingSlash(prin.URI.spec), url, 'Principal uri is correct: ' + url); + function stripPath(s) { return s.replace(/(.*\/\/.+)\/.*/, '$1'); }; + is(prin.originNoSuffix, stripPath(url), 'Principal origin is correct: ' + prin.originNoSuffix); is(prin.originAttributes.addonId, 'imaginaryaddon-' + url[url.indexOf('/') + 2], 'addonId is correct'); - is(SpecialPowers.wrap(ifr.contentWindow).document.title, 'resource test file', - 'document looks right'); + if (/_blank/.test(url)) { + is(SpecialPowers.wrap(ifr.contentWindow).document.documentElement.innerHTML, + '', 'blank document looks right'); + } else { + is(SpecialPowers.wrap(ifr.contentWindow).document.title, 'resource test file', + 'document looks right'); + } ifr.remove(); resolve(); }; @@ -104,7 +112,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1161831 } catch (e) { ifr.remove(); threw = true; - ok(/denied|insecure/.test(e), "exceiton correct: " + e); + ok(/denied|insecure/.test(e), "exception correct: " + e); } is(threw, !!shouldThrow, "Correct throwing behavior for: " + url); !threw || resolve(); @@ -126,6 +134,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1161831 .then(testLoad.bind(null, 'moz-extension://liebchen', navigateWithLocation)) .then(testLoad.bind(null, 'moz-extension://liebchen', navigateWithSrc)) .then(testLoad.bind(null, 'moz-extension://cherise', navigateWithSrc)) + .then(testLoad.bind(null, 'moz-extension://cherise/_blank.html', navigateWithSrc)) .then(SimpleTest.finish.bind(SimpleTest), function(e) { ok(false, "rejected promise: " + e); SimpleTest.finish() } ); diff --git a/configure.in b/configure.in index f76c761739d2..9ba7a2504c5a 100644 --- a/configure.in +++ b/configure.in @@ -4345,10 +4345,7 @@ cairo-cocoa) CXXFLAGS="$CXXFLAGS $TK_CFLAGS" MOZ_USER_DIR="Mozilla" MOZ_FS_LAYOUT=bundle - # skip event loop instrumentation on UIKit for now - if test "$MOZ_WIDGET_TOOLKIT" == "cocoa"; then - MOZ_INSTRUMENT_EVENT_LOOP=1 - fi + MOZ_INSTRUMENT_EVENT_LOOP=1 ;; cairo-uikit) @@ -9216,22 +9213,6 @@ if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then MOZ_SUBCONFIGURE_FFI() fi -# Hack around an Apple bug that affects the egrep that comes with OS X 10.7. -# "env ARCHPREFERENCE=i386,x86_64 arch egrep" first tries to use the 32-bit -# Intel part of the egrep fat binary, even on 64-bit systems, and falls back on -# the 64-bit part if it's not a fat binary, as can happen with MacPorts. We -# (apparently) only need this hack when egrep's "pattern" is particularly long -# (as in the following code) and the first egrep on our $PATH is Apple's. See -# bug 655339. -case "$host" in -*-apple-darwin11*) - FIXED_EGREP="env ARCHPREFERENCE=i386,x86_64 arch egrep" - ;; -*) - FIXED_EGREP="egrep" - ;; -esac - # Run jemalloc configure script if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -o -n "$MOZ_REPLACE_MALLOC"; then diff --git a/dom/alarm/AlarmService.jsm b/dom/alarm/AlarmService.jsm index 9db9d36e8322..aeaedfb724d0 100644 --- a/dom/alarm/AlarmService.jsm +++ b/dom/alarm/AlarmService.jsm @@ -5,7 +5,7 @@ "use strict"; /* static functions */ -const DEBUG = false; +const DEBUG = true; function debug(aStr) { DEBUG && dump("AlarmService: " + aStr + "\n"); diff --git a/dom/base/MultipartBlobImpl.h b/dom/base/MultipartBlobImpl.h index a74bf12272b1..0b43efbe49b6 100644 --- a/dom/base/MultipartBlobImpl.h +++ b/dom/base/MultipartBlobImpl.h @@ -98,7 +98,7 @@ public: virtual const nsTArray>* GetSubBlobImpls() const override { - return &mBlobImpls; + return mBlobImpls.Length() ? &mBlobImpls : nullptr; } virtual void GetMozFullPathInternal(nsAString& aFullPath, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index f0b1e7787bde..98973f7608aa 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -3475,17 +3475,16 @@ nsPIDOMWindow::SetFrameElementInternal(Element* aFrameElement) mOuterWindow->SetFrameElementInternal(aFrameElement); } -void +bool nsPIDOMWindow::AddAudioContext(AudioContext* aAudioContext) { MOZ_ASSERT(IsInnerWindow()); mAudioContexts.AppendElement(aAudioContext); + // Return true if the context should be muted and false if not. nsIDocShell* docShell = GetDocShell(); - if (docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline()) { - aAudioContext->Mute(); - } + return docShell && !docShell->GetAllowMedia() && !aAudioContext->IsOffline(); } void diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index 3e6404e9950c..5cda6cba2f0d 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -718,7 +718,7 @@ public: const nsAString& aPopupWindowFeatures) = 0; // Inner windows only. - void AddAudioContext(mozilla::dom::AudioContext* aAudioContext); + bool AddAudioContext(mozilla::dom::AudioContext* aAudioContext); void RemoveAudioContext(mozilla::dom::AudioContext* aAudioContext); void MuteAudioContexts(); void UnmuteAudioContexts(); diff --git a/dom/base/nsPerformance.cpp b/dom/base/nsPerformance.cpp index fbf947cf59dd..ed40e4df5f67 100644 --- a/dom/base/nsPerformance.cpp +++ b/dom/base/nsPerformance.cpp @@ -745,13 +745,7 @@ nsPerformance::InsertUserEntry(PerformanceEntry* aEntry) // If we have no URI, just put in "none". uri.AssignLiteral("none"); } - PERFLOG("Performance Entry: %s|%s|%s|%f|%f|%" PRIu64 "\n", - uri.get(), - NS_ConvertUTF16toUTF8(aEntry->GetEntryType()).get(), - NS_ConvertUTF16toUTF8(aEntry->GetName()).get(), - aEntry->StartTime(), - aEntry->Duration(), - static_cast(PR_Now() / PR_USEC_PER_MSEC)); + PerformanceBase::LogEntry(aEntry, uri); } PerformanceBase::InsertUserEntry(aEntry); @@ -980,6 +974,18 @@ PerformanceBase::ClearMeasures(const Optional& aName) ClearUserEntries(aName, NS_LITERAL_STRING("measure")); } +void +PerformanceBase::LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const +{ + PERFLOG("Performance Entry: %s|%s|%s|%f|%f|%" PRIu64 "\n", + aOwner.BeginReading(), + NS_ConvertUTF16toUTF8(aEntry->GetEntryType()).get(), + NS_ConvertUTF16toUTF8(aEntry->GetName()).get(), + aEntry->StartTime(), + aEntry->Duration(), + static_cast(PR_Now() / PR_USEC_PER_MSEC)); +} + void PerformanceBase::InsertUserEntry(PerformanceEntry* aEntry) { diff --git a/dom/base/nsPerformance.h b/dom/base/nsPerformance.h index aeb242ce5385..0ff8da712411 100644 --- a/dom/base/nsPerformance.h +++ b/dom/base/nsPerformance.h @@ -350,6 +350,8 @@ protected: return mResourceEntries.Length() >= mResourceTimingBufferSize; } + void LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const; + private: nsTArray> mUserEntries; nsTArray> mResourceEntries; diff --git a/dom/base/nsWrapperCache.cpp b/dom/base/nsWrapperCache.cpp index 74106254a57e..0b19e1a3630f 100644 --- a/dom/base/nsWrapperCache.cpp +++ b/dom/base/nsWrapperCache.cpp @@ -101,8 +101,8 @@ DebugWrapperTraceCallback(JS::GCCellPtr aPtr, const char* aName, void* aClosure) { DebugWrapperTraversalCallback* callback = static_cast(aClosure); - if (aPtr.isObject()) { - callback->NoteJSObject(aPtr.toObject()); + if (aPtr.is()) { + callback->NoteJSObject(&aPtr.as()); } } diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h index b6f37ca78b4c..af645a66a8b4 100644 --- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -322,8 +322,10 @@ private: nsScriptObjectTracer* aTracer); #ifdef DEBUG +public: void CheckCCWrapperTraversal(void* aScriptObjectHolder, nsScriptObjectTracer* aTracer); +private: #endif // DEBUG /** diff --git a/dom/base/test/file_pluginAudio.html b/dom/base/test/file_pluginAudio.html new file mode 100644 index 000000000000..02ef8bd02bd4 --- /dev/null +++ b/dom/base/test/file_pluginAudio.html @@ -0,0 +1,21 @@ + + + diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 2d667f291ecc..6feb6c1ebbd6 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -240,6 +240,7 @@ support-files = file_audioLoop.html file_webaudioLoop.html file_webaudioLoop2.html + file_pluginAudio.html referrer_helper.js referrer_testserver.sjs script_postmessages_fileList.js @@ -301,6 +302,8 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1 [test_open_null_features.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Fails on b2g-desktop, tracked in bug 1011874 [test_postMessage_solidus.html] +[test_pluginAudioNotification.html] +skip-if = (buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android') # Plugins don't work on Android and/or B2G/Mulet [test_screen_orientation.html] [test_settimeout_extra_arguments.html] [test_settimeout_inner.html] diff --git a/dom/base/test/test_pluginAudioNotification.html b/dom/base/test/test_pluginAudioNotification.html new file mode 100644 index 000000000000..cbc68672b6ab --- /dev/null +++ b/dom/base/test/test_pluginAudioNotification.html @@ -0,0 +1,117 @@ + + + + Test for audio controller in windows + + + + +
+
+ + + + + + diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index fc2e0ab85b8d..2e5d9b766470 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -879,6 +879,56 @@ struct TypeNeedsOuterization IsBaseOf::value || IsSame::value; }; +#ifdef DEBUG +template::value> +struct CheckWrapperCacheTracing +{ + static inline void Check(T* aObject) + { + } +}; + +template +struct CheckWrapperCacheTracing +{ + static void Check(T* aObject) + { + // Rooting analysis thinks QueryInterface may GC, but we're dealing with + // a subset of QueryInterface, C++ only types here. + JS::AutoSuppressGCAnalysis nogc; + + nsWrapperCache* wrapperCacheFromQI = nullptr; + aObject->QueryInterface(NS_GET_IID(nsWrapperCache), + reinterpret_cast(&wrapperCacheFromQI)); + + MOZ_ASSERT(wrapperCacheFromQI, + "Missing nsWrapperCache from QueryInterface implementation?"); + + if (!wrapperCacheFromQI->GetWrapperPreserveColor()) { + // Can't assert that we trace the wrapper, since we don't have any + // wrapper to trace. + return; + } + + nsISupports* ccISupports = nullptr; + aObject->QueryInterface(NS_GET_IID(nsCycleCollectionISupports), + reinterpret_cast(&ccISupports)); + MOZ_ASSERT(ccISupports, + "nsWrapperCache object which isn't cycle collectable?"); + + nsXPCOMCycleCollectionParticipant* participant = nullptr; + CallQueryInterface(ccISupports, &participant); + MOZ_ASSERT(participant, "Can't QI to CycleCollectionParticipant?"); + + bool wasPreservingWrapper = wrapperCacheFromQI->PreservingWrapper(); + wrapperCacheFromQI->SetPreservingWrapper(true); + wrapperCacheFromQI->CheckCCWrapperTraversal(ccISupports, participant); + wrapperCacheFromQI->SetPreservingWrapper(wasPreservingWrapper); + } +}; + +#endif + template MOZ_ALWAYS_INLINE bool DoGetOrCreateDOMReflector(JSContext* cx, T* value, @@ -903,6 +953,12 @@ DoGetOrCreateDOMReflector(JSContext* cx, T* value, // figure out whether WrapObject() threw. return false; } + +#ifdef DEBUG + if (IsBaseOf::value) { + CheckWrapperCacheTracing::Check(value); + } +#endif } #ifdef DEBUG diff --git a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp index 72108fc332b8..3cbf2c85020a 100644 --- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp +++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp @@ -700,15 +700,19 @@ BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId) // Signal JS::Rooted value(nsContentUtils::RootingCxForThread()); voiceInfo->GetRelSignalStrength(&value); - NS_ENSURE_TRUE_VOID(value.isNumber()); - mSignal = (int)ceil(value.toNumber() / 20.0); + if (value.isNumber()) { + mSignal = (int)ceil(value.toNumber() / 20.0); + } UpdateDeviceCIND(); // Operator name nsCOMPtr network; voiceInfo->GetNetwork(getter_AddRefs(network)); - NS_ENSURE_TRUE_VOID(network); + if (!network) { + BT_LOGD("Unable to get network information"); + return; + } network->GetLongName(mOperatorName); // According to GSM 07.07, " indicates if the format is alphanumeric diff --git a/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp b/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp index bb90f4c69656..aaf46e012e00 100644 --- a/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp +++ b/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp @@ -1008,6 +1008,11 @@ BluetoothAdapter::HandlePropertyChanged(const BluetoothValue& aValue) } } + if (types.IsEmpty()) { + // No adapter attribute changed + return; + } + DispatchAttributeEvent(types); } @@ -1134,7 +1139,7 @@ BluetoothAdapter::HandleDeviceUnpaired(const BluetoothValue& aValue) void BluetoothAdapter::DispatchAttributeEvent(const Sequence& aTypes) { - NS_ENSURE_TRUE_VOID(aTypes.Length()); + MOZ_ASSERT(!aTypes.IsEmpty()); BluetoothAttributeEventInit init; init.mAttrs = aTypes; diff --git a/dom/bluetooth/bluetooth2/BluetoothAdapter.h b/dom/bluetooth/bluetooth2/BluetoothAdapter.h index 588e9140e7f6..552716c13cf8 100644 --- a/dom/bluetooth/bluetooth2/BluetoothAdapter.h +++ b/dom/bluetooth/bluetooth2/BluetoothAdapter.h @@ -285,6 +285,8 @@ private: /** * Fire BluetoothAttributeEvent to trigger onattributechanged event handler. + * + * @param aTypes [in] Array of changed attributes. Must be non-empty. */ void DispatchAttributeEvent(const Sequence& aTypes); diff --git a/dom/bluetooth/bluetooth2/BluetoothDevice.cpp b/dom/bluetooth/bluetooth2/BluetoothDevice.cpp index 04e8b4c6185f..5cda4d62d381 100644 --- a/dom/bluetooth/bluetooth2/BluetoothDevice.cpp +++ b/dom/bluetooth/bluetooth2/BluetoothDevice.cpp @@ -293,13 +293,18 @@ BluetoothDevice::HandlePropertyChanged(const BluetoothValue& aValue) } } + if (types.IsEmpty()) { + // No device attribute changed + return; + } + DispatchAttributeEvent(types); } void BluetoothDevice::DispatchAttributeEvent(const Sequence& aTypes) { - NS_ENSURE_TRUE_VOID(aTypes.Length()); + MOZ_ASSERT(!aTypes.IsEmpty()); BluetoothAttributeEventInit init; init.mAttrs = aTypes; diff --git a/dom/bluetooth/bluetooth2/BluetoothDevice.h b/dom/bluetooth/bluetooth2/BluetoothDevice.h index ed27c5417be8..0fc2021d7ca8 100644 --- a/dom/bluetooth/bluetooth2/BluetoothDevice.h +++ b/dom/bluetooth/bluetooth2/BluetoothDevice.h @@ -117,6 +117,8 @@ private: /** * Fire BluetoothAttributeEvent to trigger onattributechanged event handler. + * + * @param aTypes [in] Array of changed attributes. Must be non-empty. */ void DispatchAttributeEvent(const Sequence& aTypes); diff --git a/dom/bluetooth/bluez/BluetoothHfpManager.cpp b/dom/bluetooth/bluez/BluetoothHfpManager.cpp index e0db0d0d752d..5aa46fe9ee17 100644 --- a/dom/bluetooth/bluez/BluetoothHfpManager.cpp +++ b/dom/bluetooth/bluez/BluetoothHfpManager.cpp @@ -651,9 +651,10 @@ BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId) JS::Rooted value(nsContentUtils::RootingCxForThread()); voiceInfo->GetRelSignalStrength(&value); - NS_ENSURE_TRUE_VOID(value.isNumber()); - uint8_t signal = ceil(value.toNumber() / 20.0); - UpdateCIND(CINDType::SIGNAL, signal); + if (value.isNumber()) { + uint8_t signal = ceil(value.toNumber() / 20.0); + UpdateCIND(CINDType::SIGNAL, signal); + } /** * Possible return values for mode are: @@ -667,7 +668,10 @@ BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId) nsCOMPtr network; voiceInfo->GetNetwork(getter_AddRefs(network)); - NS_ENSURE_TRUE_VOID(network); + if (!network) { + BT_LOGD("Unable to get network information"); + return; + } network->GetLongName(mOperatorName); // According to GSM 07.07, " indicates if the format is alphanumeric diff --git a/dom/cache/PrincipalVerifier.cpp b/dom/cache/PrincipalVerifier.cpp index 14abb280d9e1..7d56ba9e7f6c 100644 --- a/dom/cache/PrincipalVerifier.cpp +++ b/dom/cache/PrincipalVerifier.cpp @@ -131,6 +131,19 @@ PrincipalVerifier::VerifyOnMainThread() return; } + nsCOMPtr ssm = nsContentUtils::GetSecurityManager(); + if (NS_WARN_IF(!ssm)) { + DispatchToInitiatingThread(NS_ERROR_ILLEGAL_DURING_SHUTDOWN); + return; + } + + // Verify if a child process uses system principal, which is not allowed + // to prevent system principal is spoofed. + if (NS_WARN_IF(actor && ssm->IsSystemPrincipal(principal))) { + DispatchToInitiatingThread(NS_ERROR_FAILURE); + return; + } + // Verify that a child process claims to own the app for this principal if (NS_WARN_IF(actor && !AssertAppPrincipal(actor, principal))) { DispatchToInitiatingThread(NS_ERROR_FAILURE); @@ -138,12 +151,6 @@ PrincipalVerifier::VerifyOnMainThread() } actor = nullptr; - nsCOMPtr ssm = nsContentUtils::GetSecurityManager(); - if (NS_WARN_IF(!ssm)) { - DispatchToInitiatingThread(NS_ERROR_ILLEGAL_DURING_SHUTDOWN); - return; - } - #ifdef DEBUG // Sanity check principal origin by using it to construct a URI and security // checking it. Don't do this for the system principal, though, as its origin diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 2db6fb4a13df..b9f9efa527dc 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1825,6 +1825,12 @@ WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget, GLenum format, GLenum type, mozilla::dom::Element& elt) { + if (type == LOCAL_GL_HALF_FLOAT_OES && + !gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float)) + { + type = LOCAL_GL_HALF_FLOAT; + } + if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D)) diff --git a/dom/html/test/test_fullscreen-api-race.html b/dom/html/test/test_fullscreen-api-race.html index dd9076bf4bf4..6140b971f0ef 100644 --- a/dom/html/test/test_fullscreen-api-race.html +++ b/dom/html/test/test_fullscreen-api-race.html @@ -112,13 +112,26 @@ function next() { SimpleTest.waitForFocus(resolve, win, true); }).then(() => { return new Promise(resolve => { - function listener() { + var retried = false; + function listener(evt) { + if (!retried && evt.type == "mozfullscreenerror") { + todo(false, "Failed to enter fullscreen, but try again"); + retried = true; + SimpleTest.waitForFocus(() => { + win.document.documentElement.mozRequestFullScreen(); + }, win, true); + return; + } win.removeEventListener("mozfullscreenchange", listener); + win.removeEventListener("mozfullscreenerror", listener); + is(evt.type, "mozfullscreenchange", "Should get fullscreenchange"); ok(win.document.mozFullScreen, "Should have entered fullscreen"); ok(win.fullScreen, "The window should be in fullscreen"); test.actionFunc(win).then(resolve); } + info("About to enter fullscreen"); win.addEventListener("mozfullscreenchange", listener); + win.addEventListener("mozfullscreenerror", listener); win.document.documentElement.mozRequestFullScreen(); }); }).then(() => { diff --git a/dom/indexedDB/IDBCursor.cpp b/dom/indexedDB/IDBCursor.cpp index e64a228b8069..3aae7a2793bf 100644 --- a/dom/indexedDB/IDBCursor.cpp +++ b/dom/indexedDB/IDBCursor.cpp @@ -682,7 +682,8 @@ IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv) if (IsSourceDeleted() || !mHaveValue || mType == Type_ObjectStoreKey || - mType == Type_IndexKey) { + mType == Type_IndexKey || + mContinueCalled) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return nullptr; } diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp index df4bd790cc7c..3d7fc37c93a1 100644 --- a/dom/ipc/Blob.cpp +++ b/dom/ipc/Blob.cpp @@ -1075,6 +1075,8 @@ BlobDataFromBlobImpl(BlobImpl* aBlobImpl, BlobData& aBlobData) const nsTArray>* subBlobs = aBlobImpl->GetSubBlobImpls(); if (subBlobs) { + MOZ_ASSERT(subBlobs->Length()); + aBlobData = nsTArray(); nsTArray& subBlobDatas = aBlobData.get_ArrayOfBlobData(); @@ -1098,8 +1100,6 @@ BlobDataFromBlobImpl(BlobImpl* aBlobImpl, BlobData& aBlobData) return; } - MOZ_ASSERT(aBlobImpl->IsMemoryFile()); - ErrorResult rv; nsCOMPtr inputStream; aBlobImpl->GetInternalStream(getter_AddRefs(inputStream), rv); diff --git a/dom/media/gmp/GMPLoader.cpp b/dom/media/gmp/GMPLoader.cpp index 471537b6f5d9..e7de6635e60e 100644 --- a/dom/media/gmp/GMPLoader.cpp +++ b/dom/media/gmp/GMPLoader.cpp @@ -14,12 +14,14 @@ #include -#if defined(XP_WIN) && defined(MOZ_SANDBOX) -#include "mozilla/Scoped.h" +#ifdef XP_WIN #include "windows.h" +#ifdef MOZ_SANDBOX +#include "mozilla/Scoped.h" #include #include #endif +#endif #if defined(HASH_NODE_ID_WITH_DEVICE_ID) // In order to provide EME plugins with a "device binding" capability, @@ -196,11 +198,7 @@ GMPLoaderImpl::Load(const char* aUTF8LibPath, nodeId = std::string(aOriginSalt, aOriginSalt + aOriginSaltLen); } -#if defined(XP_WIN) && defined(MOZ_SANDBOX) - // If the GMP DLL is a side-by-side assembly with static imports then the DLL - // loader will attempt to create an activation context which will fail because - // of the sandbox. If we create an activation context before we start the - // sandbox then this one will get picked up by the DLL loader. +#ifdef XP_WIN int pathLen = MultiByteToWideChar(CP_UTF8, 0, aUTF8LibPath, -1, nullptr, 0); if (pathLen == 0) { return false; @@ -211,11 +209,17 @@ GMPLoaderImpl::Load(const char* aUTF8LibPath, return false; } +#ifdef MOZ_SANDBOX + // If the GMP DLL is a side-by-side assembly with static imports then the DLL + // loader will attempt to create an activation context which will fail because + // of the sandbox. If we create an activation context before we start the + // sandbox then this one will get picked up by the DLL loader. ACTCTX actCtx = { sizeof(actCtx) }; actCtx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID; actCtx.lpSource = widePath; actCtx.lpResourceName = ISOLATIONAWARE_MANIFEST_RESOURCE_ID; ScopedActCtxHandle actCtxHandle(CreateActCtx(&actCtx)); +#endif #endif // Start the sandbox now that we've generated the device bound node id. diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 6481f3cdfb0e..d3b202bd6e86 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -261,55 +261,86 @@ public: , mMonitor("MP4ContainerParser Index Monitor") {} - bool HasAtom(const mp4_demuxer::AtomType& aAtom, const MediaByteBuffer* aData) { - mp4_demuxer::ByteReader reader(aData); - - while (reader.Remaining() >= 8) { - uint64_t size = reader.ReadU32(); - const uint8_t* typec = reader.Peek(4); - uint32_t type = reader.ReadU32(); - MSE_DEBUGV(MP4ContainerParser ,"Checking atom:'%c%c%c%c'", - typec[0], typec[1], typec[2], typec[3]); - if (mp4_demuxer::AtomType(type) == aAtom) { - reader.DiscardRemaining(); - return true; - } - if (size == 1) { - // 64 bits size. - if (!reader.CanReadType()) { - break; - } - size = reader.ReadU64(); - } else if (size == 0) { - // Atom extends to the end of the buffer, it can't have what we're - // looking for. - break; - } - if (reader.Remaining() < size - 8) { - // Incomplete atom. - break; - } - reader.Read(size - 8); - } - reader.DiscardRemaining(); - return false; - } - bool IsInitSegmentPresent(MediaByteBuffer* aData) override { ContainerParser::IsInitSegmentPresent(aData); // Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4 // file is the 'ftyp' atom followed by a file type. We just check for a // vaguely valid 'ftyp' atom. - return HasAtom(mp4_demuxer::AtomType("ftyp"), aData); + AtomParser parser(mType, aData); + return parser.StartWithInitSegment(); } bool IsMediaSegmentPresent(MediaByteBuffer* aData) override { - ContainerParser::IsMediaSegmentPresent(aData); - return HasAtom(mp4_demuxer::AtomType("moof"), aData); + AtomParser parser(mType, aData); + return parser.StartWithMediaSegment(); } +private: + class AtomParser { + public: + AtomParser(const nsACString& aType, const MediaByteBuffer* aData) + { + const nsCString mType(aType); // for logging macro. + mp4_demuxer::ByteReader reader(aData); + mp4_demuxer::AtomType initAtom("ftyp"); + mp4_demuxer::AtomType mediaAtom("moof"); + + while (reader.Remaining() >= 8) { + uint64_t size = reader.ReadU32(); + const uint8_t* typec = reader.Peek(4); + uint32_t type = reader.ReadU32(); + MSE_DEBUGV(AtomParser ,"Checking atom:'%c%c%c%c'", + typec[0], typec[1], typec[2], typec[3]); + if (mInitOffset.isNothing() && + mp4_demuxer::AtomType(type) == initAtom) { + mInitOffset = Some(reader.Offset()); + } + if (mMediaOffset.isNothing() && + mp4_demuxer::AtomType(type) == mediaAtom) { + mMediaOffset = Some(reader.Offset()); + } + if (mInitOffset.isSome() && mMediaOffset.isSome()) { + // We have everything we need. + break; + } + if (size == 1) { + // 64 bits size. + if (!reader.CanReadType()) { + break; + } + size = reader.ReadU64(); + } else if (size == 0) { + // Atom extends to the end of the buffer, it can't have what we're + // looking for. + break; + } + if (reader.Remaining() < size - 8) { + // Incomplete atom. + break; + } + reader.Read(size - 8); + } + reader.DiscardRemaining(); + } + + bool StartWithInitSegment() + { + return mInitOffset.isSome() && + (mMediaOffset.isNothing() || mInitOffset.ref() < mMediaOffset.ref()); + } + bool StartWithMediaSegment() + { + return mMediaOffset.isSome() && + (mInitOffset.isNothing() || mMediaOffset.ref() < mInitOffset.ref()); + } + private: + Maybe mInitOffset; + Maybe mMediaOffset; + }; + +public: bool ParseStartAndEndTimestamps(MediaByteBuffer* aData, int64_t& aStart, int64_t& aEnd) override { diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index 1a20058c733c..297b6ea33712 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -781,9 +781,8 @@ void TrackBuffersManager::InitializationSegmentReceived() { MOZ_ASSERT(mParser->HasCompleteInitData()); - mInitData = mParser->InitData(); mCurrentInputBuffer = new SourceBufferResource(mType); - mCurrentInputBuffer->AppendData(mInitData); + mCurrentInputBuffer->AppendData(mParser->InitData()); uint32_t length = mParser->InitSegmentRange().mEnd - (mProcessedInput - mInputBuffer->Length()); if (mInputBuffer->Length() == length) { @@ -878,7 +877,7 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) } // 4. Let active track flag equal false. - mActiveTrack = false; + bool activeTrack = false; // Increase our stream id. uint32_t streamID = sStreamSourceID++; @@ -911,7 +910,7 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) // 7. If audioTracks.length equals 0, then run the following steps: // 1. Set the enabled property on new audio track to true. // 2. Set active track flag to true. - mActiveTrack = true; + activeTrack = true; // 8. Add new audio track to the audioTracks attribute on this SourceBuffer object. // 9. Queue a task to fire a trusted event named addtrack, that does not bubble and is not cancelable, and that uses the TrackEvent interface, at the AudioTrackList object referenced by the audioTracks attribute on this SourceBuffer object. // 10. Add new audio track to the audioTracks attribute on the HTMLMediaElement. @@ -943,7 +942,7 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) // 7. If videoTracks.length equals 0, then run the following steps: // 1. Set the selected property on new video track to true. // 2. Set active track flag to true. - mActiveTrack = true; + activeTrack = true; // 8. Add new video track to the videoTracks attribute on this SourceBuffer object. // 9. Queue a task to fire a trusted event named addtrack, that does not bubble and is not cancelable, and that uses the TrackEvent interface, at the VideoTrackList object referenced by the videoTracks attribute on this SourceBuffer object. // 10. Add new video track to the videoTracks attribute on the HTMLMediaElement. @@ -956,6 +955,9 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) // 4. For each text track in the initialization segment, run following steps: // 5. If active track flag equals true, then run the following steps: // This is handled by SourceBuffer once the promise is resolved. + if (activeTrack) { + mActiveTrack = true; + } // 6. Set first initialization segment received flag to true. mFirstInitializationSegmentReceived = true; @@ -985,6 +987,9 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) mInfo = info; } + // We now have a valid init data ; we can store it for later use. + mInitData = mParser->InitData(); + // 3. Remove the initialization segment bytes from the beginning of the input buffer. // This step has already been done in InitializationSegmentReceived when we // transferred the content into mCurrentInputBuffer. diff --git a/dom/media/mediasource/test/mochitest.ini b/dom/media/mediasource/test/mochitest.ini index 9099bdddba05..5762b2fe9cdb 100644 --- a/dom/media/mediasource/test/mochitest.ini +++ b/dom/media/mediasource/test/mochitest.ini @@ -105,3 +105,5 @@ skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) skip-if = true # Disabled due to bug 1124493 and friends. WebM MSE is deprioritized. [test_WaitingOnMissingData_mp4.html] skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ +[test_WaitingToEndedTransition_mp4.html] +skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+ diff --git a/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html b/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html new file mode 100644 index 000000000000..c5b4ca7f88cf --- /dev/null +++ b/dom/media/mediasource/test/test_WaitingToEndedTransition_mp4.html @@ -0,0 +1,58 @@ + + + + MSE: |waiting| event when source data is missing + + + + + +

+
+ + diff --git a/dom/media/test/crashtests/995289.html b/dom/media/test/crashtests/995289.html new file mode 100644 index 000000000000..c988f41fa8dd --- /dev/null +++ b/dom/media/test/crashtests/995289.html @@ -0,0 +1,9 @@ + + diff --git a/dom/media/test/crashtests/crashtests.list b/dom/media/test/crashtests/crashtests.list index 17863201549f..9af12560b6ac 100644 --- a/dom/media/test/crashtests/crashtests.list +++ b/dom/media/test/crashtests/crashtests.list @@ -67,6 +67,7 @@ load 952756.html load 966636.html load 986901.html load 990794.html +load 995289.html load 1012609.html load 1015662.html load 1020205.html diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index 9d2fdc73caae..b705970dce73 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -101,12 +101,17 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow, , mIsShutDown(false) , mCloseCalled(false) { - aWindow->AddAudioContext(this); + bool mute = aWindow->AddAudioContext(this); // Note: AudioDestinationNode needs an AudioContext that must already be // bound to the window. mDestination = new AudioDestinationNode(this, aIsOffline, aChannel, aNumberOfChannels, aLength, aSampleRate); + + // The context can't be muted until it has a destination. + if (mute) { + Mute(); + } } void diff --git a/dom/media/webaudio/WaveShaperNode.cpp b/dom/media/webaudio/WaveShaperNode.cpp index 61769f442d6e..e3f1851a4ffc 100644 --- a/dom/media/webaudio/WaveShaperNode.cpp +++ b/dom/media/webaudio/WaveShaperNode.cpp @@ -324,10 +324,14 @@ WaveShaperNode::SetCurve(const Nullable& aCurve, ErrorResult& aRv) return; } - mCurve = floats.Obj(); + if (!curve.SetLength(argLength, fallible)) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } - curve.SetLength(argLength); PodCopy(curve.Elements(), floats.Data(), floats.Length()); + + mCurve = floats.Obj(); } else { mCurve = nullptr; } diff --git a/dom/media/webaudio/blink/PeriodicWave.cpp b/dom/media/webaudio/blink/PeriodicWave.cpp index 53efae2b82be..bffe1f8b61aa 100644 --- a/dom/media/webaudio/blink/PeriodicWave.cpp +++ b/dom/media/webaudio/blink/PeriodicWave.cpp @@ -147,7 +147,7 @@ void PeriodicWave::waveDataForFundamentalFrequency(float fundamentalFrequency, f higherWaveData = m_bandLimitedTables[rangeIndex1]->Elements(); // Ranges from 0 -> 1 to interpolate between lower -> higher. - tableInterpolationFactor = pitchRange - rangeIndex1; + tableInterpolationFactor = rangeIndex2 - pitchRange; } unsigned PeriodicWave::maxNumberOfPartials() const diff --git a/dom/media/webaudio/test/mochitest.ini b/dom/media/webaudio/test/mochitest.ini index 428e2b4a74df..3e74e610419d 100644 --- a/dom/media/webaudio/test/mochitest.ini +++ b/dom/media/webaudio/test/mochitest.ini @@ -159,6 +159,7 @@ skip-if = (toolkit == 'gonk' && !debug) || android_version == '10' || android_ve [test_stereoPannerNode.html] [test_stereoPannerNodePassThrough.html] [test_periodicWave.html] +[test_periodicWaveBandLimiting.html] [test_scriptProcessorNode.html] [test_scriptProcessorNodeChannelCount.html] [test_scriptProcessorNodePassThrough.html] diff --git a/dom/media/webaudio/test/test_periodicWaveBandLimiting.html b/dom/media/webaudio/test/test_periodicWaveBandLimiting.html new file mode 100644 index 000000000000..d3680f05a667 --- /dev/null +++ b/dom/media/webaudio/test/test_periodicWaveBandLimiting.html @@ -0,0 +1,86 @@ + +Test effect of band limiting on PeriodicWave signals + + + diff --git a/dom/media/webspeech/synth/windows/SapiService.cpp b/dom/media/webspeech/synth/windows/SapiService.cpp index 15d4fc095dd4..1700a9994950 100644 --- a/dom/media/webspeech/synth/windows/SapiService.cpp +++ b/dom/media/webspeech/synth/windows/SapiService.cpp @@ -132,6 +132,8 @@ SapiCallback::OnSpeechEvent(const SPEVENT& speechEvent) mTask->DispatchBoundary(NS_LITERAL_STRING("sentence"), GetTickCount() - mStartingTime, mCurrentIndex); break; + default: + break; } } @@ -180,7 +182,7 @@ SapiService::Init() if (Preferences::GetBool("media.webspeech.synth.test")) { // When enabled, we shouldn't add OS backend (Bug 1160844) - return nullptr; + return false; } if (FAILED(CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL, IID_ISpVoice, diff --git a/dom/plugins/base/npapi.h b/dom/plugins/base/npapi.h index 35146a1b9ff6..2c773b096b3f 100644 --- a/dom/plugins/base/npapi.h +++ b/dom/plugins/base/npapi.h @@ -411,7 +411,9 @@ typedef enum { , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */ , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated Cocoa text input specification. */ +#endif , NPNVmuteAudioBool = 4000 /* Request that the browser wants to mute or unmute the plugin */ +#if defined(XP_MACOSX) , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports CA model compositing */ #endif diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index 920b1099ef42..d677d92fce9c 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -106,6 +106,8 @@ using mozilla::plugins::PluginModuleContentParent; #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GeckoPlugins" , ## args) #endif +#include "nsIAudioChannelAgent.h" + using namespace mozilla; using namespace mozilla::plugins::parent; @@ -2402,6 +2404,46 @@ _setvalue(NPP npp, NPPVariable variable, void *result) return inst->SetUsesDOMForCursor(useDOMForCursor); } + case NPPVpluginIsPlayingAudio: { + bool isMuted = !result; + + nsNPAPIPluginInstance* inst = (nsNPAPIPluginInstance*) npp->ndata; + MOZ_ASSERT(inst); + + if (isMuted && !inst->HasAudioChannelAgent()) { + return NPERR_NO_ERROR; + } + + nsCOMPtr agent; + nsresult rv = inst->GetOrCreateAudioChannelAgent(getter_AddRefs(agent)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NPERR_NO_ERROR; + } + + MOZ_ASSERT(agent); + + if (isMuted) { + rv = agent->NotifyStoppedPlaying(); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NPERR_NO_ERROR; + } + } else { + float volume = 0.0; + bool muted = true; + rv = agent->NotifyStartedPlaying(&volume, &muted); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NPERR_NO_ERROR; + } + + rv = inst->WindowVolumeChanged(volume, muted); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NPERR_NO_ERROR; + } + } + + return NPERR_NO_ERROR; + } + #ifndef MOZ_WIDGET_ANDROID // On android, their 'drawing model' uses the same constant! case NPPVpluginDrawingModel: { diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 4f35b147ab79..a15a9f209264 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -40,6 +40,7 @@ #include "mozilla/unused.h" #include "nsILoadContext.h" #include "mozilla/dom/HTMLObjectElementBinding.h" +#include "AudioChannelService.h" using namespace mozilla; using namespace mozilla::dom; @@ -169,7 +170,7 @@ using namespace mozilla::layers; static NS_DEFINE_IID(kIOutputStreamIID, NS_IOUTPUTSTREAM_IID); -NS_IMPL_ISUPPORTS0(nsNPAPIPluginInstance) +NS_IMPL_ISUPPORTS(nsNPAPIPluginInstance, nsIAudioChannelAgentCallback) nsNPAPIPluginInstance::nsNPAPIPluginInstance() : mDrawingModel(kDefaultDrawingModel) @@ -253,6 +254,7 @@ nsNPAPIPluginInstance::Destroy() { Stop(); mPlugin = nullptr; + mAudioChannelAgent = nullptr; #if MOZ_WIDGET_ANDROID if (mContentSurface) @@ -1788,3 +1790,71 @@ nsNPAPIPluginInstance::GetRunID(uint32_t* aRunID) return library->GetRunID(aRunID); } + +nsresult +nsNPAPIPluginInstance::GetOrCreateAudioChannelAgent(nsIAudioChannelAgent** aAgent) +{ + if (!mAudioChannelAgent) { + nsresult rv; + mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1", &rv); + if (NS_WARN_IF(!mAudioChannelAgent)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr window = GetDOMWindow(); + if (NS_WARN_IF(!window)) { + return NS_ERROR_FAILURE; + } + + rv = mAudioChannelAgent->Init(window->GetCurrentInnerWindow(), + (int32_t)AudioChannelService::GetDefaultAudioChannel(), + this); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + nsCOMPtr agent = mAudioChannelAgent; + agent.forget(aAgent); + return NS_OK; +} + +NS_IMETHODIMP +nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted) +{ + // We just support mute/unmute + nsresult rv = SetMuted(aMuted); + NS_WARN_IF(NS_FAILED(rv)); + return rv; +} + +NS_IMETHODIMP +nsNPAPIPluginInstance::WindowAudioCaptureChanged() +{ + return NS_OK; +} + +nsresult +nsNPAPIPluginInstance::SetMuted(bool aIsMuted) +{ + if (RUNNING != mRunning) + return NS_OK; + + PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance informing plugin of mute state change this=%p\n",this)); + + if (!mPlugin || !mPlugin->GetLibrary()) + return NS_ERROR_FAILURE; + + NPPluginFuncs* pluginFunctions = mPlugin->PluginFuncs(); + + if (!pluginFunctions->setvalue) + return NS_ERROR_FAILURE; + + PluginDestructionGuard guard(this); + + NPError error; + NPBool value = static_cast(aIsMuted); + NS_TRY_SAFE_CALL_RETURN(error, (*pluginFunctions->setvalue)(&mNPP, NPNVmuteAudioBool, &value), this, + NS_PLUGIN_CALL_UNSAFE_TO_REENTER_GECKO); + return (error == NPERR_NO_ERROR) ? NS_OK : NS_ERROR_FAILURE; +} diff --git a/dom/plugins/base/nsNPAPIPluginInstance.h b/dom/plugins/base/nsNPAPIPluginInstance.h index 21d4f3120395..157f71b53f07 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.h +++ b/dom/plugins/base/nsNPAPIPluginInstance.h @@ -17,6 +17,7 @@ #include "nsHashKeys.h" #include #include "js/TypeDecls.h" +#include "nsIAudioChannelAgent.h" #ifdef MOZ_WIDGET_ANDROID #include "nsAutoPtr.h" #include "nsIRunnable.h" @@ -74,13 +75,14 @@ public: bool needUnschedule; }; -class nsNPAPIPluginInstance : public nsISupports +class nsNPAPIPluginInstance final : public nsIAudioChannelAgentCallback { private: typedef mozilla::PluginLibrary PluginLibrary; public: NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK nsresult Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const nsACString& aMIMEType); nsresult Start(); @@ -117,6 +119,15 @@ public: nsPluginInstanceOwner* GetOwner(); void SetOwner(nsPluginInstanceOwner *aOwner); + bool HasAudioChannelAgent() const + { + return !!mAudioChannelAgent; + } + + nsresult GetOrCreateAudioChannelAgent(nsIAudioChannelAgent** aAgent); + + nsresult SetMuted(bool aIsMuted); + nsNPAPIPlugin* GetPlugin(); nsresult GetNPP(NPP * aNPP); @@ -404,6 +415,8 @@ private: uint32_t mCachedParamLength; char **mCachedParamNames; char **mCachedParamValues; + + nsCOMPtr mAudioChannelAgent; }; // On Android, we need to guard against plugin code leaking entries in the local diff --git a/dom/plugins/ipc/PPluginInstance.ipdl b/dom/plugins/ipc/PPluginInstance.ipdl index 3a4a3d521da9..40338138667b 100644 --- a/dom/plugins/ipc/PPluginInstance.ipdl +++ b/dom/plugins/ipc/PPluginInstance.ipdl @@ -87,6 +87,8 @@ child: intr NPP_GetValue_NPPVpluginNativeAccessibleAtkPlugId() returns (nsCString plug_id, NPError result); + intr NPP_SetValue_NPNVmuteAudioBool(bool muted) returns (NPError result); + intr NPP_HandleEvent(NPRemoteEvent event) returns (int16_t handled); // special cases where we need to a shared memory buffer @@ -150,6 +152,8 @@ parent: returns (NPError result); intr NPN_SetValue_NPPVpluginEventModel(int eventModel) returns (NPError result); + intr NPN_SetValue_NPPVpluginIsPlayingAudio(bool isAudioPlaying) + returns (NPError result); intr NPN_GetURL(nsCString url, nsCString target) returns (NPError result); diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index 512db7dba2c9..aa4e333d0bde 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -626,6 +626,14 @@ PluginInstanceChild::NPN_SetValue(NPPVariable aVar, void* aValue) } #endif + case NPPVpluginIsPlayingAudio: { + NPError rv = NPERR_GENERIC_ERROR; + if (!CallNPN_SetValue_NPPVpluginIsPlayingAudio((NPBool)(intptr_t)aValue, &rv)) { + return NPERR_GENERIC_ERROR; + } + return rv; + } + default: MOZ_LOG(GetPluginLog(), LogLevel::Warning, ("In PluginInstanceChild::NPN_SetValue: Unhandled NPPVariable %i (%s)", @@ -765,6 +773,20 @@ PluginInstanceChild::AnswerNPP_SetValue_NPNVprivateModeBool(const bool& value, return true; } +bool +PluginInstanceChild::AnswerNPP_SetValue_NPNVmuteAudioBool(const bool& value, + NPError* result) +{ + if (!mPluginIface->setvalue) { + *result = NPERR_GENERIC_ERROR; + return true; + } + + NPBool v = value; + *result = mPluginIface->setvalue(GetNPP(), NPNVmuteAudioBool, &v); + return true; +} + bool PluginInstanceChild::AnswerNPP_HandleEvent(const NPRemoteEvent& event, int16_t* handled) diff --git a/dom/plugins/ipc/PluginInstanceChild.h b/dom/plugins/ipc/PluginInstanceChild.h index 3c395657d52f..a37eae3a9976 100644 --- a/dom/plugins/ipc/PluginInstanceChild.h +++ b/dom/plugins/ipc/PluginInstanceChild.h @@ -80,6 +80,8 @@ protected: NPError* aResult) override; virtual bool AnswerNPP_SetValue_NPNVprivateModeBool(const bool& value, NPError* result) override; + virtual bool + AnswerNPP_SetValue_NPNVmuteAudioBool(const bool& value, NPError* result) override; virtual bool AnswerNPP_HandleEvent(const NPRemoteEvent& event, int16_t* handled) override; diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index 45c012c40b92..46a067ffc035 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -440,6 +440,15 @@ PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginEventModel( #endif } +bool +PluginInstanceParent::AnswerNPN_SetValue_NPPVpluginIsPlayingAudio( + const bool& isAudioPlaying, NPError* result) +{ + *result = mNPNIface->setvalue(mNPP, NPPVpluginIsPlayingAudio, + (void*)(intptr_t)isAudioPlaying); + return true; +} + bool PluginInstanceParent::AnswerNPN_GetURL(const nsCString& url, const nsCString& target, @@ -1142,15 +1151,22 @@ PluginInstanceParent::NPP_GetValue(NPPVariable aVariable, NPError PluginInstanceParent::NPP_SetValue(NPNVariable variable, void* value) { + NPError result; switch (variable) { case NPNVprivateModeBool: - NPError result; if (!CallNPP_SetValue_NPNVprivateModeBool(*static_cast(value), &result)) return NPERR_GENERIC_ERROR; return result; + case NPNVmuteAudioBool: + if (!CallNPP_SetValue_NPNVmuteAudioBool(*static_cast(value), + &result)) + return NPERR_GENERIC_ERROR; + + return result; + default: NS_ERROR("Unhandled NPNVariable in NPP_SetValue"); MOZ_LOG(GetPluginLog(), LogLevel::Warning, diff --git a/dom/plugins/ipc/PluginInstanceParent.h b/dom/plugins/ipc/PluginInstanceParent.h index 052408528f17..80af054cf936 100644 --- a/dom/plugins/ipc/PluginInstanceParent.h +++ b/dom/plugins/ipc/PluginInstanceParent.h @@ -128,6 +128,9 @@ public: virtual bool AnswerNPN_SetValue_NPPVpluginEventModel(const int& eventModel, NPError* result) override; + virtual bool + AnswerNPN_SetValue_NPPVpluginIsPlayingAudio(const bool& isAudioPlaying, + NPError* result) override; virtual bool AnswerNPN_GetURL(const nsCString& url, const nsCString& target, diff --git a/dom/plugins/test/testplugin/README b/dom/plugins/test/testplugin/README index e31f11cd36fa..1e7cc0473645 100644 --- a/dom/plugins/test/testplugin/README +++ b/dom/plugins/test/testplugin/README @@ -419,3 +419,14 @@ x86-only on some OSes: Returns the contents scale factor. On platforms without support for this query always returns 1.0 (a double value). Likewise on hardware without HiDPI mode support. + +== Plugin audio channel support == + +* startAudioPlayback() +Simulates the plugin starting to play back audio. + +* stopAudioPlayback() +Simulates the plugin stopping to play back audio. + +* audioMuted() +Returns the last value set by NPP_SetValue(NPNVmuteAudioBool). diff --git a/dom/plugins/test/testplugin/nptest.cpp b/dom/plugins/test/testplugin/nptest.cpp index e801d2d15bf5..b84c3f9eda80 100644 --- a/dom/plugins/test/testplugin/nptest.cpp +++ b/dom/plugins/test/testplugin/nptest.cpp @@ -168,6 +168,9 @@ static bool getNPNVdocumentOrigin(NPObject* npobj, const NPVariant* args, uint32 static bool getMouseUpEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool queryContentsScaleFactor(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static bool echoString(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); +static bool startAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); +static bool stopAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); +static bool getAudioMuted(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result); static const NPUTF8* sPluginMethodIdentifierNames[] = { "npnEvaluateTest", @@ -234,6 +237,9 @@ static const NPUTF8* sPluginMethodIdentifierNames[] = { "getMouseUpEventCount", "queryContentsScaleFactor", "echoString", + "startAudioPlayback", + "stopAudioPlayback", + "audioMuted", }; static NPIdentifier sPluginMethodIdentifiers[MOZ_ARRAY_LENGTH(sPluginMethodIdentifierNames)]; static const ScriptableFunction sPluginMethodFunctions[] = { @@ -301,6 +307,9 @@ static const ScriptableFunction sPluginMethodFunctions[] = { getMouseUpEventCount, queryContentsScaleFactor, echoString, + startAudioPlayback, + stopAudioPlayback, + getAudioMuted, }; static_assert(MOZ_ARRAY_LENGTH(sPluginMethodIdentifierNames) == @@ -784,6 +793,8 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char* instanceData->npnNewStream = false; instanceData->invalidateDuringPaint = false; instanceData->slowPaint = false; + instanceData->playingAudio = false; + instanceData->audioMuted = false; instanceData->writeCount = 0; instanceData->writeReadyCount = 0; memset(&instanceData->window, 0, sizeof(instanceData->window)); @@ -1440,6 +1451,11 @@ NPP_SetValue(NPP instance, NPNVariable variable, void* value) instanceData->lastReportedPrivateModeState = bool(*static_cast(value)); return NPERR_NO_ERROR; } + if (variable == NPNVmuteAudioBool) { + InstanceData* instanceData = (InstanceData*)(instance->pdata); + instanceData->audioMuted = bool(*static_cast(value)); + return NPERR_NO_ERROR; + } return NPERR_GENERIC_ERROR; } @@ -3707,3 +3723,45 @@ bool echoString(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVar return true; } +static bool +toggleAudioPlayback(NPObject* npobj, uint32_t argCount, bool playingAudio, NPVariant* result) +{ + if (argCount != 0) { + return false; + } + + NPP npp = static_cast(npobj)->npp; + InstanceData* id = static_cast(npp->pdata); + id->playingAudio = playingAudio; + + NPN_SetValue(npp, NPPVpluginIsPlayingAudio, (void*)playingAudio); + + VOID_TO_NPVARIANT(*result); + return true; +} + +static bool +startAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return toggleAudioPlayback(npobj, argCount, true, result); +} + +static bool +stopAudioPlayback(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + return toggleAudioPlayback(npobj, argCount, false, result); +} + +static bool +getAudioMuted(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result) +{ + if (argCount != 0) { + return false; + } + + NPP npp = static_cast(npobj)->npp; + InstanceData* id = static_cast(npp->pdata); + BOOLEAN_TO_NPVARIANT(id->audioMuted, *result); + return true; +} + diff --git a/dom/plugins/test/testplugin/nptest.h b/dom/plugins/test/testplugin/nptest.h index c929a38d7abf..fd4fb9018cd8 100644 --- a/dom/plugins/test/testplugin/nptest.h +++ b/dom/plugins/test/testplugin/nptest.h @@ -106,6 +106,8 @@ typedef struct InstanceData { bool asyncCallbackResult; bool invalidateDuringPaint; bool slowPaint; + bool playingAudio; + bool audioMuted; int32_t winX; int32_t winY; int32_t lastMouseX; diff --git a/dom/push/PushServiceChildPreload.jsm b/dom/push/PushServiceChildPreload.jsm index 4a81b575851e..e09d8bbd99e0 100644 --- a/dom/push/PushServiceChildPreload.jsm +++ b/dom/push/PushServiceChildPreload.jsm @@ -4,6 +4,8 @@ "use strict"; +this.EXPORTED_SYMBOLS = []; + const Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); diff --git a/dom/webidl/IDBCursor.webidl b/dom/webidl/IDBCursor.webidl index b195ea3a8054..20ed4550d342 100644 --- a/dom/webidl/IDBCursor.webidl +++ b/dom/webidl/IDBCursor.webidl @@ -39,6 +39,7 @@ interface IDBCursor { IDBRequest delete (); }; +[Exposed=(Window,Worker)] interface IDBCursorWithValue : IDBCursor { [Throws] readonly attribute any value; diff --git a/dom/workers/Performance.cpp b/dom/workers/Performance.cpp index 8d310a44ea35..25bc92ed2029 100644 --- a/dom/workers/Performance.cpp +++ b/dom/workers/Performance.cpp @@ -64,6 +64,16 @@ Performance::GetPerformanceTimingFromString(const nsAString& aProperty) return 0; } +void +Performance::InsertUserEntry(PerformanceEntry* aEntry) +{ + if (mWorkerPrivate->PerformanceLoggingEnabled()) { + PerformanceBase::LogEntry(aEntry, + NS_ConvertUTF16toUTF8(mWorkerPrivate->ScriptURL())); + } + PerformanceBase::InsertUserEntry(aEntry); +} + DOMHighResTimeStamp Performance::DeltaFromNavigationStart(DOMHighResTimeStamp aTime) { diff --git a/dom/workers/Performance.h b/dom/workers/Performance.h index 59fb3288b9c9..ab18b078eaf0 100644 --- a/dom/workers/Performance.h +++ b/dom/workers/Performance.h @@ -26,6 +26,8 @@ public: private: ~Performance(); + void InsertUserEntry(PerformanceEntry* aEntry) override; + WorkerPrivate* mWorkerPrivate; public: diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 1ef6a701edff..aa4de3b725ac 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -158,6 +158,7 @@ static_assert(MAX_WORKERS_PER_DOMAIN >= 1, #define PREF_DOM_CACHES_ENABLED "dom.caches.enabled" #define PREF_DOM_CACHES_TESTING_ENABLED "dom.caches.testing.enabled" +#define PREF_WORKERS_PERFORMANCE_LOGGING_ENABLED "dom.performance.enable_user_timing_logging" #define PREF_DOM_WORKERNOTIFICATION_ENABLED "dom.webnotifications.enabled" #define PREF_WORKERS_LATEST_JS_VERSION "dom.workers.latestJSVersion" #define PREF_INTL_ACCEPT_LANGUAGES "intl.accept_languages" @@ -1940,6 +1941,10 @@ RuntimeService::Init() WorkerPrefChanged, PREF_DOM_CACHES_TESTING_ENABLED, reinterpret_cast(WORKERPREF_DOM_CACHES_TESTING))) || + NS_FAILED(Preferences::RegisterCallbackAndCall( + WorkerPrefChanged, + PREF_WORKERS_PERFORMANCE_LOGGING_ENABLED, + reinterpret_cast(WORKERPREF_PERFORMANCE_LOGGING_ENABLED))) || NS_FAILED(Preferences::RegisterCallbackAndCall( WorkerPrefChanged, PREF_SERVICEWORKERS_TESTING_ENABLED, @@ -2147,6 +2152,10 @@ RuntimeService::Cleanup() WorkerPrefChanged, PREF_DOM_CACHES_TESTING_ENABLED, reinterpret_cast(WORKERPREF_DOM_CACHES_TESTING))) || + NS_FAILED(Preferences::UnregisterCallback( + WorkerPrefChanged, + PREF_WORKERS_PERFORMANCE_LOGGING_ENABLED, + reinterpret_cast(WORKERPREF_PERFORMANCE_LOGGING_ENABLED))) || NS_FAILED(Preferences::UnregisterCallback( WorkerPrefChanged, PREF_INTERCEPTION_OPAQUE_ENABLED, @@ -2708,6 +2717,7 @@ RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure) case WORKERPREF_DOM_CACHES: case WORKERPREF_DOM_CACHES_TESTING: case WORKERPREF_DOM_WORKERNOTIFICATION: + case WORKERPREF_PERFORMANCE_LOGGING_ENABLED: #ifdef DUMP_CONTROLLED_BY_PREF case WORKERPREF_DUMP: #endif diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 6e1ddcaa8498..049a970bc76b 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -1565,7 +1565,7 @@ public: init.mFilename = aFilename; init.mLineno = aLineNumber; init.mCancelable = true; - init.mBubbles = true; + init.mBubbles = false; if (aTarget) { nsRefPtr event = diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index b0c0eecdd8dc..d85d02abf545 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1321,6 +1321,13 @@ public: return mPreferences[WORKERPREF_DOM_CACHES_TESTING]; } + bool + PerformanceLoggingEnabled() const + { + AssertIsOnWorkerThread(); + return mPreferences[WORKERPREF_PERFORMANCE_LOGGING_ENABLED]; + } + bool OnLine() const { diff --git a/dom/workers/Workers.h b/dom/workers/Workers.h index 4a8fc7c791f6..899990b8dafa 100644 --- a/dom/workers/Workers.h +++ b/dom/workers/Workers.h @@ -205,6 +205,7 @@ enum WorkerPreference WORKERPREF_DOM_CACHES_TESTING, // dom.caches.testing.enabled WORKERPREF_SERVICEWORKERS_TESTING, // dom.serviceWorkers.testing.enabled WORKERPREF_INTERCEPTION_OPAQUE_ENABLED, // dom.serviceWorkers.interception.opaque.enabled + WORKERPREF_PERFORMANCE_LOGGING_ENABLED, // dom.performance.enable_user_timing_logging WORKERPREF_COUNT }; diff --git a/dom/workers/test/1158031.html b/dom/workers/test/1158031.html new file mode 100644 index 000000000000..6d896bc4667c --- /dev/null +++ b/dom/workers/test/1158031.html @@ -0,0 +1,11 @@ + + + diff --git a/dom/workers/test/crashtests.list b/dom/workers/test/crashtests.list index 02d2e6251c01..fb643291a06f 100644 --- a/dom/workers/test/crashtests.list +++ b/dom/workers/test/crashtests.list @@ -1 +1,2 @@ load 943516.html +load 1158031.html diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js index 09c8100b6616..a742963591c7 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -131,6 +131,8 @@ var interfaceNamesInGlobalScope = "Headers", // IMPORTANT: Do not change this list without review from a DOM peer! "IDBCursor", +// IMPORTANT: Do not change this list without review from a DOM peer! + "IDBCursorWithValue", // IMPORTANT: Do not change this list without review from a DOM peer! "IDBDatabase", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index 3b6bfc6b682f..88ed6d7ac390 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -123,6 +123,8 @@ var interfaceNamesInGlobalScope = "Headers", // IMPORTANT: Do not change this list without review from a DOM peer! "IDBCursor", +// IMPORTANT: Do not change this list without review from a DOM peer! + "IDBCursorWithValue", // IMPORTANT: Do not change this list without review from a DOM peer! "IDBDatabase", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/xbl/nsXBLDocumentInfo.cpp b/dom/xbl/nsXBLDocumentInfo.cpp index f9560350416e..6c7f834c8462 100644 --- a/dom/xbl/nsXBLDocumentInfo.cpp +++ b/dom/xbl/nsXBLDocumentInfo.cpp @@ -77,7 +77,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END static void UnmarkXBLJSObject(JS::GCCellPtr aPtr, const char* aName, void* aClosure) { - JS::ExposeObjectToActiveJS(aPtr.toObject()); + JS::ExposeObjectToActiveJS(&aPtr.as()); } static PLDHashOperator diff --git a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp index 8f46cef7419d..e2339ebefaa2 100644 --- a/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp +++ b/extensions/pref/autoconfig/src/nsJSConfigTriggers.cpp @@ -107,7 +107,7 @@ nsresult EvaluateAdminConfigScript(const char *js_buffer, size_t length, nsAutoCString script(js_buffer, length); JS::RootedValue v(cx); rv = xpc->EvalInSandboxObject(NS_ConvertUTF8toUTF16(script), filename, cx, - autoconfigSb, &v); + autoconfigSb, JSVERSION_LATEST, &v); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp index 05165240f146..6c39e514a54d 100644 --- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -525,23 +525,6 @@ GfxPatternToCairoPattern(const Pattern& aPattern, matrix = &pattern.mMatrix; const std::vector& stops = cairoStops->GetStops(); - if (stops.size() >= 2 && stops.front().offset == stops.back().offset) { - // Certain Cairo backends that use pixman to implement gradients can have jagged - // edges occur with hard stops. Such hard stops are used for implementing certain - // types of CSS borders. Work around this by turning these hard-stops into half-pixel - // gradients to anti-alias them. See bug 1033375 - Matrix patternToDevice = aTransform * pattern.mMatrix; - Float gradLength = (patternToDevice * pattern.mEnd - patternToDevice * pattern.mBegin).Length(); - if (gradLength > 0) { - Float aaOffset = 0.25 / gradLength; - CairoPatternAddGradientStop(pat, stops.front(), -aaOffset); - for (size_t i = 1; i < stops.size()-1; ++i) { - CairoPatternAddGradientStop(pat, stops[i]); - } - CairoPatternAddGradientStop(pat, stops.back(), aaOffset); - break; - } - } for (size_t i = 0; i < stops.size(); ++i) { CairoPatternAddGradientStop(pat, stops[i]); } diff --git a/gfx/2d/Factory.cpp b/gfx/2d/Factory.cpp index bb6fab7d1950..76ae17e2e29a 100644 --- a/gfx/2d/Factory.cpp +++ b/gfx/2d/Factory.cpp @@ -621,7 +621,9 @@ Factory::SetDirect3D10Device(ID3D10Device1 *aDevice) // do not throw on failure; return error codes and disconnect the device // On Windows 8 error codes are the default, but on Windows 7 the // default is to throw (or perhaps only with some drivers?) - aDevice->SetExceptionMode(0); + if (aDevice) { + aDevice->SetExceptionMode(0); + } mD3D10Device = aDevice; } diff --git a/gfx/cairo/cairo/src/cairo-rectangle.c b/gfx/cairo/cairo/src/cairo-rectangle.c index b94f7d511e1e..608da53eaf79 100644 --- a/gfx/cairo/cairo/src/cairo-rectangle.c +++ b/gfx/cairo/cairo/src/cairo-rectangle.c @@ -213,8 +213,7 @@ _cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line) xlen = - xlen; } - if ((t1 < 0 || t1 > xlen) && - (t2 < 0 || t2 > xlen)) + if (t1 > xlen || t2 < 0) return FALSE; } else { /* Fully vertical line -- check that X is in bounds */ @@ -232,8 +231,7 @@ _cairo_box_intersects_line_segment (cairo_box_t *box, cairo_line_t *line) ylen = - ylen; } - if ((t3 < 0 || t3 > ylen) && - (t4 < 0 || t4 > ylen)) + if (t3 > ylen || t4 < 0) return FALSE; } else { /* Fully horizontal line -- check Y */ diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index afa4f53af9a7..e0f6334d8f80 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -342,11 +342,11 @@ TextureClient::CreateForDrawing(ISurfaceAllocator* aAllocator, #ifdef XP_WIN LayersBackend parentBackend = aAllocator->GetCompositorBackendType(); if (parentBackend == LayersBackend::LAYERS_D3D11 && - (aMoz2DBackend == gfx::BackendType::DIRECT2D || - aMoz2DBackend == gfx::BackendType::DIRECT2D1_1) && - gfxWindowsPlatform::GetPlatform()->GetD3D10Device() && + ((aMoz2DBackend == gfx::BackendType::DIRECT2D && Factory::GetDirect3D10Device()) || + (aMoz2DBackend == gfx::BackendType::DIRECT2D1_1 && Factory::GetDirect3D11Device())) && aSize.width <= maxTextureSize && - aSize.height <= maxTextureSize) { + aSize.height <= maxTextureSize) + { texture = new TextureClientD3D11(aAllocator, aFormat, aTextureFlags); } if (parentBackend == LayersBackend::LAYERS_D3D9 && diff --git a/gfx/thebes/gfxASurface.cpp b/gfx/thebes/gfxASurface.cpp index 2587f979b9eb..07d4739adfc3 100644 --- a/gfx/thebes/gfxASurface.cpp +++ b/gfx/thebes/gfxASurface.cpp @@ -499,12 +499,6 @@ gfxASurface::GetSubpixelAntialiasingEnabled() #endif } -gfxMemoryLocation -gfxASurface::GetMemoryLocation() const -{ - return gfxMemoryLocation::IN_PROCESS_HEAP; -} - int32_t gfxASurface::BytePerPixelFromFormat(gfxImageFormat format) { diff --git a/gfx/thebes/gfxASurface.h b/gfx/thebes/gfxASurface.h index bee57feb07c3..fef2de0f7abc 100644 --- a/gfx/thebes/gfxASurface.h +++ b/gfx/thebes/gfxASurface.h @@ -159,12 +159,6 @@ public: // to a sub-class of gfxASurface.) virtual bool SizeOfIsMeasured() const { return false; } - /** - * Where does this surface's memory live? By default, we say it's in this - * process's heap. - */ - virtual gfxMemoryLocation GetMemoryLocation() const; - static int32_t BytePerPixelFromFormat(gfxImageFormat format); virtual const mozilla::gfx::IntSize GetSize() const; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 041e90d77cfe..8a986768a5a5 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -2237,7 +2237,7 @@ gfxPlatform::ShouldUseLayersAcceleration() if (gfxPrefs::LayersAccelerationForceEnabled()) { return true; } - if (gfxPlatform::GetPlatform()->AccelerateLayersByDefault()) { + if (AccelerateLayersByDefault()) { return true; } if (acceleratedEnv && *acceleratedEnv != '0') { diff --git a/gfx/thebes/gfxTypes.h b/gfx/thebes/gfxTypes.h index 2b01cd8a4d35..2c923e78ebe6 100644 --- a/gfx/thebes/gfxTypes.h +++ b/gfx/thebes/gfxTypes.h @@ -92,15 +92,4 @@ enum class gfxContentType { SENTINEL = 0xffff }; -/** - * The memory used by a gfxASurface (as reported by KnownMemoryUsed()) can - * either live in this process's heap, in this process but outside the - * heap, or in another process altogether. - */ -enum class gfxMemoryLocation { - IN_PROCESS_HEAP, - IN_PROCESS_NONHEAP, - OUT_OF_PROCESS -}; - #endif /* GFX_TYPES_H */ diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 1a2a4c8f01b6..79c5fcb34b51 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -373,18 +373,18 @@ public: NS_IMPL_ISUPPORTS(D3D9SharedTextureReporter, nsIMemoryReporter) gfxWindowsPlatform::gfxWindowsPlatform() - : mD3D11DeviceInitialized(false) + : mRenderMode(RENDER_GDI) , mIsWARP(false) , mHasDeviceReset(false) , mDoesD3D11TextureSharingWork(false) + , mAcceleration(FeatureStatus::Unused) , mD3D11Status(FeatureStatus::Unused) , mD2DStatus(FeatureStatus::Unused) + , mD2D1Status(FeatureStatus::Unused) { mUseClearTypeForDownloadableFonts = UNINITIALIZED_VALUE; mUseClearTypeAlways = UNINITIALIZED_VALUE; - mUsingGDIFonts = false; - /* * Initialize COM */ @@ -392,10 +392,16 @@ gfxWindowsPlatform::gfxWindowsPlatform() RegisterStrongMemoryReporter(new GfxD2DVramReporter()); - if (gfxPrefs::Direct2DUse1_1()) { - InitD3D11Devices(); + // Set up the D3D11 feature levels we can ask for. + if (IsWin8OrLater()) { + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1); } + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0); + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1); + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0); + mFeatureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3); + InitializeDevices(); UpdateRenderMode(); RegisterStrongMemoryReporter(new GPUAdapterReporter()); @@ -438,161 +444,106 @@ gfxWindowsPlatform::CanUseHardwareVideoDecoding() return !IsWARP() && gfxPlatform::CanUseHardwareVideoDecoding(); } -FeatureStatus -gfxWindowsPlatform::InitD2DSupport() -{ -#ifdef CAIRO_HAS_D2D_SURFACE - bool d2dBlocked = false; - nsCOMPtr gfxInfo = services::GetGfxInfo(); - if (gfxInfo) { - int32_t status; - if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) { - if (status != nsIGfxInfo::FEATURE_STATUS_OK) { - d2dBlocked = true; - } - } - if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) { - if (status != nsIGfxInfo::FEATURE_STATUS_OK) { - d2dBlocked = true; - } - } - } - - // If D2D is blocked or D3D9 is prefered, and D2D is not force-enabled, then - // we don't attempt to use D2D. - if (!gfxPrefs::Direct2DForceEnabled()) { - if (d2dBlocked) { - return FeatureStatus::Blacklisted; - } - if (gfxPrefs::LayersPreferD3D9()) { - return FeatureStatus::Disabled; - } - } - - // Do not ever try to use D2D if it's explicitly disabled or if we're not - // using DWrite fonts. - if (gfxPrefs::Direct2DDisabled() || mUsingGDIFonts) { - return FeatureStatus::Disabled; - } - - if (!IsVistaOrLater() || !GetD3D11Device()) { - return FeatureStatus::Unavailable; - } - if (!mDoesD3D11TextureSharingWork) { - return FeatureStatus::Failed; - } - if (InSafeMode()) { - return FeatureStatus::Blocked; - } - - VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled()); - if (!mD3D10Device || !GetD3D11Device()) { - return FeatureStatus::Failed; - } - - mRenderMode = RENDER_DIRECT2D; - mUseDirectWrite = true; - return FeatureStatus::Available; -#else - return FeatureStatus::Unavailable; -#endif -} - -void +bool gfxWindowsPlatform::InitDWriteSupport() { -#ifdef CAIRO_HAS_DWRITE_FONT - // Enable when it's preffed on -and- we're using Vista or higher. Or when - // we're going to use D2D. - if (mDWriteFactory || (!mUseDirectWrite || !IsVistaOrLater())) { - return; - } + MOZ_ASSERT(!mDWriteFactory && IsVistaOrLater()); mozilla::ScopedGfxFeatureReporter reporter("DWrite"); decltype(DWriteCreateFactory)* createDWriteFactory = (decltype(DWriteCreateFactory)*) GetProcAddress(LoadLibraryW(L"dwrite.dll"), "DWriteCreateFactory"); - if (!createDWriteFactory) { - return; + return false; } // I need a direct pointer to be able to cast to IUnknown**, I also need to // remember to release this because the nsRefPtr will AddRef it. - IDWriteFactory *factory; + RefPtr factory; HRESULT hr = createDWriteFactory( DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), - reinterpret_cast(&factory)); - - if (SUCCEEDED(hr) && factory) { - mDWriteFactory = factory; - factory->Release(); - hr = mDWriteFactory->CreateTextAnalyzer(getter_AddRefs(mDWriteAnalyzer)); + (IUnknown **)((IDWriteFactory **)byRef(factory))); + if (FAILED(hr) || !factory) { + return false; } + mDWriteFactory = factory; + SetupClearTypeParams(); + reporter.SetSuccessful(); + return true; +} - if (hr == S_OK) { - reporter.SetSuccessful(); +bool +gfxWindowsPlatform::HandleDeviceReset() +{ + DeviceResetReason resetReason = DeviceResetReason::OK; + if (!DidRenderingDeviceReset(&resetReason)) { + return false; } -#endif + + Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason)); + + // Remove devices and adapters. + mD3D10Device = nullptr; + mD3D11Device = nullptr; + mD3D11ContentDevice = nullptr; + mD3D11ImageBridgeDevice = nullptr; + mAdapter = nullptr; + Factory::SetDirect3D11Device(nullptr); + Factory::SetDirect3D10Device(nullptr); + + // Reset local state. Note: we leave feature status variables as-is. They + // will be recomputed by InitializeDevices(). + mIsWARP = false; + mHasDeviceReset = false; + mDoesD3D11TextureSharingWork = false; + mDeviceResetReason = DeviceResetReason::OK; + + imgLoader::Singleton()->ClearCache(true); + imgLoader::Singleton()->ClearCache(false); + gfxAlphaBoxBlur::ShutdownBlurCache(); + + InitializeDevices(); + return true; +} + +void +gfxWindowsPlatform::UpdateBackendPrefs() +{ + uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO); + uint32_t contentMask = BackendTypeBit(BackendType::CAIRO); + BackendType defaultBackend = BackendType::CAIRO; + if (GetD2DStatus() == FeatureStatus::Available) { + mRenderMode = RENDER_DIRECT2D; + canvasMask |= BackendTypeBit(BackendType::DIRECT2D); + contentMask |= BackendTypeBit(BackendType::DIRECT2D); + if (GetD2D1Status() == FeatureStatus::Available) { + contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1); + canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1); + defaultBackend = BackendType::DIRECT2D1_1; + } else { + defaultBackend = BackendType::DIRECT2D; + } + } else { + mRenderMode = RENDER_GDI; + canvasMask |= BackendTypeBit(BackendType::SKIA); + } + contentMask |= BackendTypeBit(BackendType::SKIA); + InitBackendPrefs(canvasMask, defaultBackend, contentMask, defaultBackend); } void gfxWindowsPlatform::UpdateRenderMode() { -/* Pick the default render mode for - * desktop. - */ - bool didReset = false; - DeviceResetReason resetReason = DeviceResetReason::OK; - if (DidRenderingDeviceReset(&resetReason)) { - Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason)); - mD3D11DeviceInitialized = false; - mD3D11Device = nullptr; - mD3D11ContentDevice = nullptr; - mAdapter = nullptr; - mDeviceResetReason = DeviceResetReason::OK; - mHasDeviceReset = false; + bool didReset = HandleDeviceReset(); - imgLoader::Singleton()->ClearCache(true); - imgLoader::Singleton()->ClearCache(false); - gfxAlphaBoxBlur::ShutdownBlurCache(); - Factory::SetDirect3D11Device(nullptr); + UpdateBackendPrefs(); - didReset = true; - } - - mRenderMode = RENDER_GDI; - mUseDirectWrite = gfxPrefs::DirectWriteFontRenderingEnabled(); - - mD2DStatus = InitD2DSupport(); - InitDWriteSupport(); - - uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO); - uint32_t contentMask = BackendTypeBit(BackendType::CAIRO); - BackendType defaultBackend = BackendType::CAIRO; - if (mRenderMode == RENDER_DIRECT2D) { - canvasMask |= BackendTypeBit(BackendType::DIRECT2D); - contentMask |= BackendTypeBit(BackendType::DIRECT2D); - if (gfxPrefs::Direct2DUse1_1() && Factory::SupportsD2D1() && - GetD3D11ContentDevice()) { - contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1); - canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1); - defaultBackend = BackendType::DIRECT2D1_1; - } else { - defaultBackend = BackendType::DIRECT2D; - } - } else { - canvasMask |= BackendTypeBit(BackendType::SKIA); - } - contentMask |= BackendTypeBit(BackendType::SKIA); - InitBackendPrefs(canvasMask, defaultBackend, - contentMask, defaultBackend); - - if (didReset) { - mScreenReferenceDrawTarget = CreateOffscreenContentDrawTarget(IntSize(1, 1), SurfaceFormat::B8G8R8A8); - } + if (didReset) { + mScreenReferenceDrawTarget = + CreateOffscreenContentDrawTarget(IntSize(1, 1), SurfaceFormat::B8G8R8A8); + } } #ifdef CAIRO_HAS_D2D_SURFACE @@ -644,11 +595,6 @@ void gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce) { #ifdef CAIRO_HAS_D2D_SURFACE - DriverInitCrashDetection detectCrashes; - if (detectCrashes.DisableAcceleration()) { - return; - } - if (mD3D10Device) { if (SUCCEEDED(mD3D10Device->GetDeviceRemovedReason())) { return; @@ -716,7 +662,6 @@ gfxWindowsPlatform::VerifyD2DDevice(bool aAttemptForce) gfxPlatformFontList* gfxWindowsPlatform::CreatePlatformFontList() { - mUsingGDIFonts = false; gfxPlatformFontList *pfl; #ifdef CAIRO_HAS_DWRITE_FONT // bug 630201 - older pre-RTM versions of Direct2D/DirectWrite cause odd @@ -730,11 +675,10 @@ gfxWindowsPlatform::CreatePlatformFontList() // but apparently it can - see bug 594865. // So we're going to fall back to GDI fonts & rendering. gfxPlatformFontList::Shutdown(); - SetRenderMode(RENDER_GDI); + DisableD2D(); } #endif pfl = new gfxGDIFontList(); - mUsingGDIFonts = true; if (NS_SUCCEEDED(pfl->InitFontList())) { return pfl; @@ -744,6 +688,22 @@ gfxWindowsPlatform::CreatePlatformFontList() return nullptr; } +// This function will permanently disable D2D for the session. It's intended to +// be used when, after initially chosing to use Direct2D, we encounter a +// scenario we can't support. +// +// This is called during gfxPlatform::Init() so at this point there should be no +// DrawTargetD2D/1 instances. +void +gfxWindowsPlatform::DisableD2D() +{ + mD2DStatus = FeatureStatus::Failed; + mD2D1Status = FeatureStatus::Failed; + Factory::SetDirect3D11Device(nullptr); + Factory::SetDirect3D10Device(nullptr); + UpdateBackendPrefs(); +} + already_AddRefed gfxWindowsPlatform::CreateOffscreenSurface(const IntSize& aSize, gfxImageFormat aFormat) @@ -1556,36 +1516,18 @@ gfxWindowsPlatform::GetD3D9DeviceManager() ID3D11Device* gfxWindowsPlatform::GetD3D11Device() { - if (mD3D11DeviceInitialized) { - return mD3D11Device; - } - - InitD3D11Devices(); - return mD3D11Device; } ID3D11Device* gfxWindowsPlatform::GetD3D11ContentDevice() { - if (mD3D11DeviceInitialized) { - return mD3D11ContentDevice; - } - - InitD3D11Devices(); - return mD3D11ContentDevice; } ID3D11Device* gfxWindowsPlatform::GetD3D11ImageBridgeDevice() { - if (mD3D11DeviceInitialized) { - return mD3D11ImageBridgeDevice; - } - - InitD3D11Devices(); - return mD3D11ImageBridgeDevice; } @@ -1918,31 +1860,42 @@ bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device) return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE); } +static inline bool +CanUseWARP() +{ + if (gfxPrefs::LayersD3D11ForceWARP()) { + return true; + } + + // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703. + if (!IsWin8OrLater() || + gfxPrefs::LayersD3D11DisableWARP() || + GetModuleHandleA("nvdxgiwrap.dll")) + { + return false; + } + return true; +} + auto gfxWindowsPlatform::CheckD3D11Support() -> D3D11Status { if (gfxPrefs::LayersD3D11ForceWARP()) { - return D3D11Status::ForceWARP; + return D3D11Status::OnlyWARP; } - if (nsCOMPtr gfxInfo = services::GetGfxInfo()) { int32_t status; if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) { if (status != nsIGfxInfo::FEATURE_STATUS_OK) { - // See if we can use WARP instead. - // - // It seems like nvdxgiwrap makes a mess of WARP. See bug 1154703 for more. - if (gfxPrefs::LayersD3D11DisableWARP() || GetModuleHandleA("nvdxgiwrap.dll")) { + if (!CanUseWARP()) { return D3D11Status::Blocked; } - return D3D11Status::TryWARP; + return D3D11Status::OnlyWARP; } } } - - // Either nsIGfxInfo was bugged or we're not blacklisted. if (!GetDXGIAdapter()) { - return D3D11Status::TryWARP; + return D3D11Status::OnlyWARP; } return D3D11Status::Ok; } @@ -1953,7 +1906,7 @@ gfxWindowsPlatform::CheckD3D11Support() -> D3D11Status decltype(D3D11CreateDevice)* sD3D11CreateDeviceFn = nullptr; bool -gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray& aFeatureLevels) +gfxWindowsPlatform::AttemptD3D11DeviceCreation() { RefPtr adapter = GetDXGIAdapter(); MOZ_ASSERT(adapter); @@ -1966,7 +1919,7 @@ gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS // to prevent bug 1092260. IE 11 also uses this flag. D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS, - aFeatureLevels.Elements(), aFeatureLevels.Length(), + mFeatureLevels.Elements(), mFeatureLevels.Length(), D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr); } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { gfxCriticalError() << "Crash during D3D11 device creation"; @@ -1986,15 +1939,14 @@ gfxWindowsPlatform::AttemptD3D11DeviceCreation(const nsTArray // Only test this when not using WARP since it can fail and cause // GetDeviceRemovedReason to return weird values. mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device); + mD3D11Device->SetExceptionMode(0); mIsWARP = false; return true; } bool -gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray& aFeatureLevels) +gfxWindowsPlatform::AttemptWARPDeviceCreation() { - MOZ_ASSERT(!mD3D11Device); - ScopedGfxFeatureReporter reporterWARP("D3D11-WARP", gfxPrefs::LayersD3D11ForceWARP()); MOZ_SEH_TRY { @@ -2004,7 +1956,7 @@ gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray& // D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS // to prevent bug 1092260. IE 11 also uses this flag. D3D11_CREATE_DEVICE_BGRA_SUPPORT, - aFeatureLevels.Elements(), aFeatureLevels.Length(), + mFeatureLevels.Elements(), mFeatureLevels.Length(), D3D11_SDK_VERSION, byRef(mD3D11Device), nullptr, nullptr); if (FAILED(hr)) { @@ -2017,14 +1969,21 @@ gfxWindowsPlatform::AttemptWARPDeviceCreation(const nsTArray& } MOZ_SEH_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { gfxCriticalError() << "Exception occurred initializing WARP D3D11 device!"; return false; + } + // Only test for texture sharing on Windows 8 since it puts the device into + // an unusable state if used on Windows 7 + if (IsWin8OrLater()) { + mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device); + } + mD3D11Device->SetExceptionMode(0); mIsWARP = true; return true; } bool -gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation(const nsTArray& aFeatureLevels) +gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation() { HRESULT hr = E_INVALIDARG; MOZ_SEH_TRY { @@ -2033,24 +1992,35 @@ gfxWindowsPlatform::AttemptD3D11ContentDeviceCreation(const nsTArraySetExceptionMode(0); + + nsRefPtr multi; + mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi)); + multi->SetMultithreadProtected(TRUE); + + Factory::SetDirect3D11Device(mD3D11ContentDevice); + return true; } bool -gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation(const nsTArray& aFeatureLevels) +gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation() { HRESULT hr = E_INVALIDARG; MOZ_SEH_TRY{ hr = sD3D11CreateDeviceFn(GetDXGIAdapter(), D3D_DRIVER_TYPE_UNKNOWN, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT, - aFeatureLevels.Elements(), aFeatureLevels.Length(), + mFeatureLevels.Elements(), mFeatureLevels.Length(), D3D11_SDK_VERSION, byRef(mD3D11ImageBridgeDevice), nullptr, nullptr); } MOZ_SEH_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { return false; @@ -2061,112 +2031,196 @@ gfxWindowsPlatform::AttemptD3D11ImageBridgeDeviceCreation(const nsTArraySetExceptionMode(0); - - return DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice); + if (!DoesD3D11AlphaTextureSharingWork(mD3D11ImageBridgeDevice)) { + mD3D11ImageBridgeDevice = nullptr; + return false; + } + return true; } void -gfxWindowsPlatform::InitD3D11Devices() +gfxWindowsPlatform::InitializeDevices() { - // This function attempts to initialize our D3D11 devices. If the hardware - // is not blacklisted for D3D11 layers. This will first attempt to create a - // hardware accelerated device. If this creation fails or the hardware is - // blacklisted, then this function will abort if WARP is disabled, causing us - // to fallback to D3D9 or Basic layers. If WARP is not disabled it will use - // a WARP device which should always be available on Windows 7 and higher. - mD3D11DeviceInitialized = true; - mDoesD3D11TextureSharingWork = false; - - MOZ_ASSERT(!mD3D11Device); - + // If we previously crashed initializing devices, or if we're in safe mode, + // bail out now. DriverInitCrashDetection detectCrashes; - if (InSafeMode() || detectCrashes.DisableAcceleration()) { - mD3D11Status = FeatureStatus::Blocked; + if (detectCrashes.DisableAcceleration() || InSafeMode()) { + mAcceleration = FeatureStatus::Blocked; return; } - D3D11Status status = CheckD3D11Support(); - if (status == D3D11Status::Blocked) { + // If acceleration is disabled, we refuse to initialize anything. + if (!ShouldUseLayersAcceleration()) { + mAcceleration = FeatureStatus::Disabled; + return; + } + + // At this point, as far as we know, we can probably accelerate. + mAcceleration = FeatureStatus::Available; + + // If we're going to prefer D3D9, stop here. The rest of this function + // attempts to use D3D11 features. + if (gfxPrefs::LayersPreferD3D9()) { + mD3D11Status = FeatureStatus::Disabled; + return; + } + + // First, initialize D3D11. If this succeeds we attempt to use Direct2D. + InitializeD3D11(); + if (mD3D11Status == FeatureStatus::Available) { + InitializeD2D(); + } +} + +void +gfxWindowsPlatform::InitializeD3D11() +{ + // This function attempts to initialize our D3D11 devices, if the hardware + // is not blacklisted for D3D11 layers. This first attempt will try to create + // a hardware accelerated device. If this creation fails or the hardware is + // blacklisted, then this function will abort if WARP is disabled, causing us + // to fallback to D3D9 or Basic layers. If WARP is not disabled it will use + // a WARP device which should always be available on Windows 7 and higher. + + // Check if D3D11 is supported on this hardware. + D3D11Status support = CheckD3D11Support(); + if (support == D3D11Status::Blocked) { mD3D11Status = FeatureStatus::Blacklisted; return; } + // Check if D3D11 is available on this system. nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll")); sD3D11CreateDeviceFn = (decltype(D3D11CreateDevice)*)GetProcAddress(d3d11Module, "D3D11CreateDevice"); - if (!sD3D11CreateDeviceFn) { // We should just be on Windows Vista or XP in this case. mD3D11Status = FeatureStatus::Unavailable; return; } - nsTArray featureLevels; - if (IsWin8OrLater()) { - featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_1); + // If hardware acceleration is allowed, attempt to create a device. If this + // fails, we fall back to WARP. + if (support == D3D11Status::Ok && !AttemptD3D11DeviceCreation()) { + support = D3D11Status::OnlyWARP; } - featureLevels.AppendElement(D3D_FEATURE_LEVEL_11_0); - featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_1); - featureLevels.AppendElement(D3D_FEATURE_LEVEL_10_0); - featureLevels.AppendElement(D3D_FEATURE_LEVEL_9_3); - - if (status == D3D11Status::Ok) { - if (!AttemptD3D11DeviceCreation(featureLevels)) { - status = D3D11Status::TryWARP; - } - } - - if (IsWin8OrLater() && - !gfxPrefs::LayersD3D11DisableWARP() && - (status == D3D11Status::TryWARP || status == D3D11Status::ForceWARP)) - { - AttemptWARPDeviceCreation(featureLevels); - mD3D11Status = FeatureStatus::Failed; - } - - // Only test for texture sharing on Windows 8 since it puts the device into - // an unusable state if used on Windows 7 - if (mD3D11Device && IsWin8OrLater()) { - mDoesD3D11TextureSharingWork = ::DoesD3D11TextureSharingWork(mD3D11Device); + if (support == D3D11Status::OnlyWARP && CanUseWARP()) { + AttemptWARPDeviceCreation(); } if (!mD3D11Device) { - // We could not get a D3D11 compositor, and there's nothing more we can try. + // Nothing more we can do. + mD3D11Status = FeatureStatus::Failed; return; } - mD3D11Device->SetExceptionMode(0); + // If we got here, we successfully got a D3D11 device. mD3D11Status = FeatureStatus::Available; - - // We create our device for D2D content drawing here. Normally we don't use - // D2D content drawing when using WARP. However when WARP is forced by - // default we will let Direct2D use WARP as well. - if (Factory::SupportsD2D1() && (!mIsWARP || (status == D3D11Status::ForceWARP))) { - if (!AttemptD3D11ContentDeviceCreation(featureLevels)) { - mD3D11ContentDevice = nullptr; - d3d11Module.disown(); - return; - } - - mD3D11ContentDevice->SetExceptionMode(0); - nsRefPtr multi; - mD3D11ContentDevice->QueryInterface(__uuidof(ID3D10Multithread), getter_AddRefs(multi)); - multi->SetMultithreadProtected(TRUE); - - Factory::SetDirect3D11Device(mD3D11ContentDevice); - } + MOZ_ASSERT(mD3D11Device); if (!mIsWARP) { - if (!AttemptD3D11ImageBridgeDeviceCreation(featureLevels)) { - mD3D11ImageBridgeDevice = nullptr; - } + AttemptD3D11ImageBridgeDeviceCreation(); } // We leak these everywhere and we need them our entire runtime anyway, let's - // leak it here as well. + // leak it here as well. We keep the pointer to sD3D11CreateDeviceFn around + // as well for D2D1 and device resets. d3d11Module.disown(); } +static bool +IsD2DBlacklisted() +{ + nsCOMPtr gfxInfo = services::GetGfxInfo(); + if (gfxInfo) { + int32_t status; + if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT2D, &status))) { + if (status != nsIGfxInfo::FEATURE_STATUS_OK) { + return true; + } + } + } + return false; +} + +void +gfxWindowsPlatform::InitializeD2D() +{ + if (!gfxPrefs::Direct2DForceEnabled()) { + if (IsD2DBlacklisted()) { + mD2DStatus = FeatureStatus::Blacklisted; + return; + } + } + + // Do not ever try to use D2D if it's explicitly disabled. + if (gfxPrefs::Direct2DDisabled()) { + mD2DStatus = FeatureStatus::Disabled; + return; + } + + // Direct2D is only Vista or higher, but we require a D3D11 compositor to + // use it. (This check may be implied by the fact that we do not get here + // without a D3D11 compositor device.) + if (!IsVistaOrLater()) { + mD2DStatus = FeatureStatus::Unavailable; + return; + } + if (!mDoesD3D11TextureSharingWork) { + mD2DStatus = FeatureStatus::Failed; + return; + } + + // Using Direct2D depends on DWrite support. + if (!mDWriteFactory && !InitDWriteSupport()) { + mD2DStatus = FeatureStatus::Failed; + return; + } + + // Initialize D2D 1.1. + InitializeD2D1(); + + // Initialize D2D 1.0. + VerifyD2DDevice(gfxPrefs::Direct2DForceEnabled()); + if (!mD3D10Device) { + mD2DStatus = FeatureStatus::Failed; + return; + } + + mD2DStatus = FeatureStatus::Available; +} + +bool +gfxWindowsPlatform::InitializeD2D1() +{ + ScopedGfxFeatureReporter d2d1_1("D2D1.1"); + + if (!Factory::SupportsD2D1()) { + mD2D1Status = FeatureStatus::Unavailable; + return false; + } + if (!gfxPrefs::Direct2DUse1_1()) { + mD2D1Status = FeatureStatus::Disabled; + return false; + } + + // Normally we don't use D2D content drawing when using WARP. However if + // WARP is force-enabled, we wlil let Direct2D use WARP as well. + if (mIsWARP && !gfxPrefs::LayersD3D11ForceWARP()) { + mD2D1Status = FeatureStatus::Blocked; + return false; + } + + if (!AttemptD3D11ContentDeviceCreation()) { + mD2D1Status = FeatureStatus::Failed; + return false; + } + + mD2D1Status = FeatureStatus::Available; + d2d1_1.SetSuccessful(); + return true; +} + already_AddRefed gfxWindowsPlatform::CreateD3D11DecoderDevice() { @@ -2442,23 +2496,33 @@ gfxWindowsPlatform::GetAcceleratedCompositorBackends(nsTArray& aB } } +// Some features are dependent on other features. If this is the case, we +// try to propagate the status of the parent feature if it wasn't available. FeatureStatus -gfxWindowsPlatform::GetD2D1Status() +gfxWindowsPlatform::GetD3D11Status() const { - if (GetD2DStatus() != FeatureStatus::Available || - !Factory::SupportsD2D1()) - { + if (mAcceleration != FeatureStatus::Available) { + return mAcceleration; + } + return mD3D11Status; +} + +FeatureStatus +gfxWindowsPlatform::GetD2DStatus() const +{ + if (GetD3D11Status() != FeatureStatus::Available) { return FeatureStatus::Unavailable; } + return mD2DStatus; +} - if (!GetD3D11ContentDevice()) { - return FeatureStatus::Failed; +FeatureStatus +gfxWindowsPlatform::GetD2D1Status() const +{ + if (GetD3D11Status() != FeatureStatus::Available) { + return FeatureStatus::Unavailable; } - - if (!gfxPrefs::Direct2DUse1_1()) { - return FeatureStatus::Disabled; - } - return FeatureStatus::Available; + return mD2D1Status; } unsigned diff --git a/gfx/thebes/gfxWindowsPlatform.h b/gfx/thebes/gfxWindowsPlatform.h index 3cfcc85dceb8..127e7189f39c 100644 --- a/gfx/thebes/gfxWindowsPlatform.h +++ b/gfx/thebes/gfxWindowsPlatform.h @@ -229,9 +229,8 @@ public: #ifdef CAIRO_HAS_DWRITE_FONT IDWriteFactory *GetDWriteFactory() { return mDWriteFactory; } - inline bool DWriteEnabled() { return mUseDirectWrite; } + inline bool DWriteEnabled() { return !!mDWriteFactory; } inline DWRITE_MEASURING_MODE DWriteMeasuringMode() { return mMeasuringMode; } - IDWriteTextAnalyzer *GetDWriteAnalyzer() { return mDWriteAnalyzer; } IDWriteRenderingParams *GetRenderingParams(TextRenderingMode aRenderMode) { return mRenderingParams[aRenderMode]; } @@ -263,17 +262,18 @@ public: } bool SupportsApzTouchInput() const override; + // Recreate devices as needed for a device reset. Returns true if a device + // reset occurred. + bool HandleDeviceReset(); + void UpdateBackendPrefs(); + // Return the diagnostic status of DirectX initialization. If // initialization has not been attempted, this returns // FeatureStatus::Unused. - mozilla::gfx::FeatureStatus GetD3D11Status() const { - return mD3D11Status; - } - mozilla::gfx::FeatureStatus GetD2DStatus() const { - return mD2DStatus; - } + mozilla::gfx::FeatureStatus GetD3D11Status() const; + mozilla::gfx::FeatureStatus GetD2DStatus() const; + mozilla::gfx::FeatureStatus GetD2D1Status() const; unsigned GetD3D11Version(); - mozilla::gfx::FeatureStatus GetD2D1Status(); virtual already_AddRefed CreateHardwareVsyncSource() override; static mozilla::Atomic sD3D11MemoryUsed; @@ -286,6 +286,7 @@ protected: return true; } void GetAcceleratedCompositorBackends(nsTArray& aBackends); + virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size); protected: RenderMode mRenderMode; @@ -296,34 +297,31 @@ protected: private: void Init(); - void InitD3D11Devices(); + void InitializeDevices(); + void InitializeD3D11(); + void InitializeD2D(); + bool InitializeD2D1(); + bool InitDWriteSupport(); - // Used by InitD3D11Devices(). + void DisableD2D(); + + // Used by InitializeD3D11(). enum class D3D11Status { Ok, - TryWARP, - ForceWARP, + OnlyWARP, Blocked }; D3D11Status CheckD3D11Support(); - bool AttemptD3D11DeviceCreation(const nsTArray& aFeatureLevels); - bool AttemptWARPDeviceCreation(const nsTArray& aFeatureLevels); - bool AttemptD3D11ImageBridgeDeviceCreation(const nsTArray& aFeatureLevels); - bool AttemptD3D11ContentDeviceCreation(const nsTArray& aFeatureLevels); - - // Used by UpdateRenderMode(). - mozilla::gfx::FeatureStatus InitD2DSupport(); - void InitDWriteSupport(); + bool AttemptD3D11DeviceCreation(); + bool AttemptWARPDeviceCreation(); + bool AttemptD3D11ImageBridgeDeviceCreation(); + bool AttemptD3D11ContentDeviceCreation(); IDXGIAdapter1 *GetDXGIAdapter(); bool IsDeviceReset(HRESULT hr, DeviceResetReason* aReason); - bool mUseDirectWrite; - bool mUsingGDIFonts; - #ifdef CAIRO_HAS_DWRITE_FONT nsRefPtr mDWriteFactory; - nsRefPtr mDWriteAnalyzer; nsRefPtr mRenderingParams[TEXT_RENDERING_COUNT]; DWRITE_MEASURING_MODE mMeasuringMode; #endif @@ -333,17 +331,20 @@ private: mozilla::RefPtr mD3D11Device; mozilla::RefPtr mD3D11ContentDevice; mozilla::RefPtr mD3D11ImageBridgeDevice; - bool mD3D11DeviceInitialized; mozilla::RefPtr mD3D11ReadbackManager; bool mIsWARP; bool mHasDeviceReset; bool mDoesD3D11TextureSharingWork; DeviceResetReason mDeviceResetReason; + // These should not be accessed directly. Use the Get[Feature]Status + // accessors instead. + mozilla::gfx::FeatureStatus mAcceleration; mozilla::gfx::FeatureStatus mD3D11Status; mozilla::gfx::FeatureStatus mD2DStatus; + mozilla::gfx::FeatureStatus mD2D1Status; - virtual void GetPlatformCMSOutputProfile(void* &mem, size_t &size); + nsTArray mFeatureLevels; }; #endif /* GFX_WINDOWS_PLATFORM_H */ diff --git a/gfx/thebes/gfxWindowsSurface.cpp b/gfx/thebes/gfxWindowsSurface.cpp index 89b8d193c505..c09309911984 100644 --- a/gfx/thebes/gfxWindowsSurface.cpp +++ b/gfx/thebes/gfxWindowsSurface.cpp @@ -300,9 +300,3 @@ gfxWindowsSurface::GetSize() const return mozilla::gfx::IntSize(cairo_win32_surface_get_width(mSurface), cairo_win32_surface_get_height(mSurface)); } - -gfxMemoryLocation -gfxWindowsSurface::GetMemoryLocation() const -{ - return gfxMemoryLocation::IN_PROCESS_NONHEAP; -} diff --git a/gfx/thebes/gfxWindowsSurface.h b/gfx/thebes/gfxWindowsSurface.h index c2d3e5c2d2cd..7e8b51746d15 100644 --- a/gfx/thebes/gfxWindowsSurface.h +++ b/gfx/thebes/gfxWindowsSurface.h @@ -65,10 +65,6 @@ public: const mozilla::gfx::IntSize GetSize() const; - // The memory used by this surface lives in this process's address space, - // but not in the heap. - virtual gfxMemoryLocation GetMemoryLocation() const; - private: void MakeInvalid(mozilla::gfx::IntSize& size); diff --git a/gfx/thebes/gfxXlibSurface.cpp b/gfx/thebes/gfxXlibSurface.cpp index fbd0f0eb2f13..a83a298fc3b6 100644 --- a/gfx/thebes/gfxXlibSurface.cpp +++ b/gfx/thebes/gfxXlibSurface.cpp @@ -606,9 +606,3 @@ gfxXlibSurface::GetGLXPixmap() return mGLXPixmap; } #endif - -gfxMemoryLocation -gfxXlibSurface::GetMemoryLocation() const -{ - return gfxMemoryLocation::OUT_OF_PROCESS; -} diff --git a/gfx/thebes/gfxXlibSurface.h b/gfx/thebes/gfxXlibSurface.h index 677b59565a93..f68406cec8f8 100644 --- a/gfx/thebes/gfxXlibSurface.h +++ b/gfx/thebes/gfxXlibSurface.h @@ -85,10 +85,6 @@ public: // Find a visual and colormap pair suitable for rendering to this surface. bool GetColormapAndVisual(Colormap* colormap, Visual **visual); - // This surface is a wrapper around X pixmaps, which are stored in the X - // server, not the main application. - virtual gfxMemoryLocation GetMemoryLocation() const override; - #if defined(GL_PROVIDER_GLX) GLXPixmap GetGLXPixmap(); #endif diff --git a/image/FrameAnimator.cpp b/image/FrameAnimator.cpp index 942c6a142d6f..6fdaa15731ac 100644 --- a/image/FrameAnimator.cpp +++ b/image/FrameAnimator.cpp @@ -334,12 +334,9 @@ DoCollectSizeOfCompositingSurfaces(const RawAccessFrameRef& aSurface, SurfaceMemoryCounter counter(key, /* aIsLocked = */ true, aType); // Extract the surface's memory usage information. - size_t heap = aSurface - ->SizeOfExcludingThis(gfxMemoryLocation::IN_PROCESS_HEAP, aMallocSizeOf); + size_t heap = 0, nonHeap = 0; + aSurface->AddSizeOfExcludingThis(aMallocSizeOf, heap, nonHeap); counter.Values().SetDecodedHeap(heap); - - size_t nonHeap = aSurface - ->SizeOfExcludingThis(gfxMemoryLocation::IN_PROCESS_NONHEAP, nullptr); counter.Values().SetDecodedNonHeap(nonHeap); // Record it. diff --git a/image/Image.h b/image/Image.h index 7e48e050b82c..2344c095e82a 100644 --- a/image/Image.h +++ b/image/Image.h @@ -8,7 +8,7 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/TimeStamp.h" -#include "gfx2DGlue.h" // for gfxMemoryLocation +#include "gfx2DGlue.h" #include "imgIContainer.h" #include "ImageURL.h" #include "nsStringFwd.h" diff --git a/image/RasterImage.h b/image/RasterImage.h index 2356fdfa0783..78143a4cf5a6 100644 --- a/image/RasterImage.h +++ b/image/RasterImage.h @@ -316,10 +316,6 @@ private: nsIntRect GetFirstFrameRect(); - size_t - SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const; - Pair> GetCurrentImage(layers::ImageContainer* aContainer, uint32_t aFlags); diff --git a/image/SurfaceCache.cpp b/image/SurfaceCache.cpp index d791b1f776b0..a19727fbe1a8 100644 --- a/image/SurfaceCache.cpp +++ b/image/SurfaceCache.cpp @@ -207,13 +207,10 @@ public: if (aCachedSurface->mSurface) { counter.SubframeSize() = Some(aCachedSurface->mSurface->GetSize()); - size_t heap = aCachedSurface->mSurface - ->SizeOfExcludingThis(gfxMemoryLocation::IN_PROCESS_HEAP, - mMallocSizeOf); + size_t heap = 0, nonHeap = 0; + aCachedSurface->mSurface->AddSizeOfExcludingThis(mMallocSizeOf, + heap, nonHeap); counter.Values().SetDecodedHeap(heap); - - size_t nonHeap = aCachedSurface->mSurface - ->SizeOfExcludingThis(gfxMemoryLocation::IN_PROCESS_NONHEAP, nullptr); counter.Values().SetDecodedNonHeap(nonHeap); } diff --git a/image/SurfaceCache.h b/image/SurfaceCache.h index 32d61b068ca1..772badee0f2e 100644 --- a/image/SurfaceCache.h +++ b/image/SurfaceCache.h @@ -14,7 +14,7 @@ #include "mozilla/Maybe.h" // for Maybe #include "mozilla/MemoryReporting.h" // for MallocSizeOf #include "mozilla/HashFunctions.h" // for HashGeneric and AddToHash -#include "gfx2DGlue.h" // for gfxMemoryLocation +#include "gfx2DGlue.h" #include "gfxPoint.h" // for gfxSize #include "nsCOMPtr.h" // for already_AddRefed #include "mozilla/gfx/Point.h" // for mozilla::gfx::IntSize diff --git a/image/imgFrame.cpp b/image/imgFrame.cpp index c699bbc95e5e..ab062eb75133 100644 --- a/image/imgFrame.cpp +++ b/image/imgFrame.cpp @@ -1115,42 +1115,28 @@ imgFrame::SetCompositingFailed(bool val) mCompositingFailed = val; } -size_t -imgFrame::SizeOfExcludingThis(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const +void +imgFrame::AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, + size_t& aHeapSizeOut, + size_t& aNonHeapSizeOut) const { MonitorAutoLock lock(mMonitor); - // aMallocSizeOf is only used if aLocation is - // gfxMemoryLocation::IN_PROCESS_HEAP. It - // should be nullptr otherwise. - MOZ_ASSERT( - (aLocation == gfxMemoryLocation::IN_PROCESS_HEAP && aMallocSizeOf) || - (aLocation != gfxMemoryLocation::IN_PROCESS_HEAP && !aMallocSizeOf), - "mismatch between aLocation and aMallocSizeOf"); - - size_t n = 0; - - if (mPalettedImageData && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) { - n += aMallocSizeOf(mPalettedImageData); + if (mPalettedImageData) { + aHeapSizeOut += aMallocSizeOf(mPalettedImageData); } - if (mImageSurface && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) { - n += aMallocSizeOf(mImageSurface); + if (mImageSurface) { + aHeapSizeOut += aMallocSizeOf(mImageSurface); } - if (mOptSurface && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) { - n += aMallocSizeOf(mOptSurface); + if (mOptSurface) { + aHeapSizeOut += aMallocSizeOf(mOptSurface); } - if (mVBuf && aLocation == gfxMemoryLocation::IN_PROCESS_HEAP) { - n += aMallocSizeOf(mVBuf); - n += mVBuf->HeapSizeOfExcludingThis(aMallocSizeOf); + if (mVBuf) { + aHeapSizeOut += aMallocSizeOf(mVBuf); + aHeapSizeOut += mVBuf->HeapSizeOfExcludingThis(aMallocSizeOf); + aNonHeapSizeOut += mVBuf->NonHeapSizeOfExcludingThis(); } - - if (mVBuf && aLocation == gfxMemoryLocation::IN_PROCESS_NONHEAP) { - n += mVBuf->NonHeapSizeOfExcludingThis(); - } - - return n; } } // namespace image diff --git a/image/imgFrame.h b/image/imgFrame.h index 9c9a0262128f..4173db66b95e 100644 --- a/image/imgFrame.h +++ b/image/imgFrame.h @@ -264,8 +264,8 @@ public: already_AddRefed GetSurface(); already_AddRefed GetDrawTarget(); - size_t SizeOfExcludingThis(gfxMemoryLocation aLocation, - MallocSizeOf aMallocSizeOf) const; + void AddSizeOfExcludingThis(MallocSizeOf aMallocSizeOf, size_t& aHeapSizeOut, + size_t& aNonHeapSizeOut) const; private: // methods diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 48b574a7475d..93cef0f9d385 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -853,6 +853,7 @@ MessageChannel::Send(Message* aMsg, Message* aReply) #ifdef OS_WIN SyncStackFrame frame(this, false); + NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION); #endif CxxStackFrame f(*this, OUT_MESSAGE, msg); @@ -994,6 +995,7 @@ MessageChannel::Call(Message* aMsg, Message* aReply) #ifdef OS_WIN SyncStackFrame frame(this, true); + NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION); #endif // This must come before MonitorAutoLock, as its destructor acquires the @@ -1032,6 +1034,12 @@ MessageChannel::Call(Message* aMsg, Message* aReply) return false; } +#ifdef OS_WIN + /* We should pump messages at this point to ensure that the IPC peer + does not become deadlocked on a pending inter-thread SendMessage() */ + neuteredRgn.PumpOnce(); +#endif + // Now might be the time to process a message deferred because of race // resolution. MaybeUndeferIncall(); @@ -1148,6 +1156,7 @@ MessageChannel::WaitForIncomingMessage() { #ifdef OS_WIN SyncStackFrame frame(this, true); + NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION); #endif { // Scope for lock diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index 519525d6e6b3..243446debba4 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -15,6 +15,9 @@ #include "mozilla/Monitor.h" #include "mozilla/Vector.h" #include "mozilla/WeakPtr.h" +#if defined(OS_WIN) +#include "mozilla/ipc/Neutering.h" +#endif // defined(OS_WIN) #include "mozilla/ipc/Transport.h" #include "MessageLink.h" #include "nsAutoPtr.h" diff --git a/ipc/glue/Neutering.h b/ipc/glue/Neutering.h new file mode 100644 index 000000000000..ea1a2bf5e9ab --- /dev/null +++ b/ipc/glue/Neutering.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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_ipc_Neutering_h +#define mozilla_ipc_Neutering_h + +#include "mozilla/GuardObjects.h" + +/** + * This header declares RAII wrappers for Window neutering. See + * WindowsMessageLoop.cpp for more details. + */ + +namespace mozilla { +namespace ipc { + +/** + * This class is a RAII wrapper around Window neutering. As long as a + * NeuteredWindowRegion object is instantiated, Win32 windows belonging to the + * current thread will be neutered. It is safe to nest multiple instances of + * this class. + */ +class MOZ_STACK_CLASS NeuteredWindowRegion +{ +public: + explicit NeuteredWindowRegion(bool aDoNeuter MOZ_GUARD_OBJECT_NOTIFIER_PARAM); + ~NeuteredWindowRegion(); + + /** + * This function clears any backlog of nonqueued messages that are pending for + * the current thread. + */ + void PumpOnce(); + +private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + bool mNeuteredByThis; +}; + +/** + * This class is analagous to MutexAutoUnlock for Mutex; it is an RAII class + * that is to be instantiated within a NeuteredWindowRegion, thus temporarily + * disabling neutering for the remainder of its enclosing block. + * @see NeuteredWindowRegion + */ +class MOZ_STACK_CLASS DeneuteredWindowRegion +{ +public: + DeneuteredWindowRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM); + ~DeneuteredWindowRegion(); + +private: + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER + bool mReneuter; +}; + +} // namespace ipc +} // namespace mozilla + +#endif // mozilla_ipc_Neutering_h + diff --git a/ipc/glue/WindowsMessageLoop.cpp b/ipc/glue/WindowsMessageLoop.cpp index 3f7afaaa1865..9bf21abcd7bd 100644 --- a/ipc/glue/WindowsMessageLoop.cpp +++ b/ipc/glue/WindowsMessageLoop.cpp @@ -8,6 +8,7 @@ #include "mozilla/DebugOnly.h" #include "WindowsMessageLoop.h" +#include "Neutering.h" #include "MessageChannel.h" #include "nsAutoPtr.h" @@ -862,6 +863,81 @@ IsTimeoutExpired(PRIntervalTime aStart, PRIntervalTime aTimeout) (aTimeout <= (PR_IntervalNow() - aStart)); } +static HHOOK gWindowHook; + +static inline void +StartNeutering() +{ + MOZ_ASSERT(gUIThreadId); + MOZ_ASSERT(!gWindowHook); + NS_ASSERTION(!MessageChannel::IsPumpingMessages(), + "Shouldn't be pumping already!"); + MessageChannel::SetIsPumpingMessages(true); + gWindowHook = ::SetWindowsHookEx(WH_CALLWNDPROC, CallWindowProcedureHook, + nullptr, gUIThreadId); + NS_ASSERTION(gWindowHook, "Failed to set hook!"); +} + +static void +StopNeutering() +{ + MOZ_ASSERT(MessageChannel::IsPumpingMessages()); + ::UnhookWindowsHookEx(gWindowHook); + gWindowHook = NULL; + ::UnhookNeuteredWindows(); + // Before returning we need to set a hook to run any deferred messages that + // we received during the IPC call. The hook will unset itself as soon as + // someone else calls GetMessage, PeekMessage, or runs code that generates + // a "nonqueued" message. + ::ScheduleDeferredMessageRun(); + MessageChannel::SetIsPumpingMessages(false); +} + +NeuteredWindowRegion::NeuteredWindowRegion(bool aDoNeuter MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) + : mNeuteredByThis(!gWindowHook) +{ + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + if (aDoNeuter && mNeuteredByThis) { + StartNeutering(); + } +} + +NeuteredWindowRegion::~NeuteredWindowRegion() +{ + if (gWindowHook && mNeuteredByThis) { + StopNeutering(); + } +} + +void +NeuteredWindowRegion::PumpOnce() +{ + MSG msg = {0}; + // Pump any COM messages so that we don't hang due to STA marshaling. + if (gCOMWindow && ::PeekMessageW(&msg, gCOMWindow, 0, 0, PM_REMOVE)) { + ::TranslateMessage(&msg); + ::DispatchMessageW(&msg); + } + // Expunge any nonqueued messages on the current thread. + ::PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE); +} + +DeneuteredWindowRegion::DeneuteredWindowRegion(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_IN_IMPL) + : mReneuter(gWindowHook != NULL) +{ + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + if (mReneuter) { + StopNeutering(); + } +} + +DeneuteredWindowRegion::~DeneuteredWindowRegion() +{ + if (mReneuter) { + StartNeutering(); + } +} + bool MessageChannel::WaitForSyncNotify() { @@ -916,15 +992,6 @@ MessageChannel::WaitForSyncNotify() NS_ASSERTION(timerId, "SetTimer failed!"); } - // Setup deferred processing of native events while we wait for a response. - NS_ASSERTION(!MessageChannel::IsPumpingMessages(), - "Shouldn't be pumping already!"); - - MessageChannel::SetIsPumpingMessages(true); - HHOOK windowHook = SetWindowsHookEx(WH_CALLWNDPROC, CallWindowProcedureHook, - nullptr, gUIThreadId); - NS_ASSERTION(windowHook, "Failed to set hook!"); - { while (1) { MSG msg = { 0 }; @@ -998,25 +1065,11 @@ MessageChannel::WaitForSyncNotify() } } - // Unhook the neutered window procedure hook. - UnhookWindowsHookEx(windowHook); - - // Unhook any neutered windows procedures so messages can be delivered - // normally. - UnhookNeuteredWindows(); - - // Before returning we need to set a hook to run any deferred messages that - // we received during the IPC call. The hook will unset itself as soon as - // someone else calls GetMessage, PeekMessage, or runs code that generates - // a "nonqueued" message. - ScheduleDeferredMessageRun(); - if (timerId) { KillTimer(nullptr, timerId); + timerId = 0; } - MessageChannel::SetIsPumpingMessages(false); - return WaitResponse(timedout); } @@ -1050,56 +1103,28 @@ MessageChannel::WaitForInterruptNotify() UINT_PTR timerId = 0; TimeoutData timeoutData = { 0 }; - // windowHook is used as a flag variable for the loop below: if it is set + // gWindowHook is used as a flag variable for the loop below: if it is set // and we start to spin a nested event loop, we need to clear the hook and // process deferred/pending messages. - // If windowHook is nullptr, MessageChannel::IsPumpingMessages should be false. - HHOOK windowHook = nullptr; - while (1) { - NS_ASSERTION((!!windowHook) == MessageChannel::IsPumpingMessages(), - "windowHook out of sync with reality"); + NS_ASSERTION((!!gWindowHook) == MessageChannel::IsPumpingMessages(), + "gWindowHook out of sync with reality"); if (mTopFrame->mSpinNestedEvents) { - if (windowHook) { - UnhookWindowsHookEx(windowHook); - windowHook = nullptr; - - if (timerId) { - KillTimer(nullptr, timerId); - timerId = 0; - } - - // Used by widget to assert on incoming native events - MessageChannel::SetIsPumpingMessages(false); - - // Unhook any neutered windows procedures so messages can be delievered - // normally. - UnhookNeuteredWindows(); - - // Send all deferred "nonqueued" message to the intended receiver. - // We're dropping into SpinInternalEventLoop so we should be fairly - // certain these will get delivered soohn. - ScheduleDeferredMessageRun(); + if (gWindowHook && timerId) { + KillTimer(nullptr, timerId); + timerId = 0; } + DeneuteredWindowRegion deneuteredRgn; SpinInternalEventLoop(); ResetEvent(mEvent); return true; } - if (!windowHook) { - MessageChannel::SetIsPumpingMessages(true); - windowHook = SetWindowsHookEx(WH_CALLWNDPROC, CallWindowProcedureHook, - nullptr, gUIThreadId); - NS_ASSERTION(windowHook, "Failed to set hook!"); - - NS_ASSERTION(!timerId, "Timer already initialized?"); - - if (mTimeoutMs != kNoTimeout) { - InitTimeoutData(&timeoutData, mTimeoutMs); - timerId = SetTimer(nullptr, 0, mTimeoutMs, nullptr); - NS_ASSERTION(timerId, "SetTimer failed!"); - } + if (mTimeoutMs != kNoTimeout && !timerId) { + InitTimeoutData(&timeoutData, mTimeoutMs); + timerId = SetTimer(nullptr, 0, mTimeoutMs, nullptr); + NS_ASSERTION(timerId, "SetTimer failed!"); } MSG msg = { 0 }; @@ -1151,27 +1176,11 @@ MessageChannel::WaitForInterruptNotify() } } - if (windowHook) { - // Unhook the neutered window procedure hook. - UnhookWindowsHookEx(windowHook); - - // Unhook any neutered windows procedures so messages can be delivered - // normally. - UnhookNeuteredWindows(); - - // Before returning we need to set a hook to run any deferred messages that - // we received during the IPC call. The hook will unset itself as soon as - // someone else calls GetMessage, PeekMessage, or runs code that generates - // a "nonqueued" message. - ScheduleDeferredMessageRun(); - - if (timerId) { - KillTimer(nullptr, timerId); - } + if (timerId) { + KillTimer(nullptr, timerId); + timerId = 0; } - MessageChannel::SetIsPumpingMessages(false); - return WaitResponse(timedout); } diff --git a/ipc/glue/moz.build b/ipc/glue/moz.build index fc4f0be808e2..2c0f541696b1 100644 --- a/ipc/glue/moz.build +++ b/ipc/glue/moz.build @@ -25,6 +25,7 @@ EXPORTS.mozilla.ipc += [ 'IOThreadChild.h', 'MessageChannel.h', 'MessageLink.h', + 'Neutering.h', 'ProcessChild.h', 'ProtocolUtils.h', 'ScopedXREEmbed.h', diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 8b6487b84d9a..57c05b30fdf2 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -163,12 +163,10 @@ class JS_FRIEND_API(GCCellPtr) MOZ_IMPLICIT GCCellPtr(decltype(nullptr)) : ptr(checkedCast(nullptr, JS::TraceKind::Null)) {} // Construction from an explicit type. - explicit GCCellPtr(JSObject* obj) : ptr(checkedCast(obj, JS::TraceKind::Object)) { } - explicit GCCellPtr(JSFunction* fun) : ptr(checkedCast(fun, JS::TraceKind::Object)) { } - explicit GCCellPtr(JSString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { } + template + explicit GCCellPtr(T* p) : ptr(checkedCast(p, JS::MapTypeToTraceKind::kind)) { } + explicit GCCellPtr(JSFunction* p) : ptr(checkedCast(p, JS::TraceKind::Object)) { } explicit GCCellPtr(JSFlatString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { } - explicit GCCellPtr(JS::Symbol* sym) : ptr(checkedCast(sym, JS::TraceKind::Symbol)) { } - explicit GCCellPtr(JSScript* script) : ptr(checkedCast(script, JS::TraceKind::Script)) { } explicit GCCellPtr(const Value& v); JS::TraceKind kind() const { @@ -185,31 +183,22 @@ class JS_FRIEND_API(GCCellPtr) } // Simplify checks to the kind. - bool isObject() const { return kind() == JS::TraceKind::Object; } - bool isScript() const { return kind() == JS::TraceKind::Script; } - bool isString() const { return kind() == JS::TraceKind::String; } - bool isSymbol() const { return kind() == JS::TraceKind::Symbol; } - bool isShape() const { return kind() == JS::TraceKind::Shape; } - bool isObjectGroup() const { return kind() == JS::TraceKind::ObjectGroup; } + template + bool is() const { return kind() == JS::MapTypeToTraceKind::kind; } // Conversions to more specific types must match the kind. Access to // further refined types is not allowed directly from a GCCellPtr. - JSObject* toObject() const { - MOZ_ASSERT(kind() == JS::TraceKind::Object); - return reinterpret_cast(asCell()); - } - JSString* toString() const { - MOZ_ASSERT(kind() == JS::TraceKind::String); - return reinterpret_cast(asCell()); - } - JSScript* toScript() const { - MOZ_ASSERT(kind() == JS::TraceKind::Script); - return reinterpret_cast(asCell()); - } - Symbol* toSymbol() const { - MOZ_ASSERT(kind() == JS::TraceKind::Symbol); - return reinterpret_cast(asCell()); + template + T& as() const { + MOZ_ASSERT(kind() == JS::MapTypeToTraceKind::kind); + // We can't use static_cast here, because the fact that JSObject + // inherits from js::gc::Cell is not part of the public API. + return *reinterpret_cast(asCell()); } + + // Return a pointer to the cell this |GCCellPtr| refers to, or |nullptr|. + // (It would be more symmetrical with |to| for this to return a |Cell&|, but + // the result can be |nullptr|, and null references are undefined behavior.) js::gc::Cell* asCell() const { return reinterpret_cast(ptr & ~OutOfLineTraceKindMask); } diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 917b8928d513..cdaeb56430ff 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -609,6 +609,10 @@ class DispatchWrapper public: // Mimic a pointer type, so that we can drop into Rooted. MOZ_IMPLICIT DispatchWrapper(const T& initial) : tracer(&T::trace), storage(initial) {} + MOZ_IMPLICIT DispatchWrapper(T&& initial) + : tracer(&T::trace), + storage(mozilla::Forward(initial)) + { } T* operator &() { return &storage; } const T* operator &() const { return &storage; } operator T&() { return storage; } diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h index 272f577399eb..0c06b9e0420a 100644 --- a/js/public/TraceKind.h +++ b/js/public/TraceKind.h @@ -7,6 +7,18 @@ #ifndef js_TraceKind_h #define js_TraceKind_h +#include "js/TypeDecls.h" + +// Forward declarations of all the types a TraceKind can denote. +namespace js { +class BaseShape; +class LazyScript; +class ObjectGroup; +namespace jit { +class JitCode; +} // namespace jit +} // namespace js + namespace JS { // When tracing a thing, the GC needs to know about the layout of the object it @@ -47,6 +59,82 @@ static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mas static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set"); static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set"); +#define JS_FOR_EACH_TRACEKIND(D) \ + /* PrettyName TypeName AddToCCKind */ \ + D(BaseShape, js::BaseShape, true) \ + D(JitCode, js::jit::JitCode, true) \ + D(LazyScript, js::LazyScript, true) \ + D(Object, JSObject, true) \ + D(ObjectGroup, js::ObjectGroup, true) \ + D(Script, JSScript, true) \ + D(Shape, js::Shape, true) \ + D(String, JSString, false) \ + D(Symbol, JS::Symbol, false) + +// Map from base trace type to the trace kind. +template struct MapTypeToTraceKind {}; +#define JS_EXPAND_DEF(name, type, _) \ + template <> struct MapTypeToTraceKind { \ + static const JS::TraceKind kind = JS::TraceKind::name; \ + }; +JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); +#undef JS_EXPAND_DEF + +// Fortunately, few places in the system need to deal with fully abstract +// cells. In those places that do, we generally want to move to a layout +// templated function as soon as possible. This template wraps the upcast +// for that dispatch. +// +// Given a call: +// +// DispatchTraceKindTyped(f, thing, traceKind, ... args) +// +// Downcast the |void *thing| to the specific type designated by |traceKind|, +// and pass it to the functor |f| along with |... args|, forwarded. Pass the +// type designated by |traceKind| as the functor's template argument. The +// |thing| parameter is optional; without it, we simply pass through |... args|. + +// GCC and Clang require an explicit template declaration in front of the +// specialization of operator() because it is a dependent template. MSVC, on +// the other hand, gets very confused if we have a |template| token there. +#ifdef _MSC_VER +# define JS_DEPENDENT_TEMPLATE_HINT +#else +# define JS_DEPENDENT_TEMPLATE_HINT template +#endif +template +auto +DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args) + -> decltype(f. JS_DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...)) +{ + switch (traceKind) { +#define JS_EXPAND_DEF(name, type, _) \ + case JS::TraceKind::name: \ + return f. JS_DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...); + JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); +#undef JS_EXPAND_DEF + default: + MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); + } +} +#undef JS_DEPENDENT_TEMPLATE_HINT + +template +auto +DispatchTraceKindTyped(F f, void* thing, JS::TraceKind traceKind, Args&&... args) + -> decltype(f(reinterpret_cast(0), mozilla::Forward(args)...)) +{ + switch (traceKind) { +#define JS_EXPAND_DEF(name, type, _) \ + case JS::TraceKind::name: \ + return f(static_cast(thing), mozilla::Forward(args)...); + JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF); +#undef JS_EXPAND_DEF + default: + MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped."); + } +} + } // namespace JS #endif // js_TraceKind_h diff --git a/js/public/TracingAPI.h b/js/public/TracingAPI.h index d66381eb65b8..a09044fed737 100644 --- a/js/public/TracingAPI.h +++ b/js/public/TracingAPI.h @@ -26,15 +26,6 @@ GCTraceKindToAscii(JS::TraceKind kind); } // namespace JS -namespace js { -class BaseShape; -class LazyScript; -class ObjectGroup; -namespace jit { -class JitCode; -} // namespace jit -} // namespace js - enum WeakMapTraceKind { DoNotTraceWeakMaps = 0, TraceWeakMapValues = 1, diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 71ad5d2b4adc..2971cfc3de18 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -35,6 +35,8 @@ using namespace js; using namespace js::gc; +using JS::MapTypeToTraceKind; + using mozilla::ArrayLength; using mozilla::DebugOnly; using mozilla::IsBaseOf; @@ -255,7 +257,7 @@ CheckTracedThing(JSTracer* trc, jsid id) #define IMPL_CHECK_TRACED_THING(_, type, __) \ template void CheckTracedThing(JSTracer*, type*); -FOR_EACH_GC_LAYOUT(IMPL_CHECK_TRACED_THING); +JS_FOR_EACH_TRACEKIND(IMPL_CHECK_TRACED_THING); #undef IMPL_CHECK_TRACED_THING } // namespace js @@ -404,7 +406,7 @@ template struct BaseGCType { typedef type_ type; }; -FOR_EACH_GC_LAYOUT(IMPL_BASE_GC_TYPE); +JS_FOR_EACH_TRACEKIND(IMPL_BASE_GC_TYPE); #undef IMPL_BASE_GC_TYPE // Our barrier templates are parameterized on the pointer types so that we can @@ -554,7 +556,7 @@ js::TraceGenericPointerRoot(JSTracer* trc, Cell** thingp, const char* name) if (!*thingp) return; TraceRootFunctor f; - CallTyped(f, (*thingp)->getTraceKind(), trc, thingp, name); + DispatchTraceKindTyped(f, (*thingp)->getTraceKind(), trc, thingp, name); } // A typed functor adaptor for TraceManuallyBarrieredEdge. @@ -572,7 +574,7 @@ js::TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, Cell** thingp, const if (!*thingp) return; TraceManuallyBarrieredEdgeFunctor f; - CallTyped(f, (*thingp)->getTraceKind(), trc, thingp, name); + DispatchTraceKindTyped(f, (*thingp)->getTraceKind(), trc, thingp, name); } // This method is responsible for dynamic dispatch to the real tracer @@ -584,7 +586,7 @@ DispatchToTracer(JSTracer* trc, T* thingp, const char* name) { #define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame::value || static_assert( - FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR) + JS_FOR_EACH_TRACEKIND(IS_SAME_TYPE_OR) mozilla::IsSame::value || mozilla::IsSame::value, "Only the base cell layout types are allowed into marking/tracing internals"); @@ -1731,7 +1733,7 @@ struct PushArenaFunctor { void gc::PushArena(GCMarker* gcmarker, ArenaHeader* aheader) { - CallTyped(PushArenaFunctor(), MapAllocToTraceKind(aheader->getAllocKind()), gcmarker, aheader); + DispatchTraceKindTyped(PushArenaFunctor(), MapAllocToTraceKind(aheader->getAllocKind()), gcmarker, aheader); } #ifdef DEBUG @@ -2116,7 +2118,7 @@ CheckIsMarkedThing(T* thingp) { #define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame::value || static_assert( - FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR) + JS_FOR_EACH_TRACEKIND(IS_SAME_TYPE_OR) false, "Only the base cell layout types are allowed into marking/tracing internals"); #undef IS_SAME_TYPE_OR diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index afede54fe377..c2afc8e7f0dd 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -526,7 +526,7 @@ BufferGrayRootsTracer::onChild(const JS::GCCellPtr& thing) // objects and scripts. We rely on gray root buffering for this to work, // but we only need to worry about uncollected dead compartments during // incremental GCs (when we do gray root buffering). - CallTyped(SetMaybeAliveFunctor(), tenured, thing.kind()); + DispatchTraceKindTyped(SetMaybeAliveFunctor(), tenured, thing.kind()); if (!zone->gcGrayRoots.append(tenured)) bufferingGrayRootsFailed = true; diff --git a/js/src/gc/Rooting.h b/js/src/gc/Rooting.h index cc8679b2b881..f6cc72c2422e 100644 --- a/js/src/gc/Rooting.h +++ b/js/src/gc/Rooting.h @@ -20,6 +20,7 @@ class ArrayObject; class GlobalObject; class PlainObject; class ScriptSourceObject; +class SavedFrame; class Shape; class ObjectGroup; @@ -33,12 +34,14 @@ typedef JS::Handle HandleLinearString; typedef JS::Handle HandlePropertyName; typedef JS::Handle HandleArrayObject; typedef JS::Handle HandlePlainObject; +typedef JS::Handle HandleSavedFrame; typedef JS::Handle HandleScriptSource; typedef JS::MutableHandle MutableHandleShape; typedef JS::MutableHandle MutableHandleAtom; typedef JS::MutableHandle MutableHandleNativeObject; typedef JS::MutableHandle MutableHandlePlainObject; +typedef JS::MutableHandle MutableHandleSavedFrame; typedef JS::Rooted RootedNativeObject; typedef JS::Rooted RootedShape; @@ -49,6 +52,7 @@ typedef JS::Rooted RootedPropertyName; typedef JS::Rooted RootedArrayObject; typedef JS::Rooted RootedGlobalObject; typedef JS::Rooted RootedPlainObject; +typedef JS::Rooted RootedSavedFrame; typedef JS::Rooted RootedScriptSource; } /* namespace js */ diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index ee24e65123bb..ae4c8b3aef84 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -53,7 +53,7 @@ DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name) } #define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type, _) \ template type* DoCallback(JS::CallbackTracer*, type**, const char*); -FOR_EACH_GC_LAYOUT(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS); +JS_FOR_EACH_TRACEKIND(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS); #undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS template @@ -193,7 +193,7 @@ js::TraceChildren(JSTracer* trc, void* thing, JS::TraceKind kind) { MOZ_ASSERT(thing); TraceChildrenFunctor f; - CallTyped(f, kind, trc, thing); + DispatchTraceKindTyped(f, kind, trc, thing); } JS_PUBLIC_API(void) @@ -331,23 +331,23 @@ struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer void ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing) { - if (thing.isObject() || thing.isScript()) { + if (thing.is() || thing.is()) { // Invoke the inner cycle collector callback on this child. It will not // recurse back into TraceChildren. innerTracer->onChild(thing); return; } - if (thing.isObjectGroup()) { + if (thing.is()) { // If this group is required to be in an ObjectGroup chain, trace it // via the provided worklist rather than continuing to recurse. - ObjectGroup* group = static_cast(thing.asCell()); - if (group->maybeUnboxedLayout()) { + ObjectGroup& group = thing.as(); + if (group.maybeUnboxedLayout()) { for (size_t i = 0; i < seen.length(); i++) { - if (seen[i] == group) + if (seen[i] == &group) return; } - if (seen.append(group) && worklist.append(group)) { + if (seen.append(&group) && worklist.append(&group)) { return; } else { // If append fails, keep tracing normally. The worst that will diff --git a/js/src/gdb/lib-for-tests/catcher.py b/js/src/gdb/lib-for-tests/catcher.py index 7fed0ab3364c..4bac2a025ead 100644 --- a/js/src/gdb/lib-for-tests/catcher.py +++ b/js/src/gdb/lib-for-tests/catcher.py @@ -15,7 +15,7 @@ import traceback try: # testlibdir is set on the GDB command line, via: # --eval-command python testlibdir=... - execfile(os.path.join(testlibdir, 'prologue.py')) + exec(open(os.path.join(testlibdir, 'prologue.py')).read()) except Exception as err: sys.stderr.write('Error running GDB prologue:\n') traceback.print_exc() diff --git a/js/src/gdb/lib-for-tests/prologue.py b/js/src/gdb/lib-for-tests/prologue.py index 8c2f213884b2..642ab0f2eb77 100644 --- a/js/src/gdb/lib-for-tests/prologue.py +++ b/js/src/gdb/lib-for-tests/prologue.py @@ -23,9 +23,9 @@ def run_fragment(fragment, function='breakpoint'): # Assert that |actual| is equal to |expected|; if not, complain in a helpful way. def assert_eq(actual, expected): if actual != expected: - raise AssertionError, """Unexpected result: + raise AssertionError("""Unexpected result: expected: %r -actual: %r""" % (expected, actual) +actual: %r""" % (expected, actual)) # Assert that |value|'s pretty-printed form is |form|. If |value| is a # string, then evaluate it with gdb.parse_and_eval to produce a value. @@ -44,10 +44,10 @@ def assert_subprinter_registered(printer, subprinter): pat = r'^( +)%(printer)s *\n(\1 +.*\n)*\1 +%(subprinter)s *\n' % names output = gdb.execute('info pretty-printer', to_string=True) if not re.search(pat, output, re.MULTILINE): - raise AssertionError, ("assert_subprinter_registered failed to find pretty-printer:\n" - " %s:%s\n" - "'info pretty-printer' says:\n" - "%s" % (printer, subprinter, output)) + raise AssertionError("assert_subprinter_registered failed to find pretty-printer:\n" + " %s:%s\n" + "'info pretty-printer' says:\n" + "%s" % (printer, subprinter, output)) # Request full stack traces for Python errors. gdb.execute('set python print-stack full') @@ -64,7 +64,7 @@ gdb.execute('set width 0') try: # testscript is set on the GDB command line, via: # --eval-command python testscript=... - execfile(testscript) + exec(open(testscript).read()) except AssertionError as err: sys.stderr.write('\nAssertion traceback:\n') (t, v, tb) = sys.exc_info() diff --git a/js/src/gdb/moz.build b/js/src/gdb/moz.build index 4887b52c3f41..67cedec79dae 100644 --- a/js/src/gdb/moz.build +++ b/js/src/gdb/moz.build @@ -9,6 +9,7 @@ GeckoProgram('gdb-tests', linkage=None) UNIFIED_SOURCES += [ 'gdb-tests.cpp', 'tests/test-asmjs.cpp', + 'tests/test-GCCellPtr.cpp', 'tests/test-Interpreter.cpp', 'tests/test-jsid.cpp', 'tests/test-JSObject.cpp', diff --git a/js/src/gdb/mozilla/GCCellPtr.py b/js/src/gdb/mozilla/GCCellPtr.py new file mode 100644 index 000000000000..87dcf73da83a --- /dev/null +++ b/js/src/gdb/mozilla/GCCellPtr.py @@ -0,0 +1,49 @@ +# Pretty-printers for GCCellPtr values. + +import gdb +import mozilla.prettyprinters + +from mozilla.prettyprinters import pretty_printer + +# Forget any printers from previous loads of this module. +mozilla.prettyprinters.clear_module_printers(__name__) + +# Cache information about the JS::TraceKind type for this objfile. +class GCCellPtrTypeCache(object): + def __init__(self, cache): + self.TraceKind_t = gdb.lookup_type('JS::TraceKind') + + # Build a mapping from TraceKind enum values to the types they denote. + e = gdb.types.make_enum_dict(self.TraceKind_t) + kind_to_type = {} + def kind(k, t): + kind_to_type[e['JS::TraceKind::' + k]] = gdb.lookup_type(t) + kind('Object', 'JSObject') + kind('String', 'JSString') + kind('Symbol', 'JS::Symbol') + kind('Script', 'JSScript') + kind('Shape', 'js::Shape') + kind('ObjectGroup', 'js::ObjectGroup') + kind('BaseShape', 'js::BaseShape') + kind('JitCode', 'js::jit::JitCode') + kind('LazyScript', 'js::LazyScript') + self.kind_to_type = kind_to_type + + self.Null = e['JS::TraceKind::Null'] + self.mask = gdb.parse_and_eval('JS::OutOfLineTraceKindMask') + +@pretty_printer('JS::GCCellPtr') +class GCCellPtr(object): + def __init__(self, value, cache): + self.value = value + if not cache.mod_GCCellPtr: + cache.mod_GCCellPtr = GCCellPtrTypeCache(cache) + self.cache = cache + + def to_string(self): + ptr = self.value['ptr'] + kind = ptr & self.cache.mod_GCCellPtr.mask + if kind == self.cache.mod_GCCellPtr.Null: + return "JS::GCCellPtr(nullptr)" + tipe = self.cache.mod_GCCellPtr.kind_to_type[int(kind)] + return "JS::GCCellPtr(({}*) {})".format(tipe, ptr.cast(self.cache.void_ptr_t)) diff --git a/js/src/gdb/mozilla/JSSymbol.py b/js/src/gdb/mozilla/JSSymbol.py index a6532d62cfb2..5d747d1077ac 100644 --- a/js/src/gdb/mozilla/JSSymbol.py +++ b/js/src/gdb/mozilla/JSSymbol.py @@ -18,7 +18,7 @@ class JSSymbolPtr(mozilla.prettyprinters.Pointer): self.value = value def to_string(self): - code = int(self.value['code_']) + code = int(self.value['code_']) & 0xffffffff desc = str(self.value['description_']) if code == InSymbolRegistry: return "Symbol.for({})".format(desc) diff --git a/js/src/gdb/mozilla/Root.py b/js/src/gdb/mozilla/Root.py index b60d49abea38..c93590731aca 100644 --- a/js/src/gdb/mozilla/Root.py +++ b/js/src/gdb/mozilla/Root.py @@ -18,6 +18,10 @@ class Common(object): # the template member holds the referent directly. handle = False + # If True, we should strip typedefs from our referent type. (Rooted + # uses template magic that gives the referent a noisy type.) + strip_typedefs = False + # Initialize a pretty-printer for |value|, using |cache|. # # If given, |content_printer| is a pretty-printer constructor to use for @@ -42,6 +46,8 @@ class Common(object): ptr = self.value[self.member] if self.handle: ptr = ptr.dereference() + if self.strip_typedefs: + ptr = ptr.cast(ptr.type.strip_typedefs()) if self.content_printer: return self.content_printer(ptr, self.cache).to_string() else: @@ -53,7 +59,7 @@ class Common(object): @template_pretty_printer("JS::Rooted") class Rooted(Common): - pass + strip_typedefs = True @template_pretty_printer("JS::Handle") class Handle(Common): diff --git a/js/src/gdb/mozilla/asmjs.py b/js/src/gdb/mozilla/asmjs.py index 790a2f9a4af1..43fac20c737f 100644 --- a/js/src/gdb/mozilla/asmjs.py +++ b/js/src/gdb/mozilla/asmjs.py @@ -25,7 +25,7 @@ def on_stop(event): AsmJSFaultHandler = gdb.parse_and_eval("AsmJSFaultHandler") if buf['__sigaction_handler']['sa_handler'] == AsmJSFaultHandler: # Advise the user that magic is happening. - print "js/src/gdb/mozilla/asmjs.py: Allowing AsmJSFaultHandler to run." + print("js/src/gdb/mozilla/asmjs.py: Allowing AsmJSFaultHandler to run.") # If AsmJSFaultHandler doesn't handle this segfault, it will unhook # itself and re-raise. diff --git a/js/src/gdb/mozilla/autoload.py b/js/src/gdb/mozilla/autoload.py index 294bbfd0c368..90aabe5d1e9e 100644 --- a/js/src/gdb/mozilla/autoload.py +++ b/js/src/gdb/mozilla/autoload.py @@ -8,13 +8,14 @@ import mozilla.prettyprinters # Import the pretty-printer modules. As a side effect, loading these # modules registers their printers with mozilla.prettyprinters. +import mozilla.GCCellPtr import mozilla.Interpreter -import mozilla.jsid import mozilla.JSObject import mozilla.JSString import mozilla.JSSymbol -import mozilla.jsval import mozilla.Root +import mozilla.jsid +import mozilla.jsval # The user may have personal pretty-printers. Get those, too, if they exist. try: diff --git a/js/src/gdb/mozilla/prettyprinters.py b/js/src/gdb/mozilla/prettyprinters.py index 6cdd0b81b48f..0ce275af4f3a 100644 --- a/js/src/gdb/mozilla/prettyprinters.py +++ b/js/src/gdb/mozilla/prettyprinters.py @@ -179,10 +179,11 @@ class TypeCache(object): except gdb.error: raise NotSpiderMonkeyObjfileError - self.mod_JSString = None - self.mod_JSObject = None - self.mod_jsval = None + self.mod_GCCellPtr = None self.mod_Interpreter = None + self.mod_JSObject = None + self.mod_JSString = None + self.mod_jsval = None # Yield a series of all the types that |t| implements, by following typedefs # and iterating over base classes. Specifically: diff --git a/js/src/gdb/run-tests.py b/js/src/gdb/run-tests.py index caec97b8be65..1e4f4783b032 100644 --- a/js/src/gdb/run-tests.py +++ b/js/src/gdb/run-tests.py @@ -161,7 +161,7 @@ class Test(TaskPool.Task): '--ex', 'file %s' % (os.path.join(OPTIONS.builddir, 'gdb-tests'),), '--eval-command', 'python testlibdir=%r' % (testlibdir,), '--eval-command', 'python testscript=%r' % (self.test_path,), - '--eval-command', 'python execfile(%r)' % os.path.join(testlibdir, 'catcher.py')] + '--eval-command', 'python exec(open(%r).read())' % os.path.join(testlibdir, 'catcher.py')] def start(self, pipe, deadline): super(Test, self).start(pipe, deadline) diff --git a/js/src/gdb/tests/test-GCCellPtr.cpp b/js/src/gdb/tests/test-GCCellPtr.cpp new file mode 100644 index 000000000000..f3d4e2f3697b --- /dev/null +++ b/js/src/gdb/tests/test-GCCellPtr.cpp @@ -0,0 +1,23 @@ +#include "gdb-tests.h" +#include "jsapi.h" + +#include "js/HeapAPI.h" + +FRAGMENT(GCCellPtr, simple) { + JS::GCCellPtr nulll(nullptr); + + JS::Rooted glob(cx, JS::CurrentGlobalOrNull(cx)); + JS::Rooted empty(cx, JS_NewStringCopyN(cx, nullptr, 0)); + JS::Rooted unique(cx, NewSymbol(cx, nullptr)); + + JS::GCCellPtr object(glob.get()); + JS::GCCellPtr string(empty.get()); + JS::GCCellPtr symbol(unique.get()); + + breakpoint(); + + (void) nulll; + (void) object; + (void) string; + (void) symbol; +} diff --git a/js/src/gdb/tests/test-GCCellPtr.py b/js/src/gdb/tests/test-GCCellPtr.py new file mode 100644 index 000000000000..d5bb3d1e1f6d --- /dev/null +++ b/js/src/gdb/tests/test-GCCellPtr.py @@ -0,0 +1,10 @@ +# Tests for GCCellPtr pretty-printing + +assert_subprinter_registered('SpiderMonkey', 'JS::GCCellPtr') + +run_fragment('GCCellPtr.simple') + +assert_pretty('nulll', 'JS::GCCellPtr(nullptr)') +assert_pretty('object', 'JS::GCCellPtr((JSObject*) )') +assert_pretty('string', 'JS::GCCellPtr((JSString*) )') +assert_pretty('symbol', 'JS::GCCellPtr((JS::Symbol*) )') diff --git a/js/src/jit-test/tests/debug/bug-1136806.js b/js/src/jit-test/tests/debug/bug-1136806.js new file mode 100644 index 000000000000..104e79b1eeba --- /dev/null +++ b/js/src/jit-test/tests/debug/bug-1136806.js @@ -0,0 +1,7 @@ +// |jit-test| allow-unhandlable-oom; allow-oom + +if (typeof oomAfterAllocations == "function") { + Debugger() + oomAfterAllocations(6) + Debugger() +} diff --git a/js/src/jit-test/tests/ion/bug1186271.js b/js/src/jit-test/tests/ion/bug1186271.js new file mode 100644 index 000000000000..2e1513abb2b9 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1186271.js @@ -0,0 +1,18 @@ +function f(x) { + return Math.imul(1, x >>> 0) / 9 | 0; +} +function g(x) { + return 1 * (x >>> 0) / 9 | 0; +} +function h(x) { + return (x >>> 0) / 9 | 0; +} + +assertEq(0, f(4294967296)); +assertEq(-238609294, f(2147483648)); + +assertEq(0, g(4294967296)); +assertEq(238609294, g(2147483648)); + +assertEq(0, h(4294967296)); +assertEq(238609294, h(2147483648)); diff --git a/js/src/jit-test/tests/saved-stacks/caching-and-ccws.js b/js/src/jit-test/tests/saved-stacks/caching-and-ccws.js new file mode 100644 index 000000000000..b61e8c3252e1 --- /dev/null +++ b/js/src/jit-test/tests/saved-stacks/caching-and-ccws.js @@ -0,0 +1,35 @@ +// Test that the SavedFrame caching doesn't get messed up in the presence of +// cross-compartment calls. + +const funcSource = "function call(f) { return f(); }"; + +const g1 = newGlobal(); +const g2 = newGlobal(); + +g1.eval(funcSource); +g2.eval(funcSource); +eval(funcSource); + +function doSaveStack() { + return saveStack(); +} + +const captureStacksAcrossCompartmens = () => + [this, g1, g2].map(g => g.call(doSaveStack)); + +(function f0() { + const stacks = []; + + for (var i = 0; i < 2; i++) + stacks.push(...captureStacksAcrossCompartmens()); + + const [s1, s2, s3, s4, s5, s6] = stacks; + + assertEq(s1 != s2, true); + assertEq(s2 != s3, true); + assertEq(s3 != s1, true); + + assertEq(s1, s4); + assertEq(s2, s5); + assertEq(s3, s6); +}()); diff --git a/js/src/jit-test/tests/saved-stacks/caching-and-frame-count.js b/js/src/jit-test/tests/saved-stacks/caching-and-frame-count.js new file mode 100644 index 000000000000..a751d0e3c658 --- /dev/null +++ b/js/src/jit-test/tests/saved-stacks/caching-and-frame-count.js @@ -0,0 +1,38 @@ +// Test that the SavedFrame caching doesn't mess up counts. Specifically, that +// if we capture only the first n frames of a stack, we don't cache that stack +// and return it for when someone else captures another stack and asks for more +// frames than that last time. + +function stackLength(stack) { + return stack === null + ? 0 + : 1 + stackLength(stack.parent); +} + +(function f0() { + (function f1() { + (function f2() { + (function f3() { + (function f4() { + (function f5() { + (function f6() { + (function f7() { + (function f8() { + (function f9() { + const s1 = saveStack(3); + const s2 = saveStack(5); + const s3 = saveStack(0 /* no limit */); + + assertEq(stackLength(s1), 3); + assertEq(stackLength(s2), 5); + assertEq(stackLength(s3), 11); + }()); + }()); + }()); + }()); + }()); + }()); + }()); + }()); + }()); +}()); diff --git a/js/src/jit-test/tests/saved-stacks/gc-frame-cache.js b/js/src/jit-test/tests/saved-stacks/gc-frame-cache.js index 4a2838015bea..cf2646f471fe 100644 --- a/js/src/jit-test/tests/saved-stacks/gc-frame-cache.js +++ b/js/src/jit-test/tests/saved-stacks/gc-frame-cache.js @@ -3,67 +3,78 @@ const FUZZ_FACTOR = 3; -function assertAboutEq(actual, expected) { - if (Math.abs(actual - expected) > FUZZ_FACTOR) - throw new Error("Assertion failed: expected about " + expected + ", got " + actual + - ". FUZZ_FACTOR = " + FUZZ_FACTOR); +function isAboutEq(actual, expected) { + return Math.abs(actual - expected) <= FUZZ_FACTOR; } var stacks = []; -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); -stacks.push(saveStack()); +(function () { + // Use an IIFE here so that we don't keep these saved stacks alive in the + // frame cache when we test that they all go away at the end of the test. -assertAboutEq(getSavedFrameCount(), 50); + var startCount = getSavedFrameCount(); + print("startCount = " + startCount); + + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + stacks.push(saveStack()); + + gc(); + + var endCount = getSavedFrameCount(); + print("endCount = " + endCount); + + assertEq(isAboutEq(endCount - startCount, 50), true); +}()); while (stacks.length) { stacks.pop(); @@ -73,4 +84,4 @@ gc(); stacks = null; gc(); -assertAboutEq(getSavedFrameCount(), 0); +assertEq(isAboutEq(getSavedFrameCount(), 0), true); diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 1970a28aa1bb..938782f5c644 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -1701,6 +1701,9 @@ CopyFromRematerializedFrame(JSContext* cx, JitActivation* act, uint8_t* fp, size for (size_t i = 0; i < frame->script()->nfixed(); i++) *frame->valueSlot(i) = rematFrame->locals()[i]; + if (rematFrame->hasCachedSavedFrame()) + frame->setHasCachedSavedFrame(); + JitSpew(JitSpew_BaselineBailouts, " Copied from rematerialized frame at (%p,%u)", fp, inlineDepth); diff --git a/js/src/jit/BaselineDebugModeOSR.cpp b/js/src/jit/BaselineDebugModeOSR.cpp index 8471a4a19b59..c366da8e755c 100644 --- a/js/src/jit/BaselineDebugModeOSR.cpp +++ b/js/src/jit/BaselineDebugModeOSR.cpp @@ -688,8 +688,10 @@ RecompileBaselineScriptForDebugMode(JSContext* cx, JSScript* script, _(Call_ScriptedApplyArray) \ _(Call_ScriptedApplyArguments) \ _(Call_ScriptedFunCall) \ - _(GetElem_NativePrototypeCallNative) \ - _(GetElem_NativePrototypeCallScripted) \ + _(GetElem_NativePrototypeCallNativeName) \ + _(GetElem_NativePrototypeCallNativeSymbol) \ + _(GetElem_NativePrototypeCallScriptedName) \ + _(GetElem_NativePrototypeCallScriptedSymbol) \ _(GetProp_CallScripted) \ _(GetProp_CallNative) \ _(GetProp_CallDOMProxyNative) \ diff --git a/js/src/jit/BaselineFrame.h b/js/src/jit/BaselineFrame.h index 9ef27a37f4e6..f986eaea34be 100644 --- a/js/src/jit/BaselineFrame.h +++ b/js/src/jit/BaselineFrame.h @@ -34,7 +34,7 @@ struct BaselineDebugModeOSRInfo; class BaselineFrame { public: - enum Flags { + enum Flags : uint32_t { // The frame has a valid return value. See also InterpreterFrame::HAS_RVAL. HAS_RVAL = 1 << 0, @@ -77,7 +77,12 @@ class BaselineFrame // If set, we're handling an exception for this frame. This is set for // debug mode OSR sanity checking when it handles corner cases which // only arise during exception handling. - HANDLING_EXCEPTION = 1 << 12 + HANDLING_EXCEPTION = 1 << 12, + + // If set, this frame has been on the stack when + // |js::SavedStacks::saveCurrentStack| was called, and so there is a + // |js::SavedFrame| object cached for this frame. + HAS_CACHED_SAVED_FRAME = 1 << 13 }; protected: // Silence Clang warning about unused private fields. @@ -323,6 +328,13 @@ class BaselineFrame flags_ &= ~HANDLING_EXCEPTION; } + bool hasCachedSavedFrame() const { + return flags_ & HAS_CACHED_SAVED_FRAME; + } + void setHasCachedSavedFrame() { + flags_ |= HAS_CACHED_SAVED_FRAME; + } + JSScript* evalScript() const { MOZ_ASSERT(isEvalFrame()); return evalScript_; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index db41f17d3318..d3befacc0fdc 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -2653,7 +2653,7 @@ CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, Register // operations. This procedure not yielding a shape should not be taken as a lack of // existence of the property on the object. static bool -EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandlePropertyName name, +EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleObject holder, MutableHandleShape shape, bool* checkDOMProxy=nullptr, DOMProxyShadowsResult* shadowsResult=nullptr, @@ -2677,7 +2677,6 @@ EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandlePropertyName n if (obj->hasUncacheableProto()) return true; - RootedId id(cx, NameToId(name)); *shadowsResult = GetDOMProxyShadowsCheck()(cx, obj, id); if (*shadowsResult == ShadowCheckFailed) return false; @@ -2694,7 +2693,7 @@ EffectlesslyLookupProperty(JSContext* cx, HandleObject obj, HandlePropertyName n return true; } - if (LookupPropertyPure(cx, checkObj, NameToId(name), holder.address(), shape.address())) + if (LookupPropertyPure(cx, checkObj, id, holder.address(), shape.address())) return true; holder.set(nullptr); @@ -2970,31 +2969,47 @@ typedef bool (*LookupNoSuchMethodHandlerFn)(JSContext*, HandleObject, HandleValu static const VMFunction LookupNoSuchMethodHandlerInfo = FunctionInfo(LookupNoSuchMethodHandler); + +template static bool GetElemNativeStubExists(ICGetElem_Fallback* stub, HandleObject obj, HandleObject holder, - HandlePropertyName propName, bool needsAtomize) + Handle key, bool needsAtomize) { bool indirect = (obj.get() != holder.get()); MOZ_ASSERT_IF(indirect, holder->isNative()); for (ICStubConstIterator iter = stub->beginChainConst(); !iter.atEnd(); iter++) { - if (iter->kind() != ICStub::GetElem_NativeSlot && - iter->kind() != ICStub::GetElem_NativePrototypeSlot && - iter->kind() != ICStub::GetElem_NativePrototypeCallNative && - iter->kind() != ICStub::GetElem_NativePrototypeCallScripted) + if (iter->kind() != ICStub::GetElem_NativeSlotName && + iter->kind() != ICStub::GetElem_NativeSlotSymbol && + iter->kind() != ICStub::GetElem_NativePrototypeSlotName && + iter->kind() != ICStub::GetElem_NativePrototypeSlotSymbol && + iter->kind() != ICStub::GetElem_NativePrototypeCallNativeName && + iter->kind() != ICStub::GetElem_NativePrototypeCallNativeSymbol && + iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedName && + iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedSymbol) { continue; } - if (indirect && (iter->kind() != ICStub::GetElem_NativePrototypeSlot && - iter->kind() != ICStub::GetElem_NativePrototypeCallNative && - iter->kind() != ICStub::GetElem_NativePrototypeCallScripted)) + if (indirect && (iter->kind() != ICStub::GetElem_NativePrototypeSlotName && + iter->kind() != ICStub::GetElem_NativePrototypeSlotSymbol && + iter->kind() != ICStub::GetElem_NativePrototypeCallNativeName && + iter->kind() != ICStub::GetElem_NativePrototypeCallNativeSymbol && + iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedName && + iter->kind() != ICStub::GetElem_NativePrototypeCallScriptedSymbol)) { continue; } - ICGetElemNativeStub* getElemNativeStub = reinterpret_cast(*iter); - if (propName != getElemNativeStub->name()) + if(mozilla::IsSame::value != + static_cast(*iter)->isSymbol()) + { + continue; + } + + ICGetElemNativeStubImpl* getElemNativeStub = + reinterpret_cast*>(*iter); + if (key != getElemNativeStub->key()) continue; if (ReceiverGuard(obj) != getElemNativeStub->receiverGuard()) @@ -3007,8 +3022,10 @@ GetElemNativeStubExists(ICGetElem_Fallback* stub, HandleObject obj, HandleObject // For prototype gets, check the holder and holder shape. if (indirect) { - if (iter->isGetElem_NativePrototypeSlot()) { - ICGetElem_NativePrototypeSlot* protoStub = iter->toGetElem_NativePrototypeSlot(); + if (iter->isGetElem_NativePrototypeSlotName() || + iter->isGetElem_NativePrototypeSlotSymbol()) { + ICGetElem_NativePrototypeSlot* protoStub = + reinterpret_cast*>(*iter); if (holder != protoStub->holder()) continue; @@ -3016,11 +3033,13 @@ GetElemNativeStubExists(ICGetElem_Fallback* stub, HandleObject obj, HandleObject if (holder->as().lastProperty() != protoStub->holderShape()) continue; } else { - MOZ_ASSERT(iter->isGetElem_NativePrototypeCallNative() || - iter->isGetElem_NativePrototypeCallScripted()); + MOZ_ASSERT(iter->isGetElem_NativePrototypeCallNativeName() || + iter->isGetElem_NativePrototypeCallNativeSymbol() || + iter->isGetElem_NativePrototypeCallScriptedName() || + iter->isGetElem_NativePrototypeCallScriptedSymbol()); - ICGetElemNativePrototypeCallStub* protoStub = - reinterpret_cast(*iter); + ICGetElemNativePrototypeCallStub* protoStub = + reinterpret_cast*>(*iter); if (holder != protoStub->holder()) continue; @@ -3035,29 +3054,40 @@ GetElemNativeStubExists(ICGetElem_Fallback* stub, HandleObject obj, HandleObject return false; } +template static void RemoveExistingGetElemNativeStubs(JSContext* cx, ICGetElem_Fallback* stub, HandleObject obj, - HandleObject holder, HandlePropertyName propName, - bool needsAtomize) + HandleObject holder, Handle key, bool needsAtomize) { bool indirect = (obj.get() != holder.get()); MOZ_ASSERT_IF(indirect, holder->isNative()); for (ICStubIterator iter = stub->beginChain(); !iter.atEnd(); iter++) { switch (iter->kind()) { - case ICStub::GetElem_NativeSlot: + case ICStub::GetElem_NativeSlotName: + case ICStub::GetElem_NativeSlotSymbol: if (indirect) continue; - case ICStub::GetElem_NativePrototypeSlot: - case ICStub::GetElem_NativePrototypeCallNative: - case ICStub::GetElem_NativePrototypeCallScripted: + case ICStub::GetElem_NativePrototypeSlotName: + case ICStub::GetElem_NativePrototypeSlotSymbol: + case ICStub::GetElem_NativePrototypeCallNativeName: + case ICStub::GetElem_NativePrototypeCallNativeSymbol: + case ICStub::GetElem_NativePrototypeCallScriptedName: + case ICStub::GetElem_NativePrototypeCallScriptedSymbol: break; default: continue; } - ICGetElemNativeStub* getElemNativeStub = reinterpret_cast(*iter); - if (propName != getElemNativeStub->name()) + if(mozilla::IsSame::value != + static_cast(*iter)->isSymbol()) + { + continue; + } + + ICGetElemNativeStubImpl* getElemNativeStub = + reinterpret_cast*>(*iter); + if (key != getElemNativeStub->key()) continue; if (ReceiverGuard(obj) != getElemNativeStub->receiverGuard()) @@ -3065,8 +3095,10 @@ RemoveExistingGetElemNativeStubs(JSContext* cx, ICGetElem_Fallback* stub, Handle // For prototype gets, check the holder and holder shape. if (indirect) { - if (iter->isGetElem_NativePrototypeSlot()) { - ICGetElem_NativePrototypeSlot* protoStub = iter->toGetElem_NativePrototypeSlot(); + if (iter->isGetElem_NativePrototypeSlotName() || + iter->isGetElem_NativePrototypeSlotSymbol()) { + ICGetElem_NativePrototypeSlot* protoStub = + reinterpret_cast*>(*iter); if (holder != protoStub->holder()) continue; @@ -3078,11 +3110,12 @@ RemoveExistingGetElemNativeStubs(JSContext* cx, ICGetElem_Fallback* stub, Handle continue; } } else { - MOZ_ASSERT(iter->isGetElem_NativePrototypeCallNative() || - iter->isGetElem_NativePrototypeCallScripted()); - - ICGetElemNativePrototypeCallStub* protoStub = - reinterpret_cast(*iter); + MOZ_ASSERT(iter->isGetElem_NativePrototypeCallNativeName() || + iter->isGetElem_NativePrototypeCallNativeSymbol() || + iter->isGetElem_NativePrototypeCallScriptedName() || + iter->isGetElem_NativePrototypeCallScriptedSymbol()); + ICGetElemNativePrototypeCallStub* protoStub = + reinterpret_cast*>(*iter); if (holder != protoStub->holder()) continue; @@ -3133,6 +3166,31 @@ ArgumentsGetElemStubExists(ICGetElem_Fallback* stub, ICGetElem_Arguments::Which return false; } +template +static T +getKey(jsid id) +{ + MOZ_ASSERT_UNREACHABLE("Key has to be PropertyName or Symbol"); + return false; +} + +template <> +JS::Symbol* getKey(jsid id) +{ + if (!JSID_IS_SYMBOL(id)) + return nullptr; + return JSID_TO_SYMBOL(id); +} + +template <> +PropertyName* getKey(jsid id) +{ + uint32_t dummy; + if (!JSID_IS_ATOM(id) || JSID_TO_ATOM(id)->isIndex(&dummy)) + return nullptr; + return JSID_TO_ATOM(id)->asPropertyName(); +} + static bool IsOptimizableElementPropertyName(JSContext* cx, HandleValue key, MutableHandleId idp) { @@ -3150,47 +3208,79 @@ IsOptimizableElementPropertyName(JSContext* cx, HandleValue key, MutableHandleId return true; } +template +static bool +checkAtomize(HandleValue key) +{ + MOZ_ASSERT_UNREACHABLE("Key has to be PropertyName or Symbol"); + return false; +} + +template <> +bool checkAtomize(HandleValue key) +{ + return false; +} + +template <> +bool checkAtomize(HandleValue key) +{ + return !key.toString()->isAtom(); +} + +template static bool TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsbytecode* pc, ICGetElem_Fallback* stub, HandleObject obj, - HandleValue key, bool* attached) + HandleValue keyVal, bool* attached) { - RootedId id(cx); - if (!IsOptimizableElementPropertyName(cx, key, &id)) - return true; + MOZ_ASSERT(keyVal.isString() || keyVal.isSymbol()); - RootedPropertyName propName(cx, JSID_TO_ATOM(id)->asPropertyName()); - bool needsAtomize = !key.toString()->isAtom(); + // Convert to id. + RootedId id(cx); + if (!ValueToId(cx, keyVal, &id)) + return false; + + Rooted key(cx, getKey(id)); + if (!key) + return true; + bool needsAtomize = checkAtomize(keyVal); bool isCallElem = (JSOp(*pc) == JSOP_CALLELEM); RootedShape shape(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, propName, &holder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) return false; if (!holder || (holder != obj && !holder->isNative())) return true; // If a suitable stub already exists, nothing else to do. - if (GetElemNativeStubExists(stub, obj, holder, propName, needsAtomize)) + if (GetElemNativeStubExists(stub, obj, holder, key, needsAtomize)) return true; // Remove any existing stubs that may interfere with the new stub being added. - RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, propName, needsAtomize); + RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, key, needsAtomize); ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); if (obj->is() && holder == obj) { - const UnboxedLayout::Property* property = - obj->as().layout().lookup(propName); + const UnboxedLayout::Property* property = obj->as().layout().lookup(id); + + // Once unboxed objects support symbol-keys, we need to change the following accordingly + MOZ_ASSERT_IF(!keyVal.isString(), !property); + if (property) { if (!cx->runtime()->jitSupportsFloatingPoint) return true; - ICGetElemNativeCompiler compiler(cx, ICStub::GetElem_UnboxedProperty, isCallElem, - monitorStub, obj, holder, propName, - ICGetElemNativeStub::UnboxedProperty, needsAtomize, - property->offset + UnboxedPlainObject::offsetOfData(), - property->type); + RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName()); + ICGetElemNativeCompiler compiler(cx, ICStub::GetElem_UnboxedPropertyName, + isCallElem, monitorStub, obj, holder, + name, + ICGetElemNativeStub::UnboxedProperty, + needsAtomize, property->offset + + UnboxedPlainObject::offsetOfData(), + property->type); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -3200,7 +3290,7 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb return true; } - Shape* shape = obj->as().maybeExpando()->lookup(cx, propName); + Shape* shape = obj->as().maybeExpando()->lookup(cx, id); if (!shape->hasDefaultGetter() || !shape->hasSlot()) return true; @@ -3211,9 +3301,9 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb ICGetElemNativeStub::AccessType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot : ICGetElemNativeStub::DynamicSlot; - ICGetElemNativeCompiler compiler(cx, ICStub::GetElem_NativeSlot, isCallElem, - monitorStub, obj, holder, propName, - acctype, needsAtomize, offset); + ICGetElemNativeCompiler compiler(cx, getGetElemStubKind(ICStub::GetElem_NativeSlotName), + isCallElem, monitorStub, obj, holder, key, + acctype, needsAtomize, offset); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -3231,8 +3321,9 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb uint32_t offset; GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset); - ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_NativeSlot - : ICStub::GetElem_NativePrototypeSlot; + ICStub::Kind kind = (obj == holder) ? ICStub::GetElem_NativeSlotName + : ICStub::GetElem_NativePrototypeSlotName; + kind = getGetElemStubKind(kind); JitSpew(JitSpew_BaselineIC, " Generating GetElem(Native %s%s slot) stub " "(obj=%p, holder=%p, holderShape=%p)", @@ -3240,10 +3331,10 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb needsAtomize ? " atomizing" : "", obj.get(), holder.get(), holder->as().lastProperty()); - ICGetElemNativeStub::AccessType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot - : ICGetElemNativeStub::DynamicSlot; - ICGetElemNativeCompiler compiler(cx, kind, isCallElem, monitorStub, obj, holder, propName, - acctype, needsAtomize, offset); + AccType acctype = isFixedSlot ? ICGetElemNativeStub::FixedSlot + : ICGetElemNativeStub::DynamicSlot; + ICGetElemNativeCompiler compiler(cx, kind, isCallElem, monitorStub, obj, holder, key, + acctype, needsAtomize, offset); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) return false; @@ -3256,24 +3347,29 @@ TryAttachNativeOrUnboxedGetValueElemStub(JSContext* cx, HandleScript script, jsb return true; } +template static bool TryAttachNativeGetAccessorElemStub(JSContext* cx, HandleScript script, jsbytecode* pc, ICGetElem_Fallback* stub, HandleNativeObject obj, - HandleValue key, bool* attached, bool* isTemporarilyUnoptimizable) + HandleValue keyVal, bool* attached, + bool* isTemporarilyUnoptimizable) { MOZ_ASSERT(!*attached); + MOZ_ASSERT(keyVal.isString() || keyVal.isSymbol()); RootedId id(cx); - if (!IsOptimizableElementPropertyName(cx, key, &id)) - return true; + if (!ValueToId(cx, keyVal, &id)) + return false; - RootedPropertyName propName(cx, JSID_TO_ATOM(id)->asPropertyName()); - bool needsAtomize = !key.toString()->isAtom(); + Rooted key(cx, getKey(id)); + if (!key) + return true; + bool needsAtomize = checkAtomize(keyVal); bool isCallElem = (JSOp(*pc) == JSOP_CALLELEM); RootedShape shape(cx); RootedObject baseHolder(cx); - if (!EffectlesslyLookupProperty(cx, obj, propName, &baseHolder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &baseHolder, &shape)) return false; if (!baseHolder || baseHolder->isNative()) return true; @@ -3298,15 +3394,16 @@ TryAttachNativeGetAccessorElemStub(JSContext* cx, HandleScript script, jsbytecod return true; // If a suitable stub already exists, nothing else to do. - if (GetElemNativeStubExists(stub, obj, holder, propName, needsAtomize)) + if (GetElemNativeStubExists(stub, obj, holder, key, needsAtomize)) return true; // Remove any existing stubs that may interfere with the new stub being added. - RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, propName, needsAtomize); + RemoveExistingGetElemNativeStubs(cx, stub, obj, holder, key, needsAtomize); ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub(); - ICStub::Kind kind = getterIsScripted ? ICStub::GetElem_NativePrototypeCallScripted - : ICStub::GetElem_NativePrototypeCallNative; + ICStub::Kind kind = getterIsScripted ? ICStub::GetElem_NativePrototypeCallScriptedName + : ICStub::GetElem_NativePrototypeCallNativeName; + kind = getGetElemStubKind(kind); if (getterIsScripted) { JitSpew(JitSpew_BaselineIC, @@ -3325,10 +3422,9 @@ TryAttachNativeGetAccessorElemStub(JSContext* cx, HandleScript script, jsbytecod obj.get(), obj->lastProperty(), holder.get(), holder->lastProperty()); } - ICGetElemNativeStub::AccessType acctype = getterIsScripted - ? ICGetElemNativeStub::ScriptedGetter - : ICGetElemNativeStub::NativeGetter; - ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, propName, acctype, + AccType acctype = getterIsScripted ? ICGetElemNativeStub::ScriptedGetter + : ICGetElemNativeStub::NativeGetter; + ICGetElemNativeCompiler compiler(cx, kind, monitorStub, obj, holder, key, acctype, needsAtomize, getter, script->pcToOffset(pc), isCallElem); ICStub* newStub = compiler.getStub(compiler.getStubSpace(script)); if (!newStub) @@ -3476,12 +3572,20 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_ } // Check for NativeObject[id] and UnboxedPlainObject[id] shape-optimizable accesses. - if ((obj->isNative() || obj->is()) && rhs.isString()) { + if (obj->isNative() || obj->is()) { RootedScript rootedScript(cx, script); - if (!TryAttachNativeOrUnboxedGetValueElemStub(cx, rootedScript, pc, stub, - obj, rhs, attached)) - { - return false; + if (rhs.isString()) { + if (!TryAttachNativeOrUnboxedGetValueElemStub(cx, rootedScript, pc, stub, + obj, rhs, attached)) + { + return false; + } + } else if (rhs.isSymbol()) { + if (!TryAttachNativeOrUnboxedGetValueElemStub(cx, rootedScript, pc, stub, + obj, rhs, attached)) + { + return false; + } } if (*attached) return true; @@ -3587,15 +3691,28 @@ DoGetElemFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_ // Try to attach an optimized getter stub. bool isTemporarilyUnoptimizable = false; - if (!attached && lhs.isObject() && lhs.toObject().isNative() && rhs.isString()){ - RootedScript rootedScript(cx, frame->script()); - RootedNativeObject obj(cx, &lhs.toObject().as()); - if (!TryAttachNativeGetAccessorElemStub(cx, rootedScript, pc, stub, obj, rhs, &attached, - &isTemporarilyUnoptimizable)) - { - return false; + if (!attached && lhs.isObject() && lhs.toObject().isNative()){ + if (rhs.isString()) { + RootedScript rootedScript(cx, frame->script()); + RootedNativeObject obj(cx, &lhs.toObject().as()); + if (!TryAttachNativeGetAccessorElemStub(cx, rootedScript, pc, stub, + obj, rhs, &attached, + &isTemporarilyUnoptimizable)) + { + return false; + } + script = rootedScript; + } else if (rhs.isSymbol()) { + RootedScript rootedScript(cx, frame->script()); + RootedNativeObject obj(cx, &lhs.toObject().as()); + if (!TryAttachNativeGetAccessorElemStub(cx, rootedScript, pc, stub, + obj, rhs, &attached, + &isTemporarilyUnoptimizable)) + { + return false; + } + script = rootedScript; } - script = rootedScript; } if (!isOptimizedArgs) { @@ -3680,8 +3797,9 @@ DoAtomizeString(JSContext* cx, HandleString string, MutableHandleValue result) typedef bool (*DoAtomizeStringFn)(JSContext*, HandleString, MutableHandleValue); static const VMFunction DoAtomizeStringInfo = FunctionInfo(DoAtomizeString); +template bool -ICGetElemNativeCompiler::emitCallNative(MacroAssembler& masm, Register objReg) +ICGetElemNativeCompiler::emitCallNative(MacroAssembler& masm, Register objReg) { AllocatableGeneralRegisterSet regs(availableGeneralRegs(0)); regs.takeUnchecked(objReg); @@ -3693,7 +3811,7 @@ ICGetElemNativeCompiler::emitCallNative(MacroAssembler& masm, Register objReg) masm.push(objReg); // Push native callee. - masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), objReg); + masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), objReg); masm.push(objReg); regs.add(objReg); @@ -3707,8 +3825,9 @@ ICGetElemNativeCompiler::emitCallNative(MacroAssembler& masm, Register objReg) return true; } +template bool -ICGetElemNativeCompiler::emitCallScripted(MacroAssembler& masm, Register objReg) +ICGetElemNativeCompiler::emitCallScripted(MacroAssembler& masm, Register objReg) { AllocatableGeneralRegisterSet regs(availableGeneralRegs(0)); regs.takeUnchecked(objReg); @@ -3732,7 +3851,7 @@ ICGetElemNativeCompiler::emitCallScripted(MacroAssembler& masm, Register objReg) regs.add(objReg); Register callee = regs.takeAny(); - masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), callee); + masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), callee); // Push argc, callee, and descriptor. { @@ -3774,31 +3893,34 @@ ICGetElemNativeCompiler::emitCallScripted(MacroAssembler& masm, Register objReg) return true; } +template bool -ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) +ICGetElemNativeCompiler::emitCheckKey(MacroAssembler& masm, Label& failure) { - MOZ_ASSERT(engine_ == Engine::Baseline); + MOZ_ASSERT_UNREACHABLE("Key has to be PropertyName or Symbol"); + return false; +} - Label failure; - Label failurePopR1; - bool popR1 = false; +template <> +bool +ICGetElemNativeCompiler::emitCheckKey(MacroAssembler& masm, Label& failure) +{ + MOZ_ASSERT(!needsAtomize_); + masm.branchTestSymbol(Assembler::NotEqual, R1, &failure); + Address symbolAddr(ICStubReg, ICGetElemNativeStubImpl::offsetOfKey()); + Register symExtract = masm.extractObject(R1, ExtractTemp1); + masm.branchPtr(Assembler::NotEqual, symbolAddr, symExtract, &failure); + return true; +} - masm.branchTestObject(Assembler::NotEqual, R0, &failure); +template <> +bool +ICGetElemNativeCompiler::emitCheckKey(MacroAssembler& masm, Label& failure) +{ masm.branchTestString(Assembler::NotEqual, R1, &failure); - - AllocatableGeneralRegisterSet regs(availableGeneralRegs(2)); - Register scratchReg = regs.takeAny(); - - // Unbox object. - Register objReg = masm.extractObject(R0, ExtractTemp0); - - // Check object shape/group. - GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratchReg, - ICGetElemNativeStub::offsetOfReceiverGuard(), &failure); - // Check key identity. Don't automatically fail if this fails, since the incoming // key maybe a non-interned string. Switch to a slowpath vm-call based check. - Address nameAddr(ICStubReg, ICGetElemNativeStub::offsetOfName()); + Address nameAddr(ICStubReg, ICGetElemNativeStubImpl::offsetOfKey()); Register strExtract = masm.extractString(R1, ExtractTemp1); // If needsAtomize_ is true, and the string is not already an atom, then atomize the @@ -3838,13 +3960,40 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) masm.bind(&skipAtomize); } + // Key has been atomized if necessary. Do identity check on string pointer. + masm.branchPtr(Assembler::NotEqual, nameAddr, strExtract, &failure); + return true; +} + +template +bool +ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) +{ + MOZ_ASSERT(engine_ == Engine::Baseline); + + Label failure; + Label failurePopR1; + bool popR1 = false; + + masm.branchTestObject(Assembler::NotEqual, R0, &failure); + + AllocatableGeneralRegisterSet regs(availableGeneralRegs(2)); + Register scratchReg = regs.takeAny(); + + // Unbox object. + Register objReg = masm.extractObject(R0, ExtractTemp0); + + // Check object shape/group. + GuardReceiverObject(masm, ReceiverGuard(obj_), objReg, scratchReg, + ICGetElemNativeStub::offsetOfReceiverGuard(), &failure); + // Since this stub sometimes enters a stub frame, we manually set this to true (lie). #ifdef DEBUG entersStubFrame_ = true; #endif - // Key has been atomized if necessary. Do identity check on string pointer. - masm.branchPtr(Assembler::NotEqual, nameAddr, strExtract, &failure); + if (!emitCheckKey(masm, failure)) + return false; Register holderReg; if (obj_ == holder_) { @@ -3867,21 +4016,23 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) holderReg = regs.takeAny(); } - if (kind == ICStub::GetElem_NativePrototypeCallNative || - kind == ICStub::GetElem_NativePrototypeCallScripted) + if (kind == ICStub::GetElem_NativePrototypeCallNativeName || + kind == ICStub::GetElem_NativePrototypeCallNativeSymbol || + kind == ICStub::GetElem_NativePrototypeCallScriptedName || + kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol) { masm.loadPtr(Address(ICStubReg, - ICGetElemNativePrototypeCallStub::offsetOfHolder()), + ICGetElemNativePrototypeCallStub::offsetOfHolder()), holderReg); masm.loadPtr(Address(ICStubReg, - ICGetElemNativePrototypeCallStub::offsetOfHolderShape()), + ICGetElemNativePrototypeCallStub::offsetOfHolderShape()), scratchReg); } else { masm.loadPtr(Address(ICStubReg, - ICGetElem_NativePrototypeSlot::offsetOfHolder()), + ICGetElem_NativePrototypeSlot::offsetOfHolder()), holderReg); masm.loadPtr(Address(ICStubReg, - ICGetElem_NativePrototypeSlot::offsetOfHolderShape()), + ICGetElem_NativePrototypeSlot::offsetOfHolderShape()), scratchReg); } masm.branchTestObjShape(Assembler::NotEqual, holderReg, scratchReg, @@ -3891,7 +4042,7 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) if (acctype_ == ICGetElemNativeStub::DynamicSlot || acctype_ == ICGetElemNativeStub::FixedSlot) { - masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub::offsetOfOffset()), + masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub::offsetOfOffset()), scratchReg); // Load from object. @@ -3956,7 +4107,7 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) #endif } else if (acctype_ == ICGetElemNativeStub::UnboxedProperty) { - masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub::offsetOfOffset()), + masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub::offsetOfOffset()), scratchReg); masm.loadUnboxedProperty(BaseIndex(objReg, scratchReg, TimesOne), unboxedType_, TypedOrValueRegister(R0)); @@ -3965,8 +4116,10 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) } else { MOZ_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter || acctype_ == ICGetElemNativeStub::ScriptedGetter); - MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallNative || - kind == ICStub::GetElem_NativePrototypeCallScripted); + MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallNativeName || + kind == ICStub::GetElem_NativePrototypeCallNativeSymbol || + kind == ICStub::GetElem_NativePrototypeCallScriptedName || + kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol); if (acctype_ == ICGetElemNativeStub::NativeGetter) { // If calling a native getter, there is no chance of failure now. @@ -3981,7 +4134,7 @@ ICGetElemNativeCompiler::generateStubCode(MacroAssembler& masm) MOZ_ASSERT(acctype_ == ICGetElemNativeStub::ScriptedGetter); // Load function in scratchReg and ensure that it has a jit script. - masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), + masm.loadPtr(Address(ICStubReg, ICGetElemNativeGetterStub::offsetOfGetter()), scratchReg); masm.branchIfFunctionHasNoScript(scratchReg, popR1 ? &failurePopR1 : &failure); masm.loadPtr(Address(scratchReg, JSFunction::offsetOfNativeOrScript()), scratchReg); @@ -5485,7 +5638,7 @@ TryAttachNativeInStub(JSContext* cx, HandleScript script, ICIn_Fallback* stub, RootedPropertyName name(cx, JSID_TO_ATOM(id)->asPropertyName()); RootedShape shape(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) return false; if (IsCacheableGetPropReadSlot(obj, holder, shape)) { @@ -6605,7 +6758,8 @@ TryAttachNativeGetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* RootedShape shape(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape)) + RootedId id(cx, NameToId(name)); + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) return false; bool isCallProp = (JSOp(*pc) == JSOP_CALLPROP); @@ -6663,7 +6817,8 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecod DOMProxyShadowsResult domProxyShadowsResult; RootedShape shape(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape, &isDOMProxy, + RootedId id(cx, NameToId(name)); + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy, &domProxyShadowsResult, &domProxyHasGeneration)) { return false; @@ -6740,7 +6895,7 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecod return true; // ICGetProp_CallNative*::Compiler::generateStubCode depends on this. MOZ_ASSERT(&((GetProxyDataLayout(outer)->values->privateSlot).toObject()) == obj); - if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape, &isDOMProxy, + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape, &isDOMProxy, &domProxyShadowsResult, &domProxyHasGeneration)) { return false; @@ -8224,7 +8379,7 @@ TryAttachSetValuePropStub(JSContext* cx, HandleScript script, jsbytecode* pc, IC RootedShape shape(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) return false; if (obj != holder) return true; @@ -8333,7 +8488,7 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc, RootedShape shape(cx); RootedObject holder(cx); - if (!EffectlesslyLookupProperty(cx, obj, name, &holder, &shape)) + if (!EffectlesslyLookupProperty(cx, obj, id, &holder, &shape)) return false; bool isScripted = false; @@ -12010,76 +12165,83 @@ ICTypeUpdate_ObjectGroup::ICTypeUpdate_ObjectGroup(JitCode* stubCode, ObjectGrou ICGetElemNativeStub::ICGetElemNativeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize) + ReceiverGuard guard, AccessType acctype, + bool needsAtomize, bool isSymbol) : ICMonitoredStub(kind, stubCode, firstMonitorStub), - receiverGuard_(guard), - name_(name) + receiverGuard_(guard) { extra_ = (static_cast(acctype) << ACCESSTYPE_SHIFT) | - (static_cast(needsAtomize) << NEEDS_ATOMIZE_SHIFT); + (static_cast(needsAtomize) << NEEDS_ATOMIZE_SHIFT) | + (static_cast(isSymbol) << ISSYMBOL_SHIFT); } ICGetElemNativeStub::~ICGetElemNativeStub() { } -ICGetElemNativeGetterStub::ICGetElemNativeGetterStub( - ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, AccessType acctype, - bool needsAtomize, JSFunction* getter, uint32_t pcOffset) - : ICGetElemNativeStub(kind, stubCode, firstMonitorStub, guard, name, acctype, needsAtomize), +template +ICGetElemNativeGetterStub::ICGetElemNativeGetterStub( + ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, + ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize, + JSFunction* getter, uint32_t pcOffset) + : ICGetElemNativeStubImpl(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize), getter_(getter), pcOffset_(pcOffset) { - MOZ_ASSERT(kind == GetElem_NativePrototypeCallNative || - kind == GetElem_NativePrototypeCallScripted); - MOZ_ASSERT(acctype == NativeGetter || acctype == ScriptedGetter); + MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallNativeName || + kind == ICStub::GetElem_NativePrototypeCallNativeSymbol || + kind == ICStub::GetElem_NativePrototypeCallScriptedName || + kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol); + MOZ_ASSERT(acctype == ICGetElemNativeStub::NativeGetter || + acctype == ICGetElemNativeStub::ScriptedGetter); } -ICGetElem_NativePrototypeSlot::ICGetElem_NativePrototypeSlot( - JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize, uint32_t offset, - JSObject* holder, Shape* holderShape) - : ICGetElemNativeSlotStub(ICStub::GetElem_NativePrototypeSlot, stubCode, firstMonitorStub, guard, - name, acctype, needsAtomize, offset), +template +ICGetElem_NativePrototypeSlot::ICGetElem_NativePrototypeSlot( + JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard, + const T* key, AccType acctype, bool needsAtomize, uint32_t offset, + JSObject* holder, Shape* holderShape) + : ICGetElemNativeSlotStub(getGetElemStubKind(ICStub::GetElem_NativePrototypeSlotName), + stubCode, firstMonitorStub, guard, key, acctype, needsAtomize, offset), holder_(holder), holderShape_(holderShape) { } -ICGetElemNativePrototypeCallStub::ICGetElemNativePrototypeCallStub( - ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize, JSFunction* getter, - uint32_t pcOffset, JSObject* holder, Shape* holderShape) - : ICGetElemNativeGetterStub(kind, stubCode, firstMonitorStub, guard, name, acctype, needsAtomize, - getter, pcOffset), +template +ICGetElemNativePrototypeCallStub::ICGetElemNativePrototypeCallStub( + ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, + ReceiverGuard guard, const T* key, AccType acctype, + bool needsAtomize, JSFunction* getter, uint32_t pcOffset, + JSObject* holder, Shape* holderShape) + : ICGetElemNativeGetterStub(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize, + getter, pcOffset), holder_(holder), holderShape_(holderShape) {} -/* static */ ICGetElem_NativePrototypeCallNative* -ICGetElem_NativePrototypeCallNative::Clone(JSContext* cx, - ICStubSpace* space, - ICStub* firstMonitorStub, - ICGetElem_NativePrototypeCallNative& other) +template +/* static */ ICGetElem_NativePrototypeCallNative* +ICGetElem_NativePrototypeCallNative::Clone(JSContext* cx, + ICStubSpace* space, + ICStub* firstMonitorStub, + ICGetElem_NativePrototypeCallNative& other) { - return New(cx, space, other.jitCode(), firstMonitorStub, - other.receiverGuard(), other.name(), other.accessType(), - other.needsAtomize(), other.getter(), other.pcOffset_, - other.holder(), other.holderShape()); + return ICStub::New>(cx, space, other.jitCode(), + firstMonitorStub, other.receiverGuard(), other.key().unsafeGet(), other.accessType(), + other.needsAtomize(), other.getter(), other.pcOffset_, other.holder(), + other.holderShape()); } -/* static */ ICGetElem_NativePrototypeCallScripted* -ICGetElem_NativePrototypeCallScripted::Clone(JSContext* cx, - ICStubSpace* space, - ICStub* firstMonitorStub, - ICGetElem_NativePrototypeCallScripted& other) +template +/* static */ ICGetElem_NativePrototypeCallScripted* +ICGetElem_NativePrototypeCallScripted::Clone(JSContext* cx, + ICStubSpace* space, + ICStub* firstMonitorStub, + ICGetElem_NativePrototypeCallScripted& other) { - return New(cx, space, other.jitCode(), firstMonitorStub, - other.receiverGuard(), other.name(), - other.accessType(), other.needsAtomize(), other.getter(), - other.pcOffset_, other.holder(), other.holderShape()); + return ICStub::New>(cx, space, other.jitCode(), + firstMonitorStub, other.receiverGuard(), other.key().unsafeGet(), other.accessType(), + other.needsAtomize(), other.getter(), other.pcOffset_, other.holder(), + other.holderShape()); } ICGetElem_Dense::ICGetElem_Dense(JitCode* stubCode, ICStub* firstMonitorStub, Shape* shape) diff --git a/js/src/jit/BaselineIC.h b/js/src/jit/BaselineIC.h index 3761195ddf19..4cbd4de69dc6 100644 --- a/js/src/jit/BaselineIC.h +++ b/js/src/jit/BaselineIC.h @@ -1532,7 +1532,6 @@ class ICGetElemNativeStub : public ICMonitoredStub protected: HeapReceiverGuard receiverGuard_; - HeapPtrPropertyName name_; static const unsigned NEEDS_ATOMIZE_SHIFT = 0; static const uint16_t NEEDS_ATOMIZE_MASK = 0x1; @@ -1540,9 +1539,11 @@ class ICGetElemNativeStub : public ICMonitoredStub static const unsigned ACCESSTYPE_SHIFT = 1; static const uint16_t ACCESSTYPE_MASK = 0x3; + static const unsigned ISSYMBOL_SHIFT = 3; + static const uint16_t ISSYMBOL_MASK = 0x1; + ICGetElemNativeStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, AccessType acctype, - bool needsAtomize); + ReceiverGuard guard, AccessType acctype, bool needsAtomize, bool isSymbol); ~ICGetElemNativeStub(); @@ -1554,13 +1555,6 @@ class ICGetElemNativeStub : public ICMonitoredStub return offsetof(ICGetElemNativeStub, receiverGuard_); } - HeapPtrPropertyName& name() { - return name_; - } - static size_t offsetOfName() { - return offsetof(ICGetElemNativeStub, name_); - } - AccessType accessType() const { return static_cast((extra_ >> ACCESSTYPE_SHIFT) & ACCESSTYPE_MASK); } @@ -1568,22 +1562,56 @@ class ICGetElemNativeStub : public ICMonitoredStub bool needsAtomize() const { return (extra_ >> NEEDS_ATOMIZE_SHIFT) & NEEDS_ATOMIZE_MASK; } + + bool isSymbol() const { + return (extra_ >> ISSYMBOL_SHIFT) & ISSYMBOL_MASK; + } }; -class ICGetElemNativeSlotStub : public ICGetElemNativeStub +template +class ICGetElemNativeStubImpl : public ICGetElemNativeStub +{ + protected: + HeapPtr key_; + + ICGetElemNativeStubImpl(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, + ReceiverGuard guard, const T* key, AccessType acctype, bool needsAtomize) + : ICGetElemNativeStub(kind, stubCode, firstMonitorStub, guard, acctype, needsAtomize, + mozilla::IsSame::value), + key_(*key) + {} + + public: + HeapPtr& key() { + return key_; + } + static size_t offsetOfKey() { + return offsetof(ICGetElemNativeStubImpl, key_); + } +}; + +typedef ICGetElemNativeStub::AccessType AccType; + +template +class ICGetElemNativeSlotStub : public ICGetElemNativeStubImpl { protected: uint32_t offset_; ICGetElemNativeSlotStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize, uint32_t offset) - : ICGetElemNativeStub(kind, stubCode, firstMonitorStub, guard, name, acctype, needsAtomize), + ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize, + uint32_t offset) + : ICGetElemNativeStubImpl(kind, stubCode, firstMonitorStub, guard, key, acctype, needsAtomize), offset_(offset) { - MOZ_ASSERT(kind == GetElem_NativeSlot || kind == GetElem_NativePrototypeSlot || - kind == GetElem_UnboxedProperty); - MOZ_ASSERT(acctype == FixedSlot || acctype == DynamicSlot || acctype == UnboxedProperty); + MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName || + kind == ICStub::GetElem_NativeSlotSymbol || + kind == ICStub::GetElem_NativePrototypeSlotName || + kind == ICStub::GetElem_NativePrototypeSlotSymbol || + kind == ICStub::GetElem_UnboxedPropertyName); + MOZ_ASSERT(acctype == ICGetElemNativeStub::FixedSlot || + acctype == ICGetElemNativeStub::DynamicSlot || + acctype == ICGetElemNativeStub::UnboxedProperty); } public: @@ -1596,15 +1624,16 @@ class ICGetElemNativeSlotStub : public ICGetElemNativeStub } }; -class ICGetElemNativeGetterStub : public ICGetElemNativeStub +template +class ICGetElemNativeGetterStub : public ICGetElemNativeStubImpl { protected: HeapPtrFunction getter_; uint32_t pcOffset_; ICGetElemNativeGetterStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, AccessType acctype, - bool needsAtomize, JSFunction* getter, uint32_t pcOffset); + ReceiverGuard guard, const T* key, AccType acctype, bool needsAtomize, + JSFunction* getter, uint32_t pcOffset); public: HeapPtrFunction& getter() { @@ -1619,37 +1648,61 @@ class ICGetElemNativeGetterStub : public ICGetElemNativeStub } }; -class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub +template +ICStub::Kind +getGetElemStubKind(ICStub::Kind kind) +{ + MOZ_ASSERT(kind == ICStub::GetElem_NativeSlotName || + kind == ICStub::GetElem_NativePrototypeSlotName || + kind == ICStub::GetElem_NativePrototypeCallNativeName || + kind == ICStub::GetElem_NativePrototypeCallScriptedName); + return static_cast(kind + mozilla::IsSame::value); +} + +template +class ICGetElem_NativeSlot : public ICGetElemNativeSlotStub { friend class ICStubSpace; - ICGetElem_NativeSlot(JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize, uint32_t offset) - : ICGetElemNativeSlotStub(ICStub::GetElem_NativeSlot, stubCode, firstMonitorStub, guard, - name, acctype, needsAtomize, offset) + ICGetElem_NativeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard, + const T* key, AccType acctype, bool needsAtomize, uint32_t offset) + : ICGetElemNativeSlotStub(getGetElemStubKind(ICStub::GetElem_NativeSlotName), + stubCode, firstMonitorStub, guard, + key, acctype, needsAtomize, offset) {} }; -class ICGetElem_UnboxedProperty : public ICGetElemNativeSlotStub +class ICGetElem_NativeSlotName : + public ICGetElem_NativeSlot +{}; +class ICGetElem_NativeSlotSymbol : + public ICGetElem_NativeSlot +{}; + +template +class ICGetElem_UnboxedProperty : public ICGetElemNativeSlotStub { friend class ICStubSpace; ICGetElem_UnboxedProperty(JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize, uint32_t offset) - : ICGetElemNativeSlotStub(ICStub::GetElem_UnboxedProperty, stubCode, firstMonitorStub, guard, - name, acctype, needsAtomize, offset) - {} + ReceiverGuard guard, const T* key, AccType acctype, + bool needsAtomize, uint32_t offset) + : ICGetElemNativeSlotStub(ICStub::GetElem_UnboxedPropertyName, stubCode, firstMonitorStub, + guard, key, acctype, needsAtomize, offset) + {} }; -class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub +class ICGetElem_UnboxedPropertyName : + public ICGetElem_UnboxedProperty +{}; + +template +class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub { friend class ICStubSpace; HeapPtrObject holder_; HeapPtrShape holderShape_; - ICGetElem_NativePrototypeSlot(JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize, uint32_t offset, + ICGetElem_NativePrototypeSlot(JitCode* stubCode, ICStub* firstMonitorStub, ReceiverGuard guard, + const T* key, AccType acctype, bool needsAtomize, uint32_t offset, JSObject* holder, Shape* holderShape); public: @@ -1668,7 +1721,15 @@ class ICGetElem_NativePrototypeSlot : public ICGetElemNativeSlotStub } }; -class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub +class ICGetElem_NativePrototypeSlotName : + public ICGetElem_NativePrototypeSlot +{}; +class ICGetElem_NativePrototypeSlotSymbol : + public ICGetElem_NativePrototypeSlot +{}; + +template +class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub { friend class ICStubSpace; HeapPtrObject holder_; @@ -1676,10 +1737,9 @@ class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub protected: ICGetElemNativePrototypeCallStub(ICStub::Kind kind, JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize, JSFunction* getter, - uint32_t pcOffset, JSObject* holder, - Shape* holderShape); + ReceiverGuard guard, const T* key, AccType acctype, + bool needsAtomize, JSFunction* getter, uint32_t pcOffset, + JSObject* holder, Shape* holderShape); public: HeapPtrObject& holder() { @@ -1697,64 +1757,81 @@ class ICGetElemNativePrototypeCallStub : public ICGetElemNativeGetterStub } }; -class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub +template +class ICGetElem_NativePrototypeCallNative : public ICGetElemNativePrototypeCallStub { friend class ICStubSpace; ICGetElem_NativePrototypeCallNative(JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize, - JSFunction* getter, uint32_t pcOffset, + ReceiverGuard guard, const T* key, AccType acctype, + bool needsAtomize, JSFunction* getter, uint32_t pcOffset, JSObject* holder, Shape* holderShape) - : ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallNative, - stubCode, firstMonitorStub, guard, name, - acctype, needsAtomize, getter, pcOffset, holder, - holderShape) + : ICGetElemNativePrototypeCallStub(getGetElemStubKind( + ICStub::GetElem_NativePrototypeCallNativeName), + stubCode, firstMonitorStub, guard, key, + acctype, needsAtomize, getter, pcOffset, holder, + holderShape) {} public: - static ICGetElem_NativePrototypeCallNative* Clone(JSContext* cx, ICStubSpace* space, - ICStub* firstMonitorStub, - ICGetElem_NativePrototypeCallNative& other); + static ICGetElem_NativePrototypeCallNative* Clone(JSContext* cx, ICStubSpace* space, + ICStub* firstMonitorStub, + ICGetElem_NativePrototypeCallNative& other); }; -class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub +class ICGetElem_NativePrototypeCallNativeName : + public ICGetElem_NativePrototypeCallNative +{}; +class ICGetElem_NativePrototypeCallNativeSymbol : + public ICGetElem_NativePrototypeCallNative +{}; + +template +class ICGetElem_NativePrototypeCallScripted : public ICGetElemNativePrototypeCallStub { friend class ICStubSpace; ICGetElem_NativePrototypeCallScripted(JitCode* stubCode, ICStub* firstMonitorStub, - ReceiverGuard guard, PropertyName* name, - AccessType acctype, bool needsAtomize, - JSFunction* getter, uint32_t pcOffset, + ReceiverGuard guard, const T* key, AccType acctype, + bool needsAtomize, JSFunction* getter, uint32_t pcOffset, JSObject* holder, Shape* holderShape) - : ICGetElemNativePrototypeCallStub(GetElem_NativePrototypeCallScripted, - stubCode, firstMonitorStub, guard, name, - acctype, needsAtomize, getter, pcOffset, holder, - holderShape) + : ICGetElemNativePrototypeCallStub(getGetElemStubKind( + ICStub::GetElem_NativePrototypeCallScriptedName), + stubCode, firstMonitorStub, guard, key, acctype, + needsAtomize, getter, pcOffset, holder, holderShape) {} public: - static ICGetElem_NativePrototypeCallScripted* + static ICGetElem_NativePrototypeCallScripted* Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub, - ICGetElem_NativePrototypeCallScripted& other); + ICGetElem_NativePrototypeCallScripted& other); }; +class ICGetElem_NativePrototypeCallScriptedName : + public ICGetElem_NativePrototypeCallScripted +{}; +class ICGetElem_NativePrototypeCallScriptedSymbol : + public ICGetElem_NativePrototypeCallScripted +{}; + // Compiler for GetElem_NativeSlot and GetElem_NativePrototypeSlot stubs. +template class ICGetElemNativeCompiler : public ICStubCompiler { bool isCallElem_; ICStub* firstMonitorStub_; HandleObject obj_; HandleObject holder_; - HandlePropertyName name_; - ICGetElemNativeStub::AccessType acctype_; + Handle key_; + AccType acctype_; bool needsAtomize_; uint32_t offset_; JSValueType unboxedType_; HandleFunction getter_; uint32_t pcOffset_; + bool emitCheckKey(MacroAssembler& masm, Label& failure); bool emitCallNative(MacroAssembler& masm, Register objReg); bool emitCallScripted(MacroAssembler& masm, Register objReg); bool generateStubCode(MacroAssembler& masm); @@ -1771,21 +1848,21 @@ class ICGetElemNativeCompiler : public ICStubCompiler (static_cast(needsAtomize_) << 18) | (static_cast(acctype_) << 19) | (static_cast(unboxedType_) << 22) | - (HeapReceiverGuard::keyBits(obj_) << 26); + (static_cast(mozilla::IsSame::value) << 26) | + (HeapReceiverGuard::keyBits(obj_) << 27); } public: ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, bool isCallElem, ICStub* firstMonitorStub, HandleObject obj, HandleObject holder, - HandlePropertyName name, ICGetElemNativeStub::AccessType acctype, - bool needsAtomize, uint32_t offset, + Handle key, AccType acctype, bool needsAtomize, uint32_t offset, JSValueType unboxedType = JSVAL_TYPE_MAGIC) : ICStubCompiler(cx, kind, Engine::Baseline), isCallElem_(isCallElem), firstMonitorStub_(firstMonitorStub), obj_(obj), holder_(holder), - name_(name), + key_(key), acctype_(acctype), needsAtomize_(needsAtomize), offset_(offset), @@ -1795,15 +1872,15 @@ class ICGetElemNativeCompiler : public ICStubCompiler {} ICGetElemNativeCompiler(JSContext* cx, ICStub::Kind kind, ICStub* firstMonitorStub, - HandleObject obj, HandleObject holder, HandlePropertyName name, - ICGetElemNativeStub::AccessType acctype, bool needsAtomize, - HandleFunction getter, uint32_t pcOffset, bool isCallElem) + HandleObject obj, HandleObject holder, Handle key, AccType acctype, + bool needsAtomize, HandleFunction getter, uint32_t pcOffset, + bool isCallElem) : ICStubCompiler(cx, kind, Engine::Baseline), isCallElem_(false), firstMonitorStub_(firstMonitorStub), obj_(obj), holder_(holder), - name_(name), + key_(key), acctype_(acctype), needsAtomize_(needsAtomize), offset_(0), @@ -1814,39 +1891,44 @@ class ICGetElemNativeCompiler : public ICStubCompiler ICStub* getStub(ICStubSpace* space) { RootedReceiverGuard guard(cx, ReceiverGuard(obj_)); - if (kind == ICStub::GetElem_NativeSlot) { + if (kind == ICStub::GetElem_NativeSlotName || kind == ICStub::GetElem_NativeSlotSymbol) { MOZ_ASSERT(obj_ == holder_); - return newStub( - space, getStubCode(), firstMonitorStub_, guard, name_, acctype_, needsAtomize_, - offset_); + return newStub>( + space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_, + needsAtomize_, offset_); } - if (kind == ICStub::GetElem_UnboxedProperty) { + if (kind == ICStub::GetElem_UnboxedPropertyName) { MOZ_ASSERT(obj_ == holder_); - return newStub( - space, getStubCode(), firstMonitorStub_, guard, name_, acctype_, needsAtomize_, - offset_); + return newStub>( + space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_, + needsAtomize_, offset_); } MOZ_ASSERT(obj_ != holder_); RootedShape holderShape(cx, holder_->as().lastProperty()); - if (kind == ICStub::GetElem_NativePrototypeSlot) { - return newStub( - space, getStubCode(), firstMonitorStub_, guard, name_, acctype_, needsAtomize_, - offset_, holder_, holderShape); + if (kind == ICStub::GetElem_NativePrototypeSlotName || + kind == ICStub::GetElem_NativePrototypeSlotSymbol) + { + return newStub>( + space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_, + needsAtomize_, offset_, holder_, holderShape); } - if (kind == ICStub::GetElem_NativePrototypeCallNative) { - return newStub( - space, getStubCode(), firstMonitorStub_, guard, name_, acctype_, needsAtomize_, - getter_, pcOffset_, holder_, holderShape); + if (kind == ICStub::GetElem_NativePrototypeCallNativeSymbol || + kind == ICStub::GetElem_NativePrototypeCallNativeName) { + return newStub>( + space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_, + needsAtomize_, getter_, pcOffset_, holder_, holderShape); } - MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScripted); - if (kind == ICStub::GetElem_NativePrototypeCallScripted) { - return newStub( - space, getStubCode(), firstMonitorStub_, guard, name_, acctype_, needsAtomize_, - getter_, pcOffset_, holder_, holderShape); + MOZ_ASSERT(kind == ICStub::GetElem_NativePrototypeCallScriptedName || + kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol); + if (kind == ICStub::GetElem_NativePrototypeCallScriptedName || + kind == ICStub::GetElem_NativePrototypeCallScriptedSymbol) { + return newStub>( + space, getStubCode(), firstMonitorStub_, guard, key_.address(), acctype_, + needsAtomize_, getter_, pcOffset_, holder_, holderShape); } MOZ_CRASH("Invalid kind."); diff --git a/js/src/jit/BaselineICList.h b/js/src/jit/BaselineICList.h index e135910eea7b..698b1cf7fb01 100644 --- a/js/src/jit/BaselineICList.h +++ b/js/src/jit/BaselineICList.h @@ -73,11 +73,15 @@ namespace jit { _(Call_IsSuspendedStarGenerator) \ \ _(GetElem_Fallback) \ - _(GetElem_NativeSlot) \ - _(GetElem_NativePrototypeSlot) \ - _(GetElem_NativePrototypeCallNative) \ - _(GetElem_NativePrototypeCallScripted) \ - _(GetElem_UnboxedProperty) \ + _(GetElem_NativeSlotName) \ + _(GetElem_NativeSlotSymbol) \ + _(GetElem_NativePrototypeSlotName) \ + _(GetElem_NativePrototypeSlotSymbol) \ + _(GetElem_NativePrototypeCallNativeName) \ + _(GetElem_NativePrototypeCallNativeSymbol) \ + _(GetElem_NativePrototypeCallScriptedName) \ + _(GetElem_NativePrototypeCallScriptedSymbol) \ + _(GetElem_UnboxedPropertyName) \ _(GetElem_String) \ _(GetElem_Dense) \ _(GetElem_UnboxedArray) \ diff --git a/js/src/jit/BaselineInspector.cpp b/js/src/jit/BaselineInspector.cpp index ee2217a4c7ca..965db229869e 100644 --- a/js/src/jit/BaselineInspector.cpp +++ b/js/src/jit/BaselineInspector.cpp @@ -744,11 +744,15 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc) case ICStub::GetProp_CallDOMProxyNative: case ICStub::GetProp_CallDOMProxyWithGenerationNative: case ICStub::GetProp_DOMProxyShadowed: - case ICStub::GetElem_NativeSlot: - case ICStub::GetElem_NativePrototypeSlot: - case ICStub::GetElem_NativePrototypeCallNative: - case ICStub::GetElem_NativePrototypeCallScripted: - case ICStub::GetElem_UnboxedProperty: + case ICStub::GetElem_NativeSlotName: + case ICStub::GetElem_NativeSlotSymbol: + case ICStub::GetElem_NativePrototypeSlotName: + case ICStub::GetElem_NativePrototypeSlotSymbol: + case ICStub::GetElem_NativePrototypeCallNativeName: + case ICStub::GetElem_NativePrototypeCallNativeSymbol: + case ICStub::GetElem_NativePrototypeCallScriptedName: + case ICStub::GetElem_NativePrototypeCallScriptedSymbol: + case ICStub::GetElem_UnboxedPropertyName: case ICStub::GetElem_String: case ICStub::GetElem_Dense: case ICStub::GetElem_TypedArray: diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index dab3f7da0667..4de1b3d03c60 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -10116,6 +10116,27 @@ IonBuilder::maybeUnboxForPropertyAccess(MDefinition* def) MUnbox* unbox = MUnbox::New(alloc(), def, type, MUnbox::Fallible); current->add(unbox); + + // Fixup type information for a common case where a property call + // is converted to the following bytecodes + // + // a.foo() + // ================= Compiles to ================ + // LOAD "a" + // DUP + // CALLPROP "foo" + // SWAP + // CALL 0 + // + // If we have better type information to unbox the first copy going into + // the CALLPROP operation, we can replace the duplicated copy on the + // stack as well. + if (*pc == JSOP_CALLPROP || *pc == JSOP_CALLELEM) { + uint32_t idx = current->stackDepth() - 1; + MOZ_ASSERT(current->getSlot(idx) == def); + current->setSlot(idx, unbox); + } + return unbox; } diff --git a/js/src/jit/JitFrames.h b/js/src/jit/JitFrames.h index b091be912de0..4b4d85cc4f88 100644 --- a/js/src/jit/JitFrames.h +++ b/js/src/jit/JitFrames.h @@ -181,9 +181,10 @@ class OsiIndex // .. locals .. // The descriptor is organized into three sections: -// [ frame size | constructing bit | frame type ] +// [ frame size | has cached saved frame bit | frame type ] // < highest - - - - - - - - - - - - - - lowest > -static const uintptr_t FRAMESIZE_SHIFT = 4; +static const uintptr_t FRAMESIZE_SHIFT = 5; +static const uintptr_t HASCACHEDSAVEDFRAME_BIT = 1 << 4; static const uintptr_t FRAMETYPE_BITS = 4; // Ion frames have a few important numbers associated with them: @@ -282,7 +283,7 @@ void UpdateJitActivationsForMinorGC(JSRuntime* rt, JSTracer* trc); static inline uint32_t MakeFrameDescriptor(uint32_t frameSize, FrameType type) { - return (frameSize << FRAMESIZE_SHIFT) | type; + return 0 | (frameSize << FRAMESIZE_SHIFT) | type; } // Returns the JSScript associated with the topmost JIT frame. @@ -343,7 +344,13 @@ class CommonFrameLayout return descriptor_ >> FRAMESIZE_SHIFT; } void setFrameDescriptor(size_t size, FrameType type) { - descriptor_ = (size << FRAMESIZE_SHIFT) | type; + descriptor_ = 0 | (size << FRAMESIZE_SHIFT) | type; + } + bool hasCachedSavedFrame() const { + return descriptor_ & HASCACHEDSAVEDFRAME_BIT; + } + void setHasCachedSavedFrame() { + descriptor_ |= HASCACHEDSAVEDFRAME_BIT; } uint8_t* returnAddress() const { return returnAddress_; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 56673fa8fc2d..693ad5fb79c6 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -2210,22 +2210,34 @@ MBinaryArithInstruction::foldsTo(TempAllocator& alloc) MDefinition* lhs = getOperand(0); MDefinition* rhs = getOperand(1); - if (MDefinition* folded = EvaluateConstantOperands(alloc, this)) + if (MConstant* folded = EvaluateConstantOperands(alloc, this)) { + if (isTruncated()) { + if (!folded->block()) + block()->insertBefore(this, folded); + return MTruncateToInt32::New(alloc, folded); + } return folded; + } // 0 + -0 = 0. So we can't remove addition if (isAdd() && specialization_ != MIRType_Int32) return this; - if (IsConstant(rhs, getIdentity())) + if (IsConstant(rhs, getIdentity())) { + if (isTruncated()) + return MTruncateToInt32::New(alloc, lhs); return lhs; + } // subtraction isn't commutative. So we can't remove subtraction when lhs equals 0 if (isSub()) return this; - if (IsConstant(lhs, getIdentity())) + if (IsConstant(lhs, getIdentity())) { + if (isTruncated()) + return MTruncateToInt32::New(alloc, rhs); return rhs; // x op id => x + } return this; } diff --git a/js/src/jit/RematerializedFrame.cpp b/js/src/jit/RematerializedFrame.cpp index a7a463ab8155..4e020071f9ce 100644 --- a/js/src/jit/RematerializedFrame.cpp +++ b/js/src/jit/RematerializedFrame.cpp @@ -36,6 +36,7 @@ RematerializedFrame::RematerializedFrame(JSContext* cx, uint8_t* top, unsigned n : prevUpToDate_(false), isDebuggee_(iter.script()->isDebuggee()), isConstructing_(iter.isConstructing()), + hasCachedSavedFrame_(false), top_(top), pc_(iter.pc()), frameNo_(iter.frameNo()), diff --git a/js/src/jit/RematerializedFrame.h b/js/src/jit/RematerializedFrame.h index d1b9c9bbf462..27bc8c81ba36 100644 --- a/js/src/jit/RematerializedFrame.h +++ b/js/src/jit/RematerializedFrame.h @@ -35,6 +35,11 @@ class RematerializedFrame // Is this frame constructing? bool isConstructing_; + // If true, this frame has been on the stack when + // |js::SavedStacks::saveCurrentStack| was called, and so there is a + // |js::SavedFrame| object cached for this frame. + bool hasCachedSavedFrame_; + // The fp of the top frame associated with this possibly inlined frame. uint8_t* top_; @@ -169,6 +174,14 @@ class RematerializedFrame return isConstructing_; } + bool hasCachedSavedFrame() const { + return hasCachedSavedFrame_; + } + + void setHasCachedSavedFrame() { + hasCachedSavedFrame_ = true; + } + unsigned numFormalArgs() const { return maybeFun() ? fun()->nargs() : 0; } diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 6418445b6883..57cbc839fdd0 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -189,31 +189,61 @@ ICStub::trace(JSTracer* trc) TraceEdge(trc, &callStub->expectedThis(), "baseline-callstringsplit-this"); break; } - case ICStub::GetElem_NativeSlot: - case ICStub::GetElem_UnboxedProperty: { - ICGetElemNativeSlotStub* getElemStub = - reinterpret_cast(this); + case ICStub::GetElem_NativeSlotName: + case ICStub::GetElem_NativeSlotSymbol: + case ICStub::GetElem_UnboxedPropertyName: { + ICGetElemNativeStub* getElemStub = static_cast(this); getElemStub->receiverGuard().trace(trc); - TraceEdge(trc, &getElemStub->name(), "baseline-getelem-native-name"); + if (getElemStub->isSymbol()) { + ICGetElem_NativeSlot* typedGetElemStub = toGetElem_NativeSlotSymbol(); + TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key"); + } else { + ICGetElemNativeSlotStub* typedGetElemStub = + reinterpret_cast*>(this); + TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-native-key"); + } break; } - case ICStub::GetElem_NativePrototypeSlot: { - ICGetElem_NativePrototypeSlot* getElemStub = toGetElem_NativePrototypeSlot(); + case ICStub::GetElem_NativePrototypeSlotName: + case ICStub::GetElem_NativePrototypeSlotSymbol: { + ICGetElemNativeStub* getElemStub = static_cast(this); getElemStub->receiverGuard().trace(trc); - TraceEdge(trc, &getElemStub->name(), "baseline-getelem-nativeproto-name"); - TraceEdge(trc, &getElemStub->holder(), "baseline-getelem-nativeproto-holder"); - TraceEdge(trc, &getElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape"); + if (getElemStub->isSymbol()) { + ICGetElem_NativePrototypeSlot* typedGetElemStub + = toGetElem_NativePrototypeSlotSymbol(); + TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key"); + TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder"); + TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape"); + } else { + ICGetElem_NativePrototypeSlot* typedGetElemStub + = toGetElem_NativePrototypeSlotName(); + TraceEdge(trc, &typedGetElemStub->key(), "baseline-getelem-nativeproto-key"); + TraceEdge(trc, &typedGetElemStub->holder(), "baseline-getelem-nativeproto-holder"); + TraceEdge(trc, &typedGetElemStub->holderShape(), "baseline-getelem-nativeproto-holdershape"); + } break; } - case ICStub::GetElem_NativePrototypeCallNative: - case ICStub::GetElem_NativePrototypeCallScripted: { - ICGetElemNativePrototypeCallStub* callStub = - reinterpret_cast(this); - callStub->receiverGuard().trace(trc); - TraceEdge(trc, &callStub->name(), "baseline-getelem-nativeprotocall-name"); - TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter"); - TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder"); - TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape"); + case ICStub::GetElem_NativePrototypeCallNativeName: + case ICStub::GetElem_NativePrototypeCallNativeSymbol: + case ICStub::GetElem_NativePrototypeCallScriptedName: + case ICStub::GetElem_NativePrototypeCallScriptedSymbol: { + ICGetElemNativeStub* getElemStub = static_cast(this); + getElemStub->receiverGuard().trace(trc); + if (getElemStub->isSymbol()) { + ICGetElemNativePrototypeCallStub* callStub = + reinterpret_cast*>(this); + TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key"); + TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter"); + TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder"); + TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape"); + } else { + ICGetElemNativePrototypeCallStub* callStub = + reinterpret_cast*>(this); + TraceEdge(trc, &callStub->key(), "baseline-getelem-nativeprotocall-key"); + TraceEdge(trc, &callStub->getter(), "baseline-getelem-nativeprotocall-getter"); + TraceEdge(trc, &callStub->holder(), "baseline-getelem-nativeprotocall-holder"); + TraceEdge(trc, &callStub->holderShape(), "baseline-getelem-nativeprotocall-holdershape"); + } break; } case ICStub::GetElem_Dense: { diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index 87afda163cf7..c69f299cede6 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -690,11 +690,15 @@ class ICStub case Call_ScriptedFunCall: case Call_StringSplit: case WarmUpCounter_Fallback: - case GetElem_NativeSlot: - case GetElem_NativePrototypeSlot: - case GetElem_NativePrototypeCallNative: - case GetElem_NativePrototypeCallScripted: - case GetElem_UnboxedProperty: + case GetElem_NativeSlotName: + case GetElem_NativeSlotSymbol: + case GetElem_NativePrototypeSlotName: + case GetElem_NativePrototypeSlotSymbol: + case GetElem_NativePrototypeCallNativeName: + case GetElem_NativePrototypeCallNativeSymbol: + case GetElem_NativePrototypeCallScriptedName: + case GetElem_NativePrototypeCallScriptedSymbol: + case GetElem_UnboxedPropertyName: case GetProp_CallScripted: case GetProp_CallNative: case GetProp_CallDOMProxyNative: diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index c86ade5f138f..5d39a43980fa 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -205,15 +205,15 @@ JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle(shape.asCell())); + MOZ_ASSERT(shape.is()); + TraceCycleCollectorChildren(trc, &shape.as()); } JS_FRIEND_API(void) JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr group) { - MOZ_ASSERT(group.isObjectGroup()); - TraceCycleCollectorChildren(trc, static_cast(group.asCell())); + MOZ_ASSERT(group.is()); + TraceCycleCollectorChildren(trc, &group.as()); } static bool @@ -852,8 +852,8 @@ struct DumpHeapTracer : public JS::CallbackTracer, public WeakMapTracer private: void trace(JSObject* map, JS::GCCellPtr key, JS::GCCellPtr value) override { JSObject* kdelegate = nullptr; - if (key.isObject()) - kdelegate = js::GetWeakmapKeyDelegate(key.toObject()); + if (key.is()) + kdelegate = js::GetWeakmapKeyDelegate(&key.as()); fprintf(output, "WeakMapEntry map=%p key=%p keyDelegate=%p value=%p\n", map, key.asCell(), kdelegate, value.asCell()); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 00ea567edd72..d5d4f5654dbe 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2609,6 +2609,7 @@ GCRuntime::updatePointersToRelocatedCells(Zone* zone) Debugger::markIncomingCrossCompartmentEdges(&trc); for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) { + c->trace(&trc); WeakMapBase::markAll(c, &trc); if (c->watchpointMap) c->watchpointMap->markAll(&trc); @@ -3720,7 +3721,7 @@ CompartmentCheckTracer::onChild(const JS::GCCellPtr& thing) { TenuredCell* tenured = TenuredCell::fromPointer(thing.asCell()); - JSCompartment* comp = CallTyped(MaybeCompartmentFunctor(), tenured, thing.kind()); + JSCompartment* comp = DispatchTraceKindTyped(MaybeCompartmentFunctor(), tenured, thing.kind()); if (comp && compartment) { MOZ_ASSERT(comp == compartment || runtime()->isAtomsCompartment(comp) || (srcKind == JS::TraceKind::Object && @@ -3743,7 +3744,8 @@ GCRuntime::checkForCompartmentMismatches() for (ZoneCellIterUnderGC i(zone, thingKind); !i.done(); i.next()) { trc.src = i.getCell(); trc.srcKind = MapAllocToTraceKind(thingKind); - trc.compartment = CallTyped(MaybeCompartmentFunctor(), trc.src, trc.srcKind); + trc.compartment = DispatchTraceKindTyped(MaybeCompartmentFunctor(), + trc.src, trc.srcKind); JS_TraceChildren(&trc, trc.src, trc.srcKind); } } @@ -6971,7 +6973,7 @@ JS::GCTraceKindToAscii(JS::TraceKind kind) { switch(kind) { #define MAP_NAME(name, _0, _1) case JS::TraceKind::name: return #name; -FOR_EACH_GC_LAYOUT(MAP_NAME); +JS_FOR_EACH_TRACEKIND(MAP_NAME); #undef MAP_NAME default: return "Invalid"; } @@ -7001,8 +7003,8 @@ JS::GCCellPtr::outOfLineKind() const bool JS::GCCellPtr::mayBeOwnedByOtherRuntime() const { - return (isString() && toString()->isPermanentAtom()) || - (isSymbol() && toSymbol()->isWellKnownSymbol()); + return (is() && as().isPermanentAtom()) || + (is() && as().isWellKnownSymbol()); } #ifdef JSGC_HASH_TABLE_CHECKS @@ -7195,7 +7197,7 @@ JS::IncrementalReferenceBarrier(GCCellPtr thing) if (!thing) return; - CallTyped(IncrementalReferenceBarrierFunctor(), thing.asCell(), thing.kind()); + DispatchTraceKindTyped(IncrementalReferenceBarrierFunctor(), thing.asCell(), thing.kind()); } JS_PUBLIC_API(void) diff --git a/js/src/jsgc.h b/js/src/jsgc.h index f0c2f261c975..0478c045d0e7 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -23,18 +23,6 @@ #include "vm/NativeObject.h" -#define FOR_EACH_GC_LAYOUT(D) \ - /* PrettyName TypeName AddToCCKind */ \ - D(BaseShape, js::BaseShape, true) \ - D(JitCode, js::jit::JitCode, true) \ - D(LazyScript, js::LazyScript, true) \ - D(Object, JSObject, true) \ - D(ObjectGroup, js::ObjectGroup, true) \ - D(Script, JSScript, true) \ - D(Shape, js::Shape, true) \ - D(String, JSString, false) \ - D(Symbol, JS::Symbol, false) - namespace js { unsigned GetCPUCount(); @@ -63,15 +51,6 @@ enum State { COMPACT }; -// Map from base trace type to the trace kind. -template struct MapTypeToTraceKind {}; -#define EXPAND_DEF(name, type, _) \ - template <> struct MapTypeToTraceKind { \ - static const JS::TraceKind kind = JS::TraceKind::name; \ - }; -FOR_EACH_GC_LAYOUT(EXPAND_DEF); -#undef EXPAND_DEF - /* Map from C++ type to alloc kind. JSObject does not have a 1:1 mapping, so must use Arena::thingSize. */ template struct MapTypeToFinalizeKind {}; template <> struct MapTypeToFinalizeKind { static const AllocKind kind = AllocKind::SCRIPT; }; @@ -89,7 +68,7 @@ template <> struct MapTypeToFinalizeKind { static const Alloc template struct ParticipatesInCC {}; #define EXPAND_PARTICIPATES_IN_CC(_, type, addToCCKind) \ template <> struct ParticipatesInCC { static const bool value = addToCCKind; }; -FOR_EACH_GC_LAYOUT(EXPAND_PARTICIPATES_IN_CC) +JS_FOR_EACH_TRACEKIND(EXPAND_PARTICIPATES_IN_CC) #undef EXPAND_PARTICIPATES_IN_CC static inline bool @@ -177,53 +156,6 @@ CanBeFinalizedInBackground(AllocKind kind, const Class* clasp) (!clasp->finalize || (clasp->flags & JSCLASS_BACKGROUND_FINALIZE))); } -// Fortunately, few places in the system need to deal with fully abstract -// cells. In those places that do, we generally want to move to a layout -// templated function as soon as possible. This template wraps the upcast -// for that dispatch. -// -// Call the functor |F f| with template parameter of the layout type. - -// GCC and Clang require an explicit template declaration in front of the -// specialization of operator() because it is a dependent template. MSVC, on -// the other hand, gets very confused if we have a |template| token there. -#ifdef _MSC_VER -# define DEPENDENT_TEMPLATE_HINT -#else -# define DEPENDENT_TEMPLATE_HINT template -#endif -template -auto -CallTyped(F f, JS::TraceKind traceKind, Args&&... args) - -> decltype(f. DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...)) -{ - switch (traceKind) { -#define EXPAND_DEF(name, type, _) \ - case JS::TraceKind::name: \ - return f. DEPENDENT_TEMPLATE_HINT operator()(mozilla::Forward(args)...); - FOR_EACH_GC_LAYOUT(EXPAND_DEF); -#undef EXPAND_DEF - default: - MOZ_CRASH("Invalid trace kind in CallTyped."); - } -} -#undef DEPENDENT_TEMPLATE_HINT - -template -auto -CallTyped(F f, void* thing, JS::TraceKind traceKind, Args&&... args) - -> decltype(f(reinterpret_cast(0), mozilla::Forward(args)...)) -{ - switch (traceKind) { -#define EXPAND_DEF(name, type, _) \ - case JS::TraceKind::name: \ - return f(static_cast(thing), mozilla::Forward(args)...); - FOR_EACH_GC_LAYOUT(EXPAND_DEF); -#undef EXPAND_DEF - default: - MOZ_CRASH("Invalid trace kind in CallTyped."); - } -} /* Capacity for slotsToThingKind */ const size_t SLOTS_TO_THING_KIND_LIMIT = 17; diff --git a/js/src/jsweakmap.h b/js/src/jsweakmap.h index 074bf22a72de..501a6e2ccab7 100644 --- a/js/src/jsweakmap.h +++ b/js/src/jsweakmap.h @@ -251,8 +251,8 @@ class WeakMap : public HashMap, publ gc::Cell* value = gc::ToMarkable(r.front().value()); if (key && value) { tracer->trace(memberOf, - JS::GCCellPtr(r.front().key()), - JS::GCCellPtr(r.front().value())); + JS::GCCellPtr(r.front().key().get()), + JS::GCCellPtr(r.front().value().get())); } } } diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 66895a133b18..7b20d77e0cea 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -79,9 +79,20 @@ class DebuggerWeakMap : private WeakMap, Relocatabl public: typedef WeakMap > Base; + explicit DebuggerWeakMap(JSContext* cx) : Base(cx), zoneCounts(cx->runtime()) { } + ~DebuggerWeakMap() { + // If our owning Debugger fails construction after already initializing + // this DebuggerWeakMap, we need to make sure that we aren't in the + // compartment's weak map list anymore. Normally, when we are destroyed + // because the GC finds us unreachable, the GC takes care of removing us + // from this list. + if (WeakMapBase::isInList()) + WeakMapBase::removeWeakMapFromList(this); + } + public: /* Expose those parts of HashMap public interface that are used by Debugger methods. */ diff --git a/js/src/vm/SavedFrame.h b/js/src/vm/SavedFrame.h new file mode 100644 index 000000000000..9143648ac495 --- /dev/null +++ b/js/src/vm/SavedFrame.h @@ -0,0 +1,124 @@ +/* -*- 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 vm_SavedFrame_h +#define vm_SavedFrame_h + +namespace js { + +class SavedFrame : public NativeObject { + friend class SavedStacks; + + public: + static const Class class_; + static const JSPropertySpec protoAccessors[]; + static const JSFunctionSpec protoFunctions[]; + static const JSFunctionSpec staticFunctions[]; + + // Prototype methods and properties to be exposed to JS. + static bool construct(JSContext* cx, unsigned argc, Value* vp); + static bool sourceProperty(JSContext* cx, unsigned argc, Value* vp); + static bool lineProperty(JSContext* cx, unsigned argc, Value* vp); + static bool columnProperty(JSContext* cx, unsigned argc, Value* vp); + static bool functionDisplayNameProperty(JSContext* cx, unsigned argc, Value* vp); + static bool asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp); + static bool asyncParentProperty(JSContext* cx, unsigned argc, Value* vp); + static bool parentProperty(JSContext* cx, unsigned argc, Value* vp); + static bool toStringMethod(JSContext* cx, unsigned argc, Value* vp); + + static void finalize(FreeOp* fop, JSObject* obj); + + // Convenient getters for SavedFrame's reserved slots for use from C++. + JSAtom* getSource(); + uint32_t getLine(); + uint32_t getColumn(); + JSAtom* getFunctionDisplayName(); + JSAtom* getAsyncCause(); + SavedFrame* getParent(); + JSPrincipals* getPrincipals(); + + bool isSelfHosted(); + + static bool isSavedFrameAndNotProto(JSObject& obj) { + return obj.is() && + !obj.as().getReservedSlot(JSSLOT_SOURCE).isNull(); + } + + struct Lookup; + struct HashPolicy; + + typedef HashSet, + HashPolicy, + SystemAllocPolicy> Set; + + class AutoLookupVector; + + class MOZ_STACK_CLASS HandleLookup { + friend class AutoLookupVector; + + Lookup& lookup; + + explicit HandleLookup(Lookup& lookup) : lookup(lookup) { } + + public: + inline Lookup& get() { return lookup; } + inline Lookup* operator->() { return &lookup; } + }; + + private: + static bool finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject proto); + void initFromLookup(HandleLookup lookup); + + enum { + // The reserved slots in the SavedFrame class. + JSSLOT_SOURCE, + JSSLOT_LINE, + JSSLOT_COLUMN, + JSSLOT_FUNCTIONDISPLAYNAME, + JSSLOT_ASYNCCAUSE, + JSSLOT_PARENT, + JSSLOT_PRINCIPALS, + JSSLOT_PRIVATE_PARENT, + + // The total number of reserved slots in the SavedFrame class. + JSSLOT_COUNT + }; + + // Because we hash the parent pointer, we need to rekey a saved frame + // whenever its parent was relocated by the GC. However, the GC doesn't + // notify us when this occurs. As a work around, we keep a duplicate copy of + // the parent pointer as a private value in a reserved slot. Whenever the + // private value parent pointer doesn't match the regular parent pointer, we + // know that GC moved the parent and we need to update our private value and + // rekey the saved frame in its hash set. These two methods are helpers for + // this process. + bool parentMoved(); + void updatePrivateParent(); + + static bool checkThis(JSContext* cx, CallArgs& args, const char* fnName, + MutableHandleObject frame); +}; + +struct SavedFrame::HashPolicy +{ + typedef SavedFrame::Lookup Lookup; + typedef PointerHasher SavedFramePtrHasher; + typedef PointerHasher JSPrincipalsPtrHasher; + + static HashNumber hash(const Lookup& lookup); + static bool match(SavedFrame* existing, const Lookup& lookup); + + typedef ReadBarriered Key; + static void rekey(Key& key, const Key& newKey); +}; + +// Assert that if the given object is not null, that it must be either a +// SavedFrame object or wrapper (Xray or CCW) around a SavedFrame object. +inline void AssertObjectIsSavedFrameOrWrapper(JSContext* cx, HandleObject stack); + +} // namespace js + +#endif // vm_SavedFrame_h diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 481f92fae75b..45976d93c291 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -8,13 +8,12 @@ #include "mozilla/Attributes.h" #include "mozilla/DebugOnly.h" -#include "mozilla/Maybe.h" +#include "mozilla/Move.h" #include #include #include "jsapi.h" -#include "jscntxt.h" #include "jscompartment.h" #include "jsfriendapi.h" #include "jshashutil.h" @@ -33,11 +32,15 @@ #include "jscntxtinlines.h" #include "vm/NativeObject-inl.h" +#include "vm/Stack-inl.h" using mozilla::AddToHash; using mozilla::DebugOnly; using mozilla::HashString; using mozilla::Maybe; +using mozilla::Move; +using mozilla::Nothing; +using mozilla::Some; namespace js { @@ -46,19 +49,110 @@ namespace js { */ const unsigned ASYNC_STACK_MAX_FRAME_COUNT = 60; +/* static */ Maybe +LiveSavedFrameCache::getFramePtr(FrameIter& iter) +{ + if (iter.hasUsableAbstractFramePtr()) + return Some(FramePtr(iter.abstractFramePtr())); + + if (iter.isPhysicalIonFrame()) + return Some(FramePtr(iter.physicalIonFrame())); + + return Nothing(); +} + +/* static */ void +LiveSavedFrameCache::trace(LiveSavedFrameCache* cache, JSTracer* trc) +{ + if (!cache->initialized()) + return; + + for (auto* entry = cache->frames->begin(); entry < cache->frames->end(); entry++) { + TraceEdge(trc, + &entry->savedFrame, + "LiveSavedFrameCache::frames SavedFrame"); + } +} + +bool +LiveSavedFrameCache::insert(JSContext* cx, FramePtr& framePtr, jsbytecode* pc, + HandleSavedFrame savedFrame) +{ + MOZ_ASSERT(initialized()); + + if (!frames->emplaceBack(framePtr, pc, savedFrame)) { + ReportOutOfMemory(cx); + return false; + } + + // Safe to dereference the cache key because the stack frames are still + // live. After this point, they should never be dereferenced again. + if (framePtr.is()) + framePtr.as().setHasCachedSavedFrame(); + else + framePtr.as()->setHasCachedSavedFrame(); + + return true; +} + +void +LiveSavedFrameCache::find(JSContext* cx, FrameIter& frameIter, MutableHandleSavedFrame frame) const +{ + MOZ_ASSERT(initialized()); + MOZ_ASSERT(!frameIter.done()); + MOZ_ASSERT(frameIter.hasCachedSavedFrame()); + + Maybe maybeFramePtr = getFramePtr(frameIter); + MOZ_ASSERT(maybeFramePtr.isSome()); + + FramePtr framePtr(*maybeFramePtr); + jsbytecode* pc = frameIter.pc(); + size_t numberStillValid = 0; + + frame.set(nullptr); + for (auto* p = frames->begin(); p < frames->end(); p++) { + numberStillValid++; + if (framePtr == p->framePtr && pc == p->pc) { + frame.set(p->savedFrame); + break; + } + } + + if (!frame) { + frames->clear(); + return; + } + + MOZ_ASSERT(0 < numberStillValid && numberStillValid <= frames->length()); + + if (frame->compartment() != cx->compartment()) { + frame.set(nullptr); + numberStillValid--; + } + + // Everything after the cached SavedFrame are stale younger frames we have + // since popped. + frames->shrinkBy(frames->length() - numberStillValid); +} + struct SavedFrame::Lookup { Lookup(JSAtom* source, uint32_t line, uint32_t column, JSAtom* functionDisplayName, JSAtom* asyncCause, SavedFrame* parent, - JSPrincipals* principals) + JSPrincipals* principals, Maybe framePtr, jsbytecode* pc, + Activation* activation) : source(source), line(line), column(column), functionDisplayName(functionDisplayName), asyncCause(asyncCause), parent(parent), - principals(principals) + principals(principals), + framePtr(framePtr), + pc(pc), + activation(activation) { MOZ_ASSERT(source); + MOZ_ASSERT(activation); } explicit Lookup(SavedFrame& savedFrame) @@ -68,19 +162,28 @@ struct SavedFrame::Lookup { functionDisplayName(savedFrame.getFunctionDisplayName()), asyncCause(savedFrame.getAsyncCause()), parent(savedFrame.getParent()), - principals(savedFrame.getPrincipals()) + principals(savedFrame.getPrincipals()), + framePtr(Nothing()), + pc(nullptr), + activation(nullptr) { MOZ_ASSERT(source); } - JSAtom* source; - uint32_t line; - uint32_t column; - JSAtom* functionDisplayName; - JSAtom* asyncCause; - SavedFrame* parent; + JSAtom* source; + uint32_t line; + uint32_t column; + JSAtom* functionDisplayName; + JSAtom* asyncCause; + SavedFrame* parent; JSPrincipals* principals; + // These are used only by the LiveSavedFrameCache and not used for identity or + // hashing. + Maybe framePtr; + jsbytecode* pc; + Activation* activation; + void trace(JSTracer* trc) { TraceManuallyBarrieredEdge(trc, &source, "SavedFrame::Lookup::source"); if (functionDisplayName) { @@ -399,8 +502,7 @@ SavedFrame::checkThis(JSContext* cx, CallArgs& args, const char* fnName, const Value& thisValue = args.thisv(); if (!thisValue.isObject()) { - JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, - InformalValueTypeName(thisValue)); + JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, InformalValueTypeName(thisValue)); return false; } @@ -814,7 +916,7 @@ SavedStacks::saveCurrentStack(JSContext* cx, MutableHandleSavedFrame frame, unsi MOZ_ASSERT(initialized()); assertSameCompartment(cx, this); - if (creatingSavedFrame) { + if (creatingSavedFrame || cx->isExceptionPending()) { frame.set(nullptr); return true; } @@ -855,13 +957,12 @@ SavedStacks::sweep(JSRuntime* rt) void SavedStacks::trace(JSTracer* trc) { - if (!pcLocationMap.initialized()) - return; - - // Mark each of the source strings in our pc to location cache. - for (PCLocationMap::Enum e(pcLocationMap); !e.empty(); e.popFront()) { - LocationValue& loc = e.front().value(); - TraceEdge(trc, &loc.source, "SavedStacks::PCLocationMap's memoized script source name"); + if (pcLocationMap.initialized()) { + // Mark each of the source strings in our pc to location cache. + for (PCLocationMap::Enum e(pcLocationMap); !e.empty(); e.popFront()) { + LocationValue& loc = e.front().value(); + TraceEdge(trc, &loc.source, "SavedStacks::PCLocationMap's memoized script source name"); + } } } @@ -906,6 +1007,8 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram Activation* asyncActivation = nullptr; RootedSavedFrame asyncStack(cx, nullptr); RootedString asyncCause(cx, nullptr); + bool parentIsInCache = false; + RootedSavedFrame cachedFrame(cx, nullptr); // Accumulate the vector of Lookup objects in |stackChain|. SavedFrame::AutoLookupVector stackChain(cx); @@ -943,6 +1046,11 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram return false; } + // The bit set means that the next older parent (frame, pc) pair *must* + // be in the cache. + if (maxFrameCount == 0) + parentIsInCache = iter.hasCachedSavedFrame(); + auto displayAtom = iter.isNonEvalFunctionFrame() ? iter.functionDisplayAtom() : nullptr; if (!stackChain->emplaceBack(location->source, location->line, @@ -950,7 +1058,10 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram displayAtom, nullptr, nullptr, - iter.compartment()->principals())) + iter.compartment()->principals(), + LiveSavedFrameCache::getFramePtr(iter), + iter.pc(), + &activation)) { ReportOutOfMemory(cx); return false; @@ -958,10 +1069,6 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram ++iter; - // If maxFrameCount is zero there's no limit on the number of frames. - if (maxFrameCount == 0) - continue; - if (maxFrameCount == 1) { // The frame we just saved was the last one we were asked to save. // If we had an async stack, ensure we don't use any of its frames. @@ -969,13 +1076,29 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram break; } + if (parentIsInCache && + !iter.done() && + iter.hasCachedSavedFrame()) + { + auto* cache = activation.getLiveSavedFrameCache(cx); + if (!cache) + return false; + cache->find(cx, iter, &cachedFrame); + if (cachedFrame) + break; + } + + // If maxFrameCount is zero there's no limit on the number of frames. + if (maxFrameCount == 0) + continue; + maxFrameCount--; } // Limit the depth of the async stack, if any, and ensure that the // SavedFrame instances we use are stored in the same compartment as the // rest of the synchronous stack chain. - RootedSavedFrame parentFrame(cx, nullptr); + RootedSavedFrame parentFrame(cx, cachedFrame); if (asyncStack && !adoptAsyncStack(cx, asyncStack, asyncCause, &parentFrame, maxFrameCount)) return false; @@ -987,6 +1110,12 @@ SavedStacks::insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFram parentFrame.set(getOrCreateSavedFrame(cx, lookup)); if (!parentFrame) return false; + + if (maxFrameCount == 0 && lookup->framePtr && parentFrame != cachedFrame) { + auto* cache = lookup->activation->getLiveSavedFrameCache(cx); + if (!cache || !cache->insert(cx, *lookup->framePtr, lookup->pc, parentFrame)) + return false; + } } frame.set(parentFrame); diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index 61857965c114..6d6ea4e1c9b8 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -11,8 +11,11 @@ #include "jsmath.h" #include "jswrapper.h" #include "js/HashTable.h" +#include "vm/SavedFrame.h" #include "vm/Stack.h" +namespace js { + // # Saved Stacks // // The `SavedStacks` class provides a compact way to capture and save JS stacks @@ -142,123 +145,6 @@ // because the cx's current compartment's principals do not subsume A's captured // principals. - -namespace js { - -class SavedFrame; -typedef JS::Handle HandleSavedFrame; -typedef JS::MutableHandle MutableHandleSavedFrame; -typedef JS::Rooted RootedSavedFrame; - -class SavedFrame : public NativeObject { - friend class SavedStacks; - - public: - static const Class class_; - static void finalize(FreeOp* fop, JSObject* obj); - static const JSPropertySpec protoAccessors[]; - static const JSFunctionSpec protoFunctions[]; - static const JSFunctionSpec staticFunctions[]; - - // Prototype methods and properties to be exposed to JS. - static bool construct(JSContext* cx, unsigned argc, Value* vp); - static bool sourceProperty(JSContext* cx, unsigned argc, Value* vp); - static bool lineProperty(JSContext* cx, unsigned argc, Value* vp); - static bool columnProperty(JSContext* cx, unsigned argc, Value* vp); - static bool functionDisplayNameProperty(JSContext* cx, unsigned argc, Value* vp); - static bool asyncCauseProperty(JSContext* cx, unsigned argc, Value* vp); - static bool asyncParentProperty(JSContext* cx, unsigned argc, Value* vp); - static bool parentProperty(JSContext* cx, unsigned argc, Value* vp); - static bool toStringMethod(JSContext* cx, unsigned argc, Value* vp); - - // Convenient getters for SavedFrame's reserved slots for use from C++. - JSAtom* getSource(); - uint32_t getLine(); - uint32_t getColumn(); - JSAtom* getFunctionDisplayName(); - JSAtom* getAsyncCause(); - SavedFrame* getParent(); - JSPrincipals* getPrincipals(); - - bool isSelfHosted(); - - static bool isSavedFrameAndNotProto(JSObject& obj) { - return obj.is() && - !obj.as().getReservedSlot(JSSLOT_SOURCE).isNull(); - } - - struct Lookup; - struct HashPolicy; - - typedef HashSet, - HashPolicy, - SystemAllocPolicy> Set; - - class AutoLookupVector; - - class MOZ_STACK_CLASS HandleLookup { - friend class AutoLookupVector; - - Lookup& lookup; - - explicit HandleLookup(Lookup& lookup) : lookup(lookup) { } - - public: - inline Lookup& get() { return lookup; } - inline Lookup* operator->() { return &lookup; } - }; - - private: - static bool finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject proto); - void initFromLookup(HandleLookup lookup); - - enum { - // The reserved slots in the SavedFrame class. - JSSLOT_SOURCE, - JSSLOT_LINE, - JSSLOT_COLUMN, - JSSLOT_FUNCTIONDISPLAYNAME, - JSSLOT_ASYNCCAUSE, - JSSLOT_PARENT, - JSSLOT_PRINCIPALS, - JSSLOT_PRIVATE_PARENT, - - // The total number of reserved slots in the SavedFrame class. - JSSLOT_COUNT - }; - - // Because we hash the parent pointer, we need to rekey a saved frame - // whenever its parent was relocated by the GC. However, the GC doesn't - // notify us when this occurs. As a work around, we keep a duplicate copy of - // the parent pointer as a private value in a reserved slot. Whenever the - // private value parent pointer doesn't match the regular parent pointer, we - // know that GC moved the parent and we need to update our private value and - // rekey the saved frame in its hash set. These two methods are helpers for - // this process. - bool parentMoved(); - void updatePrivateParent(); - - static bool checkThis(JSContext* cx, CallArgs& args, const char* fnName, - MutableHandleObject frame); -}; - -struct SavedFrame::HashPolicy -{ - typedef SavedFrame::Lookup Lookup; - typedef PointerHasher SavedFramePtrHasher; - typedef PointerHasher JSPrincipalsPtrHasher; - - static HashNumber hash(const Lookup& lookup); - static bool match(SavedFrame* existing, const Lookup& lookup); - - typedef ReadBarriered Key; - static void rekey(Key& key, const Key& newKey); -}; - -// Assert that if the given object is not null, that it must be either a -// SavedFrame object or wrapper (Xray or CCW) around a SavedFrame object. -inline void AssertObjectIsSavedFrameOrWrapper(JSContext* cx, HandleObject stack); - class SavedStacks { friend JSObject* SavedStacksMetadataCallback(JSContext* cx, JSObject* target); @@ -309,15 +195,15 @@ class SavedStacks { } }; - bool insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFrame frame, - unsigned maxFrameCount = 0); - bool adoptAsyncStack(JSContext* cx, HandleSavedFrame asyncStack, - HandleString asyncCause, - MutableHandleSavedFrame adoptedStack, - unsigned maxFrameCount); + bool insertFrames(JSContext* cx, FrameIter& iter, MutableHandleSavedFrame frame, + unsigned maxFrameCount = 0); + bool adoptAsyncStack(JSContext* cx, HandleSavedFrame asyncStack, + HandleString asyncCause, + MutableHandleSavedFrame adoptedStack, + unsigned maxFrameCount); SavedFrame* getOrCreateSavedFrame(JSContext* cx, SavedFrame::HandleLookup lookup); SavedFrame* createFrameFromLookup(JSContext* cx, SavedFrame::HandleLookup lookup); - void chooseSamplingProbability(JSContext* cx); + void chooseSamplingProbability(JSContext* cx); // Cache for memoizing PCToLineNumber lookups. diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h index 93691f519979..bc53fd977414 100644 --- a/js/src/vm/Stack-inl.h +++ b/js/src/vm/Stack-inl.h @@ -606,6 +606,27 @@ AbstractFramePtr::isDebuggerEvalFrame() const return false; } +inline bool +AbstractFramePtr::hasCachedSavedFrame() const +{ + if (isInterpreterFrame()) + return asInterpreterFrame()->hasCachedSavedFrame(); + if (isBaselineFrame()) + return asBaselineFrame()->hasCachedSavedFrame(); + return asRematerializedFrame()->hasCachedSavedFrame(); +} + +inline void +AbstractFramePtr::setHasCachedSavedFrame() +{ + if (isInterpreterFrame()) + asInterpreterFrame()->setHasCachedSavedFrame(); + else if (isBaselineFrame()) + asBaselineFrame()->setHasCachedSavedFrame(); + else + asRematerializedFrame()->setHasCachedSavedFrame(); +} + inline bool AbstractFramePtr::isDebuggee() const { @@ -866,6 +887,7 @@ Activation::Activation(JSContext* cx, Kind kind) prevProfiling_(prev_ ? prev_->mostRecentProfiling() : nullptr), savedFrameChain_(0), hideScriptedCallerCount_(0), + frameCache_(cx), asyncStack_(cx, cx->runtime_->asyncStackForNewActivations), asyncCause_(cx, cx->runtime_->asyncCauseForNewActivations), asyncCallIsExplicit_(cx->runtime_->asyncCallIsExplicit), @@ -912,6 +934,13 @@ Activation::mostRecentProfiling() return prevProfiling_; } +inline LiveSavedFrameCache* +Activation::getLiveSavedFrameCache(JSContext* cx) { + if (!frameCache_.get().initialized() && !frameCache_.get().init(cx)) + return nullptr; + return frameCache_.address(); +} + InterpreterActivation::InterpreterActivation(RunState& state, JSContext* cx, InterpreterFrame* entryFrame) : Activation(cx, Interpreter), @@ -989,6 +1018,36 @@ AsmJSActivation::cx() return cx_->asJSContext(); } +inline bool +FrameIter::hasCachedSavedFrame() const +{ + if (isAsmJS()) + return false; + + if (hasUsableAbstractFramePtr()) + return abstractFramePtr().hasCachedSavedFrame(); + + MOZ_ASSERT(data_.jitFrames_.isIonScripted()); + // SavedFrame caching is done at the physical frame granularity (rather than + // for each inlined frame) for ion. Therefore, it is impossible to have a + // cached SavedFrame if this frame is not a physical frame. + return isPhysicalIonFrame() && data_.jitFrames_.current()->hasCachedSavedFrame(); +} + +inline void +FrameIter::setHasCachedSavedFrame() +{ + MOZ_ASSERT(!isAsmJS()); + + if (hasUsableAbstractFramePtr()) { + abstractFramePtr().setHasCachedSavedFrame(); + return; + } + + MOZ_ASSERT(isPhysicalIonFrame()); + data_.jitFrames_.current()->setHasCachedSavedFrame(); +} + } /* namespace js */ #endif /* vm_Stack_inl_h */ diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index 8f26aedcf37c..cc17cb13665a 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -8,17 +8,22 @@ #define vm_Stack_h #include "mozilla/Atomics.h" +#include "mozilla/Maybe.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/Variant.h" #include "jsfun.h" #include "jsscript.h" #include "jsutil.h" #include "asmjs/AsmJSFrameIterator.h" +#include "gc/Rooting.h" #include "jit/JitFrameIterator.h" #ifdef CHECK_OSIPOINT_REGISTERS #include "jit/Registers.h" // for RegisterDump #endif +#include "js/RootingAPI.h" +#include "vm/SavedFrame.h" struct JSCompartment; @@ -34,6 +39,7 @@ class ArgumentsObject; class AsmJSModule; class InterpreterRegs; class CallObject; +class FrameIter; class ScopeObject; class ScriptFrameIter; class SPSProfiler; @@ -44,6 +50,10 @@ class ScopeCoordinate; class SavedFrame; +namespace jit { +class CommonFrameLayout; +} + // VM stack layout // // A JSRuntime's stack consists of a linked list of activations. Every activation @@ -196,6 +206,8 @@ class AbstractFramePtr inline bool isGlobalFrame() const; inline bool isEvalFrame() const; inline bool isDebuggerEvalFrame() const; + inline bool hasCachedSavedFrame() const; + inline void setHasCachedSavedFrame(); inline JSScript* script() const; inline JSFunction* fun() const; @@ -279,13 +291,13 @@ enum ExecuteType { class InterpreterFrame { public: - enum Flags { + enum Flags : uint32_t { /* Primary frame type */ - GLOBAL = 0x1, /* frame pushed for a global script */ - FUNCTION = 0x2, /* frame pushed for a scripted call */ + GLOBAL = 0x1, /* frame pushed for a global script */ + FUNCTION = 0x2, /* frame pushed for a scripted call */ /* Frame subtypes */ - EVAL = 0x4, /* frame pushed for eval() or debugger eval */ + EVAL = 0x4, /* frame pushed for eval() or debugger eval */ /* @@ -300,42 +312,50 @@ class InterpreterFrame * previous frame in memory. Iteration should treat * evalInFramePrev_ as this frame's previous frame. */ - DEBUGGER_EVAL = 0x8, + DEBUGGER_EVAL = 0x8, - CONSTRUCTING = 0x10, /* frame is for a constructor invocation */ + CONSTRUCTING = 0x10, /* frame is for a constructor invocation */ - RESUMED_GENERATOR = 0x20, /* frame is for a resumed generator invocation */ + RESUMED_GENERATOR = 0x20, /* frame is for a resumed generator invocation */ /* (0x40 and 0x80 are unused) */ /* Function prologue state */ - HAS_CALL_OBJ = 0x100, /* CallObject created for heavyweight fun */ - HAS_ARGS_OBJ = 0x200, /* ArgumentsObject created for needsArgsObj script */ + HAS_CALL_OBJ = 0x100, /* CallObject created for heavyweight fun */ + HAS_ARGS_OBJ = 0x200, /* ArgumentsObject created for needsArgsObj script */ /* Lazy frame initialization */ - HAS_RVAL = 0x800, /* frame has rval_ set */ - HAS_SCOPECHAIN = 0x1000, /* frame has scopeChain_ set */ + HAS_RVAL = 0x800, /* frame has rval_ set */ + HAS_SCOPECHAIN = 0x1000, /* frame has scopeChain_ set */ /* Debugger state */ - PREV_UP_TO_DATE = 0x4000, /* see DebugScopes::updateLiveScopes */ + PREV_UP_TO_DATE = 0x4000, /* see DebugScopes::updateLiveScopes */ /* * See comment above 'isDebuggee' in jscompartment.h for explanation of * invariants of debuggee compartments, scripts, and frames. */ - DEBUGGEE = 0x8000, /* Execution is being observed by Debugger */ + DEBUGGEE = 0x8000, /* Execution is being observed by Debugger */ /* Used in tracking calls and profiling (see vm/SPSProfiler.cpp) */ - HAS_PUSHED_SPS_FRAME = 0x10000, /* SPS was notified of enty */ + HAS_PUSHED_SPS_FRAME = 0x10000, /* SPS was notified of enty */ + /* * If set, we entered one of the JITs and ScriptFrameIter should skip * this frame. */ - RUNNING_IN_JIT = 0x20000, + RUNNING_IN_JIT = 0x20000, /* Miscellaneous state. */ - CREATE_SINGLETON = 0x40000 /* Constructed |this| object should be singleton. */ + CREATE_SINGLETON = 0x40000, /* Constructed |this| object should be singleton. */ + + /* + * If set, this frame has been on the stack when + * |js::SavedStacks::saveCurrentStack| was called, and so there is a + * |js::SavedFrame| object cached for this frame. + */ + HAS_CACHED_SAVED_FRAME = 0x80000, }; private: @@ -898,6 +918,13 @@ class InterpreterFrame inline void unsetIsDebuggee(); + bool hasCachedSavedFrame() const { + return flags_ & HAS_CACHED_SAVED_FRAME; + } + void setHasCachedSavedFrame() { + flags_ |= HAS_CACHED_SAVED_FRAME; + } + public: void mark(JSTracer* trc); void markValues(JSTracer* trc, unsigned start, unsigned end); @@ -1091,6 +1118,128 @@ struct DefaultHasher { /*****************************************************************************/ +// SavedFrame caching to minimize stack walking. +// +// SavedFrames are hash consed to minimize expensive (with regards to both space +// and time) allocations in the face of many stack frames that tend to share the +// same older tail frames. Despite that, in scenarios where we are frequently +// saving the same or similar stacks, such as when the Debugger's allocation +// site tracking is enabled, these older stack frames still get walked +// repeatedly just to create the lookup structs to find their corresponding +// SavedFrames in the hash table. This stack walking is slow, and we would like +// to minimize it. +// +// We have reserved a bit on most of SpiderMonkey's various frame +// representations (the exceptions being asm and inlined ion frames). As we +// create SavedFrame objects for live stack frames in SavedStacks::insertFrames, +// we set this bit and append the SavedFrame object to the cache. As we walk the +// stack, if we encounter a frame that has this bit set, that indicates that we +// have already captured a SavedFrame object for the given stack frame (but not +// necessarily the current pc) during a previous call to insertFrames. We know +// that the frame's parent was also captured and has its bit set as well, but +// additionally we know the parent was captured at its current pc. For the +// parent, rather than continuing the expensive stack walk, we do a quick and +// cache-friendly linear search through the frame cache. Upon finishing search +// through the frame cache, stale entries are removed. +// +// The frame cache maintains the invariant that its first E[0] .. E[j-1] +// entries are live and sorted from oldest to younger frames, where 0 < j < n +// and n = the length of the cache. When searching the cache, we require +// that we are considering the youngest live frame whose bit is set. Every +// cache entry E[i] where i >= j is a stale entry. Consider the following +// scenario: +// +// P > Q > R > S Initial stack, bits not set. +// P* > Q* > R* > S* Capture a SavedFrame stack, set bits. +// P* > Q* > R* Return from S. +// P* > Q* Return from R. +// P* > Q* > T Call T, its bit is not set. +// +// The frame cache was populated with [P, Q, R, S] when we captured a +// SavedFrame stack, but because we returned from frames R and S, their +// entries in the frame cache are now stale. This fact is unbeknownst to us +// because we do not observe frame pops. Upon capturing a second stack, we +// start stack walking at the youngest frame T, which does not have its bit +// set and must take the hash table lookup slow path rather than the frame +// cache short circuit. Next we proceed to Q and find that it has its bit +// set, and it is therefore the youngest live frame with its bit set. We +// search through the frame cache from oldest to youngest and find the cache +// entry matching Q. We know that T is the next younger live frame from Q +// and that T does not have an entry in the frame cache because its bit was +// not set. Therefore, we have found entry E[j-1] and the subsequent entries +// are stale and should be purged from the frame cache. +// +// We have a LiveSavedFrameCache for each activation to minimize the number of +// entries that must be scanned through, and to avoid the headaches of +// maintaining a cache for each compartment and invalidating stale cache entries +// in the presence of cross-compartment calls. +class LiveSavedFrameCache : public JS::StaticTraceable +{ + public: + using FramePtr = mozilla::Variant; + + private: + struct Entry + { + FramePtr framePtr; + jsbytecode* pc; + RelocatablePtr savedFrame; + + Entry(FramePtr& framePtr, jsbytecode* pc, SavedFrame* savedFrame) + : framePtr(framePtr) + , pc(pc) + , savedFrame(savedFrame) + { } + }; + + using EntryVector = Vector; + EntryVector* frames; + + LiveSavedFrameCache(const LiveSavedFrameCache&) = delete; + LiveSavedFrameCache& operator=(const LiveSavedFrameCache&) = delete; + + public: + explicit LiveSavedFrameCache() : frames(nullptr) { } + + LiveSavedFrameCache(LiveSavedFrameCache&& rhs) + : frames(rhs.frames) + { + MOZ_ASSERT(this != &rhs, "self-move disallowed"); + rhs.frames = nullptr; + } + + ~LiveSavedFrameCache() { + if (frames) { + js_delete(frames); + frames = nullptr; + } + } + + bool initialized() const { return !!frames; } + bool init(JSContext* cx) { + frames = js_new(); + if (!frames) { + JS_ReportOutOfMemory(cx); + return false; + } + return true; + } + + static mozilla::Maybe getFramePtr(FrameIter& iter); + static void trace(LiveSavedFrameCache* cache, JSTracer* trc); + + void find(JSContext* cx, FrameIter& frameIter, MutableHandleSavedFrame frame) const; + bool insert(JSContext* cx, FramePtr& framePtr, jsbytecode* pc, HandleSavedFrame savedFrame); +}; + +static_assert(sizeof(LiveSavedFrameCache) == sizeof(uintptr_t), + "Every js::Activation has a LiveSavedFrameCache, so we need to be pretty careful " + "about avoiding bloat. If you're adding members to LiveSavedFrameCache, maybe you " + "should consider figuring out a way to make js::Activation have a " + "LiveSavedFrameCache* instead of a Rooted."); + +/*****************************************************************************/ + class InterpreterActivation; class AsmJSActivation; @@ -1119,6 +1268,10 @@ class Activation // data structures instead. size_t hideScriptedCallerCount_; + // The cache of SavedFrame objects we have already captured when walking + // this activation's stack. + Rooted frameCache_; + // Youngest saved frame of an async stack that will be iterated during stack // capture in place of the actual stack of previous activations. Note that // the stack of this activation is captured entirely before this is used. @@ -1223,6 +1376,8 @@ class Activation return asyncCallIsExplicit_; } + inline LiveSavedFrameCache* getLiveSavedFrameCache(JSContext* cx); + private: Activation(const Activation& other) = delete; void operator=(const Activation& other) = delete; @@ -1638,7 +1793,7 @@ class AsmJSActivation : public Activation // // FrameIter is parameterized by what it includes in the stack iteration: // - The SavedOption controls whether FrameIter stops when it finds an -// activation that was set aside via JS_SaveFrameChain (and not yet retored +// activation that was set aside via JS_SaveFrameChain (and not yet restored // by JS_RestoreFrameChain). (Hopefully this will go away.) // - The ContextOption determines whether the iteration will view frames from // all JSContexts or just the given JSContext. (Hopefully this will go away.) @@ -1713,6 +1868,7 @@ class FrameIter bool isAsmJS() const { MOZ_ASSERT(!done()); return data_.state_ == ASMJS; } inline bool isIon() const; inline bool isBaseline() const; + inline bool isPhysicalIonFrame() const; bool isFunctionFrame() const; bool isGlobalFrame() const; @@ -1720,6 +1876,10 @@ class FrameIter bool isNonEvalFunctionFrame() const; bool hasArgs() const { return isNonEvalFunctionFrame(); } + // These two methods may not be called with asm frames. + inline bool hasCachedSavedFrame() const; + inline void setHasCachedSavedFrame(); + ScriptSource* scriptSource() const; const char* scriptFilename() const; const char16_t* scriptDisplayURL() const; @@ -1807,6 +1967,9 @@ class FrameIter // This can only be called when isInterp(): inline InterpreterFrame* interpFrame() const; + // This can only be called when isPhysicalIonFrame(): + inline jit::CommonFrameLayout* physicalIonFrame() const; + private: Data data_; jit::InlineFrameIterator ionInlineFrames_; @@ -2015,5 +2178,20 @@ FrameIter::interpFrame() const return data_.interpFrames_.frame(); } +inline bool +FrameIter::isPhysicalIonFrame() const +{ + return isJit() && + data_.jitFrames_.isIonScripted() && + ionInlineFrames_.frameNo() == 0; +} + +inline jit::CommonFrameLayout* +FrameIter::physicalIonFrame() const +{ + MOZ_ASSERT(isPhysicalIonFrame()); + return data_.jitFrames_.current(); +} + } /* namespace js */ #endif /* vm_Stack_h */ diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp index eae050f8a54a..5bd529a0a512 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -33,6 +33,7 @@ using mozilla::Some; using mozilla::UniquePtr; +using JS::DispatchTraceKindTyped; using JS::HandleValue; using JS::Value; using JS::ZoneSet; @@ -67,7 +68,7 @@ struct Node::ConstructFunctor : public js::BoolDefaultAdaptor { Node::Node(const JS::GCCellPtr &thing) { - js::gc::CallTyped(ConstructFunctor(), thing.asCell(), thing.kind(), this); + DispatchTraceKindTyped(ConstructFunctor(), thing.asCell(), thing.kind(), this); } Node::Node(HandleValue value) @@ -117,9 +118,9 @@ class SimpleEdgeVectorTracer : public JS::CallbackTracer { // Don't trace permanent atoms and well-known symbols that are owned by // a parent JSRuntime. - if (thing.isString() && thing.toString()->isPermanentAtom()) + if (thing.is() && thing.as().isPermanentAtom()) return; - if (thing.isSymbol() && thing.toSymbol()->isWellKnownSymbol()) + if (thing.is() && thing.as().isWellKnownSymbol()) return; char16_t* name16 = nullptr; @@ -204,7 +205,7 @@ TracerConcrete::edges(JSContext* cx, bool wantNames) const { if (!range) return nullptr; - if (!range->init(cx, ptr, ::js::gc::MapTypeToTraceKind::kind, wantNames)) + if (!range->init(cx, ptr, JS::MapTypeToTraceKind::kind, wantNames)) return nullptr; return UniquePtr(range.release()); diff --git a/js/xpconnect/idl/nsIXPConnect.idl b/js/xpconnect/idl/nsIXPConnect.idl index 868743ecf2bd..0edde65a4da3 100644 --- a/js/xpconnect/idl/nsIXPConnect.idl +++ b/js/xpconnect/idl/nsIXPConnect.idl @@ -266,7 +266,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } %} -[noscript, uuid(db83b3af-ac22-4dd2-99cf-7f79270ed4cd)] +[noscript, uuid(f339ea52-10ce-4103-b1f2-fd9659040e3c)] interface nsIXPConnect : nsISupports { %{ C++ @@ -486,6 +486,8 @@ interface nsIXPConnect : nsISupports * the script. The actual evaluation will happen on a new * temporary context. * @param sandbox The sandbox object to evaluate the script in. + * @param version The JavaScript version to use for evaluating the script. + * Should be a valid JSVersion from jspubtd.h. * @return The result of the evaluation as a jsval. If the caller * intends to use the return value from this call the caller * is responsible for rooting the jsval before making a call @@ -493,7 +495,8 @@ interface nsIXPConnect : nsISupports */ [noscript] jsval evalInSandboxObject(in AString source, in string filename, in JSContextPtr cx, - in JSObjectPtr sandbox); + in JSObjectPtr sandbox, + in int32_t version); /** * Whether or not XPConnect should report all JS exceptions when returning diff --git a/js/xpconnect/src/nsScriptError.cpp b/js/xpconnect/src/nsScriptError.cpp index b876ce985308..16f49172c45f 100644 --- a/js/xpconnect/src/nsScriptError.cpp +++ b/js/xpconnect/src/nsScriptError.cpp @@ -18,9 +18,7 @@ #include "nsILoadContext.h" #include "nsIDocShell.h" -NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError) - -nsScriptError::nsScriptError() +nsScriptErrorBase::nsScriptErrorBase() : mMessage(), mSourceName(), mLineNumber(0), @@ -36,10 +34,10 @@ nsScriptError::nsScriptError() { } -nsScriptError::~nsScriptError() {} +nsScriptErrorBase::~nsScriptErrorBase() {} void -nsScriptError::InitializeOnMainThread() +nsScriptErrorBase::InitializeOnMainThread() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!mInitializedOnMainThread); @@ -70,7 +68,7 @@ nsScriptError::InitializeOnMainThread() // nsIConsoleMessage methods NS_IMETHODIMP -nsScriptError::GetMessageMoz(char16_t** result) { +nsScriptErrorBase::GetMessageMoz(char16_t** result) { nsresult rv; nsAutoCString message; @@ -87,7 +85,7 @@ nsScriptError::GetMessageMoz(char16_t** result) { NS_IMETHODIMP -nsScriptError::GetLogLevel(uint32_t* aLogLevel) +nsScriptErrorBase::GetLogLevel(uint32_t* aLogLevel) { if (mFlags & (uint32_t)nsIScriptError::infoFlag) { *aLogLevel = nsIConsoleMessage::info; @@ -101,66 +99,66 @@ nsScriptError::GetLogLevel(uint32_t* aLogLevel) // nsIScriptError methods NS_IMETHODIMP -nsScriptError::GetErrorMessage(nsAString& aResult) { +nsScriptErrorBase::GetErrorMessage(nsAString& aResult) { aResult.Assign(mMessage); return NS_OK; } NS_IMETHODIMP -nsScriptError::GetSourceName(nsAString& aResult) { +nsScriptErrorBase::GetSourceName(nsAString& aResult) { aResult.Assign(mSourceName); return NS_OK; } NS_IMETHODIMP -nsScriptError::GetSourceLine(nsAString& aResult) { +nsScriptErrorBase::GetSourceLine(nsAString& aResult) { aResult.Assign(mSourceLine); return NS_OK; } NS_IMETHODIMP -nsScriptError::GetLineNumber(uint32_t* result) { +nsScriptErrorBase::GetLineNumber(uint32_t* result) { *result = mLineNumber; return NS_OK; } NS_IMETHODIMP -nsScriptError::GetColumnNumber(uint32_t* result) { +nsScriptErrorBase::GetColumnNumber(uint32_t* result) { *result = mColumnNumber; return NS_OK; } NS_IMETHODIMP -nsScriptError::GetFlags(uint32_t* result) { +nsScriptErrorBase::GetFlags(uint32_t* result) { *result = mFlags; return NS_OK; } NS_IMETHODIMP -nsScriptError::GetCategory(char** result) { +nsScriptErrorBase::GetCategory(char** result) { *result = ToNewCString(mCategory); return NS_OK; } NS_IMETHODIMP -nsScriptError::GetStack(JS::MutableHandleValue aStack) { +nsScriptErrorBase::GetStack(JS::MutableHandleValue aStack) { aStack.setUndefined(); return NS_OK; } NS_IMETHODIMP -nsScriptError::SetStack(JS::HandleValue aStack) { +nsScriptErrorBase::SetStack(JS::HandleValue aStack) { return NS_OK; } NS_IMETHODIMP -nsScriptError::Init(const nsAString& message, - const nsAString& sourceName, - const nsAString& sourceLine, - uint32_t lineNumber, - uint32_t columnNumber, - uint32_t flags, - const char* category) +nsScriptErrorBase::Init(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const char* category) { return InitWithWindowID(message, sourceName, sourceLine, lineNumber, columnNumber, flags, @@ -170,14 +168,14 @@ nsScriptError::Init(const nsAString& message, } NS_IMETHODIMP -nsScriptError::InitWithWindowID(const nsAString& message, - const nsAString& sourceName, - const nsAString& sourceLine, - uint32_t lineNumber, - uint32_t columnNumber, - uint32_t flags, - const nsACString& category, - uint64_t aInnerWindowID) +nsScriptErrorBase::InitWithWindowID(const nsAString& message, + const nsAString& sourceName, + const nsAString& sourceLine, + uint32_t lineNumber, + uint32_t columnNumber, + uint32_t flags, + const nsACString& category, + uint64_t aInnerWindowID) { mMessage.Assign(message); mSourceName.Assign(sourceName); @@ -197,7 +195,7 @@ nsScriptError::InitWithWindowID(const nsAString& message, } NS_IMETHODIMP -nsScriptError::ToString(nsACString& /*UTF8*/ aResult) +nsScriptErrorBase::ToString(nsACString& /*UTF8*/ aResult) { static const char format0[] = "[%s: \"%s\" {file: \"%s\" line: %d column: %d source: \"%s\"}]"; @@ -260,7 +258,7 @@ nsScriptError::ToString(nsACString& /*UTF8*/ aResult) } NS_IMETHODIMP -nsScriptError::GetOuterWindowID(uint64_t* aOuterWindowID) +nsScriptErrorBase::GetOuterWindowID(uint64_t* aOuterWindowID) { NS_WARN_IF_FALSE(NS_IsMainThread() || mInitializedOnMainThread, "This can't be safely determined off the main thread, " @@ -275,21 +273,21 @@ nsScriptError::GetOuterWindowID(uint64_t* aOuterWindowID) } NS_IMETHODIMP -nsScriptError::GetInnerWindowID(uint64_t* aInnerWindowID) +nsScriptErrorBase::GetInnerWindowID(uint64_t* aInnerWindowID) { *aInnerWindowID = mInnerWindowID; return NS_OK; } NS_IMETHODIMP -nsScriptError::GetTimeStamp(int64_t* aTimeStamp) +nsScriptErrorBase::GetTimeStamp(int64_t* aTimeStamp) { *aTimeStamp = mTimeStamp; return NS_OK; } NS_IMETHODIMP -nsScriptError::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow) +nsScriptErrorBase::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow) { NS_WARN_IF_FALSE(NS_IsMainThread() || mInitializedOnMainThread, "This can't be safely determined off the main thread, " @@ -302,3 +300,5 @@ nsScriptError::GetIsFromPrivateWindow(bool* aIsFromPrivateWindow) *aIsFromPrivateWindow = mIsFromPrivateWindow; return NS_OK; } + +NS_IMPL_ISUPPORTS(nsScriptError, nsIConsoleMessage, nsIScriptError) diff --git a/js/xpconnect/src/nsScriptErrorWithStack.cpp b/js/xpconnect/src/nsScriptErrorWithStack.cpp index e44418ed243e..a5717bbc8b95 100644 --- a/js/xpconnect/src/nsScriptErrorWithStack.cpp +++ b/js/xpconnect/src/nsScriptErrorWithStack.cpp @@ -6,7 +6,7 @@ /* * nsScriptErrorWithStack implementation. - * a main-thread-only, cycle-collected subclass of nsScriptError + * a main-thread-only, cycle-collected subclass of nsScriptErrorBase * that can store a SavedFrame stack trace object. */ @@ -40,8 +40,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScriptErrorWithStack) NS_INTERFACE_MAP_END nsScriptErrorWithStack::nsScriptErrorWithStack(JS::HandleObject aStack) - : nsScriptError(), - mStack(aStack) + : mStack(aStack) { MOZ_ASSERT(NS_IsMainThread(), "You can't use this class on workers."); mozilla::HoldJSObjects(this); diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 541dbb258947..26ae533daa69 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -771,8 +771,15 @@ nsXPConnect::CreateSandbox(JSContext* cx, nsIPrincipal* principal, NS_IMETHODIMP nsXPConnect::EvalInSandboxObject(const nsAString& source, const char* filename, JSContext* cx, JSObject* sandboxArg, + int32_t jsVersion, MutableHandleValue rval) { +#ifdef DEBUG + { + const char *version = JS_VersionToString(JSVersion(jsVersion)); + MOZ_ASSERT(version && strcmp(version, "unknown") != 0, "Illegal JS version passed"); + } +#endif if (!sandboxArg) return NS_ERROR_INVALID_ARG; @@ -784,7 +791,7 @@ nsXPConnect::EvalInSandboxObject(const nsAString& source, const char* filename, filenameStr = NS_LITERAL_CSTRING("x-bogus://XPConnect/Sandbox"); } return EvalInSandbox(cx, sandbox, source, filenameStr, 1, - JSVERSION_LATEST, rval); + JSVersion(jsVersion), rval); } /* JSObjectPtr getWrappedNativePrototype (in JSContextPtr aJSContext, in JSObjectPtr aScope); */ diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index fbad24cec8c6..fe5bc257c07e 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -2989,18 +2989,17 @@ xpc_PrintJSStack(JSContext* cx, bool showArgs, bool showLocals, // Definition of nsScriptError, defined here because we lack a place to put // XPCOM objects associated with the JavaScript engine. -class nsScriptError : public nsIScriptError { +class nsScriptErrorBase : public nsIScriptError { public: - nsScriptError(); + nsScriptErrorBase(); // TODO - do something reasonable on getting null from these babies. - NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSICONSOLEMESSAGE NS_DECL_NSISCRIPTERROR protected: - virtual ~nsScriptError(); + virtual ~nsScriptErrorBase(); void InitializeOnMainThread(); @@ -3022,7 +3021,16 @@ protected: bool mIsFromPrivateWindow; }; -class nsScriptErrorWithStack : public nsScriptError { +class nsScriptError final : public nsScriptErrorBase { +public: + nsScriptError() {} + NS_DECL_THREADSAFE_ISUPPORTS + +private: + virtual ~nsScriptError() {} +}; + +class nsScriptErrorWithStack : public nsScriptErrorBase { public: explicit nsScriptErrorWithStack(JS::HandleObject); diff --git a/media/webrtc/signaling/src/jsep/JsepCodecDescription.h b/media/webrtc/signaling/src/jsep/JsepCodecDescription.h index f5302a339799..5eefa96be2fb 100644 --- a/media/webrtc/signaling/src/jsep/JsepCodecDescription.h +++ b/media/webrtc/signaling/src/jsep/JsepCodecDescription.h @@ -7,8 +7,8 @@ #include #include -#include #include "signaling/src/sdp/SdpMediaSection.h" +#include "signaling/src/sdp/SdpHelper.h" #include "nsCRT.h" namespace mozilla { @@ -42,47 +42,26 @@ struct JsepCodecDescription { virtual void AddFmtps(SdpFmtpAttributeList& fmtp) const = 0; virtual void AddRtcpFbs(SdpRtcpFbAttributeList& rtcpfb) const = 0; - // TODO(bug 1142105): This probably should be a helper function in - // /sdp - static bool - GetPtAsInt(const std::string& ptString, uint16_t* ptOutparam) - { - char* end; - unsigned long pt = strtoul(ptString.c_str(), &end, 10); - size_t length = static_cast(end - ptString.c_str()); - if ((pt > UINT16_MAX) || (length != ptString.size())) { - return false; - } - *ptOutparam = pt; - return true; - } - bool GetPtAsInt(uint16_t* ptOutparam) const { - return GetPtAsInt(mDefaultPt, ptOutparam); + return SdpHelper::GetPtAsInt(mDefaultPt, ptOutparam); } virtual bool Matches(const std::string& fmt, const SdpMediaSection& remoteMsection) const { - auto& attrs = remoteMsection.GetAttributeList(); - if (!attrs.HasAttribute(SdpAttribute::kRtpmapAttribute)) { + if (mType != remoteMsection.GetMediaType()) { return false; } - const SdpRtpmapAttributeList& rtpmap = attrs.GetRtpmap(); - if (!rtpmap.HasEntry(fmt)) { - return false; - } + const SdpRtpmapAttributeList::Rtpmap* entry(remoteMsection.FindRtpmap(fmt)); - const SdpRtpmapAttributeList::Rtpmap& entry = rtpmap.GetEntry(fmt); - - if (mType == remoteMsection.GetMediaType() - && !nsCRT::strcasecmp(mName.c_str(), entry.name.c_str()) - && (mClock == entry.clock) - && (mChannels == entry.channels)) { - return ParametersMatch(entry.pt, remoteMsection); + if (entry + && !nsCRT::strcasecmp(mName.c_str(), entry->name.c_str()) + && (mClock == entry->clock) + && (mChannels == entry->channels)) { + return ParametersMatch(fmt, remoteMsection); } return false; } @@ -100,25 +79,6 @@ struct JsepCodecDescription { return true; } - // TODO(bug 1142105): This probably should be a helper function in - // /sdp - static const SdpFmtpAttributeList::Parameters* - FindParameters(const std::string& pt, - const mozilla::SdpMediaSection& remoteMsection) - { - const SdpAttributeList& attrs = remoteMsection.GetAttributeList(); - - if (attrs.HasAttribute(SdpAttribute::kFmtpAttribute)) { - const SdpFmtpAttributeList& fmtps = attrs.GetFmtp(); - for (auto i = fmtps.mFmtps.begin(); i != fmtps.mFmtps.end(); ++i) { - if (i->format == pt && i->parameters) { - return i->parameters.get(); - } - } - } - return nullptr; - } - virtual bool LoadSendParameters( const mozilla::SdpMediaSection& remoteMsection) { @@ -307,7 +267,7 @@ struct JsepVideoCodecDescription : public JsepCodecDescription { { // Will contain defaults if nothing else SdpFmtpAttributeList::H264Parameters result; - auto* params = FindParameters(pt, msection); + auto* params = msection.FindFmtp(pt); if (params && params->codec_type == SdpRtpmapAttributeList::kH264) { result = @@ -328,7 +288,7 @@ struct JsepVideoCodecDescription : public JsepCodecDescription { // Will contain defaults if nothing else SdpFmtpAttributeList::VP8Parameters result(expectedType); - auto* params = FindParameters(pt, msection); + auto* params = msection.FindFmtp(pt); if (params && params->codec_type == expectedType) { result = @@ -338,31 +298,6 @@ struct JsepVideoCodecDescription : public JsepCodecDescription { return result; } - static bool - HasRtcpFb(const SdpMediaSection& msection, - const std::string& pt, - SdpRtcpFbAttributeList::Type type, - const std::string& subType) - { - const SdpAttributeList& attrs(msection.GetAttributeList()); - - if (!attrs.HasAttribute(SdpAttribute::kRtcpFbAttribute)) { - return false; - } - - for (auto& rtcpfb : attrs.GetRtcpFb().mFeedbacks) { - if (rtcpfb.type == type) { - if (rtcpfb.pt == "*" || rtcpfb.pt == pt) { - if (rtcpfb.parameter == subType) { - return true; - } - } - } - } - - return false; - } - void NegotiateRtcpFb(const SdpMediaSection& remoteMsection, SdpRtcpFbAttributeList::Type type, @@ -370,7 +305,7 @@ struct JsepVideoCodecDescription : public JsepCodecDescription { { std::vector temp; for (auto& subType : *supportedTypes) { - if (HasRtcpFb(remoteMsection, mDefaultPt, type, subType)) { + if (remoteMsection.HasRtcpFb(mDefaultPt, type, subType)) { temp.push_back(subType); } } @@ -691,20 +626,14 @@ struct JsepApplicationCodecDescription : public JsepCodecDescription { Matches(const std::string& fmt, const SdpMediaSection& remoteMsection) const override { - auto& attrs = remoteMsection.GetAttributeList(); - if (!attrs.HasAttribute(SdpAttribute::kSctpmapAttribute)) { + if (mType != remoteMsection.GetMediaType()) { return false; } - const SdpSctpmapAttributeList& sctpmap = attrs.GetSctpmap(); - if (!sctpmap.HasEntry(fmt)) { - return false; - } + const SdpSctpmapAttributeList::Sctpmap* entry( + remoteMsection.FindSctpmap(fmt)); - const SdpSctpmapAttributeList::Sctpmap& entry = sctpmap.GetEntry(fmt); - - if (mType == remoteMsection.GetMediaType() && - !nsCRT::strcasecmp(mName.c_str(), entry.name.c_str())) { + if (entry && !nsCRT::strcasecmp(mName.c_str(), entry->name.c_str())) { return true; } return false; diff --git a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp index 31bea166515a..0936e397fc25 100644 --- a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp +++ b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp @@ -1762,7 +1762,7 @@ JsepSessionImpl::ParseSdp(const std::string& sdp, UniquePtr* parsedp) auto& formats = parsed->GetMediaSection(i).GetFormats(); for (auto f = formats.begin(); f != formats.end(); ++f) { uint16_t pt; - if (!JsepCodecDescription::GetPtAsInt(*f, &pt)) { + if (!SdpHelper::GetPtAsInt(*f, &pt)) { JSEP_SET_ERROR("Payload type \"" << *f << "\" is not a 16-bit unsigned int at level " << i); diff --git a/media/webrtc/signaling/src/sdp/SdpHelper.cpp b/media/webrtc/signaling/src/sdp/SdpHelper.cpp index 2bb153be949e..87fe42bacb3e 100644 --- a/media/webrtc/signaling/src/sdp/SdpHelper.cpp +++ b/media/webrtc/signaling/src/sdp/SdpHelper.cpp @@ -10,8 +10,9 @@ #include "nsDebug.h" #include "nsError.h" -#include "nspr/prprf.h" +#include "prprf.h" +#include #include namespace mozilla { @@ -590,6 +591,19 @@ SdpHelper::appendSdpParseErrors( *aErrorString += os.str(); } +/* static */ bool +SdpHelper::GetPtAsInt(const std::string& ptString, uint16_t* ptOutparam) +{ + char* end; + unsigned long pt = strtoul(ptString.c_str(), &end, 10); + size_t length = static_cast(end - ptString.c_str()); + if ((pt > UINT16_MAX) || (length != ptString.size())) { + return false; + } + *ptOutparam = pt; + return true; +} + } // namespace mozilla diff --git a/media/webrtc/signaling/src/sdp/SdpHelper.h b/media/webrtc/signaling/src/sdp/SdpHelper.h index fd3c4268b1cd..84b775a3a0cd 100644 --- a/media/webrtc/signaling/src/sdp/SdpHelper.h +++ b/media/webrtc/signaling/src/sdp/SdpHelper.h @@ -5,6 +5,8 @@ #ifndef _SDPHELPER_H_ #define _SDPHELPER_H_ +#include "nsError.h" + #include "signaling/src/sdp/SdpMediaSection.h" #include "signaling/src/sdp/SdpAttribute.h" @@ -88,6 +90,8 @@ class SdpHelper { const std::vector >& aErrors, std::string* aErrorString); + static bool GetPtAsInt(const std::string& ptString, uint16_t* ptOutparam); + private: std::string& mLastError; diff --git a/media/webrtc/signaling/src/sdp/SdpMediaSection.h b/media/webrtc/signaling/src/sdp/SdpMediaSection.h index d4faa9334fc6..398a0037e57d 100644 --- a/media/webrtc/signaling/src/sdp/SdpMediaSection.h +++ b/media/webrtc/signaling/src/sdp/SdpMediaSection.h @@ -148,6 +148,80 @@ public: GetAttributeList().SetAttribute(new SdpDirectionAttribute(direction)); } + const SdpFmtpAttributeList::Parameters* + FindFmtp(const std::string& pt) const + { + const SdpAttributeList& attrs = GetAttributeList(); + + if (attrs.HasAttribute(SdpAttribute::kFmtpAttribute)) { + const SdpFmtpAttributeList& fmtps = attrs.GetFmtp(); + for (auto i = fmtps.mFmtps.begin(); i != fmtps.mFmtps.end(); ++i) { + if (i->format == pt && i->parameters) { + return i->parameters.get(); + } + } + } + return nullptr; + } + + const SdpRtpmapAttributeList::Rtpmap* + FindRtpmap(const std::string& pt) const + { + auto& attrs = GetAttributeList(); + if (!attrs.HasAttribute(SdpAttribute::kRtpmapAttribute)) { + return nullptr; + } + + const SdpRtpmapAttributeList& rtpmap = attrs.GetRtpmap(); + if (!rtpmap.HasEntry(pt)) { + return nullptr; + } + + return &rtpmap.GetEntry(pt); + } + + const SdpSctpmapAttributeList::Sctpmap* + FindSctpmap(const std::string& pt) const + { + auto& attrs = GetAttributeList(); + if (!attrs.HasAttribute(SdpAttribute::kSctpmapAttribute)) { + return nullptr; + } + + const SdpSctpmapAttributeList& sctpmap = attrs.GetSctpmap(); + if (!sctpmap.HasEntry(pt)) { + return nullptr; + } + + return &sctpmap.GetEntry(pt); + } + + bool + HasRtcpFb(const std::string& pt, + SdpRtcpFbAttributeList::Type type, + const std::string& subType) const + { + const SdpAttributeList& attrs(GetAttributeList()); + + if (!attrs.HasAttribute(SdpAttribute::kRtcpFbAttribute)) { + return false; + } + + for (auto& rtcpfb : attrs.GetRtcpFb().mFeedbacks) { + if (rtcpfb.type == type) { + if (rtcpfb.pt == "*" || rtcpfb.pt == pt) { + if (rtcpfb.parameter == subType) { + return true; + } + } + } + } + + return false; + } + + + private: size_t mLevel; }; diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index bc9271cac366..7049120e7563 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -480,10 +480,14 @@ @BINPATH@/components/nsUrlClassifierHashCompleter.js @BINPATH@/components/nsUrlClassifierListManager.js @BINPATH@/components/nsUrlClassifierLib.js -@BINPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js @BINPATH@/components/url-classifier.xpt #endif +; Private Browsing +@BINPATH@/components/privatebrowsing.xpt +@BINPATH@/components/PrivateBrowsing.manifest +@BINPATH@/components/PrivateBrowsingTrackingProtectionWhitelist.js + ; GNOME hooks #ifdef MOZ_ENABLE_GNOME_COMPONENT @BINPATH@/components/@DLL_PREFIX@mozgnome@DLL_SUFFIX@ diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 65af545be48e..e7c7038d15c4 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1766,6 +1766,16 @@ pref("network.automatic-ntlm-auth.allow-proxies", true); pref("network.automatic-ntlm-auth.allow-non-fqdn", false); pref("network.automatic-ntlm-auth.trusted-uris", ""); +// The string to return to the server as the 'workstation' that the +// user is using. Bug 1046421 notes that the previous default, of the +// system hostname, could be used for user fingerprinting. +// +// However, in some network environments where allowedWorkstations is in use +// to provide a level of host-based access control, it must be set to a string +// that is listed in allowedWorkstations for the user's account in their +// AD Domain. +pref("network.generic-ntlm-auth.workstation", "WORKSTATION"); + // Sub-resources HTTP-authentication: // 0 - don't allow sub-resources to open HTTP authentication credentials // dialogs diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 155961030d05..975c920781a7 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -557,6 +557,9 @@ nsIOService::GetProtocolFlags(const char* scheme, uint32_t *flags) nsresult rv = GetProtocolHandler(scheme, getter_AddRefs(handler)); if (NS_FAILED(rv)) return rv; + // We can't call DoGetProtocolFlags here because we don't have a URI. This + // API is used by (and only used by) extensions, which is why it's still + // around. Calling this on a scheme with dynamic flags will throw. rv = handler->GetProtocolFlags(flags); return rv; } @@ -722,7 +725,7 @@ nsIOService::NewChannelFromURIWithProxyFlagsInternal(nsIURI* aURI, return rv; uint32_t protoFlags; - rv = handler->GetProtocolFlags(&protoFlags); + rv = handler->DoGetProtocolFlags(aURI, &protoFlags); if (NS_FAILED(rv)) return rv; @@ -1481,15 +1484,17 @@ nsIOService::ProtocolHasFlags(nsIURI *uri, nsAutoCString scheme; nsresult rv = uri->GetScheme(scheme); NS_ENSURE_SUCCESS(rv, rv); - - uint32_t protocolFlags; - rv = GetProtocolFlags(scheme.get(), &protocolFlags); - if (NS_SUCCEEDED(rv)) { - *result = (protocolFlags & flags) == flags; - } - - return rv; + // Grab the protocol flags from the URI. + uint32_t protocolFlags; + nsCOMPtr handler; + rv = GetProtocolHandler(scheme.get(), getter_AddRefs(handler)); + NS_ENSURE_SUCCESS(rv, rv); + rv = handler->DoGetProtocolFlags(uri, &protocolFlags); + NS_ENSURE_SUCCESS(rv, rv); + + *result = (protocolFlags & flags) == flags; + return NS_OK; } NS_IMETHODIMP diff --git a/netwerk/base/nsIProtocolHandler.idl b/netwerk/base/nsIProtocolHandler.idl index 37a8395a15bf..5bd877238090 100644 --- a/netwerk/base/nsIProtocolHandler.idl +++ b/netwerk/base/nsIProtocolHandler.idl @@ -5,14 +5,34 @@ #include "nsISupports.idl" +%{C++ +#include "nsCOMPtr.h" +%} + interface nsIURI; interface nsIChannel; interface nsILoadInfo; +/** + * nsIProtocolHandlerWithDynamicFlags + * + * Protocols that wish to return different flags depending on the URI should + * implement this interface. + */ +[scriptable, builtinclass, uuid(65a8e823-0591-4fc0-a56a-03265e0a4ce8)] +interface nsIProtocolHandlerWithDynamicFlags : nsISupports +{ + /* + * Returns protocol flags for the given URI, which may be different from the + * flags for another URI of the same scheme. + */ + unsigned long getFlagsForURI(in nsIURI aURI); +}; + /** * nsIProtocolHandler */ -[scriptable, uuid(a7aad716-e72c-435d-82f1-7582dffae661)] +[scriptable, uuid(3393c327-ce70-47f1-9be3-cc312e21c012)] interface nsIProtocolHandler : nsISupports { /** @@ -32,6 +52,15 @@ interface nsIProtocolHandler : nsISupports */ readonly attribute unsigned long protocolFlags; +%{C++ + // Helper method to get the protocol flags in the right way. + nsresult DoGetProtocolFlags(nsIURI* aURI, uint32_t* aFlags) + { + nsCOMPtr dh = do_QueryInterface(this); + return dh ? dh->GetFlagsForURI(aURI, aFlags) : GetProtocolFlags(aFlags); + } +%} + /** * Makes a URI object that is suitable for loading by this protocol, * where the URI string is given as an UTF-8 string. The caller may @@ -258,8 +287,6 @@ interface nsIProtocolHandler : nsISupports * by nsMixedContentBlocker */ const unsigned long URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT = (1<<18); - - }; %{C++ diff --git a/netwerk/base/nsProtocolProxyService.cpp b/netwerk/base/nsProtocolProxyService.cpp index e09166f807ab..fba7c22c0099 100644 --- a/netwerk/base/nsProtocolProxyService.cpp +++ b/netwerk/base/nsProtocolProxyService.cpp @@ -1663,7 +1663,7 @@ nsProtocolProxyService::GetProtocolInfo(nsIURI *uri, nsProtocolInfo *info) if (NS_FAILED(rv)) return rv; - rv = handler->GetProtocolFlags(&info->flags); + rv = handler->DoGetProtocolFlags(uri, &info->flags); if (NS_FAILED(rv)) return rv; diff --git a/netwerk/protocol/res/ExtensionProtocolHandler.cpp b/netwerk/protocol/res/ExtensionProtocolHandler.cpp index 2d6032b98401..fd26152a91db 100644 --- a/netwerk/protocol/res/ExtensionProtocolHandler.cpp +++ b/netwerk/protocol/res/ExtensionProtocolHandler.cpp @@ -6,11 +6,31 @@ #include "ExtensionProtocolHandler.h" +#include "nsIAddonPolicyService.h" +#include "nsServiceManagerUtils.h" + namespace mozilla { NS_IMPL_QUERY_INTERFACE(ExtensionProtocolHandler, nsISubstitutingProtocolHandler, - nsIProtocolHandler, nsISupportsWeakReference) + nsIProtocolHandler, nsIProtocolHandlerWithDynamicFlags, + nsISupportsWeakReference) NS_IMPL_ADDREF_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler) NS_IMPL_RELEASE_INHERITED(ExtensionProtocolHandler, SubstitutingProtocolHandler) +nsresult +ExtensionProtocolHandler::GetFlagsForURI(nsIURI* aURI, uint32_t* aFlags) +{ + // In general a moz-extension URI is only loadable by chrome, but a whitelisted + // subset are web-accessible. Check that whitelist. + nsCOMPtr aps = do_GetService("@mozilla.org/addons/policy-service;1"); + bool loadableByAnyone = false; + if (aps) { + nsresult rv = aps->ExtensionURILoadableByAnyone(aURI, &loadableByAnyone); + NS_ENSURE_SUCCESS(rv, rv); + } + + *aFlags = URI_STD | URI_IS_LOCAL_RESOURCE | (loadableByAnyone ? URI_LOADABLE_BY_ANYONE : URI_DANGEROUS_TO_LOAD); + return NS_OK; +} + } // namespace mozilla diff --git a/netwerk/protocol/res/ExtensionProtocolHandler.h b/netwerk/protocol/res/ExtensionProtocolHandler.h index 7b022b9c7401..48f7c4dfe2df 100644 --- a/netwerk/protocol/res/ExtensionProtocolHandler.h +++ b/netwerk/protocol/res/ExtensionProtocolHandler.h @@ -12,22 +12,33 @@ namespace mozilla { class ExtensionProtocolHandler final : public nsISubstitutingProtocolHandler, + public nsIProtocolHandlerWithDynamicFlags, public mozilla::SubstitutingProtocolHandler, public nsSupportsWeakReference { public: NS_DECL_ISUPPORTS_INHERITED + NS_DECL_NSIPROTOCOLHANDLERWITHDYNAMICFLAGS NS_FORWARD_NSIPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(mozilla::SubstitutingProtocolHandler::) - // In general a moz-extension URI is only loadable by chrome, but a whitelisted - // subset are web-accessible (see nsIAddonPolicyService). - ExtensionProtocolHandler() - : SubstitutingProtocolHandler("moz-extension", URI_STD | URI_DANGEROUS_TO_LOAD | URI_IS_LOCAL_RESOURCE) - {} + ExtensionProtocolHandler() : SubstitutingProtocolHandler("moz-extension") {} protected: ~ExtensionProtocolHandler() {} + + bool ResolveSpecialCases(const nsACString& aHost, const nsACString& aPath, nsACString& aResult) override + { + // Create a special about:blank-like moz-extension://foo/_blank.html for all + // registered extensions. We can't just do this as a substitution because + // substitutions can only match on host. + if (SubstitutingProtocolHandler::HasSubstitution(aHost) && aPath.EqualsLiteral("/_blank.html")) { + aResult.AssignLiteral("about:blank"); + return true; + } + + return false; + } }; } // namespace mozilla diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp index 9bfa1f34424e..6fa355dded04 100644 --- a/netwerk/protocol/res/SubstitutingProtocolHandler.cpp +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.cpp @@ -84,9 +84,23 @@ SubstitutingURL::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc) SubstitutingProtocolHandler::SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags, bool aEnforceFileOrJar) : mScheme(aScheme) - , mFlags(aFlags) , mSubstitutions(16) , mEnforceFileOrJar(aEnforceFileOrJar) +{ + mFlags.emplace(aFlags); + ConstructInternal(); +} + +SubstitutingProtocolHandler::SubstitutingProtocolHandler(const char* aScheme) + : mScheme(aScheme) + , mSubstitutions(16) + , mEnforceFileOrJar(true) +{ + ConstructInternal(); +} + +void +SubstitutingProtocolHandler::ConstructInternal() { nsresult rv; mIOService = do_GetIOService(&rv); @@ -180,7 +194,12 @@ SubstitutingProtocolHandler::GetDefaultPort(int32_t *result) nsresult SubstitutingProtocolHandler::GetProtocolFlags(uint32_t *result) { - *result = mFlags; + if (mFlags.isNothing()) { + NS_WARNING("Trying to get protocol flags the wrong way - use nsIProtocolHandlerWithDynamicFlags instead"); + return NS_ERROR_NOT_AVAILABLE; + } + + *result = mFlags.ref(); return NS_OK; } @@ -328,8 +347,7 @@ nsresult SubstitutingProtocolHandler::HasSubstitution(const nsACString& root, bool *result) { NS_ENSURE_ARG_POINTER(result); - - *result = mSubstitutions.Get(root, nullptr); + *result = HasSubstitution(root); return NS_OK; } @@ -347,6 +365,10 @@ SubstitutingProtocolHandler::ResolveURI(nsIURI *uri, nsACString &result) rv = uri->GetPath(path); if (NS_FAILED(rv)) return rv; + if (ResolveSpecialCases(host, path, result)) { + return NS_OK; + } + // Unescape the path so we can perform some checks on it. nsAutoCString unescapedPath(path); NS_UnescapeURL(unescapedPath); diff --git a/netwerk/protocol/res/SubstitutingProtocolHandler.h b/netwerk/protocol/res/SubstitutingProtocolHandler.h index d3180aadb3c5..1e9f5de251c5 100644 --- a/netwerk/protocol/res/SubstitutingProtocolHandler.h +++ b/netwerk/protocol/res/SubstitutingProtocolHandler.h @@ -13,6 +13,7 @@ #include "nsIOService.h" #include "nsStandardURL.h" #include "mozilla/chrome/RegistryMessageUtils.h" +#include "mozilla/Maybe.h" class nsIIOService; @@ -27,15 +28,19 @@ class SubstitutingProtocolHandler { public: SubstitutingProtocolHandler(const char* aScheme, uint32_t aFlags, bool aEnforceFileOrJar = true); + explicit SubstitutingProtocolHandler(const char* aScheme); NS_INLINE_DECL_REFCOUNTING(SubstitutingProtocolHandler); NS_DECL_NON_VIRTUAL_NSIPROTOCOLHANDLER; NS_DECL_NON_VIRTUAL_NSISUBSTITUTINGPROTOCOLHANDLER; + bool HasSubstitution(const nsACString& aRoot) const { return mSubstitutions.Get(aRoot, nullptr); } + void CollectSubstitutions(InfallibleTArray& aResources); protected: virtual ~SubstitutingProtocolHandler() {} + void ConstructInternal(); void SendSubstitution(const nsACString& aRoot, nsIURI* aBaseURI); @@ -47,11 +52,18 @@ protected: return NS_ERROR_NOT_AVAILABLE; } + // Override this in the subclass to check for special case when resolving URIs + // _before_ checking substitutions. + virtual bool ResolveSpecialCases(const nsACString& aHost, const nsACString& aPath, nsACString& aResult) + { + return false; + } + nsIIOService* IOService() { return mIOService; } private: nsCString mScheme; - uint32_t mFlags; + Maybe mFlags; nsInterfaceHashtable mSubstitutions; nsCOMPtr mIOService; diff --git a/security/manager/ssl/nsNTLMAuthModule.cpp b/security/manager/ssl/nsNTLMAuthModule.cpp index a975f2ccaffe..ed541b158219 100644 --- a/security/manager/ssl/nsNTLMAuthModule.cpp +++ b/security/manager/ssl/nsNTLMAuthModule.cpp @@ -539,7 +539,7 @@ GenerateType3Msg(const nsString &domain, uint32_t *outLen) { // inBuf contains Type-2 msg (the challenge) from server - + MOZ_ASSERT(NS_IsMainThread()); nsresult rv; Type2Msg msg; @@ -557,6 +557,7 @@ GenerateType3Msg(const nsString &domain, #ifdef IS_BIG_ENDIAN nsAutoString ucsDomainBuf, ucsUserBuf; #endif + nsAutoCString hostBuf; nsAutoString ucsHostBuf; // temporary buffers for oem strings nsAutoCString oemDomainBuf, oemUserBuf, oemHostBuf; @@ -615,16 +616,18 @@ GenerateType3Msg(const nsString &domain, } // - // get workstation name (use local machine's hostname) + // get workstation name + // (do not use local machine's hostname after bug 1046421) // - char hostBuf[SYS_INFO_BUFFER_LENGTH]; - if (PR_GetSystemInfo(PR_SI_HOSTNAME, hostBuf, sizeof(hostBuf)) == PR_FAILURE) - return NS_ERROR_UNEXPECTED; - hostLen = strlen(hostBuf); + rv = mozilla::Preferences::GetCString("network.generic-ntlm-auth.workstation", + &hostBuf); + if (NS_FAILED(rv)) { + return rv; + } + if (unicode) { - // hostname is ASCII, so we can do a simple zero-pad expansion: - CopyASCIItoUTF16(nsDependentCString(hostBuf, hostLen), ucsHostBuf); + ucsHostBuf = NS_ConvertUTF8toUTF16(hostBuf); hostPtr = ucsHostBuf.get(); hostLen = ucsHostBuf.Length() * 2; #ifdef IS_BIG_ENDIAN @@ -633,7 +636,10 @@ GenerateType3Msg(const nsString &domain, #endif } else - hostPtr = hostBuf; + { + hostPtr = hostBuf.get(); + hostLen = hostBuf.Length(); + } // // now that we have generated all of the strings, we can allocate outBuf. diff --git a/security/manager/ssl/tests/mochitest/bugs/mochitest.ini b/security/manager/ssl/tests/mochitest/bugs/mochitest.ini deleted file mode 100644 index e18e6979c8d6..000000000000 --- a/security/manager/ssl/tests/mochitest/bugs/mochitest.ini +++ /dev/null @@ -1,6 +0,0 @@ -[DEFAULT] -tags = psm -skip-if = buildapp == 'b2g' || e10s - -[test_bug480509.html] -skip-if = toolkit == 'android' diff --git a/security/manager/ssl/tests/mochitest/bugs/moz.build b/security/manager/ssl/tests/mochitest/bugs/moz.build index 76deffb6d1f3..4b299d0ec79b 100644 --- a/security/manager/ssl/tests/mochitest/bugs/moz.build +++ b/security/manager/ssl/tests/mochitest/bugs/moz.build @@ -4,6 +4,4 @@ # 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/. -MOCHITEST_MANIFESTS += ['mochitest.ini'] MOCHITEST_CHROME_MANIFESTS += ['chrome.ini'] - diff --git a/security/manager/ssl/tests/mochitest/bugs/test_bug480509.html b/security/manager/ssl/tests/mochitest/bugs/test_bug480509.html deleted file mode 100644 index 0d28fc26586d..000000000000 --- a/security/manager/ssl/tests/mochitest/bugs/test_bug480509.html +++ /dev/null @@ -1,84 +0,0 @@ - - - Test bug 483437 and bug 480509 - - - - - - - - - - - diff --git a/security/manager/ssl/tests/unit/moz.build b/security/manager/ssl/tests/unit/moz.build index 2433f5b843f2..04ce30856309 100644 --- a/security/manager/ssl/tests/unit/moz.build +++ b/security/manager/ssl/tests/unit/moz.build @@ -7,6 +7,7 @@ DIRS += ['tlsserver'] TEST_DIRS += [ 'test_cert_eku', + 'test_cert_embedded_null', 'test_cert_keyUsage', 'test_cert_trust', 'test_cert_version', diff --git a/security/manager/ssl/tests/unit/pycert.py b/security/manager/ssl/tests/unit/pycert.py index 77c8a600e40c..d835e58fe91b 100755 --- a/security/manager/ssl/tests/unit/pycert.py +++ b/security/manager/ssl/tests/unit/pycert.py @@ -152,7 +152,10 @@ def stringToCommonName(string): RDN with one AVA consisting of a Common Name encoded as a UTF8String.""" commonName = rfc2459.X520CommonName() - commonName.setComponentByName('utf8String', string) + # The string may have things like '\0' (i.e. a slash followed by + # the number zero) that have to be decoded into the resulting + # '\x00' (i.e. a byte with value zero). + commonName.setComponentByName('utf8String', string.decode(encoding='string_escape')) ava = rfc2459.AttributeTypeAndValue() ava.setComponentByName('type', rfc2459.id_at_commonName) ava.setComponentByName('value', commonName) @@ -333,7 +336,10 @@ class Certificate: count = 0 for dNSName in dNSNames.split(','): generalName = rfc2459.GeneralName() - generalName.setComponentByName('dNSName', dNSName) + # The string may have things like '\0' (i.e. a slash + # followed by the number zero) that have to be decoded into + # the resulting '\x00' (i.e. a byte with value zero). + generalName.setComponentByName('dNSName', dNSName.decode(encoding='string_escape')) subjectAlternativeName.setComponentByPosition(count, generalName) count += 1 self.addExtension(rfc2459.id_ce_subjectAltName, subjectAlternativeName) diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null.js b/security/manager/ssl/tests/unit/test_cert_embedded_null.js new file mode 100644 index 000000000000..4e47675605a3 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_embedded_null.js @@ -0,0 +1,38 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 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/. + +// Tests that a certificate with a clever subject common name like +// 'www.bank1.com[NUL]www.bad-guy.com' (where [NUL] is a single byte with +// value 0) will not be treated as valid for www.bank1.com. +// Includes a similar test case but for the subject alternative name extension. + +"use strict"; + +do_get_profile(); // must be called before getting nsIX509CertDB +const certdb = Cc["@mozilla.org/security/x509certdb;1"] + .getService(Ci.nsIX509CertDB); + +function do_testcase(certname, checkCommonName) { + let cert = constructCertFromFile(`test_cert_embedded_null/${certname}.pem`); + // Where applicable, check that the testcase is meaningful (i.e. that the + // certificate's subject common name has an embedded NUL in it). + if (checkCommonName) { + equal(cert.commonName, "www.bank1.com\\00www.bad-guy.com", + "certificate subject common name should have an embedded NUL byte"); + } + checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN, + certificateUsageSSLServer, {}, "www.bank1.com"); + checkCertErrorGeneric(certdb, cert, SSL_ERROR_BAD_CERT_DOMAIN, + certificateUsageSSLServer, {}, "www.bad-guy.com"); +} + +function run_test() { + addCertFromFile(certdb, "test_cert_embedded_null/ca.pem", "CTu,,"); + + do_testcase("embeddedNull", true); + do_testcase("embeddedNullSAN", false); + do_testcase("embeddedNullCNAndSAN", true); + do_testcase("embeddedNullSAN2", false); +} diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem.certspec new file mode 100644 index 000000000000..6660f5d4783c --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/ca.pem.certspec @@ -0,0 +1,4 @@ +issuer:ca +subject:ca +extension:basicConstraints:cA, +extension:keyUsage:cRLSign,keyCertSign diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem.certspec new file mode 100644 index 000000000000..d1a32349a2f4 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNull.pem.certspec @@ -0,0 +1,2 @@ +issuer:ca +subject:www.bank1.com\0www.bad-guy.com diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem.certspec new file mode 100644 index 000000000000..1029d6cdd048 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullCNAndSAN.pem.certspec @@ -0,0 +1,3 @@ +issuer:ca +subject:www.bank1.com\0www.bad-guy.com +extension:subjectAlternativeName:www.bank1.com\0www.bad-guy.com diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem.certspec new file mode 100644 index 000000000000..f224888eeee9 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN.pem.certspec @@ -0,0 +1,3 @@ +issuer:ca +subject:embedded NUL in SAN +extension:subjectAlternativeName:www.bank1.com\0www.bad-guy.com diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem.certspec b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem.certspec new file mode 100644 index 000000000000..d352d034b6ab --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/embeddedNullSAN2.pem.certspec @@ -0,0 +1,3 @@ +issuer:ca +subject:bad-guy.com +extension:subjectAlternativeName:bad-guy.com,www.bank1.com\0www.bad-guy.com diff --git a/security/manager/ssl/tests/unit/test_cert_embedded_null/moz.build b/security/manager/ssl/tests/unit/test_cert_embedded_null/moz.build new file mode 100644 index 000000000000..f0cefa12aa9a --- /dev/null +++ b/security/manager/ssl/tests/unit/test_cert_embedded_null/moz.build @@ -0,0 +1,21 @@ +# -*- 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/. + +test_certificates = ( + 'ca.pem', + 'embeddedNull.pem', + 'embeddedNullCNAndSAN.pem', + 'embeddedNullSAN.pem', + 'embeddedNullSAN2.pem', +) + +for test_certificate in test_certificates: + input_file = test_certificate + '.certspec' + GENERATED_FILES += [test_certificate] + props = GENERATED_FILES[test_certificate] + props.script = '../pycert.py' + props.inputs = [input_file] + TEST_HARNESS_FILES.xpcshell.security.manager.ssl.tests.unit.test_cert_embedded_null += ['!%s' % test_certificate] diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini index bb79ce3e8c2b..9e7e3049aa52 100644 --- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -16,6 +16,7 @@ support-files = test_cert_trust/** test_cert_version/** test_cert_eku/** + test_cert_embedded_null/** test_ocsp_url/** test_ocsp_fetch_method/** test_keysize/** @@ -102,6 +103,8 @@ run-sequentially = hardcoded ports [test_cert_eku-SA_TS.js] [test_cert_eku-TS.js] +[test_cert_embedded_null.js] + [test_pinning.js] run-sequentially = hardcoded ports # This test can take longer than 300 seconds on B2G emulator debug builds, so diff --git a/testing/marionette/client/marionette/__init__.py b/testing/marionette/client/marionette/__init__.py index 7935ecafdc0a..218d8b1aa100 100644 --- a/testing/marionette/client/marionette/__init__.py +++ b/testing/marionette/client/marionette/__init__.py @@ -3,7 +3,7 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. -__version__ = '0.16' +__version__ = '0.17' from .marionette_test import MarionetteTestCase, MarionetteJSTestCase, CommonTestCase, expectedFailure, skip, SkipTest diff --git a/testing/mozharness/mozharness.json b/testing/mozharness/mozharness.json index ab8b5fde28a1..ea17e11d20f0 100644 --- a/testing/mozharness/mozharness.json +++ b/testing/mozharness/mozharness.json @@ -1,4 +1,4 @@ { "repo": "https://hg.mozilla.org/build/mozharness", - "revision": "8978f498da2b" + "revision": "672af8a8da3e" } diff --git a/testing/mozharness/mozharness/mozilla/testing/gaia_test.py b/testing/mozharness/mozharness/mozilla/testing/gaia_test.py index 5e44697101ca..040b3ccb056f 100644 --- a/testing/mozharness/mozharness/mozilla/testing/gaia_test.py +++ b/testing/mozharness/mozharness/mozilla/testing/gaia_test.py @@ -212,7 +212,10 @@ class GaiaTest(TestingMixin, MercurialScript, TransferMixin, GaiaMixin, BlobUplo """ if code == 0: level = INFO - if passed == 0 or failed > 0: + # We used to check for passed == 0 as well but it can + # be normal to end up with empty chunks especially when + # large amounts of tests are disabled. + if failed > 0: status = 'test failures' tbpl_status = TBPL_WARNING else: diff --git a/testing/mozharness/mozharness/mozilla/testing/talos.py b/testing/mozharness/mozharness/mozilla/testing/talos.py index 29c112ea00a8..45dcf6191006 100755 --- a/testing/mozharness/mozharness/mozilla/testing/talos.py +++ b/testing/mozharness/mozharness/mozilla/testing/talos.py @@ -574,9 +574,6 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin): # XXX temporary python version check python = self.query_python_path() self.run_command([python, "--version"]) - # run talos tests - talos = os.path.join(self.talos_path, 'talos', 'PerfConfigurator.py') - command = [python, talos] + options parser = TalosOutputParser(config=self.config, log_obj=self.log_obj, error_list=TalosErrorList) env = {} @@ -587,15 +584,9 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin): env = self.query_env(partial_env=env, log_level=INFO) # sets a timeout for how long talos should run without output output_timeout = self.config.get('talos_output_timeout', 3600) - # Call PerfConfigurator to generate talos.yml - self.return_code = self.run_command(command, cwd=self.workdir, - output_timeout=output_timeout, - output_parser=parser, - env=env) - # Call run_tests on generated talos.yml + # run talos tests run_tests = os.path.join(self.talos_path, 'talos', 'run_tests.py') - options = "talos.yml" - command = [python, run_tests, '--noisy', '--debug'] + [options] + command = [python, run_tests, '--debug'] + options self.return_code = self.run_command(command, cwd=self.workdir, output_timeout=output_timeout, output_parser=parser, diff --git a/testing/mozharness/scripts/gaia_build_integration.py b/testing/mozharness/scripts/gaia_build_integration.py index b619ef102bfe..32d188ffd26c 100755 --- a/testing/mozharness/scripts/gaia_build_integration.py +++ b/testing/mozharness/scripts/gaia_build_integration.py @@ -31,14 +31,20 @@ class GaiaBuildIntegrationTest(GaiaTest): output_parser = TestSummaryOutputParserHelper( config=self.config, log_obj=self.log_obj, error_list=self.error_list) - code = self.run_command([ + cmd = [ 'make', 'build-test-integration', 'REPORTER=mocha-tbpl-reporter', 'NODE_MODULES_SRC=npm-cache', 'VIRTUALENV_EXISTS=1', 'TRY_ENV=1' - ], cwd=dirs['abs_gaia_dir'], + ] + + # for Mulet + if 'firefox' in self.binary_path: + cmd += ['RUNTIME=%s' % self.binary_path] + + code = self.run_command(cmd, cwd=dirs['abs_gaia_dir'], output_parser=output_parser, output_timeout=600) diff --git a/testing/talos/talos.json b/testing/talos/talos.json index 41a16d16c1be..55c5e1d75787 100644 --- a/testing/talos/talos.json +++ b/testing/talos/talos.json @@ -5,7 +5,7 @@ }, "global": { "talos_repo": "https://hg.mozilla.org/build/talos", - "talos_revision": "e47c566d1c11" + "talos_revision": "85587fddabcd" }, "extra_options": { "android": [ "--apkPath=%(apk_path)s" ] diff --git a/testing/taskcluster/tasks/branches/base_jobs.yml b/testing/taskcluster/tasks/branches/base_jobs.yml index a4e61a693c0c..f76fbafcb6a4 100644 --- a/testing/taskcluster/tasks/branches/base_jobs.yml +++ b/testing/taskcluster/tasks/branches/base_jobs.yml @@ -102,6 +102,8 @@ tests: allowed_build_tasks: tasks/builds/b2g_desktop_opt.yml: task: tasks/tests/b2g_build_test.yml + tasks/builds/mulet_linux.yml: + task: tasks/tests/mulet_build_test.yml gaia-build-unit: allowed_build_tasks: tasks/builds/b2g_desktop_opt.yml: diff --git a/testing/taskcluster/tasks/branches/try/job_flags.yml b/testing/taskcluster/tasks/branches/try/job_flags.yml index f2e2579073ff..e0352ebef697 100644 --- a/testing/taskcluster/tasks/branches/try/job_flags.yml +++ b/testing/taskcluster/tasks/branches/try/job_flags.yml @@ -205,6 +205,8 @@ tests: allowed_build_tasks: tasks/builds/b2g_desktop_opt.yml: task: tasks/tests/b2g_build_test.yml + tasks/builds/mulet_linux.yml: + task: tasks/tests/mulet_build_test.yml gaia-build-unit: allowed_build_tasks: tasks/builds/b2g_desktop_opt.yml: diff --git a/testing/taskcluster/tasks/builds/dbg_macosx64.yml b/testing/taskcluster/tasks/builds/dbg_macosx64.yml new file mode 100644 index 000000000000..a3bcc8876b56 --- /dev/null +++ b/testing/taskcluster/tasks/builds/dbg_macosx64.yml @@ -0,0 +1,22 @@ +$inherits: + from: 'tasks/builds/opt_macosx64.yml' + variables: + build_name: 'macosx64' + build_type: 'dbg' +task: + metadata: + name: '[TC] MacOSX64 Dbg' + description: 'MacOSX64 Dbg' + + workerType: dbg-macosx64 + + payload: + env: + MH_CUSTOM_BUILD_VARIANT_CFG: 'debug' + extra: + treeherder: + groupSymbol: tc + groupName: Submitted by taskcluster + symbol: B + collection: + debug: true diff --git a/testing/taskcluster/tasks/builds/opt_macosx64.yml b/testing/taskcluster/tasks/builds/opt_macosx64.yml new file mode 100644 index 000000000000..93bc9e62cae9 --- /dev/null +++ b/testing/taskcluster/tasks/builds/opt_macosx64.yml @@ -0,0 +1,59 @@ +$inherits: + from: 'tasks/build.yml' + variables: + build_name: 'macosx64' + build_type: 'opt' +task: + metadata: + name: '[TC] MacOSX64 Opt' + description: 'MacOSX64 Opt' + + workerType: opt-macosx64 + + routes: + - 'index.buildbot.branches.{{project}}.macosx64' + - 'index.buildbot.revisions.{{head_rev}}.{{project}}.macosx64' + + scopes: + - 'docker-worker:cache:build-macosx64-workspace' + - 'docker-worker:cache:tooltool-cache' + + payload: + image: '{{#docker_image}}desktop-build{{/docker_image}}' + cache: + build-macosx64-workspace: '/home/worker/workspace' + tooltool-cache: '/home/worker/tooltool-cache' + features: + relengAPIProxy: true + + env: + MOZHARNESS_SCRIPT: 'mozharness/scripts/fx_desktop_build.py' + MOZHARNESS_CONFIG: 'builds/releng_base_mac_cross_builds.py balrog/production.py' + MH_BRANCH: {{project}} + MH_BUILD_POOL: taskcluster + #TODO: bug 1164617 - remove Docker image hacks + LIBRARY_PATH: "" + CPLUS_INCLUDE_PATH: "" + # image paths + TOOLTOOL_CACHE: '/home/worker/tooltool-cache' + DIST_UPLOADS: 'jsshell-mac.zip' + DIST_TARGET_UPLOADS: 'x-test.mac.tar.bz2 mac.dmg mac.json tests.zip crashreporter-symbols.zip' + + maxRunTime: 36000 + + command: ["/bin/bash", "bin/build.sh"] + + extra: + treeherderEnv: + - production + - staging + treeherder: + machine: + # see https://github.com/mozilla/treeherder/blob/master/ui/js/values.js + platform: macosx64 + # Rather then enforcing particular conventions we require that all build + # tasks provide the "build" extra field to specify where the build and tests + # files are located. + locations: + build: 'public/build/target.mac.dmg' + tests: 'public/build/target.tests.zip' diff --git a/testing/taskcluster/tasks/tests/b2g_gaia_js_integration_tests.yml b/testing/taskcluster/tasks/tests/b2g_gaia_js_integration_tests.yml index 8744b765e0dc..c35fb1a325ea 100644 --- a/testing/taskcluster/tasks/tests/b2g_gaia_js_integration_tests.yml +++ b/testing/taskcluster/tasks/tests/b2g_gaia_js_integration_tests.yml @@ -33,7 +33,7 @@ task: extra: chunks: - total: 20 + total: 40 treeherderEnv: - production - staging diff --git a/testing/taskcluster/tasks/tests/mulet_build_test.yml b/testing/taskcluster/tasks/tests/mulet_build_test.yml new file mode 100644 index 000000000000..5cd589be5025 --- /dev/null +++ b/testing/taskcluster/tasks/tests/mulet_build_test.yml @@ -0,0 +1,40 @@ +--- +$inherits: + from: 'tasks/test.yml' +task: + metadata: + name: '[TC] - Gaia Build Test' + description: Gaia Build Test test run + + payload: + command: + - entrypoint # entrypoint ensures we are running in xvfb + - ./bin/pull_gaia.sh && + - > + python ./mozharness/scripts/gaia_build_integration.py + --application firefox + --no-read-buildbot-config + --config-file ./mozharness/configs/b2g/gaia_integration_config.py + --config-file ./mozharness_configs/gaia_integration_override.py + --config-file ./mozharness_configs/remove_executables.py + --installer-url {{build_url}} + --no-pull + --test-packages-url {{test_packages_url}} + --download-symbols ondemand + --gaia-repo https://hg.mozilla.org/integration/gaia-central + --gaia-dir /home/worker + --xre-url https://queue.taskcluster.net/v1/task/wXAHAaxDQpqxoWF1iljJjg/runs/0/artifacts/public/cache/xulrunner-sdk-40.zip + artifacts: + 'public/build': + type: directory + path: '/home/worker/artifacts/' + expires: '{{#from_now}}1 year{{/from_now}}' + + extra: + treeherderEnv: + - production + - staging + treeherder: + groupSymbol: "?" + symbol: 'Gb' + productName: b2g diff --git a/testing/taskcluster/tasks/tests/mulet_gaia_js_integration_tests.yml b/testing/taskcluster/tasks/tests/mulet_gaia_js_integration_tests.yml index a7a880137b83..70c6261b9853 100644 --- a/testing/taskcluster/tasks/tests/mulet_gaia_js_integration_tests.yml +++ b/testing/taskcluster/tasks/tests/mulet_gaia_js_integration_tests.yml @@ -33,7 +33,7 @@ task: extra: chunks: - total: 20 + total: 40 treeherderEnv: - production - staging diff --git a/testing/web-platform/meta/IndexedDB/idbcursor_delete_index5.htm.ini b/testing/web-platform/meta/IndexedDB/idbcursor_delete_index5.htm.ini deleted file mode 100644 index dce07dfa727c..000000000000 --- a/testing/web-platform/meta/IndexedDB/idbcursor_delete_index5.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[idbcursor_delete_index5.htm] - type: testharness - [IDBCursor.delete() - index - throw InvalidStateError when the cursor is being iterated] - expected: FAIL - diff --git a/testing/web-platform/meta/IndexedDB/idbcursor_delete_objectstore5.htm.ini b/testing/web-platform/meta/IndexedDB/idbcursor_delete_objectstore5.htm.ini deleted file mode 100644 index 796251a4efed..000000000000 --- a/testing/web-platform/meta/IndexedDB/idbcursor_delete_objectstore5.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[idbcursor_delete_objectstore5.htm] - type: testharness - [IDBCursor.delete() - object store - throw InvalidStateError when the cursor is being iterated] - expected: FAIL - diff --git a/testing/web-platform/meta/IndexedDB/interfaces.worker.js.ini b/testing/web-platform/meta/IndexedDB/interfaces.worker.js.ini index 7a5477f39d7f..6b87d141aa66 100644 --- a/testing/web-platform/meta/IndexedDB/interfaces.worker.js.ini +++ b/testing/web-platform/meta/IndexedDB/interfaces.worker.js.ini @@ -2,19 +2,3 @@ type: testharness [WorkerUtils interface: attribute indexedDB] expected: FAIL - - [IDBCursorWithValue interface: existence and properties of interface object] - expected: FAIL - - [IDBCursorWithValue interface object length] - expected: FAIL - - [IDBCursorWithValue interface: existence and properties of interface prototype object] - expected: FAIL - - [IDBCursorWithValue interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [IDBCursorWithValue interface: attribute value] - expected: FAIL - diff --git a/testing/web-platform/meta/workers/Worker_ErrorEvent_bubbles_cancelable.htm.ini b/testing/web-platform/meta/workers/Worker_ErrorEvent_bubbles_cancelable.htm.ini deleted file mode 100644 index a2028969439e..000000000000 --- a/testing/web-platform/meta/workers/Worker_ErrorEvent_bubbles_cancelable.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[Worker_ErrorEvent_bubbles_cancelable.htm] - type: testharness - [ErrorEvent on worker doesn't bubble and is cancelable] - expected: FAIL - diff --git a/toolkit/components/moz.build b/toolkit/components/moz.build index e04461c7dcb1..493e396881ff 100644 --- a/toolkit/components/moz.build +++ b/toolkit/components/moz.build @@ -37,6 +37,7 @@ DIRS += [ 'passwordmgr', 'perf', 'places', + 'privatebrowsing', 'processsingleton', 'promiseworker', 'prompts', diff --git a/toolkit/components/privatebrowsing/PrivateBrowsing.manifest b/toolkit/components/privatebrowsing/PrivateBrowsing.manifest new file mode 100644 index 000000000000..36b39bb85ee2 --- /dev/null +++ b/toolkit/components/privatebrowsing/PrivateBrowsing.manifest @@ -0,0 +1,2 @@ +component {a319b616-c45d-4037-8d86-01c592b5a9af} PrivateBrowsingTrackingProtectionWhitelist.js +contract @mozilla.org/pbm-tp-whitelist;1 {a319b616-c45d-4037-8d86-01c592b5a9af} diff --git a/toolkit/components/url-classifier/PrivateBrowsingTrackingProtectionWhitelist.js b/toolkit/components/privatebrowsing/PrivateBrowsingTrackingProtectionWhitelist.js similarity index 100% rename from toolkit/components/url-classifier/PrivateBrowsingTrackingProtectionWhitelist.js rename to toolkit/components/privatebrowsing/PrivateBrowsingTrackingProtectionWhitelist.js diff --git a/toolkit/components/privatebrowsing/moz.build b/toolkit/components/privatebrowsing/moz.build new file mode 100644 index 000000000000..a2df18696eea --- /dev/null +++ b/toolkit/components/privatebrowsing/moz.build @@ -0,0 +1,16 @@ +# -*- 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/. + +XPIDL_SOURCES += [ + 'nsIPrivateBrowsingTrackingProtectionWhitelist.idl', +] + +XPIDL_MODULE = 'privatebrowsing' + +EXTRA_COMPONENTS += [ + 'PrivateBrowsing.manifest', + 'PrivateBrowsingTrackingProtectionWhitelist.js', +] diff --git a/toolkit/components/url-classifier/nsIPrivateBrowsingTrackingProtectionWhitelist.idl b/toolkit/components/privatebrowsing/nsIPrivateBrowsingTrackingProtectionWhitelist.idl similarity index 97% rename from toolkit/components/url-classifier/nsIPrivateBrowsingTrackingProtectionWhitelist.idl rename to toolkit/components/privatebrowsing/nsIPrivateBrowsingTrackingProtectionWhitelist.idl index c3621ce233f9..d572b4e7e15f 100644 --- a/toolkit/components/url-classifier/nsIPrivateBrowsingTrackingProtectionWhitelist.idl +++ b/toolkit/components/privatebrowsing/nsIPrivateBrowsingTrackingProtectionWhitelist.idl @@ -42,5 +42,5 @@ interface nsIPrivateBrowsingTrackingProtectionWhitelist : nsISupports }; %{ C++ -#define NS_PBTRACKINGPROTECTIONWHITELIST_CONTRACTID "@mozilla.org/url-classifier/pbm-tp-whitelist;1" +#define NS_PBTRACKINGPROTECTIONWHITELIST_CONTRACTID "@mozilla.org/pbm-tp-whitelist;1" %} diff --git a/toolkit/components/satchel/AutoCompleteE10S.jsm b/toolkit/components/satchel/AutoCompleteE10S.jsm index 79d4911d66ba..94365e7341ed 100644 --- a/toolkit/components/satchel/AutoCompleteE10S.jsm +++ b/toolkit/components/satchel/AutoCompleteE10S.jsm @@ -93,7 +93,8 @@ this.AutoCompleteE10S = { this.browser = browserWindow.gBrowser.selectedBrowser; this.popup = this.browser.autoCompletePopup; this.popup.hidden = false; - this.popup.setAttribute("width", rect.width); + // don't allow the popup to become overly narrow + this.popup.setAttribute("width", Math.max(100, rect.width)); this.popup.style.direction = direction; this.x = rect.left; diff --git a/toolkit/components/url-classifier/moz.build b/toolkit/components/url-classifier/moz.build index 22a48caea393..169de362426d 100644 --- a/toolkit/components/url-classifier/moz.build +++ b/toolkit/components/url-classifier/moz.build @@ -7,7 +7,6 @@ TEST_DIRS += ['tests'] XPIDL_SOURCES += [ - 'nsIPrivateBrowsingTrackingProtectionWhitelist.idl', 'nsIUrlClassifierDBService.idl', 'nsIUrlClassifierHashCompleter.idl', 'nsIUrlClassifierPrefixSet.idl', @@ -43,7 +42,6 @@ SOURCES += [ EXTRA_COMPONENTS += [ 'nsURLClassifier.manifest', 'nsUrlClassifierHashCompleter.js', - 'PrivateBrowsingTrackingProtectionWhitelist.js', ] # Same as JS components that are run through the pre-processor. diff --git a/toolkit/components/url-classifier/nsURLClassifier.manifest b/toolkit/components/url-classifier/nsURLClassifier.manifest index fa5e41d45548..f035dea80953 100644 --- a/toolkit/components/url-classifier/nsURLClassifier.manifest +++ b/toolkit/components/url-classifier/nsURLClassifier.manifest @@ -4,5 +4,3 @@ component {ca168834-cc00-48f9-b83c-fd018e58cae3} nsUrlClassifierListManager.js contract @mozilla.org/url-classifier/listmanager;1 {ca168834-cc00-48f9-b83c-fd018e58cae3} component {9111de73-9322-4bfc-8b65-2b727f3e6ec8} nsUrlClassifierHashCompleter.js contract @mozilla.org/url-classifier/hashcompleter;1 {9111de73-9322-4bfc-8b65-2b727f3e6ec8} -component {a319b616-c45d-4037-8d86-01c592b5a9af} PrivateBrowsingTrackingProtectionWhitelist.js -contract @mozilla.org/url-classifier/pbm-tp-whitelist;1 {a319b616-c45d-4037-8d86-01c592b5a9af} diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml index e1cdfade39d0..34c2472140bd 100644 --- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -1096,8 +1096,12 @@ case "mouseup": case "mousedown": case "contextmenu": { - if (!this._ignoreMouseEvents) - this._autoScrollPopup.hidePopup(); + if (!this._ignoreMouseEvents) { + // Use a timeout to prevent the mousedown from opening the popup again. + // Ideally, we could use preventDefault here, but contenteditable + // and middlemouse paste don't interact well. See bug 1188536. + setTimeout(() => this._autoScrollPopup.hidePopup(), 0); + } this._ignoreMouseEvents = false; break; } diff --git a/toolkit/library/moz.build b/toolkit/library/moz.build index 8b502852ecd9..9e4dcd7dd3d3 100644 --- a/toolkit/library/moz.build +++ b/toolkit/library/moz.build @@ -356,7 +356,8 @@ if CONFIG['OS_ARCH'] == 'WINNT': 'wbemuuid', 'wintrust', 'wtsapi32', - 'locationapi' + 'locationapi', + 'sapi', ] if CONFIG['ACCESSIBILITY']: OS_LIBS += [ diff --git a/toolkit/modules/PrivateBrowsingUtils.jsm b/toolkit/modules/PrivateBrowsingUtils.jsm index 8eec35dd7808..3690de560922 100644 --- a/toolkit/modules/PrivateBrowsingUtils.jsm +++ b/toolkit/modules/PrivateBrowsingUtils.jsm @@ -52,13 +52,13 @@ this.PrivateBrowsingUtils = { }, addToTrackingAllowlist(aURI) { - let pbmtpWhitelist = Cc["@mozilla.org/url-classifier/pbm-tp-whitelist;1"] + let pbmtpWhitelist = Cc["@mozilla.org/pbm-tp-whitelist;1"] .getService(Ci.nsIPrivateBrowsingTrackingProtectionWhitelist); pbmtpWhitelist.addToAllowList(aURI); }, removeFromTrackingAllowlist(aURI) { - let pbmtpWhitelist = Cc["@mozilla.org/url-classifier/pbm-tp-whitelist;1"] + let pbmtpWhitelist = Cc["@mozilla.org/pbm-tp-whitelist;1"] .getService(Ci.nsIPrivateBrowsingTrackingProtectionWhitelist); pbmtpWhitelist.removeFromAllowList(aURI); }, diff --git a/widget/cocoa/moz.build b/widget/cocoa/moz.build index 4c11eedee108..23ac3de736fe 100644 --- a/widget/cocoa/moz.build +++ b/widget/cocoa/moz.build @@ -69,6 +69,11 @@ SOURCES += [ 'nsCocoaDebugUtils.mm', ] +if not CONFIG['RELEASE_BUILD'] or CONFIG['DEBUG']: + SOURCES += [ + 'nsSandboxViolationSink.mm', + ] + include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' diff --git a/widget/cocoa/nsAppShell.mm b/widget/cocoa/nsAppShell.mm index c89cee92b098..c94245f63295 100644 --- a/widget/cocoa/nsAppShell.mm +++ b/widget/cocoa/nsAppShell.mm @@ -34,6 +34,9 @@ #include "mozilla/HangMonitor.h" #include "GeckoProfiler.h" #include "pratom.h" +#if !defined(RELEASE_BUILD) || defined(DEBUG) +#include "nsSandboxViolationSink.h" +#endif #include #include "nsIDOMWakeLockListener.h" @@ -320,6 +323,13 @@ nsAppShell::Init() CGSSetDebugOptions(0x80000007); } +#if !defined(RELEASE_BUILD) || defined(DEBUG) + if (nsCocoaFeatures::OnMavericksOrLater() && + Preferences::GetBool("security.sandbox.mac.track.violations", false)) { + nsSandboxViolationSink::Start(); + } +#endif + [localPool release]; return rv; @@ -674,6 +684,12 @@ nsAppShell::Exit(void) mTerminated = true; +#if !defined(RELEASE_BUILD) || defined(DEBUG) + if (nsCocoaFeatures::OnMavericksOrLater()) { + nsSandboxViolationSink::Stop(); + } +#endif + // Quoting from Apple's doc on the [NSApplication stop:] method (from their // doc on the NSApplication class): "If this method is invoked during a // modal event loop, it will break that loop but not the main event loop." diff --git a/widget/cocoa/nsSandboxViolationSink.h b/widget/cocoa/nsSandboxViolationSink.h new file mode 100644 index 000000000000..35b5d89af52e --- /dev/null +++ b/widget/cocoa/nsSandboxViolationSink.h @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 20; 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 nsSandboxViolationSink_h_ +#define nsSandboxViolationSink_h_ + +#include + +// Class for tracking sandbox violations. Currently it just logs them to +// stdout and the system console. In the future it may do more. + +// What makes this possible is the fact that Apple' sandboxd calls +// notify_post("com.apple.sandbox.violation.*") whenever it's notified by the +// Sandbox kernel extension of a sandbox violation. We register to receive +// these notifications. But the notifications are empty, and are sent for +// every violation in every process. So we need to do more to get only "our" +// violations, and to find out what kind of violation they were. See the +// implementation of nsSandboxViolationSink::ViolationHandler(). + +#define SANDBOX_VIOLATION_QUEUE_NAME "org.mozilla.sandbox.violation.queue" +#define SANDBOX_VIOLATION_NOTIFICATION_NAME "com.apple.sandbox.violation.*" + +class nsSandboxViolationSink +{ +public: + static void Start(); + static void Stop(); +private: + static void ViolationHandler(); + static int mNotifyToken; + static uint64_t mLastMsgReceived; +}; + +#endif // nsSandboxViolationSink_h_ diff --git a/widget/cocoa/nsSandboxViolationSink.mm b/widget/cocoa/nsSandboxViolationSink.mm new file mode 100644 index 000000000000..fb3710bbd376 --- /dev/null +++ b/widget/cocoa/nsSandboxViolationSink.mm @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 20; 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 "nsSandboxViolationSink.h" + +#include +#include +#include +#include +#include +#include "nsCocoaDebugUtils.h" +#include "mozilla/Preferences.h" + +int nsSandboxViolationSink::mNotifyToken = 0; +uint64_t nsSandboxViolationSink::mLastMsgReceived = 0; + +void +nsSandboxViolationSink::Start() +{ + if (mNotifyToken) { + return; + } + notify_register_dispatch(SANDBOX_VIOLATION_NOTIFICATION_NAME, + &mNotifyToken, + dispatch_queue_create(SANDBOX_VIOLATION_QUEUE_NAME, + DISPATCH_QUEUE_SERIAL), + ^(int token) { ViolationHandler(); }); +} + +void +nsSandboxViolationSink::Stop() +{ + if (!mNotifyToken) { + return; + } + notify_cancel(mNotifyToken); + mNotifyToken = 0; +} + +// We need to query syslogd to find out what violations occurred, and whether +// they were "ours". We can use the Apple System Log facility to do this. +// Besides calling notify_post("com.apple.sandbox.violation.*"), Apple's +// sandboxd also reports all sandbox violations (sent to it by the Sandbox +// kernel extension) to syslogd, which stores them and makes them viewable +// in the system console. This is the database we query. + +// ViolationHandler() is always called on its own secondary thread. This +// makes it unlikely it will interfere with other browser activity. + +void +nsSandboxViolationSink::ViolationHandler() +{ + aslmsg query = asl_new(ASL_TYPE_QUERY); + + asl_set_query(query, ASL_KEY_FACILITY, "com.apple.sandbox", + ASL_QUERY_OP_EQUAL); + + // Only get reports that were generated very recently. + char query_time[30] = {0}; + snprintf(query_time, sizeof(query_time), "%li", time(NULL) - 2); + asl_set_query(query, ASL_KEY_TIME, query_time, + ASL_QUERY_OP_NUMERIC | ASL_QUERY_OP_GREATER_EQUAL); + + // This code is easier to test if we don't just track "our" violations, + // which are (normally) few and far between. For example (for the time + // being at least) four appleeventsd sandbox violations happen every time + // we start the browser in e10s mode. But it makes sense to default to + // only tracking "our" violations. + if (mozilla::Preferences::GetBool( + "security.sandbox.mac.track.violations.oursonly", true)) { + // This makes each of our processes log its own violations. It might + // be better to make the chrome process log all the other processes' + // violations. + char query_pid[20] = {0}; + snprintf(query_pid, sizeof(query_pid), "%u", getpid()); + asl_set_query(query, ASL_KEY_REF_PID, query_pid, ASL_QUERY_OP_EQUAL); + } + + aslresponse response = asl_search(nullptr, query); + + // Each time ViolationHandler() is called we grab as many messages as are + // available. Otherwise we might not get them all. + if (response) { + while (true) { + aslmsg hit = nullptr; + aslmsg found = nullptr; + const char* id_str; + + while ((hit = aslresponse_next(response))) { + // Record the message id to avoid logging the same violation more + // than once. + id_str = asl_get(hit, ASL_KEY_MSG_ID); + uint64_t id_val = atoll(id_str); + if (id_val <= mLastMsgReceived) { + continue; + } + mLastMsgReceived = id_val; + found = hit; + break; + } + if (!found) { + break; + } + + const char* pid_str = asl_get(found, ASL_KEY_REF_PID); + const char* message_str = asl_get(found, ASL_KEY_MSG); + nsCocoaDebugUtils::DebugLog("nsSandboxViolationSink::ViolationHandler(): id %s, pid %s, message %s", + id_str, pid_str, message_str); + } + aslresponse_free(response); + } +} diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index f96dd87da83c..d8ec1b44ba68 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -134,7 +134,7 @@ struct NoteWeakMapChildrenTracer : public JS::CallbackTracer void NoteWeakMapChildrenTracer::onChild(const JS::GCCellPtr& aThing) { - if (aThing.isString()) { + if (aThing.is()) { return; } @@ -168,7 +168,7 @@ NoteWeakMapsTracer::trace(JSObject* aMap, JS::GCCellPtr aKey, // If nothing that could be held alive by this entry is marked gray, return. if ((!aKey || !JS::GCThingIsMarkedGray(aKey)) && MOZ_LIKELY(!mCb.WantAllTraces())) { - if (!aValue || !JS::GCThingIsMarkedGray(aValue) || aValue.isString()) { + if (!aValue || !JS::GCThingIsMarkedGray(aValue) || aValue.is()) { return; } } @@ -188,8 +188,8 @@ NoteWeakMapsTracer::trace(JSObject* aMap, JS::GCCellPtr aKey, } JSObject* kdelegate = nullptr; - if (aKey.isObject()) { - kdelegate = js::GetWeakmapKeyDelegate(aKey.toObject()); + if (aKey.is()) { + kdelegate = js::GetWeakmapKeyDelegate(&aKey.as()); } if (AddToCCKind(aValue.kind())) { @@ -200,7 +200,7 @@ NoteWeakMapsTracer::trace(JSObject* aMap, JS::GCCellPtr aKey, mChildTracer.mKey = aKey; mChildTracer.mKeyDelegate = kdelegate; - if (aValue.isString()) { + if (aValue.is()) { JS_TraceChildren(&mChildTracer, aValue.asCell(), aValue.kind()); } @@ -244,8 +244,8 @@ struct FixWeakMappingGrayBitsTracer : public js::WeakMapTracer aKey = nullptr; } - if (delegateMightNeedMarking && aKey.isObject()) { - JSObject* kdelegate = js::GetWeakmapKeyDelegate(aKey.toObject()); + if (delegateMightNeedMarking && aKey.is()) { + JSObject* kdelegate = js::GetWeakmapKeyDelegate(&aKey.as()); if (kdelegate && !JS::ObjectIsMarkedGray(kdelegate)) { if (JS::UnmarkGrayGCThingRecursively(aKey)) { mAnyMarked = true; @@ -343,21 +343,21 @@ TraversalTracer::onChild(const JS::GCCellPtr& aThing) getTracingEdgeName(buffer, sizeof(buffer)); mCb.NoteNextEdgeName(buffer); } - if (aThing.isObject()) { - mCb.NoteJSObject(aThing.toObject()); + if (aThing.is()) { + mCb.NoteJSObject(&aThing.as()); } else { - mCb.NoteJSScript(aThing.toScript()); + mCb.NoteJSScript(&aThing.as()); } - } else if (aThing.isShape()) { + } else if (aThing.is()) { // The maximum depth of traversal when tracing a Shape is unbounded, due to // the parent pointers on the shape. JS_TraceShapeCycleCollectorChildren(this, aThing); - } else if (aThing.isObjectGroup()) { + } else if (aThing.is()) { // The maximum depth of traversal when tracing an ObjectGroup is unbounded, // due to information attached to the groups which can lead other groups to // be traced. JS_TraceObjectGroupCycleCollectorChildren(this, aThing); - } else if (!aThing.isString()) { + } else if (!aThing.is()) { JS_TraceChildren(this, aThing.asCell(), aThing.kind()); } } @@ -483,8 +483,8 @@ CycleCollectedJSRuntime::DescribeGCThing(bool aIsMarked, JS::GCCellPtr aThing, char name[72]; uint64_t compartmentAddress = 0; - if (aThing.isObject()) { - JSObject* obj = aThing.toObject(); + if (aThing.is()) { + JSObject* obj = &aThing.as(); compartmentAddress = (uint64_t)js::GetObjectCompartment(obj); const js::Class* clasp = js::GetObjectClass(obj); @@ -582,8 +582,8 @@ CycleCollectedJSRuntime::TraverseGCThing(TraverseSelect aTs, JS::GCCellPtr aThin NoteGCThingJSChildren(aThing, aCb); } - if (aThing.isObject()) { - JSObject* obj = aThing.toObject(); + if (aThing.is()) { + JSObject* obj = &aThing.as(); NoteGCThingXPCOMChildren(js::GetObjectClass(obj), obj, aCb); } } @@ -635,7 +635,7 @@ CycleCollectedJSRuntime::TraverseObjectShim(void* aData, JS::GCCellPtr aThing) TraverseObjectShimClosure* closure = static_cast(aData); - MOZ_ASSERT(aThing.isObject()); + MOZ_ASSERT(aThing.is()); closure->self->TraverseGCThing(CycleCollectedJSRuntime::TRAVERSE_CPP, aThing, closure->cb); } diff --git a/xpcom/glue/nsCycleCollectionParticipant.cpp b/xpcom/glue/nsCycleCollectionParticipant.cpp index b0763def432d..ec452e9b013d 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.cpp +++ b/xpcom/glue/nsCycleCollectionParticipant.cpp @@ -23,10 +23,10 @@ nsScriptObjectTracer::NoteJSChild(JS::GCCellPtr aGCThing, const char* aName, nsCycleCollectionTraversalCallback* cb = static_cast(aClosure); NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, aName); - if (aGCThing.isObject()) { - cb->NoteJSObject(aGCThing.toObject()); - } else if (aGCThing.isScript()) { - cb->NoteJSScript(aGCThing.toScript()); + if (aGCThing.is()) { + cb->NoteJSObject(&aGCThing.as()); + } else if (aGCThing.is()) { + cb->NoteJSScript(&aGCThing.as()); } else { MOZ_ASSERT(!mozilla::AddToCCKind(aGCThing.kind())); } @@ -97,33 +97,33 @@ void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); } void TraceCallbackFunc::Trace(JS::TenuredHeap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); + mCallback(JS::GCCellPtr(aPtr->getPtr()), aName, aClosure); } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); } void TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const { - mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); + mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); } diff --git a/xpcom/glue/nsStringAPI.h b/xpcom/glue/nsStringAPI.h index 19279481a7f2..e1b9efae0f74 100644 --- a/xpcom/glue/nsStringAPI.h +++ b/xpcom/glue/nsStringAPI.h @@ -1228,7 +1228,7 @@ public: #ifdef MOZ_USE_CHAR16_WRAPPER explicit NS_ConvertUTF16toUTF8(char16ptr_t aString, uint32_t aLength = UINT32_MAX) - : NS_ConvertUTF16toUTF8(static_cast(aString)) + : NS_ConvertUTF16toUTF8(static_cast(aString), aLength) { } #endif