author | Ryan VanderMeulen <ryanvm@gmail.com> |
Mon, 10 Aug 2015 09:46:20 -0400 | |
changeset 257121 | 86b3b49cae3712b44f0474d9acd8be0ecd85a9b5 |
parent 257120 | 2fcd73fa8a7e713719ae9ce2c04cc6a458d7735a (current diff) |
parent 257066 | c07833808ff1098d9eec76397d4f17881e6c2222 (diff) |
child 257122 | 93338c9fb309dd687dab0eb673783382d21f044a |
push id | 63526 |
push user | kwierso@gmail.com |
push date | Mon, 10 Aug 2015 22:02:03 +0000 |
treeherder | mozilla-inbound@c4ab17503c09 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 42.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -14,17 +14,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -12,17 +12,17 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -14,17 +14,17 @@ <!--original fetch url was git://github.com/apitrace/--> <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/> <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/> <!-- Gonk specific things and forks --> <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/> - <project name="gaia.git" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f", + "git_revision": "fa89e03dc489e79baa0e74cb1d205260c7924caa", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "27c4198462ca807ccff1e51229a77830930eb182", + "revision": "0224f3b60c5bb9d2dcae2d6bc0f125113bbd934f", "repo_path": "integration/gaia-central" }
--- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -12,17 +12,17 @@ <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <!-- Stock Android things --> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/> <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -10,17 +10,17 @@ <!--original fetch url was git://codeaurora.org/--> <remote fetch="https://git.mozilla.org/external/caf" name="caf"/> <!--original fetch url was https://git.mozilla.org/releases--> <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/> <!-- B2G specific things. --> <project name="platform_build" path="build" remote="b2g" revision="05a36844c1046a1eb07d5b1325f85ed741f961ea"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="fa89e03dc489e79baa0e74cb1d205260c7924caa"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/> <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/> <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/> <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/> <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
--- a/browser/confvars.sh +++ b/browser/confvars.sh @@ -61,15 +61,8 @@ MOZ_WEBGL_CONFORMANT=1 MOZ_PAY=1 # Enable activities. These are used for FxOS developers currently. MOZ_ACTIVITIES=1 MOZ_JSDOWNLOADS=1 MOZ_WEBM_ENCODER=1 # Enable checking that add-ons are signed by the trusted root MOZ_ADDON_SIGNING=1 -if test "$MOZ_OFFICIAL_BRANDING"; then - if test "$MOZ_UPDATE_CHANNEL" = "beta" -o \ - "$MOZ_UPDATE_CHANNEL" = "release" -o \ - "$MOZ_UPDATE_CHANNEL" = "esr"; then - MOZ_REQUIRE_SIGNING=1 - fi -fi
--- a/build/clang-plugin/clang-plugin.cpp +++ b/build/clang-plugin/clang-plugin.cpp @@ -45,29 +45,16 @@ public: ASTConsumerPtr makeASTConsumer() { return astMatcher.newASTConsumer(); } private: class ScopeChecker : public MatchFinder::MatchCallback { public: - enum Scope { - eLocal, - eGlobal - }; - ScopeChecker(Scope scope_) : - scope(scope_) {} - virtual void run(const MatchFinder::MatchResult &Result); - private: - Scope scope; - }; - - class NonHeapClassChecker : public MatchFinder::MatchCallback { - public: virtual void run(const MatchFinder::MatchResult &Result); }; class ArithmeticArgChecker : public MatchFinder::MatchCallback { public: virtual void run(const MatchFinder::MatchResult &Result); }; @@ -111,19 +98,17 @@ private: virtual void run(const MatchFinder::MatchResult &Result); }; class ExplicitImplicitChecker : public MatchFinder::MatchCallback { public: virtual void run(const MatchFinder::MatchResult &Result); }; - ScopeChecker stackClassChecker; - ScopeChecker globalClassChecker; - NonHeapClassChecker nonheapClassChecker; + ScopeChecker scopeChecker; ArithmeticArgChecker arithmeticArgChecker; TrivialCtorDtorChecker trivialCtorDtorChecker; NaNExprChecker nanExprChecker; NoAddRefReleaseOnReturnChecker noAddRefReleaseOnReturnChecker; RefCountedInsideLambdaChecker refCountedInsideLambdaChecker; ExplicitOperatorBoolChecker explicitOperatorBoolChecker; NoDuplicateRefCntMemberChecker noDuplicateRefCntMemberChecker; NeedsNoVTableTypeChecker needsNoVTableTypeChecker; @@ -272,16 +257,18 @@ private: }; static CustomTypeAnnotation StackClass = CustomTypeAnnotation("moz_stack_class", "stack"); static CustomTypeAnnotation GlobalClass = CustomTypeAnnotation("moz_global_class", "global"); static CustomTypeAnnotation NonHeapClass = CustomTypeAnnotation("moz_nonheap_class", "non-heap"); +static CustomTypeAnnotation HeapClass = + CustomTypeAnnotation("moz_heap_class", "heap"); static CustomTypeAnnotation MustUse = CustomTypeAnnotation("moz_must_use", "must-use"); class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> { DiagnosticsEngine &Diag; const CompilerInstance &CI; DiagnosticsMatcher matcher; public: @@ -609,34 +596,16 @@ bool typeHasVTable(QualType T) { return offender && offender->hasDefinition() && offender->isDynamicClass(); } } namespace clang { namespace ast_matchers { -/// This matcher will match any class with the stack class assertion or an -/// array of such classes. -AST_MATCHER(QualType, stackClassAggregate) { - return StackClass.hasEffectiveAnnotation(Node); -} - -/// This matcher will match any class with the global class assertion or an -/// array of such classes. -AST_MATCHER(QualType, globalClassAggregate) { - return GlobalClass.hasEffectiveAnnotation(Node); -} - -/// This matcher will match any class with the stack class assertion or an -/// array of such classes. -AST_MATCHER(QualType, nonheapClassAggregate) { - return NonHeapClass.hasEffectiveAnnotation(Node); -} - /// This matcher will match any function declaration that is declared as a heap /// allocator. AST_MATCHER(FunctionDecl, heapAllocator) { return MozChecker::hasCustomAnnotation(&Node, "moz_heap_allocator"); } /// This matcher will match any declaration that is marked as not accepting /// arithmetic expressions in its arguments. @@ -941,64 +910,33 @@ CustomTypeAnnotation::AnnotationReason C } } AnnotationReason Reason = { QualType(), RK_None, nullptr }; Cache[Key] = Reason; return Reason; } -bool isPlacementNew(const CXXNewExpr *expr) { +bool isPlacementNew(const CXXNewExpr *Expr) { // Regular new expressions aren't placement new - if (expr->getNumPlacementArgs() == 0) + if (Expr->getNumPlacementArgs() == 0) return false; - if (MozChecker::hasCustomAnnotation(expr->getOperatorNew(), - "moz_heap_allocator")) + const FunctionDecl *Decl = Expr->getOperatorNew(); + if (Decl && MozChecker::hasCustomAnnotation(Decl, "moz_heap_allocator")) { return false; + } return true; } -DiagnosticsMatcher::DiagnosticsMatcher() - : stackClassChecker(ScopeChecker::eLocal), - globalClassChecker(ScopeChecker::eGlobal) -{ - // Stack class assertion: non-local variables of a stack class are forbidden - // (non-localness checked in the callback) - astMatcher.addMatcher(varDecl(hasType(stackClassAggregate())).bind("node"), - &stackClassChecker); - // Stack class assertion: new stack class is forbidden (unless placement new) - astMatcher.addMatcher(newExpr(hasType(pointerType( - pointee(stackClassAggregate()) - ))).bind("node"), &stackClassChecker); - // Global class assertion: non-global variables of a global class are forbidden - // (globalness checked in the callback) - astMatcher.addMatcher(varDecl(hasType(globalClassAggregate())).bind("node"), - &globalClassChecker); - // Global class assertion: new global class is forbidden - astMatcher.addMatcher(newExpr(hasType(pointerType( - pointee(globalClassAggregate()) - ))).bind("node"), &globalClassChecker); - // Non-heap class assertion: new non-heap class is forbidden (unless placement - // new) - astMatcher.addMatcher(newExpr(hasType(pointerType( - pointee(nonheapClassAggregate()) - ))).bind("node"), &nonheapClassChecker); - - // Any heap allocation function that returns a non-heap or a stack class or - // a global class is definitely doing something wrong - astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(), - returns(pointerType(pointee(nonheapClassAggregate()))))))).bind("node"), - &nonheapClassChecker); - astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(), - returns(pointerType(pointee(stackClassAggregate()))))))).bind("node"), - &stackClassChecker); - - astMatcher.addMatcher(callExpr(callee(functionDecl(allOf(heapAllocator(), - returns(pointerType(pointee(globalClassAggregate()))))))).bind("node"), - &globalClassChecker); +DiagnosticsMatcher::DiagnosticsMatcher() { + astMatcher.addMatcher(varDecl().bind("node"), &scopeChecker); + astMatcher.addMatcher(newExpr().bind("node"), &scopeChecker); + astMatcher.addMatcher(materializeTemporaryExpr().bind("node"), &scopeChecker); + astMatcher.addMatcher(callExpr(callee(functionDecl(heapAllocator()))).bind("node"), + &scopeChecker); astMatcher.addMatcher(callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()), anyOf( hasDescendant(binaryOperator(allOf(binaryArithmeticOperator(), hasLHS(hasDescendant(declRefExpr())), hasRHS(hasDescendant(declRefExpr())) )).bind("node")), hasDescendant(unaryOperator(allOf(unaryArithmeticOperator(), @@ -1082,86 +1020,147 @@ DiagnosticsMatcher::DiagnosticsMatcher() astMatcher.addMatcher( constructorDecl(isInterestingImplicitCtor(), ofClass(allOf(isConcreteClass(), decl().bind("class"))), unless(isMarkedImplicit())).bind("ctor"), &explicitImplicitChecker); } +// These enum variants determine whether an allocation has occured in the code. +enum AllocationVariety { + AV_None, + AV_Global, + AV_Automatic, + AV_Temporary, + AV_Heap, +}; + void DiagnosticsMatcher::ScopeChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "variable of type %0 only valid on the stack"); - unsigned globalID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "variable of type %0 only valid as global"); + // There are a variety of different reasons why something could be allocated + AllocationVariety Variety = AV_None; SourceLocation Loc; QualType T; - if (const VarDecl *d = Result.Nodes.getNodeAs<VarDecl>("node")) { - if (scope == eLocal) { - // Ignore the match if it's a local variable. - if (d->hasLocalStorage()) - return; - } else if (scope == eGlobal) { - // Ignore the match if it's a global variable or a static member of a - // class. The latter is technically not in the global scope, but for the - // use case of classes that intend to avoid introducing static - // initializers that is fine. - if (d->hasGlobalStorage() && !d->isStaticLocal()) - return; + + // Determine the type of allocation which we detected + if (const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node")) { + if (D->hasGlobalStorage()) { + Variety = AV_Global; + } else { + Variety = AV_Automatic; } - - Loc = d->getLocation(); - T = d->getType(); - } else if (const CXXNewExpr *expr = - Result.Nodes.getNodeAs<CXXNewExpr>("node")) { - // If it's placement new, then this match doesn't count. - if (scope == eLocal && isPlacementNew(expr)) - return; - - Loc = expr->getStartLoc(); - T = expr->getAllocatedType(); - } else if (const CallExpr *expr = - Result.Nodes.getNodeAs<CallExpr>("node")) { - Loc = expr->getLocStart(); - T = GetCallReturnType(expr)->getPointeeType(); + T = D->getType(); + Loc = D->getLocStart(); + } else if (const CXXNewExpr *E = Result.Nodes.getNodeAs<CXXNewExpr>("node")) { + // New allocates things on the heap. + // We don't consider placement new to do anything, as it doesn't actually + // allocate the storage, and thus gives us no useful information. + if (!isPlacementNew(E)) { + Variety = AV_Heap; + T = E->getAllocatedType(); + Loc = E->getLocStart(); + } + } else if (const Expr *E = Result.Nodes.getNodeAs<MaterializeTemporaryExpr>("node")) { + Variety = AV_Temporary; + T = E->getType().getUnqualifiedType(); + Loc = E->getLocStart(); + } else if (const CallExpr *E = Result.Nodes.getNodeAs<CallExpr>("node")) { + T = E->getType()->getPointeeType(); + if (!T.isNull()) { + // This will always allocate on the heap, as the heapAllocator() check + // was made in the matcher + Variety = AV_Heap; + Loc = E->getLocStart(); + } } - if (scope == eLocal) { - Diag.Report(Loc, stackID) << T; - StackClass.dumpAnnotationReason(Diag, T, Loc); - } else if (scope == eGlobal) { - Diag.Report(Loc, globalID) << T; - GlobalClass.dumpAnnotationReason(Diag, T, Loc); - } -} + // Error messages for incorrect allocations. + unsigned StackID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "variable of type %0 only valid on the stack"); + unsigned GlobalID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "variable of type %0 only valid as global"); + unsigned HeapID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "variable of type %0 only valid on the heap"); + unsigned NonHeapID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Error, "variable of type %0 is not valid on the heap"); -void DiagnosticsMatcher::NonHeapClassChecker::run( - const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned stackID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "variable of type %0 is not valid on the heap"); + unsigned StackNoteID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Note, "value incorrectly allocated in an automatic variable"); + unsigned GlobalNoteID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Note, "value incorrectly allocated in a global variable"); + unsigned HeapNoteID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Note, "value incorrectly allocated on the heap"); + unsigned TemporaryNoteID = Diag.getDiagnosticIDs()->getCustomDiagID( + DiagnosticIDs::Note, "value incorrectly allocated in a temporary"); + + // Report errors depending on the annotations on the input types. + switch (Variety) { + case AV_None: + return; + + case AV_Global: + if (StackClass.hasEffectiveAnnotation(T)) { + Diag.Report(Loc, StackID) << T; + Diag.Report(Loc, GlobalNoteID); + StackClass.dumpAnnotationReason(Diag, T, Loc); + } + if (HeapClass.hasEffectiveAnnotation(T)) { + Diag.Report(Loc, HeapID) << T; + Diag.Report(Loc, GlobalNoteID); + HeapClass.dumpAnnotationReason(Diag, T, Loc); + } + break; - SourceLocation Loc; - QualType T; - if (const CXXNewExpr *expr = Result.Nodes.getNodeAs<CXXNewExpr>("node")) { - // If it's placement new, then this match doesn't count. - if (isPlacementNew(expr)) - return; - Loc = expr->getLocStart(); - T = expr->getAllocatedType(); - } else if (const CallExpr *expr = Result.Nodes.getNodeAs<CallExpr>("node")) { - Loc = expr->getLocStart(); - T = GetCallReturnType(expr)->getPointeeType(); + case AV_Automatic: + if (GlobalClass.hasEffectiveAnnotation(T)) { + Diag.Report(Loc, GlobalID) << T; + Diag.Report(Loc, StackNoteID); + GlobalClass.dumpAnnotationReason(Diag, T, Loc); + } + if (HeapClass.hasEffectiveAnnotation(T)) { + Diag.Report(Loc, HeapID) << T; + Diag.Report(Loc, StackNoteID); + HeapClass.dumpAnnotationReason(Diag, T, Loc); + } + break; + + case AV_Temporary: + if (GlobalClass.hasEffectiveAnnotation(T)) { + Diag.Report(Loc, GlobalID) << T; + Diag.Report(Loc, TemporaryNoteID); + GlobalClass.dumpAnnotationReason(Diag, T, Loc); + } + if (HeapClass.hasEffectiveAnnotation(T)) { + Diag.Report(Loc, HeapID) << T; + Diag.Report(Loc, TemporaryNoteID); + HeapClass.dumpAnnotationReason(Diag, T, Loc); + } + break; + + case AV_Heap: + if (GlobalClass.hasEffectiveAnnotation(T)) { + Diag.Report(Loc, GlobalID) << T; + Diag.Report(Loc, HeapNoteID); + GlobalClass.dumpAnnotationReason(Diag, T, Loc); + } + if (StackClass.hasEffectiveAnnotation(T)) { + Diag.Report(Loc, StackID) << T; + Diag.Report(Loc, HeapNoteID); + StackClass.dumpAnnotationReason(Diag, T, Loc); + } + if (NonHeapClass.hasEffectiveAnnotation(T)) { + Diag.Report(Loc, NonHeapID) << T; + Diag.Report(Loc, HeapNoteID); + NonHeapClass.dumpAnnotationReason(Diag, T, Loc); + } + break; } - - Diag.Report(Loc, stackID) << T; - NonHeapClass.dumpAnnotationReason(Diag, T, Loc); } void DiagnosticsMatcher::ArithmeticArgChecker::run( const MatchFinder::MatchResult &Result) { DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); unsigned errorID = Diag.getDiagnosticIDs()->getCustomDiagID( DiagnosticIDs::Error, "cannot pass an arithmetic expression of built-in types to %0"); const Expr *expr = Result.Nodes.getNodeAs<Expr>("node");
--- a/build/clang-plugin/tests/TestCustomHeap.cpp +++ b/build/clang-plugin/tests/TestCustomHeap.cpp @@ -18,11 +18,11 @@ void *operator new(size_t x, int qual) M template <typename T> T *customAlloc() MOZ_HEAP_ALLOCATOR { T *arg = static_cast<T*>(malloc(sizeof(T))); return new (arg) T(); } template <typename T> void misuseX(T q) { - X *foo = customAlloc<X>(); // expected-error {{variable of type 'X' is not valid on the heap}} - X *foo2 = new (100) X(); // expected-error {{variable of type 'X' is not valid on the heap}} + X *foo = customAlloc<X>(); // expected-error {{variable of type 'X' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + X *foo2 = new (100) X(); // expected-error {{variable of type 'X' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} }
--- a/build/clang-plugin/tests/TestGlobalClass.cpp +++ b/build/clang-plugin/tests/TestGlobalClass.cpp @@ -10,43 +10,43 @@ struct MOZ_GLOBAL_CLASS Global { template <class T> struct MOZ_GLOBAL_CLASS TemplateClass { T i; }; void gobble(void *) { } void misuseGlobalClass(int len) { - Global notValid; // expected-error {{variable of type 'Global' only valid as global}} - Global alsoNotValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}} expected-note {{'Global [2]' is a global type because it is an array of global type 'Global'}} - static Global notValid2; // expected-error {{variable of type 'Global' only valid as global}} - static Global alsoNotValid2[2]; // expected-error {{variable of type 'Global [2]' only valid as global}} expected-note {{'Global [2]' is a global type because it is an array of global type 'Global'}} + Global notValid; // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}} + Global alsoNotValid[2]; // expected-error {{variable of type 'Global [2]' only valid as global}} expected-note {{'Global [2]' is a global type because it is an array of global type 'Global'}} expected-note {{value incorrectly allocated in an automatic variable}} + static Global valid; + static Global alsoValid[2]; - gobble(¬Valid2); gobble(¬Valid); - gobble(&alsoNotValid2[0]); + gobble(&valid); + gobble(&alsoValid[0]); - gobble(new Global); // expected-error {{variable of type 'Global' only valid as global}} - gobble(new Global[10]); // expected-error {{variable of type 'Global' only valid as global}} - gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid as global}} - gobble(len <= 5 ? ¬Valid2 : new Global); // expected-error {{variable of type 'Global' only valid as global}} + gobble(new Global); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + gobble(new Global[10]); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid as global}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new Global); // expected-error {{variable of type 'Global' only valid as global}} expected-note {{value incorrectly allocated on the heap}} char buffer[sizeof(Global)]; - gobble(new (buffer) Global); // expected-error {{variable of type 'Global' only valid as global}} + gobble(new (buffer) Global); } Global valid; struct RandomClass { Global nonstaticMember; // expected-note {{'RandomClass' is a global type because member 'nonstaticMember' is a global type 'Global'}} static Global staticMember; }; struct MOZ_GLOBAL_CLASS RandomGlobalClass { Global nonstaticMember; static Global staticMember; }; struct BadInherit : Global {}; // expected-note {{'BadInherit' is a global type because it inherits from a global type 'Global'}} struct MOZ_GLOBAL_CLASS GoodInherit : Global {}; void misuseGlobalClassEvenMore(int len) { - BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid as global}} - RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid as global}} + BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}} + RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid as global}} expected-note {{value incorrectly allocated in an automatic variable}} }
new file mode 100644 --- /dev/null +++ b/build/clang-plugin/tests/TestHeapClass.cpp @@ -0,0 +1,64 @@ +#define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class"))) +#define MOZ_IMPLICIT __attribute__((annotate("moz_implicit"))) + +#include <stddef.h> + +struct MOZ_HEAP_CLASS Heap { + int i; + Heap() {} + MOZ_IMPLICIT Heap(int i) {} + Heap(int i, int j) {} + void *operator new(size_t x) throw() { return 0; } + void *operator new(size_t blah, char *buffer) { return buffer; } +}; + +template <class T> +struct MOZ_HEAP_CLASS TemplateClass { + T i; +}; + +void gobble(void *) { } + +void gobbleref(const Heap&) { } + +void misuseHeapClass(int len) { + Heap invalid; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} + Heap alsoInvalid[2]; // expected-error {{variable of type 'Heap [2]' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} expected-note {{'Heap [2]' is a heap type because it is an array of heap type 'Heap'}} + static Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} + static Heap alsoInvalidStatic[2]; // expected-error {{variable of type 'Heap [2]' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} expected-note {{'Heap [2]' is a heap type because it is an array of heap type 'Heap'}} + + gobble(&invalid); + gobble(&invalidStatic); + gobble(&alsoInvalid[0]); + + gobbleref(Heap()); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(Heap(10, 20)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(Heap(10)); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + gobbleref(10); // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a temporary}} + + gobble(new Heap); + gobble(new Heap[10]); + gobble(new TemplateClass<int>); + gobble(len <= 5 ? &invalid : new Heap); + + char buffer[sizeof(Heap)]; + gobble(new (buffer) Heap); +} + +Heap invalidStatic; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} +struct RandomClass { + Heap nonstaticMember; // expected-note {{'RandomClass' is a heap type because member 'nonstaticMember' is a heap type 'Heap'}} + static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} +}; +struct MOZ_HEAP_CLASS RandomHeapClass { + Heap nonstaticMember; + static Heap staticMember; // expected-error {{variable of type 'Heap' only valid on the heap}} expected-note {{value incorrectly allocated in a global variable}} +}; + +struct BadInherit : Heap {}; // expected-note {{'BadInherit' is a heap type because it inherits from a heap type 'Heap'}} +struct MOZ_HEAP_CLASS GoodInherit : Heap {}; + +void useStuffWrongly() { + BadInherit i; // expected-error {{variable of type 'BadInherit' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} + RandomClass r; // expected-error {{variable of type 'RandomClass' only valid on the heap}} expected-note {{value incorrectly allocated in an automatic variable}} +}
--- a/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp +++ b/build/clang-plugin/tests/TestInheritTypeAnnotationsFromTemplateArgs.cpp @@ -5,13 +5,13 @@ class Normal {}; class MOZ_STACK_CLASS Stack {}; class IndirectStack : Stack {}; // expected-note {{'IndirectStack' is a stack type because it inherits from a stack type 'Stack'}} template<class T> class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS Template {}; // expected-note 2 {{'Template<Stack>' is a stack type because it has a template argument stack type 'Stack'}} expected-note {{'Template<IndirectStack>' is a stack type because it has a template argument stack type 'IndirectStack'}} class IndirectTemplate : Template<Stack> {}; // expected-note {{'IndirectTemplate' is a stack type because it inherits from a stack type 'Template<Stack>'}} -static Template<Stack> a; // expected-error {{variable of type 'Template<Stack>' only valid on the stack}} -static Template<IndirectStack> b; // expected-error {{variable of type 'Template<IndirectStack>' only valid on the stack}} +static Template<Stack> a; // expected-error {{variable of type 'Template<Stack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +static Template<IndirectStack> b; // expected-error {{variable of type 'Template<IndirectStack>' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} static Template<Normal> c; -static IndirectTemplate d; // expected-error {{variable of type 'IndirectTemplate' only valid on the stack}} +static IndirectTemplate d; // expected-error {{variable of type 'IndirectTemplate' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
--- a/build/clang-plugin/tests/TestMultipleAnnotations.cpp +++ b/build/clang-plugin/tests/TestMultipleAnnotations.cpp @@ -1,14 +1,14 @@ #define MOZ_MUST_USE __attribute__((annotate("moz_must_use"))) #define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) class MOZ_MUST_USE MOZ_STACK_CLASS TestClass {}; -TestClass foo; // expected-error {{variable of type 'TestClass' only valid on the stack}} +TestClass foo; // expected-error {{variable of type 'TestClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} TestClass f() { TestClass bar; return bar; } void g()
--- a/build/clang-plugin/tests/TestNonHeapClass.cpp +++ b/build/clang-plugin/tests/TestNonHeapClass.cpp @@ -20,20 +20,20 @@ void misuseNonHeapClass(int len) { NonHeap alsoValid[2]; static NonHeap validStatic; static NonHeap alsoValidStatic[2]; gobble(&valid); gobble(&validStatic); gobble(&alsoValid[0]); - gobble(new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} - gobble(new NonHeap[10]); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} - gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' is not valid on the heap}} - gobble(len <= 5 ? &valid : new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} + gobble(new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(new NonHeap[10]); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new NonHeap); // expected-error {{variable of type 'NonHeap' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} char buffer[sizeof(NonHeap)]; gobble(new (buffer) NonHeap); } NonHeap validStatic; struct RandomClass { NonHeap nonstaticMember; // expected-note {{'RandomClass' is a non-heap type because member 'nonstaticMember' is a non-heap type 'NonHeap'}} @@ -43,20 +43,20 @@ struct MOZ_NONHEAP_CLASS RandomNonHeapCl NonHeap nonstaticMember; static NonHeap staticMember; }; struct BadInherit : NonHeap {}; // expected-note {{'BadInherit' is a non-heap type because it inherits from a non-heap type 'NonHeap'}} struct MOZ_NONHEAP_CLASS GoodInherit : NonHeap {}; void useStuffWrongly() { - gobble(new BadInherit); // expected-error {{variable of type 'BadInherit' is not valid on the heap}} - gobble(new RandomClass); // expected-error {{variable of type 'RandomClass' is not valid on the heap}} + gobble(new BadInherit); // expected-error {{variable of type 'BadInherit' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} + gobble(new RandomClass); // expected-error {{variable of type 'RandomClass' is not valid on the heap}} expected-note {{value incorrectly allocated on the heap}} } // Stack class overrides non-heap typees. struct MOZ_STACK_CLASS StackClass {}; struct MOZ_NONHEAP_CLASS InferredStackClass : GoodInherit { NonHeap nonstaticMember; StackClass stackClass; // expected-note {{'InferredStackClass' is a stack type because member 'stackClass' is a stack type 'StackClass'}} }; -InferredStackClass global; // expected-error {{variable of type 'InferredStackClass' only valid on the stack}} +InferredStackClass global; // expected-error {{variable of type 'InferredStackClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
--- a/build/clang-plugin/tests/TestStackClass.cpp +++ b/build/clang-plugin/tests/TestStackClass.cpp @@ -12,39 +12,39 @@ struct MOZ_STACK_CLASS TemplateClass { T i; }; void gobble(void *) { } void misuseStackClass(int len) { Stack valid; Stack alsoValid[2]; - static Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} - static Stack alsoNotValid[2]; // expected-error {{variable of type 'Stack [2]' only valid on the stack}} expected-note {{'Stack [2]' is a stack type because it is an array of stack type 'Stack'}} + static Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} + static Stack alsoNotValid[2]; // expected-error {{variable of type 'Stack [2]' only valid on the stack}} expected-note {{'Stack [2]' is a stack type because it is an array of stack type 'Stack'}} expected-note {{value incorrectly allocated in a global variable}} gobble(&valid); gobble(¬Valid); gobble(&alsoValid[0]); - gobble(new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} - gobble(new Stack[10]); // expected-error {{variable of type 'Stack' only valid on the stack}} - gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid on the stack}} - gobble(len <= 5 ? &valid : new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} + gobble(new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + gobble(new Stack[10]); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + gobble(new TemplateClass<int>); // expected-error {{variable of type 'TemplateClass<int>' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} + gobble(len <= 5 ? &valid : new Stack); // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated on the heap}} char buffer[sizeof(Stack)]; gobble(new (buffer) Stack); } -Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} +Stack notValid; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} struct RandomClass { Stack nonstaticMember; // expected-note {{'RandomClass' is a stack type because member 'nonstaticMember' is a stack type 'Stack'}} - static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} + static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} }; struct MOZ_STACK_CLASS RandomStackClass { Stack nonstaticMember; - static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} + static Stack staticMember; // expected-error {{variable of type 'Stack' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} }; struct BadInherit : Stack {}; // expected-note {{'BadInherit' is a stack type because it inherits from a stack type 'Stack'}} struct MOZ_STACK_CLASS GoodInherit : Stack {}; -BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid on the stack}} -RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid on the stack}} +BadInherit moreInvalid; // expected-error {{variable of type 'BadInherit' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}} +RandomClass evenMoreInvalid; // expected-error {{variable of type 'RandomClass' only valid on the stack}} expected-note {{value incorrectly allocated in a global variable}}
--- a/build/clang-plugin/tests/moz.build +++ b/build/clang-plugin/tests/moz.build @@ -4,16 +4,17 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. SOURCES += [ 'TestBadImplicitConversionCtor.cpp', 'TestCustomHeap.cpp', 'TestExplicitOperatorBool.cpp', 'TestGlobalClass.cpp', + 'TestHeapClass.cpp', 'TestInheritTypeAnnotationsFromTemplateArgs.cpp', 'TestMultipleAnnotations.cpp', 'TestMustOverride.cpp', 'TestMustUse.cpp', 'TestNANTestingExpr.cpp', 'TestNANTestingExprC.c', 'TestNeedsNoVTableType.cpp', 'TestNoAddRefReleaseOnReturn.cpp',
--- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -164,17 +164,17 @@ GetWindowURI(nsIDOMWindow *aWindow) static void AppendWindowURI(nsGlobalWindow *aWindow, nsACString& aStr, bool aAnonymize) { nsCOMPtr<nsIURI> uri = GetWindowURI(aWindow); if (uri) { if (aAnonymize && !aWindow->IsChromeWindow()) { - aStr.AppendPrintf("<anonymized-%d>", aWindow->WindowID()); + aStr.AppendPrintf("<anonymized-%llu>", aWindow->WindowID()); } else { nsCString spec; uri->GetSpec(spec); // A hack: replace forward slashes with '\\' so they aren't // treated as path separators. Users of the reporters // (such as about:memory) have to undo this change. spec.ReplaceChar('/', '\\'); @@ -273,19 +273,17 @@ CollectWindowReports(nsGlobalWindow *aWi } } windowPath += NS_LITERAL_CSTRING("window-objects/"); if (top) { windowPath += NS_LITERAL_CSTRING("top("); AppendWindowURI(top, windowPath, aAnonymize); - windowPath += NS_LITERAL_CSTRING(", id="); - windowPath.AppendInt(top->WindowID()); - windowPath += NS_LITERAL_CSTRING(")"); + windowPath.AppendPrintf(", id=%llu)", top->WindowID()); aTopWindowPaths->Put(aWindow->WindowID(), windowPath); windowPath += aWindow->IsFrozen() ? NS_LITERAL_CSTRING("/cached/") : NS_LITERAL_CSTRING("/active/"); } else { if (aGhostWindowIDs->Contains(aWindow->WindowID())) { windowPath += NS_LITERAL_CSTRING("top(none)/ghost/");
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp +++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp @@ -36,19 +36,16 @@ #include "BluetoothReplyRunnable.h" #include "BluetoothUtils.h" #include "BluetoothUuid.h" #include "mozilla/dom/bluetooth/BluetoothTypes.h" #include "mozilla/ipc/SocketBase.h" #include "mozilla/StaticMutex.h" #include "mozilla/StaticPtr.h" #include "mozilla/unused.h" -#ifndef MOZ_B2G_BT_API_V1 -#include "nsDataHashtable.h" -#endif #define ENSURE_BLUETOOTH_IS_READY(runnable, result) \ do { \ if (!sBtInterface || !IsEnabled()) { \ DispatchReplyError(runnable, \ NS_LITERAL_STRING("Bluetooth is not ready")); \ return result; \ } \ @@ -84,57 +81,18 @@ // Rendering: Major service class = 0x20 (Bit 18 is set) #define SET_RENDERING_BIT(cod) (cod |= 0x40000) #endif using namespace mozilla; using namespace mozilla::ipc; USING_BLUETOOTH_NAMESPACE -static nsString sAdapterBdAddress; -static nsString sAdapterBdName; - -static bool sAdapterDiscoverable(false); -static bool sAdapterDiscovering(false); - -// InfallibleTArray is an alias for nsTArray. -static InfallibleTArray<nsString> sAdapterBondedAddressArray; - static BluetoothInterface* sBtInterface; - static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray; -static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack; -static nsTArray<int> sRequestedDeviceCountArray; - -static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray; -static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray; - -static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray; -static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray; -static bool sIsRestart(false); -static bool sIsFirstTimeToggleOffBt(false); - -#ifndef MOZ_B2G_BT_API_V1 -static bool sAdapterEnabled(false); - -// Static hash table to map device name from address -static nsDataHashtable<nsStringHashKey, nsString> sDeviceNameMap; - -static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeAdapterStateRunnableArray; -static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray; -static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sFetchUuidsRunnableArray; -#else -// Missing in Bluetooth v1 -#endif - -#ifndef MOZ_B2G_BT_API_V1 -// Missing in Bluetooth v2 -#else -static uint32_t sAdapterDiscoverableTimeout(0); -#endif /* * Static methods */ ControlPlayStatus BluetoothServiceBluedroid::PlayStatusStringToControlPlayStatus( const nsAString& aPlayStatus) @@ -344,18 +302,18 @@ public: BluetoothGattManager::InitGattInterface #else // Missing in Bluetooth v1 #endif }; MOZ_ASSERT(NS_IsMainThread()); - // Register all the bluedroid callbacks before enable() get called - // It is required to register a2dp callbacks before a2dp media task starts up. + // Register all the bluedroid callbacks before enable() gets called. This is + // required to register a2dp callbacks before a2dp media task starts up. // If any interface cannot be initialized, turn on bluetooth core anyway. nsRefPtr<ProfileInitResultHandler> res = new ProfileInitResultHandler(MOZ_ARRAY_LENGTH(sInitManager)); for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sInitManager); ++i) { sInitManager[i](res); } } @@ -430,46 +388,57 @@ BluetoothServiceBluedroid::StopGonkBluet return NS_OK; } /* * Member functions */ BluetoothServiceBluedroid::BluetoothServiceBluedroid() + : mEnabled(false) + , mDiscoverable(false) + , mDiscovering(false) +#ifndef MOZ_B2G_BT_API_V1 + // Missing in Bluetooth v2 +#else + , mDiscoverableTimeout(0) +#endif + , mIsRestart(false) + , mIsFirstTimeToggleOffBt(false) { sBtInterface = BluetoothInterface::GetInstance(); if (!sBtInterface) { BT_LOGR("Error! Failed to get instance of bluetooth interface"); + return; } } BluetoothServiceBluedroid::~BluetoothServiceBluedroid() { } #ifndef MOZ_B2G_BT_API_V1 nsresult BluetoothServiceBluedroid::StartInternal(BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); // aRunnable will be a nullptr while startup if (aRunnable) { - sChangeAdapterStateRunnableArray.AppendElement(aRunnable); + mChangeAdapterStateRunnables.AppendElement(aRunnable); } nsresult ret = StartGonkBluetooth(); if (NS_FAILED(ret)) { BluetoothService::AcknowledgeToggleBt(false); // Reject Promise if (aRunnable) { DispatchReplyError(aRunnable, NS_LITERAL_STRING("StartBluetoothError")); - sChangeAdapterStateRunnableArray.RemoveElement(aRunnable); + mChangeAdapterStateRunnables.RemoveElement(aRunnable); } BT_LOGR("Error"); } return ret; } @@ -501,27 +470,27 @@ BluetoothServiceBluedroid::StopInternal( } else if (!profileName.EqualsLiteral("OPP") && !profileName.EqualsLiteral("PBAP")) { sProfiles[i]->Reset(); } } // aRunnable will be a nullptr during starup and shutdown if (aRunnable) { - sChangeAdapterStateRunnableArray.AppendElement(aRunnable); + mChangeAdapterStateRunnables.AppendElement(aRunnable); } nsresult ret = StopGonkBluetooth(); if (NS_FAILED(ret)) { BluetoothService::AcknowledgeToggleBt(true); // Reject Promise if (aRunnable) { DispatchReplyError(aRunnable, NS_LITERAL_STRING("StopBluetoothError")); - sChangeAdapterStateRunnableArray.RemoveElement(aRunnable); + mChangeAdapterStateRunnables.RemoveElement(aRunnable); } BT_LOGR("Error"); } return ret; } #else @@ -790,104 +759,115 @@ BluetoothServiceBluedroid::GetAdaptersIn */ BluetoothValue adaptersProperties = InfallibleTArray<BluetoothNamedValue>(); uint32_t numAdapters = 1; // Bluedroid supports single adapter only for (uint32_t i = 0; i < numAdapters; i++) { BluetoothValue properties = InfallibleTArray<BluetoothNamedValue>(); BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(), - "State", sAdapterEnabled); + "State", mEnabled); BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(), - "Address", sAdapterBdAddress); + "Address", mBdAddress); BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(), - "Name", sAdapterBdName); + "Name", mBdName); BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(), - "Discoverable", sAdapterDiscoverable); + "Discoverable", mDiscoverable); BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(), - "Discovering", sAdapterDiscovering); + "Discovering", mDiscovering); BT_APPEND_NAMED_VALUE(properties.get_ArrayOfBluetoothNamedValue(), - "PairedDevices", sAdapterBondedAddressArray); + "PairedDevices", mBondedAddresses); BT_APPEND_NAMED_VALUE(adaptersProperties.get_ArrayOfBluetoothNamedValue(), "Adapter", properties); } DispatchReplySuccess(aRunnable, adaptersProperties); return NS_OK; } #else nsresult BluetoothServiceBluedroid::GetDefaultAdapterPathInternal( BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); - // Since Atomic<*> is not acceptable for BT_APPEND_NAMED_VALUE(), - // create another variable to store data. - bool discoverable = sAdapterDiscoverable; - uint32_t discoverableTimeout = sAdapterDiscoverableTimeout; - BluetoothValue v = InfallibleTArray<BluetoothNamedValue>(); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), - "Address", sAdapterBdAddress); + "Address", mBdAddress); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), - "Name", sAdapterBdName); + "Name", mBdName); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), - "Discoverable", discoverable); + "Discoverable", mDiscoverable); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), - "DiscoverableTimeout", discoverableTimeout); + "DiscoverableTimeout", mDiscoverableTimeout); BT_APPEND_NAMED_VALUE(v.get_ArrayOfBluetoothNamedValue(), - "Devices", sAdapterBondedAddressArray); + "Devices", mBondedAddresses); DispatchReplySuccess(aRunnable, v); return NS_OK; } #endif +class BluetoothServiceBluedroid::GetDeviceRequest final +{ +public: + GetDeviceRequest(int aDeviceCount, BluetoothReplyRunnable* aRunnable) + : mDeviceCount(aDeviceCount) + , mRunnable(aRunnable) + { } + + int mDeviceCount; + InfallibleTArray<BluetoothNamedValue> mDevicesPack; + nsRefPtr<BluetoothReplyRunnable> mRunnable; +}; + class BluetoothServiceBluedroid::GetRemoteDevicePropertiesResultHandler final : public BluetoothResultHandler { public: - GetRemoteDevicePropertiesResultHandler(const nsAString& aDeviceAddress) - : mDeviceAddress(aDeviceAddress) + GetRemoteDevicePropertiesResultHandler( + nsTArray<GetDeviceRequest>& aRequests, + const nsAString& aDeviceAddress) + : mRequests(aRequests) + , mDeviceAddress(aDeviceAddress) { } void OnError(BluetoothStatus aStatus) override { MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mRequests.IsEmpty()); BT_WARNING("GetRemoteDeviceProperties(%s) failed: %d", NS_ConvertUTF16toUTF8(mDeviceAddress).get(), aStatus); - /* dispatch result after final pending operation */ - if (--sRequestedDeviceCountArray[0] == 0) { - if (!sGetDeviceRunnableArray.IsEmpty()) { + /* Dispatch result after the final pending operation */ + if (--mRequests[0].mDeviceCount == 0) { + if (mRequests[0].mRunnable) { #ifndef MOZ_B2G_BT_API_V1 - DispatchReplyError(sGetDeviceRunnableArray[0], + DispatchReplyError(mRequests[0].mRunnable, NS_LITERAL_STRING("GetRemoteDeviceProperties failed")); #else - DispatchReplySuccess(sGetDeviceRunnableArray[0], sRemoteDevicesPack); + DispatchReplySuccess(mRequests[0].mRunnable, + mRequests[0].mDevicesPack); #endif - sGetDeviceRunnableArray.RemoveElementAt(0); } - - sRequestedDeviceCountArray.RemoveElementAt(0); - sRemoteDevicesPack.Clear(); + mRequests.RemoveElementAt(0); } } private: + nsTArray<GetDeviceRequest> mRequests; nsString mDeviceAddress; }; nsresult BluetoothServiceBluedroid::GetConnectedDevicePropertiesInternal( uint16_t aServiceUuid, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); @@ -896,89 +876,83 @@ BluetoothServiceBluedroid::GetConnectedD BluetoothProfileManagerBase* profile = BluetoothUuidHelper::GetBluetoothProfileManager(aServiceUuid); if (!profile) { DispatchReplyError(aRunnable, NS_LITERAL_STRING(ERR_UNKNOWN_PROFILE)); return NS_OK; } - nsTArray<nsString> deviceAddresses; - if (profile->IsConnected()) { - nsString address; - profile->GetAddress(address); - deviceAddresses.AppendElement(address); - } - - int requestedDeviceCount = deviceAddresses.Length(); - if (requestedDeviceCount == 0) { - InfallibleTArray<BluetoothNamedValue> emptyArr; - DispatchReplySuccess(aRunnable, emptyArr); + // Reply success if no device of this profile is connected + if (!profile->IsConnected()) { + DispatchReplySuccess(aRunnable, InfallibleTArray<BluetoothNamedValue>()); return NS_OK; } - sRequestedDeviceCountArray.AppendElement(requestedDeviceCount); - sGetDeviceRunnableArray.AppendElement(aRunnable); - - for (int i = 0; i < requestedDeviceCount; i++) { - // Retrieve all properties of devices - sBtInterface->GetRemoteDeviceProperties(deviceAddresses[i], - new GetRemoteDevicePropertiesResultHandler(deviceAddresses[i])); - } + // Get address of the connected device + nsString address; + profile->GetAddress(address); + + // Append request of the connected device + GetDeviceRequest request(1, aRunnable); + mGetDeviceRequests.AppendElement(request); + + sBtInterface->GetRemoteDeviceProperties(address, + new GetRemoteDevicePropertiesResultHandler(mGetDeviceRequests, address)); return NS_OK; } nsresult BluetoothServiceBluedroid::GetPairedDevicePropertiesInternal( const nsTArray<nsString>& aDeviceAddress, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); - int requestedDeviceCount = aDeviceAddress.Length(); - + if (aDeviceAddress.IsEmpty()) { #ifndef MOZ_B2G_BT_API_V1 - if (requestedDeviceCount == 0) { DispatchReplySuccess(aRunnable); +#else + DispatchReplySuccess(aRunnable, InfallibleTArray<BluetoothNamedValue>()); +#endif return NS_OK; } -#else - if (requestedDeviceCount == 0) { - DispatchReplySuccess(aRunnable, InfallibleTArray<BluetoothNamedValue>()); - return NS_OK; - } - - sRequestedDeviceCountArray.AppendElement(requestedDeviceCount); - sGetDeviceRunnableArray.AppendElement(aRunnable); -#endif - - for (int i = 0; i < requestedDeviceCount; i++) { + + // Append request of all paired devices + GetDeviceRequest request(aDeviceAddress.Length(), aRunnable); + mGetDeviceRequests.AppendElement(request); + + for (uint8_t i = 0; i < aDeviceAddress.Length(); i++) { // Retrieve all properties of devices sBtInterface->GetRemoteDeviceProperties(aDeviceAddress[i], - new GetRemoteDevicePropertiesResultHandler(aDeviceAddress[i])); + new GetRemoteDevicePropertiesResultHandler(mGetDeviceRequests, + aDeviceAddress[i])); } return NS_OK; } class BluetoothServiceBluedroid::StartDiscoveryResultHandler final : public BluetoothResultHandler { public: - StartDiscoveryResultHandler(BluetoothReplyRunnable* aRunnable) - : mRunnable(aRunnable) + StartDiscoveryResultHandler( + nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray, + BluetoothReplyRunnable* aRunnable) + : mRunnableArray(aRunnableArray) + , mRunnable(aRunnable) { } #ifndef MOZ_B2G_BT_API_V1 void OnError(BluetoothStatus aStatus) override { MOZ_ASSERT(NS_IsMainThread()); - sChangeDiscoveryRunnableArray.RemoveElement(mRunnable); + mRunnableArray.RemoveElement(mRunnable); DispatchReplyError(mRunnable, aStatus); } #else void StartDiscovery() override { MOZ_ASSERT(NS_IsMainThread()); DispatchReplySuccess(mRunnable); } @@ -986,48 +960,53 @@ public: void OnError(BluetoothStatus aStatus) override { MOZ_ASSERT(NS_IsMainThread()); ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("StartDiscovery")); } #endif private: + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray; BluetoothReplyRunnable* mRunnable; }; void BluetoothServiceBluedroid::StartDiscoveryInternal( BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable); #ifndef MOZ_B2G_BT_API_V1 - sChangeDiscoveryRunnableArray.AppendElement(aRunnable); + mChangeDiscoveryRunnables.AppendElement(aRunnable); + sBtInterface->StartDiscovery( + new StartDiscoveryResultHandler(mChangeDiscoveryRunnables, aRunnable)); #else - // Missing in bluetooth1 + sBtInterface->StartDiscovery( + new StartDiscoveryResultHandler(nullptr, aRunnable)); #endif - - sBtInterface->StartDiscovery(new StartDiscoveryResultHandler(aRunnable)); } class BluetoothServiceBluedroid::CancelDiscoveryResultHandler final : public BluetoothResultHandler { public: - CancelDiscoveryResultHandler(BluetoothReplyRunnable* aRunnable) - : mRunnable(aRunnable) + CancelDiscoveryResultHandler( + nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray, + BluetoothReplyRunnable* aRunnable) + : mRunnableArray(aRunnableArray) + , mRunnable(aRunnable) { } #ifndef MOZ_B2G_BT_API_V1 void OnError(BluetoothStatus aStatus) override { MOZ_ASSERT(NS_IsMainThread()); - sChangeDiscoveryRunnableArray.RemoveElement(mRunnable); + mRunnableArray.RemoveElement(mRunnable); DispatchReplyError(mRunnable, aStatus); } #else void CancelDiscovery() override { MOZ_ASSERT(NS_IsMainThread()); DispatchReplySuccess(mRunnable); } @@ -1035,118 +1014,131 @@ public: void OnError(BluetoothStatus aStatus) override { MOZ_ASSERT(NS_IsMainThread()); ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("StopDiscovery")); } #endif private: + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray; BluetoothReplyRunnable* mRunnable; }; #ifndef MOZ_B2G_BT_API_V1 class BluetoothServiceBluedroid::GetRemoteServicesResultHandler final : public BluetoothResultHandler { public: - GetRemoteServicesResultHandler(BluetoothReplyRunnable* aRunnable) - : mRunnable(aRunnable) + GetRemoteServicesResultHandler( + nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray, + BluetoothReplyRunnable* aRunnable) + : mRunnableArray(aRunnableArray) + , mRunnable(aRunnable) { } void OnError(BluetoothStatus aStatus) override { MOZ_ASSERT(NS_IsMainThread()); - sFetchUuidsRunnableArray.RemoveElement(mRunnable); + mRunnableArray.RemoveElement(mRunnable); DispatchReplyError(mRunnable, aStatus); } private: + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray; BluetoothReplyRunnable* mRunnable; }; nsresult BluetoothServiceBluedroid::FetchUuidsInternal( const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); /* * get_remote_services request will not be performed by bluedroid * if it is currently discovering nearby remote devices. */ - if (sAdapterDiscovering) { - sBtInterface->CancelDiscovery(new CancelDiscoveryResultHandler(aRunnable)); + if (mDiscovering) { + sBtInterface->CancelDiscovery( + new CancelDiscoveryResultHandler(mChangeDiscoveryRunnables, aRunnable)); } - sFetchUuidsRunnableArray.AppendElement(aRunnable); + mFetchUuidsRunnables.AppendElement(aRunnable); sBtInterface->GetRemoteServices(aDeviceAddress, - new GetRemoteServicesResultHandler(aRunnable)); + new GetRemoteServicesResultHandler(mFetchUuidsRunnables, aRunnable)); return NS_OK; } #else // Missing in bluetooth1 #endif void BluetoothServiceBluedroid::StopDiscoveryInternal( BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable); #ifndef MOZ_B2G_BT_API_V1 - sChangeDiscoveryRunnableArray.AppendElement(aRunnable); + mChangeDiscoveryRunnables.AppendElement(aRunnable); + sBtInterface->CancelDiscovery( + new CancelDiscoveryResultHandler(mChangeDiscoveryRunnables, + aRunnable)); #else - // Missing in bluetooth1 + sBtInterface->CancelDiscovery( + new CancelDiscoveryResultHandler(nullptr, aRunnable)); #endif - - sBtInterface->CancelDiscovery(new CancelDiscoveryResultHandler(aRunnable)); } class BluetoothServiceBluedroid::SetAdapterPropertyResultHandler final : public BluetoothResultHandler { public: - SetAdapterPropertyResultHandler(BluetoothReplyRunnable* aRunnable) - : mRunnable(aRunnable) + SetAdapterPropertyResultHandler( + nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray, + BluetoothReplyRunnable* aRunnable) + : mRunnableArray(aRunnableArray) + , mRunnable(aRunnable) { } void OnError(BluetoothStatus aStatus) override { MOZ_ASSERT(NS_IsMainThread()); #ifndef MOZ_B2G_BT_API_V1 - sSetPropertyRunnableArray.RemoveElement(mRunnable); + mRunnableArray.RemoveElement(mRunnable); DispatchReplyError(mRunnable, aStatus); #else ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("SetProperty")); #endif } private: + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray; BluetoothReplyRunnable* mRunnable; }; nsresult BluetoothServiceBluedroid::SetProperty(BluetoothObjectType aType, const BluetoothNamedValue& aValue, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); - sSetPropertyRunnableArray.AppendElement(aRunnable); + mSetAdapterPropertyRunnables.AppendElement(aRunnable); sBtInterface->SetAdapterProperty(aValue, - new SetAdapterPropertyResultHandler(aRunnable)); + new SetAdapterPropertyResultHandler(mSetAdapterPropertyRunnables, + aRunnable)); return NS_OK; } nsresult BluetoothServiceBluedroid::GetServiceChannel( const nsAString& aDeviceAddress, const nsAString& aServiceUuid, @@ -1162,90 +1154,99 @@ BluetoothServiceBluedroid::UpdateSdpReco { return true; } class BluetoothServiceBluedroid::CreateBondResultHandler final : public BluetoothResultHandler { public: - CreateBondResultHandler(BluetoothReplyRunnable* aRunnable) - : mRunnable(aRunnable) + CreateBondResultHandler( + nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray, + BluetoothReplyRunnable* aRunnable) + : mRunnableArray(aRunnableArray) + , mRunnable(aRunnable) { MOZ_ASSERT(mRunnable); } void OnError(BluetoothStatus aStatus) override { - sBondingRunnableArray.RemoveElement(mRunnable); + mRunnableArray.RemoveElement(mRunnable); #ifndef MOZ_B2G_BT_API_V1 DispatchReplyError(mRunnable, aStatus); #else ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("CreatedPairedDevice")); #endif } private: + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray; nsRefPtr<BluetoothReplyRunnable> mRunnable; }; nsresult BluetoothServiceBluedroid::CreatePairedDeviceInternal( const nsAString& aDeviceAddress, int aTimeout, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); - sBondingRunnableArray.AppendElement(aRunnable); + mCreateBondRunnables.AppendElement(aRunnable); sBtInterface->CreateBond(aDeviceAddress, TRANSPORT_AUTO, - new CreateBondResultHandler(aRunnable)); + new CreateBondResultHandler(mCreateBondRunnables, aRunnable)); + return NS_OK; } class BluetoothServiceBluedroid::RemoveBondResultHandler final : public BluetoothResultHandler { public: - RemoveBondResultHandler(BluetoothReplyRunnable* aRunnable) - : mRunnable(aRunnable) + RemoveBondResultHandler( + nsTArray<nsRefPtr<BluetoothReplyRunnable>>& aRunnableArray, + BluetoothReplyRunnable* aRunnable) + : mRunnableArray(aRunnableArray) + , mRunnable(aRunnable) { MOZ_ASSERT(mRunnable); } void OnError(BluetoothStatus aStatus) override { - sUnbondingRunnableArray.RemoveElement(mRunnable); + mRunnableArray.RemoveElement(mRunnable); #ifndef MOZ_B2G_BT_API_V1 DispatchReplyError(mRunnable, aStatus); #else ReplyStatusError(mRunnable, aStatus, NS_LITERAL_STRING("RemoveDevice")); #endif } private: + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRunnableArray; nsRefPtr<BluetoothReplyRunnable> mRunnable; }; nsresult BluetoothServiceBluedroid::RemoveDeviceInternal( const nsAString& aDeviceAddress, BluetoothReplyRunnable* aRunnable) { MOZ_ASSERT(NS_IsMainThread()); ENSURE_BLUETOOTH_IS_READY(aRunnable, NS_OK); - sUnbondingRunnableArray.AppendElement(aRunnable); + mRemoveBondRunnables.AppendElement(aRunnable); sBtInterface->RemoveBond(aDeviceAddress, - new RemoveBondResultHandler(aRunnable)); + new RemoveBondResultHandler(mRemoveBondRunnables, aRunnable)); return NS_OK; } class BluetoothServiceBluedroid::PinReplyResultHandler final : public BluetoothResultHandler { public: @@ -1436,18 +1437,18 @@ BluetoothServiceBluedroid::ConnectDiscon BluetoothProfileController* controller = new BluetoothProfileController(aConnect, aDeviceAddress, aRunnable, NextBluetoothProfileController, aServiceUuid, aCod); sControllerArray.AppendElement(controller); /** - * If the request is the first element of the quene, start from here. Note - * that other request is pushed into the quene and is popped out after the + * If the request is the first element of the queue, start from here. Note + * that other requests are pushed into the queue and popped out after the * first one is completed. See NextBluetoothProfileController() for details. */ if (sControllerArray.Length() == 1) { sControllerArray[0]->StartSession(); } } void @@ -1766,18 +1767,19 @@ public: /* |ProfileDeinitResultHandler| collects the results of all profile * result handlers and cleans up the Bluedroid driver after all handlers * have been run. */ class BluetoothServiceBluedroid::ProfileDeinitResultHandler final : public BluetoothProfileResultHandler { public: - ProfileDeinitResultHandler(unsigned char aNumProfiles) + ProfileDeinitResultHandler(unsigned char aNumProfiles, bool aIsRestart) : mNumProfiles(aNumProfiles) + , mIsRestart(aIsRestart) { MOZ_ASSERT(mNumProfiles); } void Deinit() override { if (!(--mNumProfiles)) { Proceed(); @@ -1789,24 +1791,26 @@ public: if (!(--mNumProfiles)) { Proceed(); } } private: void Proceed() const { - if (!sIsRestart) { - sBtInterface->Cleanup(new CleanupResultHandler()); - } else { + if (mIsRestart) { BT_LOGR("ProfileDeinitResultHandler::Proceed cancel cleanup() "); + return; } + + sBtInterface->Cleanup(new CleanupResultHandler()); } unsigned char mNumProfiles; + bool mIsRestart; }; class BluetoothServiceBluedroid::SetAdapterPropertyDiscoverableResultHandler final : public BluetoothResultHandler { public: void OnError(BluetoothStatus aStatus) override @@ -1818,83 +1822,84 @@ public: void BluetoothServiceBluedroid::AdapterStateChangedNotification(bool aState) { #ifndef MOZ_B2G_BT_API_V1 MOZ_ASSERT(NS_IsMainThread()); BT_LOGR("BT_STATE: %d", aState); - if (sIsRestart && aState) { + if (mIsRestart && aState) { // daemon restarted, reset flag BT_LOGR("daemon restarted, reset flag"); - sIsRestart = false; - sIsFirstTimeToggleOffBt = false; + mIsRestart = false; + mIsFirstTimeToggleOffBt = false; } - sAdapterEnabled = aState; - - if (!sAdapterEnabled) { + mEnabled = aState; + + if (!mEnabled) { static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = { BluetoothHfpManager::DeinitHfpInterface, BluetoothA2dpManager::DeinitA2dpInterface, BluetoothGattManager::DeinitGattInterface }; // Return error if BluetoothService is unavailable BluetoothService* bs = BluetoothService::Get(); NS_ENSURE_TRUE_VOID(bs); // Cleanup static adapter properties and notify adapter. - sAdapterBdAddress.Truncate(); - sAdapterBdName.Truncate(); + mBdAddress.Truncate(); + mBdName.Truncate(); InfallibleTArray<BluetoothNamedValue> props; - BT_APPEND_NAMED_VALUE(props, "Name", sAdapterBdName); - BT_APPEND_NAMED_VALUE(props, "Address", sAdapterBdAddress); - if (sAdapterDiscoverable) { - sAdapterDiscoverable = false; + BT_APPEND_NAMED_VALUE(props, "Name", mBdName); + BT_APPEND_NAMED_VALUE(props, "Address", mBdAddress); + if (mDiscoverable) { + mDiscoverable = false; BT_APPEND_NAMED_VALUE(props, "Discoverable", false); } - if (sAdapterDiscovering) { - sAdapterDiscovering = false; + if (mDiscovering) { + mDiscovering = false; BT_APPEND_NAMED_VALUE(props, "Discovering", false); } bs->DistributeSignal(NS_LITERAL_STRING("PropertyChanged"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(props)); // Cleanup Bluetooth interfaces after state becomes BT_STATE_OFF. This // will also stop the Bluetooth daemon and disable the adapter. nsRefPtr<ProfileDeinitResultHandler> res = - new ProfileDeinitResultHandler(MOZ_ARRAY_LENGTH(sDeinitManager)); + new ProfileDeinitResultHandler(MOZ_ARRAY_LENGTH(sDeinitManager), + mIsRestart); for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sDeinitManager); ++i) { sDeinitManager[i](res); } } - if (sAdapterEnabled) { + if (mEnabled) { // We enable the Bluetooth adapter here. Disabling is implemented // in |CleanupResultHandler|, which runs at the end of the shutdown // procedure. We cannot disable the adapter immediately, because re- // enabling it might interfere with the shutdown procedure. BluetoothService::AcknowledgeToggleBt(true); // Bluetooth just enabled, clear profile controllers and runnable arrays. sControllerArray.Clear(); - sChangeDiscoveryRunnableArray.Clear(); - sSetPropertyRunnableArray.Clear(); - sGetDeviceRunnableArray.Clear(); - sFetchUuidsRunnableArray.Clear(); - sBondingRunnableArray.Clear(); - sUnbondingRunnableArray.Clear(); - sDeviceNameMap.Clear(); + mGetDeviceRequests.Clear(); + mChangeDiscoveryRunnables.Clear(); + mSetAdapterPropertyRunnables.Clear(); + mFetchUuidsRunnables.Clear(); + mCreateBondRunnables.Clear(); + mRemoveBondRunnables.Clear(); + mDeviceNameMap.Clear(); // Bluetooth scan mode is SCAN_MODE_CONNECTABLE by default, i.e., it should // be connectable and non-discoverable. NS_ENSURE_TRUE_VOID(sBtInterface); sBtInterface->SetAdapterProperty( BluetoothNamedValue(NS_ConvertUTF8toUTF16("Discoverable"), false), new SetAdapterPropertyDiscoverableResultHandler()); @@ -1906,69 +1911,69 @@ BluetoothServiceBluedroid::AdapterStateC BluetoothPbapManager* pbap = BluetoothPbapManager::Get(); if (!pbap || !pbap->Listen()) { BT_LOGR("Fail to start BluetoothPbapManager listening"); } } // Resolve promise if existed - if (!sChangeAdapterStateRunnableArray.IsEmpty()) { - DispatchReplySuccess(sChangeAdapterStateRunnableArray[0]); - sChangeAdapterStateRunnableArray.RemoveElementAt(0); + if (!mChangeAdapterStateRunnables.IsEmpty()) { + DispatchReplySuccess(mChangeAdapterStateRunnables[0]); + mChangeAdapterStateRunnables.RemoveElementAt(0); } - // After ProfileManagers deinit and cleanup, now restarts bluetooth daemon - if (sIsRestart && !aState) { - BT_LOGR("sIsRestart and off, now restart"); + // After ProfileManagers deinit and cleanup, now restart bluetooth daemon + if (mIsRestart && !aState) { + BT_LOGR("mIsRestart and off, now restart"); StartBluetooth(false, nullptr); } #else MOZ_ASSERT(NS_IsMainThread()); BT_LOGR("BT_STATE: %d", aState); - if (sIsRestart && aState) { + if (mIsRestart && aState) { // daemon restarted, reset flag BT_LOGR("daemon restarted, reset flag"); - sIsRestart = false; - sIsFirstTimeToggleOffBt = false; + mIsRestart = false; + mIsFirstTimeToggleOffBt = false; } bool isBtEnabled = (aState == true); if (!isBtEnabled) { static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = { BluetoothHfpManager::DeinitHfpInterface, BluetoothA2dpManager::DeinitA2dpInterface }; // Set discoverable cache to default value after state becomes BT_STATE_OFF. - if (sAdapterDiscoverable) { - sAdapterDiscoverable = false; + if (mDiscoverable) { + mDiscoverable = false; } // Cleanup bluetooth interfaces after BT state becomes BT_STATE_OFF. nsRefPtr<ProfileDeinitResultHandler> res = new ProfileDeinitResultHandler(MOZ_ARRAY_LENGTH(sDeinitManager)); for (size_t i = 0; i < MOZ_ARRAY_LENGTH(sDeinitManager); ++i) { sDeinitManager[i](res); } } BluetoothService::AcknowledgeToggleBt(isBtEnabled); if (isBtEnabled) { // Bluetooth just enabled, clear profile controllers and runnable arrays. sControllerArray.Clear(); - sBondingRunnableArray.Clear(); - sGetDeviceRunnableArray.Clear(); - sSetPropertyRunnableArray.Clear(); - sUnbondingRunnableArray.Clear(); + mCreateBondRunnables.Clear(); + mGetDeviceRunnables.Clear(); + mSetAdapterPropertyRunnables.Clear(); + mRemoveBondRunnables.Clear(); // Bluetooth scan mode is SCAN_MODE_CONNECTABLE by default, i.e., It should // be connectable and non-discoverable. NS_ENSURE_TRUE_VOID(sBtInterface); sBtInterface->SetAdapterProperty( BluetoothNamedValue(NS_ConvertUTF8toUTF16("Discoverable"), false), new SetAdapterPropertyDiscoverableResultHandler()); @@ -1988,148 +1993,135 @@ BluetoothServiceBluedroid::AdapterStateC BluetoothPbapManager* pbap = BluetoothPbapManager::Get(); if (!pbap || !pbap->Listen()) { BT_LOGR("Fail to start BluetoothPbapManager listening"); } } // After ProfileManagers deinit and cleanup, now restarts bluetooth daemon - if (sIsRestart && !aState) { - BT_LOGR("sIsRestart and off, now restart"); + if (mIsRestart && !aState) { + BT_LOGR("mIsRestart and off, now restart"); StartBluetooth(false); } #endif } /** - * AdapterPropertiesNotification will be called after enable() but - * before AdapterStateChangeCallback is called. At that moment, both - * BluetoothManager and BluetoothAdapter, do not register observer - * yet. + * AdapterPropertiesNotification will be called after enable() but before + * AdapterStateChangeCallback is called. At that moment, both BluetoothManager + * and BluetoothAdapter have not registered observer yet. */ void BluetoothServiceBluedroid::AdapterPropertiesNotification( BluetoothStatus aStatus, int aNumProperties, const BluetoothProperty* aProperties) { #ifndef MOZ_B2G_BT_API_V1 MOZ_ASSERT(NS_IsMainThread()); InfallibleTArray<BluetoothNamedValue> propertiesArray; for (int i = 0; i < aNumProperties; i++) { const BluetoothProperty& p = aProperties[i]; if (p.mType == PROPERTY_BDADDR) { - sAdapterBdAddress = p.mString; - BT_APPEND_NAMED_VALUE(propertiesArray, "Address", sAdapterBdAddress); + mBdAddress = p.mString; + BT_APPEND_NAMED_VALUE(propertiesArray, "Address", mBdAddress); } else if (p.mType == PROPERTY_BDNAME) { - sAdapterBdName = p.mString; - BT_APPEND_NAMED_VALUE(propertiesArray, "Name", sAdapterBdName); + mBdName = p.mString; + BT_APPEND_NAMED_VALUE(propertiesArray, "Name", mBdName); } else if (p.mType == PROPERTY_ADAPTER_SCAN_MODE) { // If BT is not enabled, Bluetooth scan mode should be non-discoverable - // by defalut. 'AdapterStateChangedNotification' would set the default + // by defalut. |AdapterStateChangedNotification| would set default // properties to bluetooth backend once Bluetooth is enabled. if (IsEnabled()) { - sAdapterDiscoverable = - (p.mScanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE); - BT_APPEND_NAMED_VALUE(propertiesArray, "Discoverable", - sAdapterDiscoverable); + mDiscoverable = (p.mScanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE); + BT_APPEND_NAMED_VALUE(propertiesArray, "Discoverable", mDiscoverable); } } else if (p.mType == PROPERTY_ADAPTER_BONDED_DEVICES) { // We have to cache addresses of bonded devices. Unlike BlueZ, // Bluedroid would not send another PROPERTY_ADAPTER_BONDED_DEVICES // event after bond completed. BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d", p.mStringArray.Length()); // Whenever reloading paired devices, force refresh - sAdapterBondedAddressArray.Clear(); - sAdapterBondedAddressArray.AppendElements(p.mStringArray); + mBondedAddresses.Clear(); + mBondedAddresses.AppendElements(p.mStringArray); BT_APPEND_NAMED_VALUE(propertiesArray, "PairedDevices", - sAdapterBondedAddressArray); + mBondedAddresses); } else if (p.mType == PROPERTY_UNKNOWN) { /* Bug 1065999: working around unknown properties */ } else { BT_LOGD("Unhandled adapter property type: %d", p.mType); continue; } } NS_ENSURE_TRUE_VOID(propertiesArray.Length() > 0); DistributeSignal(NS_LITERAL_STRING("PropertyChanged"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(propertiesArray)); // Send reply for SetProperty - if (!sSetPropertyRunnableArray.IsEmpty()) { - DispatchReplySuccess(sSetPropertyRunnableArray[0]); - sSetPropertyRunnableArray.RemoveElementAt(0); + if (!mSetAdapterPropertyRunnables.IsEmpty()) { + DispatchReplySuccess(mSetAdapterPropertyRunnables[0]); + mSetAdapterPropertyRunnables.RemoveElementAt(0); } #else MOZ_ASSERT(NS_IsMainThread()); - BluetoothValue propertyValue; InfallibleTArray<BluetoothNamedValue> props; for (int i = 0; i < aNumProperties; i++) { const BluetoothProperty& p = aProperties[i]; if (p.mType == PROPERTY_BDADDR) { - sAdapterBdAddress = p.mString; - propertyValue = sAdapterBdAddress; - BT_APPEND_NAMED_VALUE(props, "Address", propertyValue); + mBdAddress = p.mString; + BT_APPEND_NAMED_VALUE(props, "Address", mBdAddress); } else if (p.mType == PROPERTY_BDNAME) { - sAdapterBdName = p.mString; - propertyValue = sAdapterBdName; - BT_APPEND_NAMED_VALUE(props, "Name", propertyValue); + mBdName = p.mString; + BT_APPEND_NAMED_VALUE(props, "Name", mBdName); } else if (p.mType == PROPERTY_ADAPTER_SCAN_MODE) { BluetoothScanMode newMode = p.mScanMode; // If BT is not enabled, Bluetooth scan mode should be non-discoverable // by defalut. 'AdapterStateChangedNotification' would set the default // properties to bluetooth backend once Bluetooth is enabled. - if (newMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE && IsEnabled()) { - propertyValue = sAdapterDiscoverable = true; - } else { - propertyValue = sAdapterDiscoverable = false; - } - - BT_APPEND_NAMED_VALUE(props, "Discoverable", propertyValue); + mDiscoverable = + (newMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE && IsEnabled()); + BT_APPEND_NAMED_VALUE(props, "Discoverable", mDiscoverable); } else if (p.mType == PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) { - propertyValue = sAdapterDiscoverableTimeout = p.mUint32; - BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", propertyValue); + mDiscoverableTimeout = p.mUint32; + BT_APPEND_NAMED_VALUE(props, "DiscoverableTimeout", + mDiscoverableTimeout); } else if (p.mType == PROPERTY_ADAPTER_BONDED_DEVICES) { // We have to cache addresses of bonded devices. Unlike BlueZ, // Bluedroid would not send another PROPERTY_ADAPTER_BONDED_DEVICES // event after bond completed. BT_LOGD("Adapter property: BONDED_DEVICES. Count: %d", p.mStringArray.Length()); // Whenever reloading paired devices, force refresh - sAdapterBondedAddressArray.Clear(); - - for (size_t index = 0; index < p.mStringArray.Length(); index++) { - sAdapterBondedAddressArray.AppendElement(p.mStringArray[index]); - } - - propertyValue = sAdapterBondedAddressArray; - BT_APPEND_NAMED_VALUE(props, "Devices", propertyValue); + mBondedAddresses.Clear(); + mBondedAddresses.AppendElements(p.mStringArray); + + BT_APPEND_NAMED_VALUE(props, "Devices", mBondedAddresses); } else if (p.mType == PROPERTY_UUIDS) { //FIXME: This will be implemented in the later patchset continue; } else if (p.mType == PROPERTY_UNKNOWN) { /* Bug 1065999: working around unknown properties */ continue; } else { @@ -2140,19 +2132,19 @@ BluetoothServiceBluedroid::AdapterProper NS_ENSURE_TRUE_VOID(props.Length() > 0); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(props))); // Send reply for SetProperty - if (!sSetPropertyRunnableArray.IsEmpty()) { - DispatchReplySuccess(sSetPropertyRunnableArray[0]); - sSetPropertyRunnableArray.RemoveElementAt(0); + if (!mSetAdapterPropertyRunnables.IsEmpty()) { + DispatchReplySuccess(mSetAdapterPropertyRunnables[0]); + mSetAdapterPropertyRunnables.RemoveElementAt(0); } #endif } /** * RemoteDevicePropertiesNotification will be called * * (1) automatically by Bluedroid when BT is turning on, or @@ -2177,18 +2169,18 @@ BluetoothServiceBluedroid::RemoteDeviceP for (int i = 0; i < aNumProperties; ++i) { const BluetoothProperty& p = aProperties[i]; if (p.mType == PROPERTY_BDNAME) { BT_APPEND_NAMED_VALUE(propertiesArray, "Name", p.mString); // Update <address, name> mapping - sDeviceNameMap.Remove(bdAddr); - sDeviceNameMap.Put(bdAddr, p.mString); + mDeviceNameMap.Remove(bdAddr); + mDeviceNameMap.Put(bdAddr, p.mString); } else if (p.mType == PROPERTY_CLASS_OF_DEVICE) { uint32_t cod = p.mUint32; BT_APPEND_NAMED_VALUE(propertiesArray, "Cod", cod); } else if (p.mType == PROPERTY_UUIDS) { nsTArray<nsString> uuids; // Construct a sorted uuid set @@ -2221,48 +2213,45 @@ BluetoothServiceBluedroid::RemoteDeviceP // // |DispatchReplySuccess| creates its own internal runnable, which is // always run after we completed the current method. This means that we // can exchange |DispatchReplySuccess| with other operations without // changing the order of (1,2) and (3). // Update to registered BluetoothDevice objects BluetoothSignal signal(NS_LITERAL_STRING("PropertyChanged"), - nsString(aBdAddr), propertiesArray); + bdAddr, propertiesArray); // FetchUuids task - if (!sFetchUuidsRunnableArray.IsEmpty()) { + if (!mFetchUuidsRunnables.IsEmpty()) { // propertiesArray contains Address and Uuids only - DispatchReplySuccess(sFetchUuidsRunnableArray[0], + DispatchReplySuccess(mFetchUuidsRunnables[0], propertiesArray[1].value()); /* Uuids */ - sFetchUuidsRunnableArray.RemoveElementAt(0); + mFetchUuidsRunnables.RemoveElementAt(0); DistributeSignal(signal); return; } // GetDevices task - if (sRequestedDeviceCountArray.IsEmpty()) { - // This is possible because the callback would be called after turning - // Bluetooth on. + if (mGetDeviceRequests.IsEmpty()) { + // Callback is called after Bluetooth is turned on DistributeSignal(signal); return; } // Use address as the index - sRemoteDevicesPack.AppendElement( - BluetoothNamedValue(nsString(aBdAddr), propertiesArray)); - - if (--sRequestedDeviceCountArray[0] == 0) { - if (!sGetDeviceRunnableArray.IsEmpty()) { - DispatchReplySuccess(sGetDeviceRunnableArray[0], sRemoteDevicesPack); - sGetDeviceRunnableArray.RemoveElementAt(0); + mGetDeviceRequests[0].mDevicesPack.AppendElement( + BluetoothNamedValue(bdAddr, propertiesArray)); + + if (--mGetDeviceRequests[0].mDeviceCount == 0) { + if (mGetDeviceRequests[0].mRunnable) { + DispatchReplySuccess(mGetDeviceRequests[0].mRunnable, + mGetDeviceRequests[0].mDevicesPack); } - - sRequestedDeviceCountArray.RemoveElementAt(0); - sRemoteDevicesPack.Clear(); + mGetDeviceRequests.RemoveElementAt(0); } DistributeSignal(signal); #else MOZ_ASSERT(NS_IsMainThread()); InfallibleTArray<BluetoothNamedValue> props; @@ -2328,46 +2317,44 @@ BluetoothServiceBluedroid::RemoteDeviceP BT_LOGD("Other non-handled device properties. Type: %d", p.mType); } } // BlueDroid wouldn't notify the status of connection, therefore, query the // connection state and append to properties array BT_APPEND_NAMED_VALUE(props, "Connected", IsConnected(aBdAddr)); - if (sRequestedDeviceCountArray.IsEmpty()) { + if (mGetDeviceRequests.IsEmpty()) { /** * This is possible when * * (1) the callback is called when BT is turning on, or * (2) remote device properties get updated during discovery, or * (3) as result of CreateBond */ - if (sAdapterDiscovering) { + if (mDiscovering) { // Fire 'devicefound' again to update device name for (2). // See bug 1076553 for more information. DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("DeviceFound"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(props))); } return; } // Use address as the index - sRemoteDevicesPack.AppendElement( - BluetoothNamedValue(nsString(aBdAddr), props)); - - if (--sRequestedDeviceCountArray[0] == 0) { - if (!sGetDeviceRunnableArray.IsEmpty()) { - DispatchReplySuccess(sGetDeviceRunnableArray[0], sRemoteDevicesPack); - sGetDeviceRunnableArray.RemoveElementAt(0); + mGetDeviceRequests[0].mDevicesPack.AppendElement( + BluetoothNamedValue(nsString(aBdAddr), propertiesArray)); + + if (--mGetDeviceRequests[0].mDeviceCount == 0) { + if (mGetDeviceRequests[0].mRunnable) { + DispatchReplySuccess(mGetDeviceRequests[0].mRunnable, + mGetDeviceRequests[0].mDevicesPack); } - - sRequestedDeviceCountArray.RemoveElementAt(0); - sRemoteDevicesPack.Clear(); + mGetDeviceRequests.RemoveElementAt(0); } // Update to registered BluetoothDevice objects DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"), nsString(aBdAddr), BluetoothValue(props))); #endif } @@ -2416,18 +2403,18 @@ BluetoothServiceBluedroid::DeviceFoundNo } else if (p.mType == PROPERTY_UNKNOWN) { /* Bug 1065999: working around unknown properties */ } else { BT_LOGD("Not handled remote device property: %d", p.mType); } } // Update <address, name> mapping - sDeviceNameMap.Remove(bdAddr); - sDeviceNameMap.Put(bdAddr, bdName); + mDeviceNameMap.Remove(bdAddr); + mDeviceNameMap.Put(bdAddr, bdName); DistributeSignal(NS_LITERAL_STRING("DeviceFound"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(propertiesArray)); #else MOZ_ASSERT(NS_IsMainThread()); BluetoothValue propertyValue; @@ -2466,70 +2453,69 @@ BluetoothServiceBluedroid::DeviceFoundNo } void BluetoothServiceBluedroid::DiscoveryStateChangedNotification(bool aState) { #ifndef MOZ_B2G_BT_API_V1 MOZ_ASSERT(NS_IsMainThread()); - sAdapterDiscovering = aState; + mDiscovering = aState; // Fire PropertyChanged of Discovering InfallibleTArray<BluetoothNamedValue> propertiesArray; - BT_APPEND_NAMED_VALUE(propertiesArray, "Discovering", sAdapterDiscovering); + BT_APPEND_NAMED_VALUE(propertiesArray, "Discovering", mDiscovering); DistributeSignal(NS_LITERAL_STRING("PropertyChanged"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(propertiesArray)); // Reply that Promise is resolved - if (!sChangeDiscoveryRunnableArray.IsEmpty()) { - DispatchReplySuccess(sChangeDiscoveryRunnableArray[0]); - sChangeDiscoveryRunnableArray.RemoveElementAt(0); + if (!mChangeDiscoveryRunnables.IsEmpty()) { + DispatchReplySuccess(mChangeDiscoveryRunnables[0]); + mChangeDiscoveryRunnables.RemoveElementAt(0); } #else MOZ_ASSERT(NS_IsMainThread()); - sAdapterDiscovering = aState; + mDiscovering = aState; DistributeSignal( BluetoothSignal(NS_LITERAL_STRING(DISCOVERY_STATE_CHANGED_ID), - NS_LITERAL_STRING(KEY_ADAPTER), sAdapterDiscovering)); + NS_LITERAL_STRING(KEY_ADAPTER), mDiscovering)); // Distribute "PropertyChanged" signal to notice adapter this change since // Bluedroid don' treat "discovering" as a property of adapter. InfallibleTArray<BluetoothNamedValue> props; - BT_APPEND_NAMED_VALUE(props, "Discovering", - BluetoothValue(sAdapterDiscovering)); + BT_APPEND_NAMED_VALUE(props, "Discovering", mDiscovering); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(props))); #endif } void BluetoothServiceBluedroid::PinRequestNotification(const nsAString& aRemoteBdAddr, const nsAString& aBdName, uint32_t aCod) { #ifndef MOZ_B2G_BT_API_V1 MOZ_ASSERT(NS_IsMainThread()); InfallibleTArray<BluetoothNamedValue> propertiesArray; - // If |aBdName| is empty, get device name from |sDeviceNameMap|; + // If |aBdName| is empty, get device name from |mDeviceNameMap|; // Otherwise update <address, name> mapping with |aBdName| nsString bdAddr(aRemoteBdAddr); nsString bdName(aBdName); if (bdName.IsEmpty()) { - sDeviceNameMap.Get(bdAddr, &bdName); + mDeviceNameMap.Get(bdAddr, &bdName); } else { - sDeviceNameMap.Remove(bdAddr); - sDeviceNameMap.Put(bdAddr, bdName); + mDeviceNameMap.Remove(bdAddr); + mDeviceNameMap.Put(bdAddr, bdName); } BT_APPEND_NAMED_VALUE(propertiesArray, "address", bdAddr); BT_APPEND_NAMED_VALUE(propertiesArray, "name", bdName); BT_APPEND_NAMED_VALUE(propertiesArray, "passkey", EmptyString()); BT_APPEND_NAMED_VALUE(propertiesArray, "type", NS_LITERAL_STRING(PAIRING_REQ_TYPE_ENTERPINCODE)); @@ -2557,25 +2543,25 @@ BluetoothServiceBluedroid::SspRequestNot const nsAString& aRemoteBdAddr, const nsAString& aBdName, uint32_t aCod, BluetoothSspVariant aPairingVariant, uint32_t aPassKey) { MOZ_ASSERT(NS_IsMainThread()); #ifndef MOZ_B2G_BT_API_V1 InfallibleTArray<BluetoothNamedValue> propertiesArray; - // If |aBdName| is empty, get device name from |sDeviceNameMap|; + // If |aBdName| is empty, get device name from |mDeviceNameMap|; // Otherwise update <address, name> mapping with |aBdName| nsString bdAddr(aRemoteBdAddr); nsString bdName(aBdName); if (bdName.IsEmpty()) { - sDeviceNameMap.Get(bdAddr, &bdName); + mDeviceNameMap.Get(bdAddr, &bdName); } else { - sDeviceNameMap.Remove(bdAddr); - sDeviceNameMap.Put(bdAddr, bdName); + mDeviceNameMap.Remove(bdAddr); + mDeviceNameMap.Put(bdAddr, bdName); } /** * Assign pairing request type and passkey based on the pairing variant. * * passkey value based on pairing request type: * 1) aPasskey: PAIRING_REQ_TYPE_CONFIRMATION and * PAIRING_REQ_TYPE_DISPLAYPASSKEY @@ -2643,41 +2629,41 @@ BluetoothServiceBluedroid::BondStateChan if (!bonded) { // Active/passive pair failed BT_LOGR("Pair failed! Abort pairing."); // Notify adapter of pairing aborted DistributeSignal(NS_LITERAL_STRING(PAIRING_ABORTED_ID), NS_LITERAL_STRING(KEY_ADAPTER)); // Reject pair promise - if (!sBondingRunnableArray.IsEmpty()) { - DispatchReplyError(sBondingRunnableArray[0], aStatus); - sBondingRunnableArray.RemoveElementAt(0); + if (!mCreateBondRunnables.IsEmpty()) { + DispatchReplyError(mCreateBondRunnables[0], aStatus); + mCreateBondRunnables.RemoveElementAt(0); } - } else if (!sUnbondingRunnableArray.IsEmpty()) { // Active unpair failed + } else if (!mRemoveBondRunnables.IsEmpty()) { // Active unpair failed // Reject unpair promise - DispatchReplyError(sUnbondingRunnableArray[0], aStatus); - sUnbondingRunnableArray.RemoveElementAt(0); + DispatchReplyError(mRemoveBondRunnables[0], aStatus); + mRemoveBondRunnables.RemoveElementAt(0); } return; } // Query pairing device name from hash table nsString remoteBdAddr(aRemoteBdAddr); nsString remotebdName; - sDeviceNameMap.Get(remoteBdAddr, &remotebdName); + mDeviceNameMap.Get(remoteBdAddr, &remotebdName); // Update bonded address array and append pairing device name InfallibleTArray<BluetoothNamedValue> propertiesArray; if (!bonded) { - sAdapterBondedAddressArray.RemoveElement(remoteBdAddr); + mBondedAddresses.RemoveElement(remoteBdAddr); } else { - if (!sAdapterBondedAddressArray.Contains(remoteBdAddr)) { - sAdapterBondedAddressArray.AppendElement(remoteBdAddr); + if (!mBondedAddresses.Contains(remoteBdAddr)) { + mBondedAddresses.AppendElement(remoteBdAddr); } // We don't assert |!remotebdName.IsEmpty()| since empty string is also // valid, according to Bluetooth Core Spec. v3.0 - Sec. 6.22: // "a valid Bluetooth name is a UTF-8 encoding string which is up to 248 // bytes in length." BT_APPEND_NAMED_VALUE(propertiesArray, "Name", remotebdName); } @@ -2691,61 +2677,61 @@ BluetoothServiceBluedroid::BondStateChan // Notify adapter of device paired/unpaired BT_INSERT_NAMED_VALUE(propertiesArray, 0, "Address", remoteBdAddr); DistributeSignal(bonded ? NS_LITERAL_STRING(DEVICE_PAIRED_ID) : NS_LITERAL_STRING(DEVICE_UNPAIRED_ID), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(propertiesArray)); // Resolve existing pair/unpair promise - if (bonded && !sBondingRunnableArray.IsEmpty()) { - DispatchReplySuccess(sBondingRunnableArray[0]); - sBondingRunnableArray.RemoveElementAt(0); - } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) { - DispatchReplySuccess(sUnbondingRunnableArray[0]); - sUnbondingRunnableArray.RemoveElementAt(0); + if (bonded && !mCreateBondRunnables.IsEmpty()) { + DispatchReplySuccess(mCreateBondRunnables[0]); + mCreateBondRunnables.RemoveElementAt(0); + } else if (!bonded && !mRemoveBondRunnables.IsEmpty()) { + DispatchReplySuccess(mRemoveBondRunnables[0]); + mRemoveBondRunnables.RemoveElementAt(0); } #else if (aState == BOND_STATE_BONDED && - sAdapterBondedAddressArray.Contains(aRemoteBdAddr)) { + mBondedAddresses.Contains(aRemoteBdAddr)) { // See bug 940271 for more details about this case. return; } switch (aStatus) { case STATUS_SUCCESS: { bool bonded; if (aState == BOND_STATE_NONE) { bonded = false; - sAdapterBondedAddressArray.RemoveElement(aRemoteBdAddr); + mBondedAddresses.RemoveElement(aRemoteBdAddr); } else if (aState == BOND_STATE_BONDED) { bonded = true; - sAdapterBondedAddressArray.AppendElement(aRemoteBdAddr); + mBondedAddresses.AppendElement(aRemoteBdAddr); } else { return; } // Update bonded address list to BluetoothAdapter InfallibleTArray<BluetoothNamedValue> propertiesChangeArray; BT_APPEND_NAMED_VALUE(propertiesChangeArray, "Devices", - sAdapterBondedAddressArray); + mBondedAddresses); DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("PropertyChanged"), NS_LITERAL_STRING(KEY_ADAPTER), BluetoothValue(propertiesChangeArray))); - if (bonded && !sBondingRunnableArray.IsEmpty()) { - DispatchReplySuccess(sBondingRunnableArray[0]); - - sBondingRunnableArray.RemoveElementAt(0); - } else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) { - DispatchReplySuccess(sUnbondingRunnableArray[0]); - - sUnbondingRunnableArray.RemoveElementAt(0); + if (bonded && !mCreateBondRunnables.IsEmpty()) { + DispatchReplySuccess(mCreateBondRunnables[0]); + + mCreateBondRunnables.RemoveElementAt(0); + } else if (!bonded && !mRemoveBondRunnables.IsEmpty()) { + DispatchReplySuccess(mRemoveBondRunnables[0]); + + mRemoveBondRunnables.RemoveElementAt(0); } // Update bonding status to gaia InfallibleTArray<BluetoothNamedValue> propertiesArray; BT_APPEND_NAMED_VALUE(propertiesArray, "address", nsString(aRemoteBdAddr)); BT_APPEND_NAMED_VALUE(propertiesArray, "status", bonded); DistributeSignal( @@ -2758,30 +2744,30 @@ BluetoothServiceBluedroid::BondStateChan case STATUS_AUTH_FAILURE: case STATUS_RMT_DEV_DOWN: { InfallibleTArray<BluetoothNamedValue> propertiesArray; DistributeSignal(BluetoothSignal(NS_LITERAL_STRING("Cancel"), NS_LITERAL_STRING(KEY_LOCAL_AGENT), BluetoothValue(propertiesArray))); - if (!sBondingRunnableArray.IsEmpty()) { - DispatchReplyError(sBondingRunnableArray[0], + if (!mCreateBondRunnables.IsEmpty()) { + DispatchReplyError(mCreateBondRunnables[0], NS_LITERAL_STRING("Authentication failure")); - sBondingRunnableArray.RemoveElementAt(0); + mCreateBondRunnables.RemoveElementAt(0); } break; } default: BT_WARNING("Got an unhandled status of BondStateChangedCallback!"); // Dispatch a reply to unblock the waiting status of pairing. - if (!sBondingRunnableArray.IsEmpty()) { - DispatchReplyError(sBondingRunnableArray[0], + if (!mCreateBondRunnables.IsEmpty()) { + DispatchReplyError(mCreateBondRunnables[0], NS_LITERAL_STRING("Internal failure")); - sBondingRunnableArray.RemoveElementAt(0); + mCreateBondRunnables.RemoveElementAt(0); } break; } #endif } void BluetoothServiceBluedroid::AclStateChangedNotification( @@ -2836,35 +2822,35 @@ BluetoothServiceBluedroid::BackendErrorN */ BluetoothHfpManager* hfp = BluetoothHfpManager::Get(); NS_ENSURE_TRUE_VOID(hfp); hfp->HandleBackendError(); BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get(); NS_ENSURE_TRUE_VOID(a2dp); a2dp->HandleBackendError(); - sIsRestart = true; + mIsRestart = true; BT_LOGR("Recovery step2: stop bluetooth"); #ifndef MOZ_B2G_BT_API_V1 StopBluetooth(false, nullptr); #else StopBluetooth(false); #endif } void BluetoothServiceBluedroid::CompleteToggleBt(bool aEnabled) { MOZ_ASSERT(NS_IsMainThread()); - if (sIsRestart && !aEnabled && sIsFirstTimeToggleOffBt) { + if (mIsRestart && !aEnabled && mIsFirstTimeToggleOffBt) { // Both StopBluetooth and AdapterStateChangedNotification // trigger CompleteToggleBt. We don't need to call CompleteToggleBt again - } else if (sIsRestart && !aEnabled && !sIsFirstTimeToggleOffBt) { + } else if (mIsRestart && !aEnabled && !mIsFirstTimeToggleOffBt) { // Recovery step 3: cleanup and deinit Profile managers - BT_LOGR("CompleteToggleBt set sIsFirstTimeToggleOffBt = true"); - sIsFirstTimeToggleOffBt = true; + BT_LOGR("CompleteToggleBt set mIsFirstTimeToggleOffBt = true"); + mIsFirstTimeToggleOffBt = true; BluetoothService::CompleteToggleBt(aEnabled); AdapterStateChangedNotification(false); } else { BluetoothService::CompleteToggleBt(aEnabled); } }
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h +++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h @@ -5,16 +5,19 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_bluetooth_bluedroid_BluetoothServiceBluedroid_h #define mozilla_dom_bluetooth_bluedroid_BluetoothServiceBluedroid_h #include "BluetoothCommon.h" #include "BluetoothInterface.h" #include "BluetoothService.h" +#ifndef MOZ_B2G_BT_API_V1 +#include "nsDataHashtable.h" +#endif BEGIN_BLUETOOTH_NAMESPACE class BluetoothServiceBluedroid : public BluetoothService , public BluetoothNotificationHandler { class CancelDiscoveryResultHandler; class CleanupResultHandler; @@ -32,16 +35,18 @@ class BluetoothServiceBluedroid : public class ProfileDeinitResultHandler; class ProfileInitResultHandler; class RemoveBondResultHandler; class SetAdapterPropertyDiscoverableResultHandler; class SetAdapterPropertyResultHandler; class SspReplyResultHandler; class StartDiscoveryResultHandler; + class GetDeviceRequest; + public: BluetoothServiceBluedroid(); ~BluetoothServiceBluedroid(); #ifndef MOZ_B2G_BT_API_V1 virtual nsresult StartInternal(BluetoothReplyRunnable* aRunnable); virtual nsresult StopInternal(BluetoothReplyRunnable* aRunnable); #else @@ -385,13 +390,51 @@ protected: static bool EnsureBluetoothHalLoad(); static void ClassToIcon(uint32_t aClass, nsAString& aRetIcon); uint16_t UuidToServiceClassInt(const BluetoothUuid& mUuid); static bool IsConnected(const nsAString& aRemoteBdAddr); #endif + + // Adapter properties + nsString mBdAddress; + nsString mBdName; + bool mEnabled; + bool mDiscoverable; + bool mDiscovering; + nsTArray<nsString> mBondedAddresses; +#ifndef MOZ_B2G_BT_API_V1 + // Missing in Bluetooth v2 +#else + uint32_t mDiscoverableTimeout; +#endif + + // Backend error recovery + bool mIsRestart; + bool mIsFirstTimeToggleOffBt; + + // Array of get device requests. Each request remembers + // 1) remaining device count to receive properties, + // 2) received remote device properties, and + // 3) runnable to reply success/error + nsTArray<GetDeviceRequest> mGetDeviceRequests; + + // Runnable arrays + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mSetAdapterPropertyRunnables; + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mCreateBondRunnables; + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mRemoveBondRunnables; + +#ifndef MOZ_B2G_BT_API_V1 + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mChangeAdapterStateRunnables; + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mChangeDiscoveryRunnables; + nsTArray<nsRefPtr<BluetoothReplyRunnable>> mFetchUuidsRunnables; + + // <address, name> mapping table for remote devices + nsDataHashtable<nsStringHashKey, nsString> mDeviceNameMap; +#endif + }; END_BLUETOOTH_NAMESPACE #endif // mozilla_dom_bluetooth_bluedroid_BluetoothServiceBluedroid_h
--- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -1008,35 +1008,32 @@ void MediaDecoder::ChangeState(PlayState MOZ_ASSERT(NS_IsMainThread()); ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); if (mNextState == aState) { mNextState = PLAY_STATE_PAUSED; } if (mPlayState == PLAY_STATE_SHUTDOWN) { - GetReentrantMonitor().NotifyAll(); return; } DECODER_LOG("ChangeState %s => %s", ToPlayStateStr(mPlayState), ToPlayStateStr(aState)); mPlayState = aState; if (mPlayState == PLAY_STATE_PLAYING) { ConstructMediaTracks(); } else if (IsEnded()) { RemoveMediaTracks(); } CancelDormantTimer(); // Start dormant timer if necessary StartDormantTimer(); - - GetReentrantMonitor().NotifyAll(); } void MediaDecoder::UpdateLogicalPosition(MediaDecoderEventVisibility aEventVisibility) { MOZ_ASSERT(NS_IsMainThread()); if (mShuttingDown) return;
--- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -1093,25 +1093,21 @@ protected: // Media duration set explicitly by JS. At present, this is only ever present // for MSE. Canonical<Maybe<double>> mExplicitDuration; // Set to one of the valid play states. // This can only be changed on the main thread while holding the decoder // monitor. Thus, it can be safely read while holding the decoder monitor // OR on the main thread. - // Any change to the state on the main thread must call NotifyAll on the - // monitor so the decode thread can wake up. Canonical<PlayState> mPlayState; // This can only be changed on the main thread while holding the decoder // monitor. Thus, it can be safely read while holding the decoder monitor // OR on the main thread. - // Any change to the state must call NotifyAll on the monitor. - // This can only be PLAY_STATE_PAUSED or PLAY_STATE_PLAYING. Canonical<PlayState> mNextState; // True if the decoder is seeking. Canonical<bool> mLogicallySeeking; // True if the media is same-origin with the element. Data can only be // passed to MediaStreams when this is true. Canonical<bool> mSameOriginMedia;
--- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -655,19 +655,16 @@ MediaDecoderStateMachine::Push(VideoData MOZ_ASSERT(aSample); // TODO: Send aSample to MSG and recalculate readystate before pushing, // otherwise AdvanceFrame may pop the sample before we have a chance // to reach playing. aSample->mFrameID = ++mCurrentFrameID; VideoQueue().Push(aSample); UpdateNextFrameStatus(); DispatchDecodeTasksIfNeeded(); - - // XXXbholley - Is this still necessary? - mDecoder->GetReentrantMonitor().NotifyAll(); } void MediaDecoderStateMachine::PushFront(VideoData* aSample) { MOZ_ASSERT(OnTaskQueue()); MOZ_ASSERT(aSample); @@ -689,19 +686,16 @@ MediaDecoderStateMachine::OnAudioPopped( void MediaDecoderStateMachine::OnVideoPopped(const MediaData* aSample) { MOZ_ASSERT(OnTaskQueue()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->UpdatePlaybackOffset(aSample->mOffset); UpdateNextFrameStatus(); DispatchVideoDecodeTaskIfNeeded(); - // Notify the decode thread that the video queue's buffers may have - // free'd up space for more frames. - mDecoder->GetReentrantMonitor().NotifyAll(); } void MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType, MediaDecoderReader::NotDecodedReason aReason) { MOZ_ASSERT(OnTaskQueue()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); @@ -773,17 +767,16 @@ MediaDecoderStateMachine::OnNotDecoded(M } switch (mState) { case DECODER_STATE_BUFFERING: case DECODER_STATE_DECODING: { if (MaybeFinishDecodeFirstFrame()) { return; } CheckIfDecodeComplete(); - mDecoder->GetReentrantMonitor().NotifyAll(); // Schedule the state machine to notify track ended as soon as possible. if (mAudioCaptured) { ScheduleStateMachine(); } return; } case DECODER_STATE_SEEKING: { if (!mCurrentSeek.Exists()) { @@ -1088,17 +1081,16 @@ void MediaDecoderStateMachine::MaybeStar StartAudioThread(); // Tell DecodedStream to start playback with specified start time and media // info. This is consistent with how we create AudioSink in StartAudioThread(). if (mAudioCaptured) { mDecodedStream->StartPlayback(GetMediaTime(), mInfo); } - mDecoder->GetReentrantMonitor().NotifyAll(); DispatchDecodeTasksIfNeeded(); } void MediaDecoderStateMachine::UpdatePlaybackPositionInternal(int64_t aTime) { MOZ_ASSERT(OnTaskQueue()); SAMPLE_LOG("UpdatePlaybackPositionInternal(%lld)", aTime); AssertCurrentThreadInMonitor(); @@ -1255,23 +1247,21 @@ void MediaDecoderStateMachine::SetDorman // Note that we do not wait for the decode task queue to go idle before // queuing the ReleaseMediaResources task - instead, we disconnect promises, // reset state, and put a ResetDecode in the decode task queue. Any tasks // that run after ResetDecode are supposed to run with a clean slate. We rely // on that in other places (i.e. seeking), so it seems reasonable to rely on // it here as well. nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources); DecodeTaskQueue()->Dispatch(r.forget()); - mDecoder->GetReentrantMonitor().NotifyAll(); } else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) { mDecodingFrozenAtStateDecoding = true; ScheduleStateMachine(); mDecodingFirstFrame = true; SetState(DECODER_STATE_DECODING_NONE); - mDecoder->GetReentrantMonitor().NotifyAll(); } } void MediaDecoderStateMachine::Shutdown() { MOZ_ASSERT(OnTaskQueue()); // Once we've entered the shutdown state here there's no going back. @@ -1904,20 +1894,16 @@ MediaDecoderStateMachine::DecodeError() } // Change state to error, which will cause the state machine to wait until // the MediaDecoder shuts it down. SetState(DECODER_STATE_ERROR); ScheduleStateMachine(); DECODER_WARN("Decode error, changed state to ERROR"); - // XXXbholley - Is anybody actually waiting on this monitor, or is it just - // a leftover from when we used to do sync dispatch for the below? - mDecoder->GetReentrantMonitor().NotifyAll(); - // MediaDecoder::DecodeError notifies the owner, and then shuts down the state // machine. nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(mDecoder, &MediaDecoder::DecodeError); AbstractThread::MainThread()->Dispatch(event.forget()); } void @@ -2351,18 +2337,16 @@ nsresult MediaDecoderStateMachine::RunSt OutOfDecodedVideo(), VideoRequestStatus()); return NS_OK; } DECODER_LOG("Changed state from BUFFERING to DECODING"); DECODER_LOG("Buffered for %.3lfs", (now - mBufferingStart).ToSeconds()); StartDecoding(); - // Notify to allow blocked decoder thread to continue - mDecoder->GetReentrantMonitor().NotifyAll(); NS_ASSERTION(IsStateMachineScheduled(), "Must have timer scheduled"); return NS_OK; } case DECODER_STATE_SEEKING: { if (mPendingSeek.Exists()) { InitiateSeek(); } @@ -3071,19 +3055,16 @@ void MediaDecoderStateMachine::OnAudioSi { MOZ_ASSERT(OnTaskQueue()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); MOZ_ASSERT(!mAudioCaptured, "Should be disconnected when capturing audio."); mAudioSinkPromise.Complete(); ResyncAudioClock(); mAudioCompleted = true; - - // Kick the decode thread; it may be sleeping waiting for this to finish. - mDecoder->GetReentrantMonitor().NotifyAll(); } void MediaDecoderStateMachine::OnAudioSinkError() { MOZ_ASSERT(OnTaskQueue()); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); MOZ_ASSERT(!mAudioCaptured, "Should be disconnected when capturing audio.");
--- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -107,19 +107,18 @@ extern PRLogModuleInfo* gMediaDecoderLog extern PRLogModuleInfo* gMediaSampleLog; /* The state machine class. This manages the decoding and seeking in the MediaDecoderReader on the decode task queue, and A/V sync on the shared state machine thread, and controls the audio "push" thread. All internal state is synchronised via the decoder monitor. State changes - are either propagated by NotifyAll on the monitor (typically when state - changes need to be propagated to non-state machine threads) or by scheduling - the state machine to run another cycle on the shared state machine thread. + are propagated by scheduling the state machine to run another cycle on the + shared state machine thread. See MediaDecoder.h for more details. */ class MediaDecoderStateMachine { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine) public: typedef MediaDecoderReader::AudioDataPromise AudioDataPromise; @@ -881,18 +880,16 @@ private: // Queue of audio frames. This queue is threadsafe, and is accessed from // the audio, decoder, state machine, and main threads. MediaQueue<MediaData> mAudioQueue; // Queue of video frames. This queue is threadsafe, and is accessed from // the decoder, state machine, and main threads. MediaQueue<MediaData> mVideoQueue; // The decoder monitor must be obtained before modifying this state. - // NotifyAll on the monitor must be called when the state is changed so - // that interested threads can wake up and alter behaviour if appropriate // Accessed on state machine, audio, main, and AV thread. Watchable<State> mState; // The task queue in which we run decode tasks. This is referred to as // the "decode thread", though in practise tasks can run on a different // thread every time they're called. TaskQueue* DecodeTaskQueue() const { return mReader->OwnerThread(); }
--- a/gfx/harfbuzz/src/hb-ot-shape-fallback.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-fallback.cc @@ -413,23 +413,22 @@ position_cluster (const hb_ot_shape_plan void _hb_ot_shape_fallback_position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) { _hb_buffer_assert_gsubgpos_vars (buffer); unsigned int start = 0; - unsigned int last_cluster = buffer->info[0].cluster; unsigned int count = buffer->len; + hb_glyph_info_t *info = buffer->info; for (unsigned int i = 1; i < count; i++) - if (buffer->info[i].cluster != last_cluster) { + if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) { position_cluster (plan, font, buffer, start, i); start = i; - last_cluster = buffer->info[i].cluster; } position_cluster (plan, font, buffer, start, count); } /* Performs old-style TrueType kerning. */ void _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan,
--- a/gfx/harfbuzz/src/hb-ot-shape-normalize.cc +++ b/gfx/harfbuzz/src/hb-ot-shape-normalize.cc @@ -318,17 +318,17 @@ void /* First round, decompose */ buffer->clear_output (); count = buffer->len; for (buffer->idx = 0; buffer->idx < count;) { unsigned int end; for (end = buffer->idx + 1; end < count; end++) - if (buffer->cur().cluster != buffer->info[end].cluster) + if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))) break; decompose_cluster (&c, end, might_short_circuit, always_short_circuit); } buffer->swap_buffers (); /* Second round, reorder (inplace) */
--- a/gfx/tests/crashtests/crashtests.list +++ b/gfx/tests/crashtests/crashtests.list @@ -97,17 +97,17 @@ load 633322-1.html load 665218.html load 686190-1.html load 693143-1.html load 768079-1.html load 783041-1.html load 783041-2.html load 783041-3.html load 783041-4.html -load 798853.html # bug 868792 +asserts-if(gtkWidget,0-1) load 798853.html # bug 868792 asserts-if(winWidget,0-1) skip-if(B2G) load 815489.html load 836225-1.html load 839745-1.html load 856784-1.html load 893572-1.html load 893572-2.html load 893572-3.html load 893572-4.html
--- a/gfx/thebes/gfxHarfBuzzShaper.cpp +++ b/gfx/thebes/gfxHarfBuzzShaper.cpp @@ -1563,16 +1563,18 @@ gfxHarfBuzzShaper::ShapeText(gfxContext } hb_buffer_set_language(buffer, language); uint32_t length = aLength; hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16_t*>(aText), length, 0, length); + hb_buffer_set_cluster_level(buffer, HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); + hb_shape(mHBFont, buffer, features.Elements(), features.Length()); if (isRightToLeft) { hb_buffer_reverse(buffer); } nsresult rv = SetGlyphsFromRun(aContext, aShapedText, aOffset, aLength, aText, buffer, aVertical);
--- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -4760,16 +4760,20 @@ CanOptimizeDenseOrUnboxedArraySetElem(JS *isAddingCaseOut = false; *protoDepthOut = 0; // Some initial sanity checks. if (initLength < oldInitLength || capacity < oldCapacity) return false; + // Unboxed arrays need to be able to emit floating point code. + if (obj->is<UnboxedArrayObject>() && !obj->runtimeFromMainThread()->jitSupportsFloatingPoint) + return false; + Shape* shape = obj->maybeShape(); // Cannot optimize if the shape changed. if (oldShape != shape) return false; // Cannot optimize if the capacity changed. if (oldCapacity != capacity)
--- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -3118,22 +3118,17 @@ GenerateSetUnboxed(JSContext* cx, MacroA if (unboxedType == JSVAL_TYPE_OBJECT) masm.callPreBarrier(address, MIRType_Object); else if (unboxedType == JSVAL_TYPE_STRING) masm.callPreBarrier(address, MIRType_String); else MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(unboxedType)); } - // If unboxed objects in this group have have never been converted to - // native objects then the type set check performed above ensures the value - // being written can be stored in the unboxed object. - Label* storeFailure = obj->group()->unboxedLayout().nativeGroup() ? &failure : nullptr; - - masm.storeUnboxedProperty(address, unboxedType, value, storeFailure); + masm.storeUnboxedProperty(address, unboxedType, value, &failure); attacher.jumpRejoin(masm); masm.bind(&failurePopObject); masm.pop(object); masm.bind(&failure); attacher.jumpNextStub(masm);
--- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -769,24 +769,23 @@ IonBuilder::inlineArrayPush(CallInfo& ca MDefinition* obj = convertUnboxedObjects(callInfo.thisArg()); MDefinition* value = callInfo.getArg(0); if (PropertyWriteNeedsTypeBarrier(alloc(), constraints(), current, &obj, nullptr, &value, /* canModify = */ false)) { trackOptimizationOutcome(TrackedOutcome::NeedsTypeBarrier); return InliningStatus_NotInlined; } - MOZ_ASSERT(obj == callInfo.thisArg() && value == callInfo.getArg(0)); if (getInlineReturnType() != MIRType_Int32) return InliningStatus_NotInlined; - if (callInfo.thisArg()->type() != MIRType_Object) + if (obj->type() != MIRType_Object) return InliningStatus_NotInlined; - TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet(); + TemporaryTypeSet* thisTypes = obj->resultTypeSet(); if (!thisTypes) return InliningStatus_NotInlined; const Class* clasp = thisTypes->getKnownClass(constraints()); if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_) return InliningStatus_NotInlined; if (thisTypes->hasObjectFlags(constraints(), OBJECT_FLAG_SPARSE_INDEXES | OBJECT_FLAG_LENGTH_OVERFLOW)) { @@ -803,23 +802,22 @@ IonBuilder::inlineArrayPush(CallInfo& ca thisTypes->convertDoubleElements(constraints()); if (conversion == TemporaryTypeSet::AmbiguousDoubleConversion) { trackOptimizationOutcome(TrackedOutcome::ArrayDoubleConversion); return InliningStatus_NotInlined; } JSValueType unboxedType = JSVAL_TYPE_MAGIC; if (clasp == &UnboxedArrayObject::class_) { - unboxedType = UnboxedArrayElementType(constraints(), callInfo.thisArg(), nullptr); + unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr); if (unboxedType == JSVAL_TYPE_MAGIC) return InliningStatus_NotInlined; } callInfo.setImplicitlyUsedUnchecked(); - value = callInfo.getArg(0); if (conversion == TemporaryTypeSet::AlwaysConvertToDoubles || conversion == TemporaryTypeSet::MaybeConvertToDoubles) { MInstruction* valueDouble = MToDouble::New(alloc(), value); current->add(valueDouble); value = valueDouble; } @@ -934,16 +932,23 @@ IonBuilder::inlineArrayConcat(CallInfo& continue; if (key->unknownProperties()) return InliningStatus_NotInlined; HeapTypeSetKey elemTypes = key->property(JSID_VOID); if (!elemTypes.knownSubset(constraints(), thisElemTypes)) return InliningStatus_NotInlined; + + if (thisGroup->clasp() == &UnboxedArrayObject::class_ && + !CanStoreUnboxedType(alloc(), thisGroup->unboxedLayout().elementType(), + MIRType_Value, elemTypes.maybeTypes())) + { + return InliningStatus_NotInlined; + } } // Inline the call. JSObject* templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat); if (!templateObj || templateObj->group() != thisGroup) return InliningStatus_NotInlined; callInfo.setImplicitlyUsedUnchecked();
--- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -1851,16 +1851,50 @@ jit::EqualTypes(MIRType type1, Temporary return TypeSetIncludes(typeset1, type2, nullptr); if (!typeset1 && typeset2) return TypeSetIncludes(typeset2, type1, nullptr); // Typesets should equal. return typeset1->equals(typeset2); } +// Tests whether input/inputTypes can always be stored to an unboxed +// object/array property with the given unboxed type. +bool +jit::CanStoreUnboxedType(TempAllocator& alloc, + JSValueType unboxedType, MIRType input, TypeSet* inputTypes) +{ + TemporaryTypeSet types; + + switch (unboxedType) { + case JSVAL_TYPE_BOOLEAN: + case JSVAL_TYPE_INT32: + case JSVAL_TYPE_DOUBLE: + case JSVAL_TYPE_STRING: + types.addType(TypeSet::PrimitiveType(unboxedType), alloc.lifoAlloc()); + break; + + case JSVAL_TYPE_OBJECT: + types.addType(TypeSet::AnyObjectType(), alloc.lifoAlloc()); + types.addType(TypeSet::NullType(), alloc.lifoAlloc()); + break; + + default: + MOZ_CRASH("Bad unboxed type"); + } + + return TypeSetIncludes(&types, input, inputTypes); +} + +static bool +CanStoreUnboxedType(TempAllocator& alloc, JSValueType unboxedType, MDefinition* value) +{ + return CanStoreUnboxedType(alloc, unboxedType, value->type(), value->resultTypeSet()); +} + bool MPhi::specializeType() { #ifdef DEBUG MOZ_ASSERT(!specialized_); specialized_ = true; #endif @@ -5409,16 +5443,30 @@ jit::PropertyWriteNeedsTypeBarrier(TempA // or a VM call is required. A VM call is always required if pobj // and pvalue cannot be modified. if (!canModify) return true; success = TryAddTypeBarrierForWrite(alloc, constraints, current, types, name, pvalue, implicitType); break; } + + // Perform additional filtering to make sure that any unboxed property + // being written can accommodate the value. + if (key->isGroup() && key->group()->maybeUnboxedLayout()) { + const UnboxedLayout& layout = key->group()->unboxedLayout(); + if (name) { + const UnboxedLayout::Property* property = layout.lookup(name); + if (property && !CanStoreUnboxedType(alloc, property->type, *pvalue)) + return true; + } else { + if (layout.isArray() && !CanStoreUnboxedType(alloc, layout.elementType(), *pvalue)) + return true; + } + } } if (success) return false; // If all of the objects except one have property types which reflect the // value, and the remaining object has no types at all for the property, // add a guard that the object does not have that remaining object's type.
--- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -2836,16 +2836,20 @@ MergeTypes(MIRType* ptype, TemporaryType bool TypeSetIncludes(TypeSet* types, MIRType input, TypeSet* inputTypes); bool EqualTypes(MIRType type1, TemporaryTypeSet* typeset1, MIRType type2, TemporaryTypeSet* typeset2); +bool +CanStoreUnboxedType(TempAllocator& alloc, + JSValueType unboxedType, MIRType input, TypeSet* inputTypes); + #ifdef DEBUG bool IonCompilationCanUseNurseryPointers(); #endif // Helper class to check that GC pointers embedded in MIR instructions are in // in the nursery only when the store buffer has been marked as needing to // cancel all ion compilations. Otherwise, off-thread Ion compilation and
--- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -124,17 +124,17 @@ class UnboxedLayout : public mozilla::Li js_free(traceList_); nativeGroup_.init(nullptr); nativeShape_.init(nullptr); replacementGroup_.init(nullptr); constructorCode_.init(nullptr); } - bool isArray() { + bool isArray() const { return elementType_ != JSVAL_TYPE_MAGIC; } void detachFromCompartment(); const PropertyVector& properties() const { return properties_; }
--- a/mfbt/Attributes.h +++ b/mfbt/Attributes.h @@ -392,20 +392,25 @@ * an array of such objects, as a global or static variable, or as the type of * a new expression (unless placement new is being used). If a member of * another class uses this class, or if another class inherits from this * class, then it is considered to be a stack class as well, although this * attribute need not be provided in such cases. * MOZ_NONHEAP_CLASS: Applies to all classes. Any class with this annotation is * expected to live on the stack or in static storage, so it is a compile-time * error to use it, or an array of such objects, as the type of a new - * expression (unless placement new is being used). If a member of another - * class uses this class, or if another class inherits from this class, then - * it is considered to be a non-heap class as well, although this attribute - * need not be provided in such cases. + * expression. If a member of another class uses this class, or if another + * class inherits from this class, then it is considered to be a non-heap class + * as well, although this attribute need not be provided in such cases. + * MOZ_HEAP_CLASS: Applies to all classes. Any class with this annotation is + * expected to live on the heap, so it is a compile-time error to use it, or + * an array of such objects, as the type of a variable declaration, or as a + * temporary object. If a member of another class uses this class, or if + * another class inherits from this class, then it is considered to be a heap + * class as well, although this attribute need not be provided in such cases. * MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS: Applies to all classes that are * intended to prevent introducing static initializers. This attribute * currently makes it a compile-time error to instantiate these classes * anywhere other than at the global scope, or as a static member of a class. * MOZ_TRIVIAL_CTOR_DTOR: Applies to all classes that must have both a trivial * constructor and a trivial destructor. Setting this attribute on a class * makes it a compile-time error for that class to get a non-trivial * constructor or destructor for any reason. @@ -470,16 +475,17 @@ * declarations where an instance of the template should be considered, for * static analysis purposes, to inherit any type annotations (such as * MOZ_MUST_USE and MOZ_STACK_CLASS) from its template arguments. */ #ifdef MOZ_CLANG_PLUGIN # define MOZ_MUST_OVERRIDE __attribute__((annotate("moz_must_override"))) # define MOZ_STACK_CLASS __attribute__((annotate("moz_stack_class"))) # define MOZ_NONHEAP_CLASS __attribute__((annotate("moz_nonheap_class"))) +# define MOZ_HEAP_CLASS __attribute__((annotate("moz_heap_class"))) # define MOZ_TRIVIAL_CTOR_DTOR __attribute__((annotate("moz_trivial_ctor_dtor"))) # ifdef DEBUG /* in debug builds, these classes do have non-trivial constructors. */ # define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) # else # define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS __attribute__((annotate("moz_global_class"))) \ MOZ_TRIVIAL_CTOR_DTOR # endif @@ -504,16 +510,17 @@ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ __attribute__((annotate("moz_heap_allocator"))) \ _Pragma("clang diagnostic pop") #else # define MOZ_MUST_OVERRIDE /* nothing */ # define MOZ_STACK_CLASS /* nothing */ # define MOZ_NONHEAP_CLASS /* nothing */ +# define MOZ_HEAP_CLASS /* nothing */ # define MOZ_TRIVIAL_CTOR_DTOR /* nothing */ # define MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS /* nothing */ # define MOZ_IMPLICIT /* nothing */ # define MOZ_NO_ARITHMETIC_EXPR_IN_ARGUMENT /* nothing */ # define MOZ_HEAP_ALLOCATOR /* nothing */ # define MOZ_OWNING_REF /* nothing */ # define MOZ_NON_OWNING_REF /* nothing */ # define MOZ_UNSAFE_REF(reason) /* nothing */
--- a/mobile/android/confvars.sh +++ b/mobile/android/confvars.sh @@ -107,14 +107,8 @@ export JS_GC_SMALL_CHUNK_SIZE=1 # Enable FxAccount Avatar if test "$NIGHTLY_BUILD"; then MOZ_ANDROID_FIREFOX_ACCOUNT_PROFILES=1 fi # Enable checking that add-ons are signed by the trusted root MOZ_ADDON_SIGNING=1 -if test "$MOZ_OFFICIAL_BRANDING"; then - if test "$MOZ_UPDATE_CHANNEL" = "beta" -o \ - "$MOZ_UPDATE_CHANNEL" = "release"; then - MOZ_REQUIRE_SIGNING=1 - fi -fi
--- a/netwerk/cache2/CacheIndex.cpp +++ b/netwerk/cache2/CacheIndex.cpp @@ -1483,74 +1483,68 @@ CacheIndex::HasEntryChanged(CacheIndexEn void CacheIndex::ProcessPendingOperations() { LOG(("CacheIndex::ProcessPendingOperations()")); AssertOwnsLock(); - mPendingUpdates.EnumerateEntries(&CacheIndex::UpdateEntryInIndex, this); + for (auto iter = mPendingUpdates.Iter(); !iter.Done(); iter.Next()) { + CacheIndexEntryUpdate* update = iter.Get(); + + LOG(("CacheIndex::ProcessPendingOperations() [hash=%08x%08x%08x%08x%08x]", + LOGSHA1(update->Hash()))); + + MOZ_ASSERT(update->IsFresh()); + + CacheIndexEntry* entry = mIndex.GetEntry(*update->Hash()); + + { + CacheIndexEntryAutoManage emng(update->Hash(), this); + emng.DoNotSearchInUpdates(); + + if (update->IsRemoved()) { + if (entry) { + if (entry->IsRemoved()) { + MOZ_ASSERT(entry->IsFresh()); + MOZ_ASSERT(entry->IsDirty()); + } else if (!entry->IsDirty() && entry->IsFileEmpty()) { + // Entries with empty file are not stored in index on disk. Just + // remove the entry, but only in case the entry is not dirty, i.e. + // the entry file was empty when we wrote the index. + mIndex.RemoveEntry(*update->Hash()); + entry = nullptr; + } else { + entry->MarkRemoved(); + entry->MarkDirty(); + entry->MarkFresh(); + } + } + } else if (entry) { + // Some information in mIndex can be newer than in mPendingUpdates (see + // bug 1074832). This will copy just those values that were really + // updated. + update->ApplyUpdate(entry); + } else { + // There is no entry in mIndex, copy all information from + // mPendingUpdates to mIndex. + entry = mIndex.PutEntry(*update->Hash()); + *entry = *update; + } + } + + iter.Remove(); + } MOZ_ASSERT(mPendingUpdates.Count() == 0); EnsureCorrectStats(); } -// static -PLDHashOperator -CacheIndex::UpdateEntryInIndex(CacheIndexEntryUpdate *aEntry, void* aClosure) -{ - CacheIndex *index = static_cast<CacheIndex *>(aClosure); - - LOG(("CacheFile::UpdateEntryInIndex() [hash=%08x%08x%08x%08x%08x]", - LOGSHA1(aEntry->Hash()))); - - MOZ_ASSERT(aEntry->IsFresh()); - - CacheIndexEntry *entry = index->mIndex.GetEntry(*aEntry->Hash()); - - CacheIndexEntryAutoManage emng(aEntry->Hash(), index); - emng.DoNotSearchInUpdates(); - - if (aEntry->IsRemoved()) { - if (entry) { - if (entry->IsRemoved()) { - MOZ_ASSERT(entry->IsFresh()); - MOZ_ASSERT(entry->IsDirty()); - } else if (!entry->IsDirty() && entry->IsFileEmpty()) { - // Entries with empty file are not stored in index on disk. Just remove - // the entry, but only in case the entry is not dirty, i.e. the entry - // file was empty when we wrote the index. - index->mIndex.RemoveEntry(*aEntry->Hash()); - entry = nullptr; - } else { - entry->MarkRemoved(); - entry->MarkDirty(); - entry->MarkFresh(); - } - } - - return PL_DHASH_REMOVE; - } - - if (entry) { - // Some information in mIndex can be newer than in mPendingUpdates (see bug - // 1074832). This will copy just those values that were really updated. - aEntry->ApplyUpdate(entry); - } else { - // There is no entry in mIndex, copy all information from mPendingUpdates - // to mIndex. - entry = index->mIndex.PutEntry(*aEntry->Hash()); - *entry = *aEntry; - } - - return PL_DHASH_REMOVE; -} - bool CacheIndex::WriteIndexToDiskIfNeeded() { if (mState != READY || mShuttingDown) { return false; } if (!mLastDumpTime.IsNull() && @@ -1705,17 +1699,35 @@ CacheIndex::FinishWrite(bool aSucceeded) mIndexHandle = nullptr; mRWHash = nullptr; ReleaseBuffer(); if (aSucceeded) { // Opening of the file must not be in progress if writing succeeded. MOZ_ASSERT(!mIndexFileOpener); - mIndex.EnumerateEntries(&CacheIndex::ApplyIndexChanges, this); + for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) { + CacheIndexEntry* entry = iter.Get(); + + bool remove = false; + { + CacheIndexEntryAutoManage emng(entry->Hash(), this); + + if (entry->IsRemoved()) { + emng.DoNotSearchInIndex(); + remove = true; + } else if (entry->IsDirty()) { + entry->ClearDirty(); + } + } + if (remove) { + iter.Remove(); + } + } + mIndexOnDiskIsValid = true; } else { if (mIndexFileOpener) { // If opening of the file is still in progress (e.g. WRITE process was // canceled by RemoveAll()) then we need to cancel the opener to make sure // that OnFileOpenedInternal() won't be called. mIndexFileOpener->Cancel(); mIndexFileOpener = nullptr; @@ -1762,36 +1774,16 @@ CacheIndex::CopyRecordsToRWBuf(CacheInde aEntry->WriteToBuf(data->mBuf); data->mBuf += sizeof(CacheIndexRecord); data->mProcessed++; return PL_DHASH_NEXT; } -// static -PLDHashOperator -CacheIndex::ApplyIndexChanges(CacheIndexEntry *aEntry, void* aClosure) -{ - CacheIndex *index = static_cast<CacheIndex *>(aClosure); - - CacheIndexEntryAutoManage emng(aEntry->Hash(), index); - - if (aEntry->IsRemoved()) { - emng.DoNotSearchInIndex(); - return PL_DHASH_REMOVE; - } - - if (aEntry->IsDirty()) { - aEntry->ClearDirty(); - } - - return PL_DHASH_NEXT; -} - nsresult CacheIndex::GetFile(const nsACString &aName, nsIFile **_retval) { nsresult rv; nsCOMPtr<nsIFile> file; rv = mCacheDirectory->Clone(getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv); @@ -1966,17 +1958,23 @@ CacheIndex::WriteLogToDisk() mIndexStats.Log(); PRFileDesc *fd = nullptr; rv = logFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 0600, &fd); NS_ENSURE_SUCCESS(rv, rv); WriteLogHelper wlh(fd); - mIndex.EnumerateEntries(&CacheIndex::WriteEntryToLog, &wlh); + for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) { + CacheIndexEntry* entry = iter.Get(); + if (entry->IsRemoved() || entry->IsDirty()) { + wlh.AddEntry(entry); + } + iter.Remove(); + } rv = wlh.Finish(); PR_Close(fd); NS_ENSURE_SUCCESS(rv, rv); rv = indexFile->OpenNSPRFileDesc(PR_RDWR, 0600, &fd); NS_ENSURE_SUCCESS(rv, rv); @@ -1999,29 +1997,16 @@ CacheIndex::WriteLogToDisk() PR_Close(fd); if (bytesWritten != sizeof(CacheIndexHeader)) { return NS_ERROR_FAILURE; } return NS_OK; } -// static -PLDHashOperator -CacheIndex::WriteEntryToLog(CacheIndexEntry *aEntry, void* aClosure) -{ - WriteLogHelper *wlh = static_cast<WriteLogHelper *>(aClosure); - - if (aEntry->IsRemoved() || aEntry->IsDirty()) { - wlh->AddEntry(aEntry); - } - - return PL_DHASH_REMOVE; -} - void CacheIndex::ReadIndexFromDisk() { LOG(("CacheIndex::ReadIndexFromDisk()")); nsresult rv; AssertOwnsLock(); @@ -2389,43 +2374,39 @@ CacheIndex::ProcessJournalEntry(CacheInd } void CacheIndex::EnsureNoFreshEntry() { #ifdef DEBUG_STATS CacheIndexStats debugStats; debugStats.DisableLogging(); - mIndex.EnumerateEntries(&CacheIndex::SumIndexStats, &debugStats); + for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) { + debugStats.BeforeChange(nullptr); + debugStats.AfterChange(iter.Get()); + } MOZ_ASSERT(debugStats.Fresh() == 0); #endif } void CacheIndex::EnsureCorrectStats() { #ifdef DEBUG_STATS MOZ_ASSERT(mPendingUpdates.Count() == 0); CacheIndexStats debugStats; debugStats.DisableLogging(); - mIndex.EnumerateEntries(&CacheIndex::SumIndexStats, &debugStats); + for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) { + debugStats.BeforeChange(nullptr); + debugStats.AfterChange(iter.Get()); + } MOZ_ASSERT(debugStats == mIndexStats); #endif } -// static -PLDHashOperator -CacheIndex::SumIndexStats(CacheIndexEntry *aEntry, void* aClosure) -{ - CacheIndexStats *stats = static_cast<CacheIndexStats *>(aClosure); - stats->BeforeChange(nullptr); - stats->AfterChange(aEntry); - return PL_DHASH_NEXT; -} - void CacheIndex::FinishRead(bool aSucceeded) { LOG(("CacheIndex::FinishRead() [succeeded=%d]", aSucceeded)); AssertOwnsLock(); MOZ_ASSERT((!aSucceeded && mState == SHUTDOWN) || mState == READING); @@ -2472,17 +2453,17 @@ CacheIndex::FinishRead(bool aSucceeded) return; } if (!mIndexOnDiskIsValid) { MOZ_ASSERT(mTmpJournal.Count() == 0); EnsureNoFreshEntry(); ProcessPendingOperations(); // Remove all entries that we haven't seen during this session - mIndex.EnumerateEntries(&CacheIndex::RemoveNonFreshEntries, this); + RemoveNonFreshEntries(); StartUpdatingIndex(true); return; } if (!mJournalReadSuccessfully) { mTmpJournal.Clear(); EnsureNoFreshEntry(); ProcessPendingOperations(); @@ -3060,44 +3041,46 @@ CacheIndex::FinishUpdate(bool aSucceeded if (mState == SHUTDOWN) { return; } if (mState == UPDATING && aSucceeded) { // If we've iterated over all entries successfully then all entries that // really exist on the disk are now marked as fresh. All non-fresh entries // don't exist anymore and must be removed from the index. - mIndex.EnumerateEntries(&CacheIndex::RemoveNonFreshEntries, this); + RemoveNonFreshEntries(); } // Make sure we won't start update. If the build or update failed, there is no // reason to believe that it will succeed next time. mIndexNeedsUpdate = false; ChangeState(READY); mLastDumpTime = TimeStamp::NowLoRes(); // Do not dump new index immediately } -// static -PLDHashOperator -CacheIndex::RemoveNonFreshEntries(CacheIndexEntry *aEntry, void* aClosure) +void +CacheIndex::RemoveNonFreshEntries() { - if (aEntry->IsFresh()) { - return PL_DHASH_NEXT; + for (auto iter = mIndex.Iter(); !iter.Done(); iter.Next()) { + CacheIndexEntry* entry = iter.Get(); + if (entry->IsFresh()) { + continue; + } + + LOG(("CacheIndex::RemoveNonFreshEntries() - Removing entry. " + "[hash=%08x%08x%08x%08x%08x]", LOGSHA1(entry->Hash()))); + + { + CacheIndexEntryAutoManage emng(entry->Hash(), this); + emng.DoNotSearchInIndex(); + } + + iter.Remove(); } - - LOG(("CacheFile::RemoveNonFreshEntries() - Removing entry. " - "[hash=%08x%08x%08x%08x%08x]", LOGSHA1(aEntry->Hash()))); - - CacheIndex *index = static_cast<CacheIndex *>(aClosure); - - CacheIndexEntryAutoManage emng(aEntry->Hash(), index); - emng.DoNotSearchInIndex(); - - return PL_DHASH_REMOVE; } // static char const * CacheIndex::StateString(EState aState) { switch (aState) { case INITIAL: return "INITIAL";
--- a/netwerk/cache2/CacheIndex.h +++ b/netwerk/cache2/CacheIndex.h @@ -718,18 +718,16 @@ private: // Checks whether any of the information about the entry has changed. static bool HasEntryChanged(CacheIndexEntry *aEntry, const uint32_t *aFrecency, const uint32_t *aExpirationTime, const uint32_t *aSize); // Merge all pending operations from mPendingUpdates into mIndex. void ProcessPendingOperations(); - static PLDHashOperator UpdateEntryInIndex(CacheIndexEntryUpdate *aEntry, - void* aClosure); // Following methods perform writing of the index file. // // The index is written periodically, but not earlier than once in // kMinDumpInterval and there must be at least kMinUnwrittenChanges // differences between index on disk and in memory. Index is always first // written to a temporary file and the old index file is replaced when the // writing process succeeds. @@ -742,35 +740,30 @@ private: // Serializes part of mIndex hashtable to the write buffer a writes the buffer // to the file. void WriteRecords(); // Finalizes writing process. void FinishWrite(bool aSucceeded); static PLDHashOperator CopyRecordsToRWBuf(CacheIndexEntry *aEntry, void* aClosure); - static PLDHashOperator ApplyIndexChanges(CacheIndexEntry *aEntry, - void* aClosure); // Following methods perform writing of the journal during shutdown. All these // methods must be called only during shutdown since they write/delete files // directly on the main thread instead of using CacheFileIOManager that does // it asynchronously on IO thread. Journal contains only entries that are // dirty, i.e. changes that are not present in the index file on the disk. // When the log is written successfully, the dirty flag in index file is // cleared. nsresult GetFile(const nsACString &aName, nsIFile **_retval); nsresult RemoveFile(const nsACString &aName); void RemoveIndexFromDisk(); // Writes journal to the disk and clears dirty flag in index header. nsresult WriteLogToDisk(); - static PLDHashOperator WriteEntryToLog(CacheIndexEntry *aEntry, - void* aClosure); - // Following methods perform reading of the index from the disk. // // Index is read at startup just after initializing the CacheIndex. There are // 3 files used when manipulating with index: index file, journal file and // a temporary file. All files contain the hash of the data, so we can check // whether the content is valid and complete. Index file contains also a dirty // flag in the index header which is unset on a clean shutdown. During opening // and reading of the files we determine the status of the whole index from @@ -815,17 +808,16 @@ private: // Merges entries from journal into mIndex. void MergeJournal(); // In debug build this method checks that we have no fresh entry in mIndex // after we finish reading index and before we process pending operations. void EnsureNoFreshEntry(); // In debug build this method is called after processing pending operations // to make sure mIndexStats contains correct information. void EnsureCorrectStats(); - static PLDHashOperator SumIndexStats(CacheIndexEntry *aEntry, void* aClosure); // Finalizes reading process. void FinishRead(bool aSucceeded); static PLDHashOperator ProcessJournalEntry(CacheIndexEntry *aEntry, void* aClosure); // Following methods perform updating and building of the index. // Timer callback that starts update or build process. @@ -848,18 +840,17 @@ private: void StartUpdatingIndex(bool aRebuild); // Iterates through all files in entries directory that we didn't create/open // during this session and theirs last modified time is newer than timestamp // in the index header. Parses the files and adds the entries to the index. void UpdateIndex(); // Finalizes update or build process. void FinishUpdate(bool aSucceeded); - static PLDHashOperator RemoveNonFreshEntries(CacheIndexEntry *aEntry, - void* aClosure); + void RemoveNonFreshEntries(); enum EState { // Initial state in which the index is not usable // Possible transitions: // -> READING INITIAL = 0, // Index is being read from the disk.
--- a/widget/windows/WinIMEHandler.cpp +++ b/widget/windows/WinIMEHandler.cpp @@ -700,17 +700,17 @@ IMEHandler::ShowOnScreenKeyboard() wchar_t path[MAX_PATH]; // The path to TabTip.exe is defined at the following registry key. // This is pulled out of the 64-bit registry hive directly. const wchar_t kRegKeyName[] = L"Software\\Classes\\CLSID\\" L"{054AAE20-4BEA-4347-8A35-64A533254A9D}\\LocalServer32"; if (!WinUtils::GetRegistryKey(HKEY_LOCAL_MACHINE, kRegKeyName, - 0, + nullptr, path, sizeof path)) { return; } std::wstring wstrpath(path); // The path provided by the registry will often contain // %CommonProgramFiles%, which will need to be replaced if it is present. @@ -740,36 +740,37 @@ IMEHandler::ShowOnScreenKeyboard() } else { PWSTR path = nullptr; HRESULT hres = WinUtils::SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, nullptr, &path); if (FAILED(hres) || !path) { return; } - commonProgramFilesPath = nsDependentString(path).get(); + commonProgramFilesPath = + static_cast<const wchar_t*>(nsDependentString(path).get()); ::CoTaskMemFree(path); } wstrpath.replace(commonProgramFilesOffset, wcslen(L"%CommonProgramFiles%"), commonProgramFilesPath); } cachedPath.Assign(wstrpath.data()); Preferences::SetString(kOskPathPrefName, cachedPath); } - LPCWSTR cachedPathPtr; + const char16_t *cachedPathPtr; cachedPath.GetData(&cachedPathPtr); - HINSTANCE ret = ::ShellExecuteW(nullptr, - L"", - cachedPathPtr, - nullptr, - nullptr, - SW_SHOW); + ShellExecuteW(nullptr, + L"", + char16ptr_t(cachedPathPtr), + nullptr, + nullptr, + SW_SHOW); sShowingOnScreenKeyboard = true; } // Based on DismissVirtualKeyboard() in Chromium's base/win/win_util.cc. // static void IMEHandler::DismissOnScreenKeyboard() {