Merge m-c to fx-team. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-09-02 14:57:38 -04:00
commit 9688a15055
159 changed files with 3111 additions and 2159 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<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="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="e1a50a20b3383e3b0959e5b32ef429425fd6be5b"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
@ -110,7 +110,7 @@
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="b0f9410d2f7111d2fc9b30e2f7bb14dd89af0259"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="fd241573c00112ca6e456b8021fb68df0349f6dd"/>
<project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
<project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<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="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="e1a50a20b3383e3b0959e5b32ef429425fd6be5b"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
@ -115,7 +115,7 @@
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="b0f9410d2f7111d2fc9b30e2f7bb14dd89af0259"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="fd241573c00112ca6e456b8021fb68df0349f6dd"/>
<project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
<project name="platform/system/media" path="system/media" revision="188b3e51e0a2ce1e16dc8067edef7be3d2365ad9"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>

View File

@ -5,5 +5,12 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

View File

@ -19,7 +19,7 @@
<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="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>

View File

@ -5,5 +5,12 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

View File

@ -17,10 +17,10 @@
</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="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="e1a50a20b3383e3b0959e5b32ef429425fd6be5b"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
@ -118,7 +118,7 @@
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
<project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="b0f9410d2f7111d2fc9b30e2f7bb14dd89af0259"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="fd241573c00112ca6e456b8021fb68df0349f6dd"/>
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>

View File

@ -5,5 +5,12 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<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="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="e1a50a20b3383e3b0959e5b32ef429425fd6be5b"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
@ -115,7 +115,7 @@
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b562b01c93de9578d5db537b6a602a38e1aaa0ce"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="387f03e815f57d536dd922706db1622bddba8d81"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="b0f9410d2f7111d2fc9b30e2f7bb14dd89af0259"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="fd241573c00112ca6e456b8021fb68df0349f6dd"/>
<project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
<project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>

View File

@ -5,5 +5,12 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

View File

@ -15,7 +15,7 @@
<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="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<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="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="e1a50a20b3383e3b0959e5b32ef429425fd6be5b"/>
<!-- Stock Android things -->
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
@ -126,7 +126,7 @@
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="2c0d193349c55337e37196a7f2d5cef37753ed3e"/>
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="61a10cbd19d6b7fc052a8cb92dfa1b37b93754f3"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="9e892a67a01671f312c76b0880dedaa6ba478148"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="b0f9410d2f7111d2fc9b30e2f7bb14dd89af0259"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="fd241573c00112ca6e456b8021fb68df0349f6dd"/>
<project name="platform/system/extras" path="system/extras" revision="47fa016e2248b80aebd5928402c7409f8e0ca64e"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
<project name="platform/system/media" path="system/media" revision="70bfebc66d9c6a4c614a8c7efde90e8e7e1d8641"/>

View File

@ -5,5 +5,12 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

View File

@ -5,5 +5,12 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

View File

@ -5,5 +5,12 @@
"algorithm": "sha512",
"filename": "gcc.tar.xz",
"unpack": "True"
},
{
"size": 12057960,
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
"algorithm": "sha512",
"filename": "gtk3.tar.xz",
"unpack": true
}
]

View File

@ -19,7 +19,7 @@
<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="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<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="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="e1a50a20b3383e3b0959e5b32ef429425fd6be5b"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
@ -109,7 +109,7 @@
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="b0f9410d2f7111d2fc9b30e2f7bb14dd89af0259"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="fd241573c00112ca6e456b8021fb68df0349f6dd"/>
<project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
<project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "e2fab8f6ac345ecde10a1350e699be9ceb6987d6",
"git_revision": "29f363d6236bf7db8141d7a1f1185a1dcd809bf7",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "1ab9e5d9915dc22fed71384a53dc565bce1709aa",
"revision": "90326c2ed68fa44fe6e71dd88bf996180c4aad24",
"repo_path": "integration/gaia-central"
}

View File

@ -17,10 +17,10 @@
</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="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="51ebaf824cc634665c5efcae95b8301ad1758c5e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="e1a50a20b3383e3b0959e5b32ef429425fd6be5b"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
@ -118,7 +118,7 @@
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
<project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="b0f9410d2f7111d2fc9b30e2f7bb14dd89af0259"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="fd241573c00112ca6e456b8021fb68df0349f6dd"/>
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>

View File

@ -15,7 +15,7 @@
<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="e2fab8f6ac345ecde10a1350e699be9ceb6987d6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29f363d6236bf7db8141d7a1f1185a1dcd809bf7"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9e2923fd6cab93cf88b4b9ada82225e44fe6635"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
@ -23,7 +23,7 @@
<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="b4f6fd4afd03161f53c7d2a663750f94762bd238"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="e1a50a20b3383e3b0959e5b32ef429425fd6be5b"/>
<!-- Stock Android things -->
<project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
<project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
@ -126,7 +126,7 @@
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="2c0d193349c55337e37196a7f2d5cef37753ed3e"/>
<project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="61a10cbd19d6b7fc052a8cb92dfa1b37b93754f3"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="9e892a67a01671f312c76b0880dedaa6ba478148"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="b0f9410d2f7111d2fc9b30e2f7bb14dd89af0259"/>
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="fd241573c00112ca6e456b8021fb68df0349f6dd"/>
<project name="platform/system/extras" path="system/extras" revision="47fa016e2248b80aebd5928402c7409f8e0ca64e"/>
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="34adfb400e031f3dd3353d92413572db5e3a7376"/>
<project name="platform/system/media" path="system/media" revision="70bfebc66d9c6a4c614a8c7efde90e8e7e1d8641"/>
@ -141,7 +141,7 @@
<default remote="caf" revision="refs/tags/android-5.1.0_r1" sync-j="4"/>
<!-- Nexus 5 specific things -->
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="fe7df1bc8dd0fd71571505d7be1c31a4ad1e40fb"/>
<project name="device-hammerhead" path="device/lge/hammerhead" remote="b2g" revision="e728bf3ff61dfab1b97c2416096a3b850b47cf25"/>
<project name="device-hammerhead" path="device/lge/hammerhead" remote="b2g" revision="31b5bafd0d234984f1133a3b3d08839521f2b718"/>
<project name="device_lge_hammerhead-kernel" path="device/lge/hammerhead-kernel" remote="b2g" revision="8b3ffcfdd3d3852eca5488628f8bb2a08acbffa7"/>
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="5d0ae53d9588c3d70c005aec9be94af9a534de16"/>
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="c15b6e266136cd0cdd9b94d0bbed1962d9dd6672"/>

View File

@ -1598,6 +1598,14 @@ Navigator::HasFeature(const nsAString& aName, ErrorResult& aRv)
return nullptr;
}
// Hardcoded web-extensions feature which is b2g specific.
#ifdef MOZ_B2G
if (aName.EqualsLiteral("web-extensions")) {
p->MaybeResolve(true);
return p.forget();
}
#endif
// Hardcoded manifest features. Some are still b2g specific.
const char manifestFeatures[][64] = {
"manifest.origin"

View File

@ -13,22 +13,17 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1009645
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1009645">Mozilla Bug 1009645</a>
<script type="application/javascript">
function testAPIs() {
function pref(name) {
try {
return SpecialPowers.getBoolPref(name);
} catch (e) {
return false;
}
var b2gOnly;
function pref(name) {
try {
return SpecialPowers.getBoolPref(name);
} catch (e) {
return false;
}
}
var b2gOnly = (function() {
var isAndroid = !!navigator.userAgent.includes("Android");
var isMulet = pref("b2g.is_mulet");
var isB2g = isMulet || (!isAndroid && /Mobile|Tablet/.test(navigator.userAgent));
return isB2g ? true : undefined;
})();
function testAPIs() {
var APIEndPoints = [
{ name: "MozMobileNetworkInfo", enabled: pref("dom.mobileconnection.enabled") },
// { name: "Navigator.mozBluetooth", enabled: b2gOnly }, // conditional on MOZ_B2G_BT, tricky to test
@ -52,25 +47,45 @@ function testAPIs() {
APIEndPoints.forEach(function(v) {
promises.push(navigator.hasFeature("api.window." + v.name));
});
Promise.all(promises).then(function(values) {
return Promise.all(promises).then(function(values) {
for (var i = 0; i < values.length; ++i) {
is(values[i], APIEndPoints[i].enabled,
"Endpoint " + APIEndPoints[i].name + " resolved with the correct value. " +
"If this is failing because you're changing how an API is exposed, you " +
"must contact the Marketplace team to let them know about the change.");
}
SimpleTest.finish();
}, function() {
ok(false, "The Promise should not be rejected");
SimpleTest.finish();
});
}
function testExtensions() {
if (!b2gOnly) {
return Promise.resolve();
}
return navigator.hasFeature("web-extensions").then(function(value) {
is(value, true, "Resolve the Promise with " + value + " for web-extensions");
}, function() {
ok(false, "The Promise should not be rejected");
});
}
SpecialPowers.pushPermissions([
{type: "feature-detection", allow: true, context: document}
], function() {
b2gOnly = (function() {
var isAndroid = !!navigator.userAgent.includes("Android");
var isMulet = pref("b2g.is_mulet");
var isB2g = isMulet || (!isAndroid && /Mobile|Tablet/.test(navigator.userAgent));
return isB2g ? true : undefined;
})();
ok('hasFeature' in navigator, "navigator.hasFeature should exist");
testAPIs();
testAPIs().then(testExtensions).catch(function(e) {
ok(false, "The Promise should not be rejected: " + e);
}).then(SimpleTest.finish);
});
SimpleTest.waitForExplicitFinish();

View File

@ -428,7 +428,7 @@ class CGDOMJSClass(CGThing):
""",
objectMoved=objectMovedHook)
if self.descriptor.isGlobal():
classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS)"
traceHook = "JS_GlobalObjectTraceHook"
reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
if self.descriptor.interface.identifier.name == "Window":

View File

@ -1419,6 +1419,47 @@ BluetoothDaemonHandsfreeModule::KeyPressedNtf(
KeyPressedInitOp(aPDU));
}
// Init operator class for WbsNotification
class BluetoothDaemonHandsfreeModule::WbsInitOp final
: private PDUInitOp
{
public:
WbsInitOp(DaemonSocketPDU& aPDU)
: PDUInitOp(aPDU)
{ }
nsresult
operator () (BluetoothHandsfreeWbsConfig& aArg1, nsString& aArg2) const
{
DaemonSocketPDU& pdu = GetPDU();
/* Read state */
nsresult rv = UnpackPDU(pdu, aArg1);
if (NS_FAILED(rv)) {
return rv;
}
/* Read address */
rv = UnpackPDU(
pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
if (NS_FAILED(rv)) {
return rv;
}
WarnAboutTrailingData();
return NS_OK;
}
};
void
BluetoothDaemonHandsfreeModule::WbsNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
WbsNotification::Dispatch(
&BluetoothHandsfreeNotificationHandler::WbsNotification,
WbsInitOp(aPDU));
}
void
BluetoothDaemonHandsfreeModule::HandleNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
@ -1441,7 +1482,8 @@ BluetoothDaemonHandsfreeModule::HandleNtf(
[12] = &BluetoothDaemonHandsfreeModule::CopsNtf,
[13] = &BluetoothDaemonHandsfreeModule::ClccNtf,
[14] = &BluetoothDaemonHandsfreeModule::UnknownAtNtf,
[15] = &BluetoothDaemonHandsfreeModule::KeyPressedNtf
[15] = &BluetoothDaemonHandsfreeModule::KeyPressedNtf,
[16] = &BluetoothDaemonHandsfreeModule::WbsNtf
};
MOZ_ASSERT(!NS_IsMainThread());

View File

@ -292,6 +292,11 @@ protected:
NotificationHandlerWrapper, void, nsString, const nsAString&>
KeyPressedNotification;
typedef mozilla::ipc::DaemonNotificationRunnable2<
NotificationHandlerWrapper, void, BluetoothHandsfreeWbsConfig, nsString,
BluetoothHandsfreeWbsConfig, const nsAString&>
WbsNotification;
class ConnectionStateInitOp;
class AudioStateInitOp;
class VoiceRecognitionInitOp;
@ -309,6 +314,7 @@ protected:
class VolumeInitOp;
class UnknownAtInitOp;
class KeyPressedInitOp;
class WbsInitOp;
void ConnectionStateNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
@ -358,6 +364,9 @@ protected:
void KeyPressedNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void WbsNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void HandleNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
void* aUserData);

View File

@ -1467,6 +1467,13 @@ UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeNRECState& aOut)
aPDU, UnpackConversion<uint8_t, BluetoothHandsfreeNRECState>(aOut));
}
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeWbsConfig& aOut)
{
return UnpackPDU(
aPDU, UnpackConversion<uint8_t, BluetoothHandsfreeWbsConfig>(aOut));
}
nsresult
UnpackPDU(DaemonSocketPDU& aPDU,
BluetoothHandsfreeVoiceRecognitionState& aOut)

View File

@ -848,6 +848,9 @@ UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeConnectionState& aOut);
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeNRECState& aOut);
nsresult
UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHandsfreeWbsConfig& aOut);
nsresult
UnpackPDU(DaemonSocketPDU& aPDU,
BluetoothHandsfreeVoiceRecognitionState& aOut);

View File

@ -1204,6 +1204,9 @@ bool CanvasRenderingContext2D::SwitchRenderingMode(RenderingMode aRenderingMode)
transform = mTarget->GetTransform();
} else {
MOZ_ASSERT(mBufferProvider);
// When mBufferProvider is true but we have no mTarget, our current state's
// transform is always valid. See ReturnTarget().
transform = CurrentState().transform;
snapshot = mBufferProvider->GetSnapshot();
}
mTarget = nullptr;

View File

@ -471,7 +471,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrcMediaSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrcStream)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlaybackStream)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSrcAttrStream)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourcePointer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadBlockedDoc)
@ -623,8 +622,8 @@ NS_IMETHODIMP HTMLMediaElement::GetError(nsIDOMMediaError * *aError)
bool
HTMLMediaElement::Ended()
{
if (mSrcStream) {
return GetSrcMediaStream()->IsFinished();
if (MediaStream* stream = GetSrcMediaStream()) {
return stream->IsFinished();
}
if (mDecoder) {
@ -1391,11 +1390,11 @@ NS_IMETHODIMP HTMLMediaElement::GetSeeking(bool* aSeeking)
double
HTMLMediaElement::CurrentTime() const
{
if (mSrcStream) {
MediaStream* stream = GetSrcMediaStream();
if (stream) {
return stream->StreamTimeToSeconds(stream->GetCurrentTime());
if (MediaStream* stream = GetSrcMediaStream()) {
if (mSrcStreamPausedCurrentTime >= 0) {
return mSrcStreamPausedCurrentTime;
}
return stream->StreamTimeToSeconds(stream->GetCurrentTime());
}
if (mDecoder) {
@ -1703,14 +1702,9 @@ HTMLMediaElement::Pause(ErrorResult& aRv)
mAutoplaying = false;
// We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference
AddRemoveSelfReference();
UpdateSrcMediaStreamPlaying();
if (!oldPaused) {
if (mSrcStream) {
MediaStream* stream = GetSrcMediaStream();
if (stream) {
stream->ChangeExplicitBlockerCount(1);
}
}
FireTimeUpdate(false);
DispatchAsyncEvent(NS_LITERAL_STRING("pause"));
}
@ -1825,8 +1819,10 @@ void HTMLMediaElement::SetVolumeInternal()
if (mDecoder) {
mDecoder->SetVolume(effectiveVolume);
} else if (mSrcStream) {
GetSrcMediaStream()->SetAudioOutputVolume(this, effectiveVolume);
} else if (MediaStream* stream = GetSrcMediaStream()) {
if (mSrcStreamIsPlaying) {
stream->SetAudioOutputVolume(this, effectiveVolume);
}
}
UpdateAudioChannelPlayingState();
@ -2038,6 +2034,7 @@ HTMLMediaElement::LookupMediaElementURITable(nsIURI* aURI)
HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo),
mWatchManager(this, AbstractThread::MainThread()),
mSrcStreamPausedCurrentTime(-1),
mCurrentLoadID(0),
mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING, "HTMLMediaElement::mReadyState"),
@ -2080,6 +2077,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
mHasSelfReference(false),
mShuttingDown(false),
mSuspendedForPreloadNone(false),
mSrcStreamIsPlaying(false),
mMediaSecurityVerified(false),
mCORSMode(CORS_NONE),
mIsEncrypted(false),
@ -2255,9 +2253,6 @@ HTMLMediaElement::Play(ErrorResult& aRv)
// TODO: If the playback has ended, then the user agent must set
// seek to the effective start.
if (mPaused) {
if (mSrcStream) {
GetSrcMediaStream()->ChangeExplicitBlockerCount(-1);
}
DispatchAsyncEvent(NS_LITERAL_STRING("play"));
switch (mReadyState) {
case nsIDOMHTMLMediaElement::HAVE_NOTHING:
@ -2281,6 +2276,7 @@ HTMLMediaElement::Play(ErrorResult& aRv)
// and our preload status.
AddRemoveSelfReference();
UpdatePreloadAction();
UpdateSrcMediaStreamPlaying();
}
NS_IMETHODIMP HTMLMediaElement::Play()
@ -2889,6 +2885,7 @@ public:
mElement(aElement),
mHaveCurrentData(false),
mBlocked(false),
mFinished(false),
mMutex(aName),
mPendingNotifyOutput(false)
{}
@ -2897,23 +2894,29 @@ public:
// Main thread
void DoNotifyFinished()
{
mFinished = true;
if (mElement) {
nsRefPtr<HTMLMediaElement> deathGrip = mElement;
mElement->PlaybackEnded();
// Update NextFrameStatus() to move to NEXT_FRAME_UNAVAILABLE and
// HAVE_CURRENT_DATA.
mElement = nullptr;
// NotifyWatchers before calling PlaybackEnded since PlaybackEnded
// can remove watchers.
NotifyWatchers();
deathGrip->PlaybackEnded();
}
}
MediaDecoderOwner::NextFrameStatus NextFrameStatus()
{
if (!mElement || !mHaveCurrentData) {
if (!mElement || !mHaveCurrentData || mFinished) {
return MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE;
}
return mBlocked ? MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING
: MediaDecoderOwner::NEXT_FRAME_AVAILABLE;
return mBlocked
? MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING
: MediaDecoderOwner::NEXT_FRAME_AVAILABLE;
}
void DoNotifyBlocked()
@ -2993,6 +2996,7 @@ private:
HTMLMediaElement* mElement;
bool mHaveCurrentData;
bool mBlocked;
bool mFinished;
// mMutex protects the fields below; they can be accessed on any thread
Mutex mMutex;
@ -3072,6 +3076,77 @@ private:
HTMLMediaElement* mElement;
};
void HTMLMediaElement::UpdateSrcMediaStreamPlaying(uint32_t aFlags)
{
if (!mSrcStream) {
return;
}
// We might be in cycle collection with mSrcStream->GetStream() already
// returning null due to unlinking.
MediaStream* stream = mSrcStream->GetStream();
bool shouldPlay = !(aFlags & REMOVING_SRC_STREAM) && !mPaused &&
!mPausedForInactiveDocumentOrChannel && stream;
if (shouldPlay == mSrcStreamIsPlaying) {
return;
}
mSrcStreamIsPlaying = shouldPlay;
if (shouldPlay) {
mSrcStreamPausedCurrentTime = -1;
mMediaStreamListener = new StreamListener(this,
"HTMLMediaElement::mMediaStreamListener");
mMediaStreamSizeListener = new StreamSizeListener(this);
stream->AddListener(mMediaStreamListener);
stream->AddListener(mMediaStreamSizeListener);
mWatchManager.Watch(*mMediaStreamListener,
&HTMLMediaElement::UpdateReadyStateInternal);
stream->AddAudioOutput(this);
SetVolumeInternal();
#ifdef MOZ_WIDGET_GONK
bool bUseOverlayImage = mSrcStream->AsDOMHwMediaStream() != nullptr;
#else
bool bUseOverlayImage = false;
#endif
VideoFrameContainer* container;
if (bUseOverlayImage) {
container = GetOverlayImageVideoFrameContainer();
} else {
container = GetVideoFrameContainer();
}
if (container) {
stream->AddVideoOutput(container);
}
} else {
if (stream) {
mSrcStreamPausedCurrentTime = CurrentTime();
stream->RemoveListener(mMediaStreamListener);
stream->RemoveListener(mMediaStreamSizeListener);
stream->RemoveAudioOutput(this);
VideoFrameContainer* container = GetVideoFrameContainer();
if (container) {
stream->RemoveVideoOutput(container);
}
}
// If stream is null, then DOMMediaStream::Destroy must have been
// called and that will remove all listeners/outputs.
mWatchManager.Unwatch(*mMediaStreamListener,
&HTMLMediaElement::UpdateReadyStateInternal);
mMediaStreamListener->Forget();
mMediaStreamListener = nullptr;
mMediaStreamSizeListener->Forget();
mMediaStreamSizeListener = nullptr;
}
}
void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
{
NS_ASSERTION(!mSrcStream && !mMediaStreamListener && !mMediaStreamSizeListener,
@ -3084,121 +3159,38 @@ void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
return;
}
// XXX Remove this if with CameraPreviewMediaStream per bug 1124630.
if (!mSrcStream->GetStream()->AsCameraPreviewStream()) {
// Now that we have access to |mSrcStream| we can pipe it to our shadow
// version |mPlaybackStream|. If two media elements are playing the
// same realtime DOMMediaStream, this allows them to pause playback
// independently of each other.
MediaStreamGraph* graph = mSrcStream->GetStream()->Graph();
mPlaybackStream = DOMMediaStream::CreateTrackUnionStream(window, graph);
mPlaybackStreamInputPort = mPlaybackStream->GetStream()->AsProcessedStream()->
AllocateInputPort(mSrcStream->GetStream(), MediaInputPort::FLAG_BLOCK_OUTPUT);
nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
mPlaybackStream->CombineWithPrincipal(principal);
// Let |mSrcStream| decide when the stream has finished.
GetSrcMediaStream()->AsProcessedStream()->SetAutofinish(true);
}
nsRefPtr<MediaStream> stream = mSrcStream->GetStream();
if (stream) {
stream->SetAudioChannelType(mAudioChannel);
}
// XXX if we ever support capturing the output of a media element which is
// playing a stream, we'll need to add a CombineWithPrincipal call here.
mMediaStreamListener = new StreamListener(this, "HTMLMediaElement::mMediaStreamListener");
mMediaStreamSizeListener = new StreamSizeListener(this);
mWatchManager.Watch(*mMediaStreamListener, &HTMLMediaElement::UpdateReadyStateInternal);
GetSrcMediaStream()->AddListener(mMediaStreamListener);
// Listen for an initial image size on mSrcStream so we can get results even
// if we block the mPlaybackStream.
stream->AddListener(mMediaStreamSizeListener);
if (mPaused) {
GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
}
if (mPausedForInactiveDocumentOrChannel) {
GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
}
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
ChangeDelayLoadStatus(false);
GetSrcMediaStream()->AddAudioOutput(this);
SetVolumeInternal();
#ifdef MOZ_WIDGET_GONK
bool bUseOverlayImage = mSrcStream->AsDOMHwMediaStream() != nullptr;
#else
bool bUseOverlayImage = false;
#endif
VideoFrameContainer* container;
if (bUseOverlayImage) {
container = GetOverlayImageVideoFrameContainer();
}
else {
container = GetVideoFrameContainer();
}
if (container) {
GetSrcMediaStream()->AddVideoOutput(container);
}
CheckAutoplayDataReady();
UpdateSrcMediaStreamPlaying();
// Note: we must call DisconnectTrackListListeners(...) before dropping
// mSrcStream
// mSrcStream.
// If we pause this media element, track changes in the underlying stream
// will continue to fire events at this element and alter its track list.
// That's simpler than delaying the events, but probably confusing...
mSrcStream->ConstructMediaTracks(AudioTracks(), VideoTracks());
mSrcStream->OnTracksAvailable(new MediaStreamTracksAvailableCallback(this));
ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
ChangeDelayLoadStatus(false);
CheckAutoplayDataReady();
// FirstFrameLoaded() will be called when the stream has current data.
}
void HTMLMediaElement::EndSrcMediaStreamPlayback()
{
MediaStream* stream = GetSrcMediaStream();
if (stream) {
stream->RemoveListener(mMediaStreamListener);
}
if (mSrcStream->GetStream()) {
mSrcStream->GetStream()->RemoveListener(mMediaStreamSizeListener);
}
MOZ_ASSERT(mSrcStream);
UpdateSrcMediaStreamPlaying(REMOVING_SRC_STREAM);
mSrcStream->DisconnectTrackListListeners(AudioTracks(), VideoTracks());
if (mPlaybackStreamInputPort) {
mPlaybackStreamInputPort->Destroy();
}
// Kill its reference to this element
mWatchManager.Unwatch(*mMediaStreamListener, &HTMLMediaElement::UpdateReadyStateInternal);
mMediaStreamListener->Forget();
mMediaStreamListener = nullptr;
mMediaStreamSizeListener->Forget();
mMediaStreamSizeListener = nullptr;
if (stream) {
stream->RemoveAudioOutput(this);
}
VideoFrameContainer* container = GetVideoFrameContainer();
if (container) {
if (stream) {
stream->RemoveVideoOutput(container);
}
container->ClearCurrentFrame();
}
if (mPaused && stream) {
stream->ChangeExplicitBlockerCount(-1);
}
if (mPausedForInactiveDocumentOrChannel && stream) {
stream->ChangeExplicitBlockerCount(-1);
}
mSrcStream = nullptr;
mPlaybackStreamInputPort = nullptr;
mPlaybackStream = nullptr;
}
void HTMLMediaElement::ProcessMediaFragmentURI()
@ -3791,6 +3783,7 @@ void HTMLMediaElement::CheckAutoplayDataReady()
mPaused = false;
// We changed mPaused which can affect AddRemoveSelfReference
AddRemoveSelfReference();
UpdateSrcMediaStreamPlaying();
if (mDecoder) {
SetPlayedOrSeeked(true);
@ -3800,7 +3793,6 @@ void HTMLMediaElement::CheckAutoplayDataReady()
mDecoder->Play();
} else if (mSrcStream) {
SetPlayedOrSeeked(true);
GetSrcMediaStream()->ChangeExplicitBlockerCount(-1);
}
DispatchAsyncEvent(NS_LITERAL_STRING("play"));
@ -3990,6 +3982,7 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
if (aPauseElement != mPausedForInactiveDocumentOrChannel) {
mPausedForInactiveDocumentOrChannel = aPauseElement;
UpdateSrcMediaStreamPlaying();
if (aPauseElement) {
if (mMediaSource) {
ReportMSETelemetry();
@ -4015,8 +4008,6 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
if (mDecoder) {
mDecoder->Pause();
mDecoder->Suspend();
} else if (mSrcStream) {
GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
}
mEventDeliveryPaused = aSuspendEvents;
} else {
@ -4028,8 +4019,6 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
if (!mPaused && !mDecoder->IsEndedOrShutdown()) {
mDecoder->Play();
}
} else if (mSrcStream) {
GetSrcMediaStream()->ChangeExplicitBlockerCount(-1);
}
if (mEventDeliveryPaused) {
mEventDeliveryPaused = false;
@ -4770,11 +4759,11 @@ NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged()
MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
AudioChannel::Normal);
if (!mPlaybackStream) {
if (mSrcStream) {
mCaptureStreamPort = msg->ConnectToCaptureStream(id, mSrcStream->GetStream());
} else {
nsRefPtr<DOMMediaStream> stream = CaptureStreamInternal(false, msg);
mCaptureStreamPort = msg->ConnectToCaptureStream(id, stream->GetStream());
} else {
mCaptureStreamPort = msg->ConnectToCaptureStream(id, mPlaybackStream->GetStream());
}
} else {
mAudioCapturedByWindow = false;

View File

@ -347,14 +347,14 @@ public:
*/
virtual void FireTimeUpdate(bool aPeriodic) final override;
/**
* This will return null if mSrcStream is null, or if mSrcStream is not
* null but its GetStream() returns null --- which can happen during
* cycle collection unlinking!
*/
MediaStream* GetSrcMediaStream() const
{
NS_ASSERTION(mSrcStream, "Don't call this when not playing a stream");
if (!mPlaybackStream) {
// XXX Remove this check with CameraPreviewMediaStream per bug 1124630.
return mSrcStream->GetStream();
}
return mPlaybackStream->GetStream();
return mSrcStream ? mSrcStream->GetStream() : nullptr;
}
// WebIDL
@ -747,6 +747,11 @@ protected:
* Stop playback on mSrcStream.
*/
void EndSrcMediaStreamPlayback();
/**
* Ensure we're playing mSrcStream if and only if we're not paused.
*/
enum { REMOVING_SRC_STREAM = 0x1 };
void UpdateSrcMediaStreamPlaying(uint32_t aFlags = 0);
/**
* Returns an nsDOMMediaStream containing the played contents of this
@ -1081,8 +1086,9 @@ protected:
// At most one of mDecoder and mSrcStream can be non-null.
nsRefPtr<DOMMediaStream> mSrcStream;
// Holds a reference to a MediaInputPort connecting mSrcStream to mPlaybackStream.
nsRefPtr<MediaInputPort> mPlaybackStreamInputPort;
// If non-negative, the time we should return for currentTime while playing
// mSrcStream.
double mSrcStreamPausedCurrentTime;
// Holds a reference to the stream connecting this stream to the capture sink.
nsRefPtr<MediaInputPort> mCaptureStreamPort;
@ -1370,6 +1376,9 @@ protected:
// stored in mPreloadURI.
bool mSuspendedForPreloadNone;
// True if we've connected mSrcStream to the media element output.
bool mSrcStreamIsPlaying;
// True if a same-origin check has been done for the media element and resource.
bool mMediaSecurityVerified;

View File

@ -15,6 +15,7 @@
#include "MediaDecoderStateMachine.h"
#include "MediaTimer.h"
#include "mediasink/DecodedAudioDataSink.h"
#include "mediasink/AudioSinkWrapper.h"
#include "nsTArray.h"
#include "MediaDecoder.h"
#include "MediaDecoderReader.h"
@ -287,6 +288,15 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mTaskQueue, this, &MediaDecoderStateMachine::OnAudioPopped);
mVideoQueueListener = VideoQueue().PopEvent().Connect(
mTaskQueue, this, &MediaDecoderStateMachine::OnVideoPopped);
nsRefPtr<MediaDecoderStateMachine> self = this;
auto audioSinkCreator = [self] () {
MOZ_ASSERT(self->OnTaskQueue());
return new DecodedAudioDataSink(
self->mAudioQueue, self->GetMediaTime(),
self->mInfo.mAudio, self->mDecoder->GetAudioChannel());
};
mAudioSink = new AudioSinkWrapper(mTaskQueue, audioSinkCreator);
}
MediaDecoderStateMachine::~MediaDecoderStateMachine()
@ -331,6 +341,9 @@ MediaDecoderStateMachine::InitializationTask()
mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged);
mWatchManager.Watch(mLogicallySeeking, &MediaDecoderStateMachine::LogicallySeekingChanged);
mWatchManager.Watch(mSameOriginMedia, &MediaDecoderStateMachine::SameOriginMediaChanged);
// Propagate mSameOriginMedia to mDecodedStream.
SameOriginMediaChanged();
}
bool MediaDecoderStateMachine::HasFutureAudio()
@ -362,7 +375,7 @@ int64_t MediaDecoderStateMachine::GetDecodedAudioDuration()
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
int64_t audioDecoded = AudioQueue().Duration();
if (AudioEndTime() != -1) {
if (mAudioSink->IsStarted()) {
audioDecoded += AudioEndTime() - GetMediaTime();
}
return audioDecoded;
@ -372,7 +385,7 @@ void MediaDecoderStateMachine::DiscardStreamData()
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
MOZ_ASSERT(!mAudioSink, "Should've been stopped in RunStateMachine()");
MOZ_ASSERT(!mAudioSink->IsStarted(), "Should've been stopped in RunStateMachine()");
const auto clockTime = GetClock();
while (true) {
@ -1137,9 +1150,7 @@ void MediaDecoderStateMachine::VolumeChanged()
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mAudioSink) {
mAudioSink->SetVolume(mVolume);
}
mAudioSink->SetVolume(mVolume);
mDecodedStream->SetVolume(mVolume);
}
@ -1260,6 +1271,8 @@ void MediaDecoderStateMachine::Shutdown()
Reset();
mAudioSink->Shutdown();
// Shut down our start time rendezvous.
if (mStartTimeRendezvous) {
mStartTimeRendezvous->Destroy();
@ -1456,12 +1469,11 @@ void MediaDecoderStateMachine::StopAudioSink()
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
if (mAudioSink) {
DECODER_LOG("Shutdown audio thread");
mAudioSink->Shutdown();
mAudioSink = nullptr;
if (mAudioSink->IsStarted()) {
DECODER_LOG("Stop AudioSink");
mAudioSink->Stop();
mAudioSinkPromise.DisconnectIfExists();
}
mAudioSinkPromise.DisconnectIfExists();
}
void
@ -1743,25 +1755,19 @@ MediaDecoderStateMachine::StartAudioSink()
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
if (mAudioCaptured) {
MOZ_ASSERT(!mAudioSink);
MOZ_ASSERT(!mAudioSink->IsStarted());
return;
}
if (HasAudio() && !mAudioSink) {
if (HasAudio() && !mAudioSink->IsStarted()) {
mAudioCompleted = false;
mAudioSink = new DecodedAudioDataSink(mAudioQueue,
GetMediaTime(), mInfo.mAudio,
mDecoder->GetAudioChannel());
mAudioSink->Start(GetMediaTime(), mInfo);
mAudioSinkPromise.Begin(
mAudioSink->Init()->Then(
mAudioSink->OnEnded(TrackInfo::kAudioTrack)->Then(
OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioSinkComplete,
&MediaDecoderStateMachine::OnAudioSinkError));
mAudioSink->SetVolume(mVolume);
mAudioSink->SetPlaybackRate(mPlaybackRate);
mAudioSink->SetPreservesPitch(mPreservesPitch);
}
}
@ -1799,7 +1805,7 @@ int64_t MediaDecoderStateMachine::AudioDecodedUsecs()
// The amount of audio we have decoded is the amount of audio data we've
// already decoded and pushed to the hardware, plus the amount of audio
// data waiting to be pushed to the hardware.
int64_t pushed = (AudioEndTime() != -1) ? (AudioEndTime() - GetMediaTime()) : 0;
int64_t pushed = mAudioSink->IsStarted() ? (AudioEndTime() - GetMediaTime()) : 0;
// Currently for real time streams, AudioQueue().Duration() produce
// wrong values (Bug 1114434), so we use frame counts to calculate duration.
@ -1828,7 +1834,7 @@ bool MediaDecoderStateMachine::OutOfDecodedAudio()
MOZ_ASSERT(OnTaskQueue());
return IsAudioDecoding() && !AudioQueue().IsFinished() &&
AudioQueue().GetSize() == 0 &&
(!mAudioSink || !mAudioSink->HasUnplayedFrames());
!mAudioSink->HasUnplayedFrames(TrackInfo::kAudioTrack);
}
bool MediaDecoderStateMachine::HasLowUndecodedData()
@ -2391,8 +2397,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
mSentPlaybackEndedEvent = true;
// Stop audio sink after call to AudioEndTime() above, otherwise it will
// return an incorrect value due to a null mAudioSink.
// MediaSink::GetEndTime() must be called before stopping playback.
StopAudioSink();
StopDecodedStream();
}
@ -2568,8 +2573,8 @@ MediaDecoderStateMachine::GetAudioClock() const
AssertCurrentThreadInMonitor();
MOZ_ASSERT(HasAudio() && !mAudioCompleted && IsPlaying());
// Since this function is called while we are playing and AudioSink is
// created once playback starts, mAudioSink is guaranteed to be non-null.
MOZ_ASSERT(mAudioSink);
// started once playback starts, IsStarted() is guaranteed to be true.
MOZ_ASSERT(mAudioSink->IsStarted());
return mAudioSink->GetPosition();
}
@ -2909,9 +2914,7 @@ void MediaDecoderStateMachine::SetPlayStartTime(const TimeStamp& aTimeStamp)
AssertCurrentThreadInMonitor();
mPlayStartTime = aTimeStamp;
if (mAudioSink) {
mAudioSink->SetPlaying(!mPlayStartTime.IsNull());
}
mAudioSink->SetPlaying(!mPlayStartTime.IsNull());
// Have DecodedStream remember the playing state so it doesn't need to
// ask MDSM about IsPlaying(). Note we have to do this even before capture
// happens since capture could happen in the middle of playback.
@ -3004,9 +3007,7 @@ MediaDecoderStateMachine::LogicalPlaybackRateChanged()
}
mPlaybackRate = mLogicalPlaybackRate;
if (mAudioSink) {
mAudioSink->SetPlaybackRate(mPlaybackRate);
}
mAudioSink->SetPlaybackRate(mPlaybackRate);
ScheduleStateMachine();
}
@ -3015,10 +3016,7 @@ void MediaDecoderStateMachine::PreservesPitchChanged()
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mAudioSink) {
mAudioSink->SetPreservesPitch(mPreservesPitch);
}
mAudioSink->SetPreservesPitch(mPreservesPitch);
}
bool MediaDecoderStateMachine::IsShutdown()
@ -3045,15 +3043,12 @@ MediaDecoderStateMachine::AudioEndTime() const
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
if (mAudioSink) {
return mAudioSink->GetEndTime();
if (mAudioSink->IsStarted()) {
return mAudioSink->GetEndTime(TrackInfo::kAudioTrack);
} else if (mAudioCaptured) {
return mDecodedStream->AudioEndTime();
}
// Don't call this after mAudioSink becomes null since we can't distinguish
// "before StartAudioSink" and "after StopAudioSink" where mAudioSink
// is null in both cases.
MOZ_ASSERT(!mAudioCompleted);
MOZ_ASSERT(!HasAudio());
return -1;
}

View File

@ -100,7 +100,7 @@ hardware (via AudioStream).
namespace mozilla {
namespace media {
class AudioSink;
class MediaSink;
}
class AudioSegment;
@ -999,8 +999,8 @@ private:
// Media Fragment end time in microseconds. Access controlled by decoder monitor.
int64_t mFragmentEndTime;
// The audio sink resource. Used on state machine and audio threads.
RefPtr<media::AudioSink> mAudioSink;
// The audio sink resource. Used on the state machine thread.
nsRefPtr<media::MediaSink> mAudioSink;
// The reader, don't call its methods with the decoder monitor held.
// This is created in the state machine's constructor.

View File

@ -461,6 +461,9 @@ public:
}
void RemoveVideoOutputImpl(VideoFrameContainer* aContainer)
{
// Ensure that any frames currently queued for playback by the compositor
// are removed.
aContainer->ClearFutureFrames();
mVideoOutputs.RemoveElement(aContainer);
}
void ChangeExplicitBlockerCountImpl(GraphTime aTime, int32_t aDelta)

View File

@ -93,7 +93,24 @@ void VideoFrameContainer::ClearCurrentFrame()
mImageContainer->GetCurrentImages(&kungFuDeathGrip);
mImageContainer->ClearAllImages();
mImageSizeChanged = false;
}
void VideoFrameContainer::ClearFutureFrames()
{
MutexAutoLock lock(mMutex);
// See comment in SetCurrentFrame for the reasoning behind
// using a kungFuDeathGrip here.
nsTArray<ImageContainer::OwningImage> kungFuDeathGrip;
mImageContainer->GetCurrentImages(&kungFuDeathGrip);
if (!kungFuDeathGrip.IsEmpty()) {
nsTArray<ImageContainer::NonOwningImage> currentFrame;
const ImageContainer::OwningImage& img = kungFuDeathGrip[0];
currentFrame.AppendElement(ImageContainer::NonOwningImage(img.mImage,
img.mTimeStamp, img.mFrameID, img.mProducerID));
mImageContainer->SetCurrentImages(currentFrame);
}
}
ImageContainer* VideoFrameContainer::GetImageContainer() {

View File

@ -52,6 +52,9 @@ public:
}
void ClearCurrentFrame();
// Make the current frame the only frame in the container, i.e. discard
// all future frames.
void ClearFutureFrames();
// Time in seconds by which the last painted video frame was late by.
// E.g. if the last painted frame should have been painted at time t,
// but was actually painted at t+n, this returns n in seconds. Threadsafe.

View File

@ -0,0 +1,160 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioSink.h"
#include "AudioSinkWrapper.h"
namespace mozilla {
namespace media {
AudioSinkWrapper::~AudioSinkWrapper()
{
}
void
AudioSinkWrapper::Shutdown()
{
AssertOwnerThread();
MOZ_ASSERT(!mIsStarted, "Must be called after playback stopped.");
mCreator = nullptr;
}
const MediaSink::PlaybackParams&
AudioSinkWrapper::GetPlaybackParams() const
{
AssertOwnerThread();
return mParams;
}
void
AudioSinkWrapper::SetPlaybackParams(const PlaybackParams& aParams)
{
AssertOwnerThread();
if (mAudioSink) {
mAudioSink->SetVolume(aParams.volume);
mAudioSink->SetPlaybackRate(aParams.playbackRate);
mAudioSink->SetPreservesPitch(aParams.preservesPitch);
}
mParams = aParams;
}
nsRefPtr<GenericPromise>
AudioSinkWrapper::OnEnded(TrackType aType)
{
AssertOwnerThread();
MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
if (aType == TrackInfo::kAudioTrack) {
return mEndPromise;
}
return nullptr;
}
int64_t
AudioSinkWrapper::GetEndTime(TrackType aType) const
{
AssertOwnerThread();
MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
if (aType == TrackInfo::kAudioTrack && mAudioSink) {
return mAudioSink->GetEndTime();
}
return -1;
}
int64_t
AudioSinkWrapper::GetPosition() const
{
AssertOwnerThread();
MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
return mAudioSink->GetPosition();
}
bool
AudioSinkWrapper::HasUnplayedFrames(TrackType aType) const
{
AssertOwnerThread();
return mAudioSink ? mAudioSink->HasUnplayedFrames() : false;
}
void
AudioSinkWrapper::SetVolume(double aVolume)
{
AssertOwnerThread();
mParams.volume = aVolume;
if (mAudioSink) {
mAudioSink->SetVolume(aVolume);
}
}
void
AudioSinkWrapper::SetPlaybackRate(double aPlaybackRate)
{
AssertOwnerThread();
mParams.playbackRate = aPlaybackRate;
if (mAudioSink) {
mAudioSink->SetPlaybackRate(aPlaybackRate);
}
}
void
AudioSinkWrapper::SetPreservesPitch(bool aPreservesPitch)
{
AssertOwnerThread();
mParams.preservesPitch = aPreservesPitch;
if (mAudioSink) {
mAudioSink->SetPreservesPitch(aPreservesPitch);
}
}
void
AudioSinkWrapper::SetPlaying(bool aPlaying)
{
AssertOwnerThread();
// Resume/pause matters only when playback started.
if (!mIsStarted) {
return;
}
if (mAudioSink) {
mAudioSink->SetPlaying(aPlaying);
}
}
void
AudioSinkWrapper::Start(int64_t aStartTime, const MediaInfo& aInfo)
{
AssertOwnerThread();
MOZ_ASSERT(!mIsStarted, "playback already started.");
mIsStarted = true;
mAudioSink = mCreator->Create();
mEndPromise = mAudioSink->Init();
SetPlaybackParams(mParams);
}
void
AudioSinkWrapper::Stop()
{
AssertOwnerThread();
MOZ_ASSERT(mIsStarted, "playback not started.");
mIsStarted = false;
mAudioSink->Shutdown();
mAudioSink = nullptr;
mEndPromise = nullptr;
}
bool
AudioSinkWrapper::IsStarted() const
{
AssertOwnerThread();
return mIsStarted;
}
} // namespace media
} // namespace mozilla

View File

@ -0,0 +1,93 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef AudioSinkWrapper_h_
#define AudioSinkWrapper_h_
#include "mozilla/AbstractThread.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "mozilla/nsRefPtr.h"
#include "mozilla/UniquePtr.h"
#include "MediaSink.h"
namespace mozilla {
class MediaData;
template <class T> class MediaQueue;
namespace media {
class AudioSink;
/**
* A wrapper around AudioSink to provide the interface of MediaSink.
*/
class AudioSinkWrapper : public MediaSink {
// An AudioSink factory.
class Creator {
public:
virtual ~Creator() {}
virtual AudioSink* Create() = 0;
};
// Wrap around a function object which creates AudioSinks.
template <typename Function>
class CreatorImpl : public Creator {
public:
explicit CreatorImpl(const Function& aFunc) : mFunction(aFunc) {}
AudioSink* Create() override { return mFunction(); }
private:
Function mFunction;
};
public:
template <typename Function>
AudioSinkWrapper(AbstractThread* aOwnerThread, const Function& aFunc)
: mOwnerThread(aOwnerThread)
, mCreator(new CreatorImpl<Function>(aFunc))
, mIsStarted(false)
{}
const PlaybackParams& GetPlaybackParams() const override;
void SetPlaybackParams(const PlaybackParams& aParams) override;
nsRefPtr<GenericPromise> OnEnded(TrackType aType) override;
int64_t GetEndTime(TrackType aType) const override;
int64_t GetPosition() const override;
bool HasUnplayedFrames(TrackType aType) const override;
void SetVolume(double aVolume) override;
void SetPlaybackRate(double aPlaybackRate) override;
void SetPreservesPitch(bool aPreservesPitch) override;
void SetPlaying(bool aPlaying) override;
void Start(int64_t aStartTime, const MediaInfo& aInfo) override;
void Stop() override;
bool IsStarted() const override;
void Shutdown() override;
private:
virtual ~AudioSinkWrapper();
void AssertOwnerThread() const {
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
}
const nsRefPtr<AbstractThread> mOwnerThread;
UniquePtr<Creator> mCreator;
nsRefPtr<AudioSink> mAudioSink;
nsRefPtr<GenericPromise> mEndPromise;
bool mIsStarted;
PlaybackParams mParams;
};
} // namespace media
} // namespace mozilla
#endif //AudioSinkWrapper_h_

View File

@ -0,0 +1,115 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MediaSink_h_
#define MediaSink_h_
#include "mozilla/nsRefPtr.h"
#include "mozilla/MozPromise.h"
#include "nsISupportsImpl.h"
#include "MediaInfo.h"
namespace mozilla {
namespace media {
/**
* A consumer of audio/video data which plays audio and video tracks and
* manages A/V sync between them.
*
* A typical sink sends audio/video outputs to the speaker and screen.
* However, there are also sinks which capture the output of an media element
* and send the output to a MediaStream.
*
* This class is used to move A/V sync management and audio/video rendering
* out of MDSM so it is possible for subclasses to do external rendering using
* specific hardware which is required by TV projects and CDM.
*
* Note this class is not thread-safe and should be called from the state
* machine thread only.
*/
class MediaSink {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaSink);
typedef mozilla::TrackInfo::TrackType TrackType;
struct PlaybackParams {
PlaybackParams()
: volume(1.0) , playbackRate(1.0) , preservesPitch(true) {}
double volume;
double playbackRate;
bool preservesPitch;
};
// Return the playback parameters of this sink.
// Can be called in any state.
virtual const PlaybackParams& GetPlaybackParams() const = 0;
// Set the playback parameters of this sink.
// Can be called in any state.
virtual void SetPlaybackParams(const PlaybackParams& aParams) = 0;
// Return a promise which is resolved when the track finishes
// or null if no such track.
// Must be called after playback starts.
virtual nsRefPtr<GenericPromise> OnEnded(TrackType aType) = 0;
// Return the end time of the audio/video data that has been consumed
// or -1 if no such track.
// Must be called after playback starts.
virtual int64_t GetEndTime(TrackType aType) const = 0;
// Return playback position of the media.
// Since A/V sync is always maintained by this sink, there is no need to
// specify whether we want to get audio or video position.
// Must be called after playback starts.
virtual int64_t GetPosition() const = 0;
// Return true if there are data consumed but not played yet.
// Can be called in any state.
virtual bool HasUnplayedFrames(TrackType aType) const = 0;
// Set volume of the audio track.
// Do nothing if this sink has no audio track.
// Can be called in any state.
virtual void SetVolume(double aVolume) {}
// Set the playback rate.
// Can be called in any state.
virtual void SetPlaybackRate(double aPlaybackRate) {}
// Whether to preserve pitch of the audio track.
// Do nothing if this sink has no audio track.
// Can be called in any state.
virtual void SetPreservesPitch(bool aPreservesPitch) {}
// Pause/resume the playback. Only work after playback starts.
virtual void SetPlaying(bool aPlaying) = 0;
// Begin a playback session with the provided start time and media info.
// Must be called when playback is stopped.
virtual void Start(int64_t aStartTime, const MediaInfo& aInfo) = 0;
// Finish a playback session.
// Must be called after playback starts.
virtual void Stop() = 0;
// Return true if playback has started.
// Can be called in any state.
virtual bool IsStarted() const = 0;
// Called on the state machine thread to shut down the sink. All resources
// allocated by this sink should be released.
// Must be called after playback stopped.
virtual void Shutdown() {}
protected:
virtual ~MediaSink() {}
};
} // namespace media
} // namespace mozilla
#endif //MediaSink_h_

View File

@ -5,6 +5,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
UNIFIED_SOURCES += [
'AudioSinkWrapper.cpp',
'DecodedAudioDataSink.cpp',
]

View File

@ -782,6 +782,8 @@ skip-if = (toolkit == 'android' && processor == 'x86') #timeout x86 only bug 914
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
[test_streams_autoplay.html]
tags=msg capturestream
[test_streams_capture_origin.html]
tags=msg capturestream
[test_streams_element_capture.html]
#x86 only bug 914439, b2g desktop bug 752796
skip-if = (toolkit == 'android' && processor == 'x86') || (buildapp == 'b2g' && toolkit != 'gonk')

View File

@ -0,0 +1,44 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 1189506</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1189506">Mozilla Bug 1189506</a>
<p id="display"></p>
<video id="vin"></video>
<video id="vout" style="position:absolute; top:0; left:0"></video>
<canvas id="c"></canvas>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 1189506 **/
SimpleTest.waitForExplicitFinish();
var resource = getPlayableVideo(gSmallTests).name;
vin.src = "http://example.org:8000/tests/dom/media/test/" + resource;
var stream = vin.mozCaptureStreamUntilEnded();
vout.srcObject = stream;
vin.play();
vout.play();
vout.onended = function() {
var ctx = SpecialPowers.wrap(c.getContext("2d"));
ctx.drawWindow(window, 0, 0, 10, 10, "rgb(255, 255, 0)", 0);
var data = ctx.getImageData(2, 2, 1, 1);
// Captured cross-origin video streams should render entirely black.
is(data.data.join(','), "0,0,0,255", "expected black");
vout.style.position = "";
SimpleTest.finish();
};
</script>
</pre>
</body>
</html>

View File

@ -9,6 +9,7 @@
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SimpleTest.waitForExplicitFinish();
// longer timeout for slow platforms
if (isSlowPlatform()) {
@ -16,8 +17,6 @@ if (isSlowPlatform()) {
SimpleTest.requestCompleteLog();
}
var manager = new MediaTestManager;
function checkDrawImage(vout) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
@ -26,14 +25,14 @@ function checkDrawImage(vout) {
is(imgData.data[3], 255, "Check video frame pixel has been drawn");
}
function startTest(test, token) {
manager.started(token);
function isGreaterThanOrEqualEps(a, b, msg) {
ok(a >= b - 0.01,
"Got " + a + ", expected at least " + b + "; " + msg);
}
function startTest(test) {
var v = document.createElement('video');
var vout = document.createElement('video');
vout.token = token;
v.name = token + "(v)";
vout.name = token + "(vout)";
v.src = test.name;
var stream = v.mozCaptureStreamUntilEnded();
@ -44,8 +43,8 @@ function startTest(test, token) {
var checkEnded = function(test, vout, stream) { return function() {
is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
if (test.duration) {
ok(Math.abs(vout.currentTime - test.duration) < 0.1,
test.name + " current time at end: " + vout.currentTime + " should be: " + test.duration);
isGreaterThanOrEqualEps(vout.currentTime, test.duration,
test.name + " current time at end");
}
is(vout.readyState, vout.HAVE_CURRENT_DATA, test.name + " checking readyState");
ok(vout.ended, test.name + " checking playback has ended");
@ -53,8 +52,8 @@ function startTest(test, token) {
checkDrawImage(vout);
}
vout.parentNode.removeChild(vout);
manager.finished(vout.token);
removeNodeAndSource(v);
SimpleTest.finish();
}}(test, vout, stream);
vout.addEventListener("ended", checkEnded, false);
@ -76,7 +75,16 @@ function startTest(test, token) {
}
manager.runTests(gSmallTests, startTest);
// We only test one playable video because for some of the audio files
// --- small-shot.mp3.mp4 and small-shot.m4a --- GStreamer doesn't decode
// as much data as indicated by the duration, causing this test to fail on
// Linux. See bug 1084185.
var testVideo = getPlayableVideo(gSmallTests);
if (testVideo) {
startTest(testVideo);
} else {
todo(false, "No playable video");
}
</script>
</pre>
</body>

View File

@ -21,6 +21,11 @@ function checkDrawImage(vout) {
is(imgData.data[3], 255, "Check video frame pixel has been drawn");
}
function isGreaterThanOrEqualEps(a, b, msg) {
ok(a >= b - 0.01,
"Got " + a + ", expected at least " + b + "; " + msg);
}
function startTest(test, token) {
manager.started(token);
@ -36,8 +41,8 @@ function startTest(test, token) {
var checkEnded = function(test, vout, stream) { return function() {
is(stream.currentTime, vout.currentTime, test.name + " stream final currentTime");
if (test.duration) {
ok(Math.abs(vout.currentTime - test.duration) < 0.1,
test.name + " current time at end: " + vout.currentTime + " should be: " + test.duration);
isGreaterThanOrEqualEps(vout.currentTime, test.duration,
test.name + " current time at end");
}
is(vout.readyState, vout.HAVE_CURRENT_DATA, test.name + " checking readyState");
ok(vout.ended, test.name + " checking playback has ended");

View File

@ -39,19 +39,24 @@ function isWithinEps(a, b, msg) {
"Got " + a + ", expected " + b + "; " + msg);
}
function isGreaterThanOrEqualEps(a, b, msg) {
ok(a >= b - 0.01,
"Got " + a + ", expected at least " + b + "; " + msg);
}
function startTest(test) {
var seekTime = test.duration/2;
function endedAfterReplay() {
isWithinEps(v.currentTime, test.duration, "checking v.currentTime at third 'ended' event");
isWithinEps(vout.currentTime, (test.duration - seekTime) + test.duration*2,
isGreaterThanOrEqualEps(v.currentTime, test.duration, "checking v.currentTime at third 'ended' event");
isGreaterThanOrEqualEps(vout.currentTime, (test.duration - seekTime) + test.duration*2,
"checking vout.currentTime after seeking, playing through and reloading");
SimpleTest.finish();
};
function endedAfterSeek() {
isWithinEps(v.currentTime, test.duration, "checking v.currentTime at second 'ended' event");
isWithinEps(vout.currentTime, (test.duration - seekTime) + test.duration,
isGreaterThanOrEqualEps(v.currentTime, test.duration, "checking v.currentTime at second 'ended' event");
isGreaterThanOrEqualEps(vout.currentTime, (test.duration - seekTime) + test.duration,
"checking vout.currentTime after seeking and playing through again");
v.removeEventListener("ended", endedAfterSeek, false);
v.addEventListener("ended", endedAfterReplay, false);
@ -60,8 +65,8 @@ function startTest(test) {
};
function seeked() {
isWithinEps(v.currentTime, seekTime, "Finished seeking");
isWithinEps(vout.currentTime, test.duration,
isGreaterThanOrEqualEps(v.currentTime, seekTime, "Finished seeking");
isGreaterThanOrEqualEps(vout.currentTime, test.duration,
"checking vout.currentTime has not changed after seeking");
v.removeEventListener("seeked", seeked, false);
function dontPlayAgain() {
@ -80,8 +85,8 @@ function startTest(test) {
return;
}
isWithinEps(vout.currentTime, test.duration, "checking vout.currentTime at first 'ended' event");
isWithinEps(v.currentTime, test.duration, "checking v.currentTime at first 'ended' event");
isGreaterThanOrEqualEps(vout.currentTime, test.duration, "checking vout.currentTime at first 'ended' event");
isGreaterThanOrEqualEps(v.currentTime, test.duration, "checking v.currentTime at first 'ended' event");
is(vout.ended, false, "checking vout has not ended");
is(vout_untilended.ended, true, "checking vout_untilended has actually ended");

View File

@ -463,8 +463,9 @@ MobileMessageManager::GetMessages(const MobileMessageFilter& aFilter,
read = aFilter.mRead.Value();
}
bool hasThreadId = !aFilter.mThreadId.IsNull();
uint64_t threadId = 0;
if (!aFilter.mThreadId.IsNull()) {
if (hasThreadId) {
threadId = aFilter.mThreadId.Value();
}
@ -476,7 +477,7 @@ MobileMessageManager::GetMessages(const MobileMessageFilter& aFilter,
ptrNumbers, numbersCount,
delivery,
hasRead, read,
threadId,
hasThreadId, threadId,
aReverse, cursorCallback,
getter_AddRefs(continueCallback));
if (NS_FAILED(rv)) {

View File

@ -56,6 +56,7 @@ MobileMessageDatabaseService::CreateMessageCursor(bool aHasStartDate,
const nsAString& aDelivery,
bool aHasRead,
bool aRead,
bool aHasThreadId,
uint64_t aThreadId,
bool aReverse,
nsIMobileMessageCursorCallback* aCallback,

View File

@ -4045,7 +4045,8 @@ MobileMessageDB.prototype = {
*/
createMessageCursor: function(aHasStartDate, aStartDate, aHasEndDate,
aEndDate, aNumbers, aNumbersCount, aDelivery,
aHasRead, aRead, aThreadId, aReverse, aCallback) {
aHasRead, aRead, aHasThreadId, aThreadId,
aReverse, aCallback) {
if (DEBUG) {
debug("Creating a message cursor. Filters:" +
" startDate: " + (aHasStartDate ? aStartDate : "(null)") +
@ -4053,7 +4054,7 @@ MobileMessageDB.prototype = {
" delivery: " + aDelivery +
" numbers: " + (aNumbersCount ? aNumbers : "(null)") +
" read: " + (aHasRead ? aRead : "(null)") +
" threadId: " + aThreadId +
" threadId: " + (aHasThreadId ? aThreadId : "(null)") +
" reverse: " + aReverse);
}
@ -4073,7 +4074,7 @@ MobileMessageDB.prototype = {
if (aHasRead) {
filter.read = aRead;
}
if (aThreadId) {
if (aHasThreadId) {
filter.threadId = aThreadId;
}

View File

@ -110,11 +110,12 @@ MobileMessageDatabaseService.prototype = {
createMessageCursor: function(aHasStartDate, aStartDate, aHasEndDate,
aEndDate, aNumbers, aNumbersCount, aDelivery,
aHasRead, aRead, aThreadId, aReverse, aCallback) {
aHasRead, aRead, aHasThreadId, aThreadId,
aReverse, aCallback) {
return this.mmdb.createMessageCursor(aHasStartDate, aStartDate, aHasEndDate,
aEndDate, aNumbers, aNumbersCount,
aDelivery, aHasRead, aRead, aThreadId,
aReverse, aCallback);
aDelivery, aHasRead, aRead, aHasThreadId,
aThreadId, aReverse, aCallback);
},
markMessageRead: function(aMessageId, aValue, aSendReadReport, aRequest) {

View File

@ -15,7 +15,7 @@ interface nsICursorContinueCallback;
interface nsIMobileMessageCallback;
interface nsIMobileMessageCursorCallback;
[scriptable, uuid(ead626bc-f5b4-47e1-921c-0b956c9298e0)]
[scriptable, uuid(18672be2-c185-4f9c-8af6-2e6ea004de73)]
interface nsIMobileMessageDatabaseService : nsISupports
{
[binaryname(GetMessageMoz)]
@ -35,6 +35,7 @@ interface nsIMobileMessageDatabaseService : nsISupports
[Null(Null), Undefined(Null)] in DOMString delivery,
in boolean hasRead,
in boolean read,
in boolean hasThreadId,
in unsigned long long threadId,
in boolean reverse,
in nsIMobileMessageCursorCallback callback);

View File

@ -260,6 +260,7 @@ SmsIPCService::CreateMessageCursor(bool aHasStartDate,
const nsAString& aDelivery,
bool aHasRead,
bool aRead,
bool aHasThreadId,
uint64_t aThreadId,
bool aReverse,
nsIMobileMessageCursorCallback* aCursorCallback,
@ -284,6 +285,7 @@ SmsIPCService::CreateMessageCursor(bool aHasStartDate,
data.delivery() = aDelivery;
data.hasRead() = aHasRead;
data.read() = aRead;
data.hasThreadId() = aHasThreadId;
data.threadId() = aThreadId;
return SendCursorRequest(CreateMessageCursorRequest(data, aReverse),

View File

@ -847,6 +847,7 @@ MobileMessageCursorParent::DoRequest(const CreateMessageCursorRequest& aRequest)
filter.delivery(),
filter.hasRead(),
filter.read(),
filter.hasThreadId(),
filter.threadId(),
aRequest.reverse(),
this,

View File

@ -85,6 +85,7 @@ struct SmsFilterData
nsString delivery;
bool hasRead;
bool read;
bool hasThreadId;
uint64_t threadId;
};

View File

@ -341,6 +341,7 @@ function createMessageCursor(aMmdb, aStartDate = null, aEndDate = null,
aDelivery || null,
aRead !== null,
aRead || false,
aThreadId !== null,
aThreadId || 0,
aReverse || false);
}

View File

@ -206,7 +206,7 @@ CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj,
const static js::Class sNPObjectJSWrapperClass =
{
NPRUNTIME_JSCLASS_NAME,
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
JSCLASS_HAS_PRIVATE,
NPObjWrapper_AddProperty,
NPObjWrapper_DelProperty,
NPObjWrapper_GetProperty,
@ -264,7 +264,7 @@ NPObjectMember_Trace(JSTracer *trc, JSObject *obj);
static const JSClass sNPObjectMemberClass =
{
"NPObject Ambiguous Member class", JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS,
"NPObject Ambiguous Member class", JSCLASS_HAS_PRIVATE,
nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, NPObjectMember_Convert,
NPObjectMember_Finalize, NPObjectMember_Call,

View File

@ -72,7 +72,7 @@ dictionary MobileMessageFilter
boolean? read = null;
// Filtering by a message's threadId attribute.
[EnforceRange] unsigned long long? threadId = 0;
[EnforceRange] unsigned long long? threadId = null;
};
/**

View File

@ -596,24 +596,18 @@ nsEditorSpellCheck::SetCurrentDictionary(const nsAString& aDictionary)
// Ignore pending dictionary fetchers by increasing this number.
mDictionaryFetcherGroup++;
nsDefaultStringComparator comparator;
nsAutoString langCode;
int32_t dashIdx = aDictionary.FindChar('-');
if (dashIdx != -1) {
langCode.Assign(Substring(aDictionary, 0, dashIdx));
} else {
langCode.Assign(aDictionary);
}
uint32_t flags = 0;
mEditor->GetFlags(&flags);
if (!(flags & nsIPlaintextEditor::eEditorMailMask)) {
if (mPreferredLang.IsEmpty() ||
!nsStyleUtil::DashMatchCompare(mPreferredLang, langCode, comparator)) {
if (mPreferredLang.IsEmpty() || !mPreferredLang.Equals(aDictionary)) {
// When user sets dictionary manually, we store this value associated
// with editor url.
// with editor url, if it doesn't match the document language exactly.
// For example on "en" sites, we need to store "en-GB", otherwise
// the language might jump back to en-US although the user explicitly
// chose otherwise.
StoreCurrentDictionary(mEditor, aDictionary);
} else {
// If user sets a dictionary matching (even partially), lang defined by
// If user sets a dictionary matching the language defined by
// document, we consider content pref has been canceled, and we clear it.
ClearCurrentDictionary(mEditor);
}

View File

@ -619,8 +619,7 @@ struct JSClass {
// SetNewObjectMetadata itself
#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports*)
#define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM
#define JSCLASS_IMPLEMENTS_BARRIERS (1<<5) // Correctly implements GC read
// and write barriers
// Bit 5 is unused.
#define JSCLASS_EMULATES_UNDEFINED (1<<6) // objects of this class act
// like the value undefined,
// in some contexts

View File

@ -213,9 +213,6 @@ GCForReason(JSRuntime* rt, JSGCInvocationKind gckind, gcreason::Reason reason);
* JS_GC().
* - The GC mode must have been set to JSGC_MODE_INCREMENTAL with
* JS_SetGCParameter().
* - All native objects that have their own trace hook must indicate that they
* implement read and write barriers with the JSCLASS_IMPLEMENTS_BARRIERS
* flag.
*
* Note: Even if incremental GC is enabled and working correctly,
* non-incremental collections can still happen when low on memory.

View File

@ -132,8 +132,8 @@ namespace JS {
_(ICGetElemStub_Dense) \
_(ICGetElemStub_DenseHole) \
_(ICGetElemStub_TypedArray) \
_(ICGetElemStub_ArgsElement) \
_(ICGetElemStub_ArgsElementStrict) \
_(ICGetElemStub_ArgsElementMapped) \
_(ICGetElemStub_ArgsElementUnmapped) \
\
_(ICSetElemStub_Dense) \
_(ICSetElemStub_TypedArray) \
@ -150,7 +150,6 @@ namespace JS {
_(CantInlineClassConstructor) \
_(CantInlineDisabledIon) \
_(CantInlineTooManyArgs) \
_(CantInlineHeavyweight) \
_(CantInlineNeedsArgsObj) \
_(CantInlineDebuggee) \
_(CantInlineUnknownProps) \

View File

@ -1025,7 +1025,7 @@ AsmJSModuleObject_trace(JSTracer* trc, JSObject* obj)
const Class AsmJSModuleObject::class_ = {
"AsmJSModuleObject",
JSCLASS_IS_ANONYMOUS | JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_DELAY_METADATA_CALLBACK |
JSCLASS_IS_ANONYMOUS | JSCLASS_DELAY_METADATA_CALLBACK |
JSCLASS_HAS_RESERVED_SLOTS(AsmJSModuleObject::RESERVED_SLOTS),
nullptr, /* addProperty */
nullptr, /* delProperty */

View File

@ -99,7 +99,7 @@ enum AsmJSSimdOperation
// These labels describe positions in the prologue/epilogue of functions while
// compiling an AsmJSModule.
struct AsmJSFunctionLabels
struct MOZ_STACK_CLASS AsmJSFunctionLabels
{
AsmJSFunctionLabels(jit::Label& entry, jit::Label& overflowExit)
: entry(entry), overflowExit(overflowExit) {}
@ -542,7 +542,10 @@ class AsmJSModule
class CodeRange
{
protected:
uint32_t nameIndex_;
private:
uint32_t lineNumber_;
uint32_t begin_;
uint32_t profilingReturn_;
@ -627,6 +630,24 @@ class AsmJSModule
}
};
class FunctionCodeRange : public CodeRange
{
private:
PropertyName* name_;
public:
FunctionCodeRange(PropertyName* name, uint32_t lineNumber, const AsmJSFunctionLabels& l)
: CodeRange(UINT32_MAX, lineNumber, l), name_(name)
{}
PropertyName* name() const { return name_; }
void initNameIndex(uint32_t nameIndex) {
MOZ_ASSERT(nameIndex_ == UINT32_MAX);
nameIndex_ = nameIndex;
}
};
class FuncPtrTable
{
uint32_t globalDataOffset_;
@ -1137,15 +1158,14 @@ class AsmJSModule
bool addCodeRange(CodeRange::Kind kind, uint32_t begin, uint32_t pret, uint32_t end) {
return codeRanges_.append(CodeRange(kind, begin, pret, end));
}
bool addFunctionCodeRange(PropertyName* name, uint32_t lineNumber,
const AsmJSFunctionLabels& labels)
bool addFunctionCodeRange(PropertyName* name, FunctionCodeRange&& codeRange)
{
MOZ_ASSERT(!isFinished());
MOZ_ASSERT(name->isTenured());
if (names_.length() >= UINT32_MAX)
return false;
uint32_t nameIndex = names_.length();
return names_.append(name) && codeRanges_.append(CodeRange(nameIndex, lineNumber, labels));
codeRange.initNameIndex(names_.length());
return names_.append(name) && codeRanges_.append(Move(codeRange));
}
bool addBuiltinThunkCodeRange(AsmJSExit::BuiltinKind builtin, uint32_t begin,
uint32_t profilingReturn, uint32_t end)
@ -1191,12 +1211,10 @@ class AsmJSModule
return functionCounts_.append(counts);
}
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
bool addProfiledFunction(PropertyName* name, unsigned codeStart, unsigned codeEnd,
unsigned line, unsigned column)
bool addProfiledFunction(ProfiledFunction&& func)
{
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
ProfiledFunction func(name, codeStart, codeEnd, line, column);
return profiledFunctions_.append(func);
return profiledFunctions_.append(mozilla::Move(func));
}
unsigned numProfiledFunctions() const {
MOZ_ASSERT(isFinishedWithModulePrologue());
@ -1208,11 +1226,9 @@ class AsmJSModule
}
#endif
#ifdef JS_ION_PERF
bool addProfiledBlocks(PropertyName* name, unsigned codeBegin, unsigned inlineEnd,
unsigned codeEnd, jit::BasicBlocksVector& basicBlocks)
bool addProfiledBlocks(ProfiledBlocksFunction&& func)
{
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
ProfiledBlocksFunction func(name, codeBegin, inlineEnd, codeEnd, basicBlocks);
return perfProfiledBlocksFunctions_.append(mozilla::Move(func));
}
unsigned numPerfBlocksFunctions() const {

File diff suppressed because it is too large Load Diff

View File

@ -78,6 +78,13 @@ ReportBadArrayType(JSContext* cx)
return false;
}
static bool
ReportOutOfRange(JSContext* cx)
{
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_ATOMICS_BAD_INDEX);
return false;
}
static bool
GetSharedTypedArray(JSContext* cx, HandleValue v,
MutableHandle<SharedTypedArrayObject*> viewp)
@ -90,36 +97,17 @@ GetSharedTypedArray(JSContext* cx, HandleValue v,
return true;
}
// Returns true so long as the conversion succeeds, and then *inRange
// is set to false if the index is not in range.
static bool
GetSharedTypedArrayIndex(JSContext* cx, HandleValue v, Handle<SharedTypedArrayObject*> view,
uint32_t* offset, bool* inRange)
uint32_t* offset)
{
RootedId id(cx);
if (!ValueToId<CanGC>(cx, v, &id))
return false;
uint64_t index;
if (!IsTypedArrayIndex(id, &index) || index >= view->length()) {
*inRange = false;
} else {
*offset = (uint32_t)index;
*inRange = true;
}
return true;
}
void
js::atomics_fullMemoryBarrier()
{
jit::AtomicOperations::fenceSeqCst();
}
static bool
AtomicsFence(JSContext* cx, MutableHandleValue r)
{
atomics_fullMemoryBarrier();
r.setUndefined();
if (!IsTypedArrayIndex(id, &index) || index >= view->length())
return ReportOutOfRange(cx);
*offset = (uint32_t)index;
return true;
}
@ -127,7 +115,9 @@ bool
js::atomics_fence(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return AtomicsFence(cx, args.rval());
jit::AtomicOperations::fenceSeqCst();
args.rval().setUndefined();
return true;
}
static int32_t
@ -198,8 +188,7 @@ js::atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp)
if (!GetSharedTypedArray(cx, objv, &view))
return false;
uint32_t offset;
bool inRange;
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset, &inRange))
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset))
return false;
int32_t oldCandidate;
if (!ToInt32(cx, oldv, &oldCandidate))
@ -208,9 +197,6 @@ js::atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp)
if (!ToInt32(cx, newv, &newCandidate))
return false;
if (!inRange)
return AtomicsFence(cx, r);
bool badType = false;
int32_t result = CompareExchange(view->type(), oldCandidate, newCandidate, view->viewData(), offset, &badType);
@ -236,13 +222,9 @@ js::atomics_load(JSContext* cx, unsigned argc, Value* vp)
if (!GetSharedTypedArray(cx, objv, &view))
return false;
uint32_t offset;
bool inRange;
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset, &inRange))
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset))
return false;
if (!inRange)
return AtomicsFence(cx, r);
switch (view->type()) {
case Scalar::Uint8:
case Scalar::Uint8Clamped: {
@ -356,19 +338,12 @@ ExchangeOrStore(JSContext* cx, unsigned argc, Value* vp)
if (!GetSharedTypedArray(cx, objv, &view))
return false;
uint32_t offset;
bool inRange;
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset, &inRange))
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset))
return false;
int32_t numberValue;
if (!ToInt32(cx, valv, &numberValue))
return false;
if (!inRange) {
atomics_fullMemoryBarrier();
r.set(valv);
return true;
}
bool badType = false;
int32_t result = ExchangeOrStore<op>(view->type(), numberValue, view->viewData(), offset, &badType);
@ -403,16 +378,12 @@ AtomicsBinop(JSContext* cx, HandleValue objv, HandleValue idxv, HandleValue valv
if (!GetSharedTypedArray(cx, objv, &view))
return false;
uint32_t offset;
bool inRange;
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset, &inRange))
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset))
return false;
int32_t numberValue;
if (!ToInt32(cx, valv, &numberValue))
return false;
if (!inRange)
return AtomicsFence(cx, r);
switch (view->type()) {
case Scalar::Int8: {
int8_t v = (int8_t)numberValue;
@ -804,8 +775,7 @@ js::atomics_futexWait(JSContext* cx, unsigned argc, Value* vp)
if (view->type() != Scalar::Int32)
return ReportBadArrayType(cx);
uint32_t offset;
bool inRange;
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset, &inRange))
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset))
return false;
int32_t value;
if (!ToInt32(cx, valv, &value))
@ -822,12 +792,6 @@ js::atomics_futexWait(JSContext* cx, unsigned argc, Value* vp)
timeout_ms = 0;
}
if (!inRange) {
atomics_fullMemoryBarrier();
r.setUndefined();
return true;
}
// This lock also protects the "waiters" field on SharedArrayRawBuffer,
// and it provides the necessary memory fence.
AutoLockFutexAPI lock;
@ -883,14 +847,8 @@ js::atomics_futexWake(JSContext* cx, unsigned argc, Value* vp)
if (view->type() != Scalar::Int32)
return ReportBadArrayType(cx);
uint32_t offset;
bool inRange;
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset, &inRange))
if (!GetSharedTypedArrayIndex(cx, idxv, view, &offset))
return false;
if (!inRange) {
atomics_fullMemoryBarrier();
r.setUndefined();
return true;
}
double count;
if (!ToInteger(cx, countv, &count))
return false;
@ -938,8 +896,7 @@ js::atomics_futexWakeOrRequeue(JSContext* cx, unsigned argc, Value* vp)
if (view->type() != Scalar::Int32)
return ReportBadArrayType(cx);
uint32_t offset1;
bool inRange1;
if (!GetSharedTypedArrayIndex(cx, idx1v, view, &offset1, &inRange1))
if (!GetSharedTypedArrayIndex(cx, idx1v, view, &offset1))
return false;
double count;
if (!ToInteger(cx, countv, &count))
@ -950,14 +907,8 @@ js::atomics_futexWakeOrRequeue(JSContext* cx, unsigned argc, Value* vp)
if (!ToInt32(cx, valv, &value))
return false;
uint32_t offset2;
bool inRange2;
if (!GetSharedTypedArrayIndex(cx, idx2v, view, &offset2, &inRange2))
if (!GetSharedTypedArrayIndex(cx, idx2v, view, &offset2))
return false;
if (!(inRange1 && inRange2)) {
atomics_fullMemoryBarrier();
r.setUndefined();
return true;
}
AutoLockFutexAPI lock;

View File

@ -29,8 +29,6 @@ class AtomicsObject : public JSObject
};
};
void atomics_fullMemoryBarrier();
bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp);
bool atomics_load(JSContext* cx, unsigned argc, Value* vp);

View File

@ -106,7 +106,6 @@ namespace {
const Class MapIteratorObject::class_ = {
"Map Iterator",
JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount),
nullptr, /* addProperty */
nullptr, /* delProperty */
@ -223,7 +222,7 @@ MapIteratorObject::next(JSContext* cx, Handle<MapIteratorObject*> mapIterator,
const Class MapObject::class_ = {
"Map",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_CACHED_PROTO(JSProto_Map),
nullptr, // addProperty
nullptr, // delProperty
@ -831,7 +830,6 @@ class SetIteratorObject : public NativeObject
const Class SetIteratorObject::class_ = {
"Set Iterator",
JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount),
nullptr, /* addProperty */
nullptr, /* delProperty */
@ -972,7 +970,7 @@ SetIteratorObject::next(JSContext* cx, unsigned argc, Value* vp)
const Class SetObject::class_ = {
"Set",
JSCLASS_HAS_PRIVATE | JSCLASS_IMPLEMENTS_BARRIERS |
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_CACHED_PROTO(JSProto_Set),
nullptr, // addProperty
nullptr, // delProperty

View File

@ -69,8 +69,7 @@ ImportEntryObject::class_ = {
"ImportEntry",
JSCLASS_HAS_RESERVED_SLOTS(ImportEntryObject::SlotCount) |
JSCLASS_HAS_CACHED_PROTO(JSProto_ImportEntry) |
JSCLASS_IS_ANONYMOUS |
JSCLASS_IMPLEMENTS_BARRIERS
JSCLASS_IS_ANONYMOUS
};
DEFINE_GETTER_FUNCTIONS(ImportEntryObject, moduleRequest, ModuleRequestSlot)
@ -138,8 +137,7 @@ ExportEntryObject::class_ = {
"ExportEntry",
JSCLASS_HAS_RESERVED_SLOTS(ExportEntryObject::SlotCount) |
JSCLASS_HAS_CACHED_PROTO(JSProto_ExportEntry) |
JSCLASS_IS_ANONYMOUS |
JSCLASS_IMPLEMENTS_BARRIERS
JSCLASS_IS_ANONYMOUS
};
DEFINE_GETTER_FUNCTIONS(ExportEntryObject, exportName, ExportNameSlot)
@ -218,8 +216,7 @@ ModuleObject::class_ = {
"Module",
JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) |
JSCLASS_HAS_CACHED_PROTO(JSProto_Module) |
JSCLASS_IS_ANONYMOUS |
JSCLASS_IMPLEMENTS_BARRIERS,
JSCLASS_IS_ANONYMOUS,
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */

View File

@ -2247,7 +2247,7 @@ OutlineTransparentTypedObject::getOrCreateBuffer(JSContext* cx)
#define DEFINE_TYPEDOBJ_CLASS(Name, Trace) \
const Class Name::class_ = { \
# Name, \
Class::NON_NATIVE | JSCLASS_IMPLEMENTS_BARRIERS, \
Class::NON_NATIVE, \
nullptr, /* addProperty */ \
nullptr, /* delProperty */ \
nullptr, /* getProperty */ \

View File

@ -25,7 +25,7 @@ using mozilla::UniquePtr;
const Class WeakSetObject::class_ = {
"WeakSet",
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet) |
JSCLASS_HAS_CACHED_PROTO(JSProto_WeakSet) |
JSCLASS_HAS_RESERVED_SLOTS(WeakSetObject::RESERVED_SLOTS)
};

View File

@ -559,7 +559,7 @@ static const JSClass sCDataProtoClass = {
static const JSClass sCTypeClass = {
"CType",
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS),
JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS),
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, CType::Finalize,
CType::ConstructData, CType::HasInstance, CType::ConstructData,
@ -576,7 +576,7 @@ static const JSClass sCDataClass = {
static const JSClass sCClosureClass = {
"CClosure",
JSCLASS_IMPLEMENTS_BARRIERS | JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS),
JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS),
nullptr, nullptr, nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, CClosure::Finalize,
nullptr, nullptr, nullptr, CClosure::Trace

View File

@ -273,7 +273,8 @@ function isRootedGCPointerTypeName(name)
name == "WrappableJSErrorResult" ||
name == "frontend::TokenStream" ||
name == "frontend::TokenStream::Position" ||
name == "ModuleCompiler")
name == "ModuleCompiler" ||
name == "ModuleValidator")
{
return true;
}

View File

@ -1808,7 +1808,7 @@ BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn)
MOZ_ASSERT(pn->pn_atom == fun->atom());
/*
* Leave pn->isOp(JSOP_GETNAME) if this->fun is heavyweight to
* Leave pn->isOp(JSOP_GETNAME) if this->fun needs a CallObject to
* address two cases: a new binding introduced by eval, and
* assignment to the name in strict mode.
*
@ -1828,10 +1828,10 @@ BytecodeEmitter::bindNameToSlotHelper(ParseNode* pn)
* has no effect. But in strict mode, this attempt to mutate an
* immutable binding must throw a TypeError. We implement this by
* not optimizing such assignments and by marking such functions as
* heavyweight, ensuring that the function name is represented in
* needsCallObject, ensuring that the function name is represented in
* the scope chain so that assignment will throw a TypeError.
*/
if (!sc->asFunctionBox()->isHeavyweight()) {
if (!sc->asFunctionBox()->needsCallObject()) {
op = JSOP_CALLEE;
pn->pn_dflags |= PND_CONST;
}
@ -3599,7 +3599,7 @@ BytecodeEmitter::maybeEmitVarDecl(JSOp prologueOp, ParseNode* pn, jsatomid* resu
}
if (JOF_OPTYPE(pn->getOp()) == JOF_ATOM &&
(!sc->isFunctionBox() || sc->asFunctionBox()->isHeavyweight()))
(!sc->isFunctionBox() || sc->asFunctionBox()->needsCallObject()))
{
switchToPrologue();
if (!updateSourceCoordNotes(pn->pn_pos.begin))

View File

@ -1081,12 +1081,13 @@ Parser<FullParseHandler>::checkFunctionArguments()
/*
* Check whether any parameters have been assigned within this
* function. In strict mode parameters do not alias arguments[i], and
* to make the arguments object reflect initial parameter values prior
* to any mutation we create it eagerly whenever parameters are (or
* might, in the case of calls to eval) be assigned.
* function. If the arguments object is unmapped (strict mode or
* function with default/rest/destructing args), parameters do not alias
* arguments[i], and to make the arguments object reflect initial
* parameter values prior to any mutation we create it eagerly whenever
* parameters are (or might, in the case of calls to eval) assigned.
*/
if (pc->sc->needStrictChecks()) {
if (!funbox->hasMappedArgsObj()) {
for (AtomDefnListMap::Range r = pc->decls().all(); !r.empty(); r.popFront()) {
DefinitionList& dlist = r.front().value();
for (DefinitionList::Range dr = dlist.all(); !dr.empty(); dr.popFront()) {
@ -8358,7 +8359,7 @@ Parser<ParseHandler>::memberExpr(YieldHandling yieldHandling, TokenKind tt, bool
JSOp op = JSOP_CALL;
if (PropertyName* name = handler.maybeNameAnyParentheses(lhs)) {
if (tt == TOK_LP && name == context->names().eval) {
/* Select JSOP_EVAL and flag pc as heavyweight. */
/* Select JSOP_EVAL and flag pc as needsCallObject. */
op = pc->sc->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
pc->sc->setBindingsAccessedDynamically();
pc->sc->setHasDirectEval();

View File

@ -240,7 +240,7 @@ class SharedContext
inline bool allLocalsAliased();
bool strict() {
bool strict() const {
return strictScript || localStrict;
}
bool setLocalStrictMode(bool strict) {
@ -250,7 +250,7 @@ class SharedContext
}
// JSOPTION_EXTRA_WARNINGS warnings or strict mode errors.
bool needStrictChecks() {
bool needStrictChecks() const {
return strict() || extraWarnings;
}
@ -347,6 +347,10 @@ class FunctionBox : public ObjectBox, public SharedContext
return length != function()->nargs() - function()->hasRest();
}
bool hasMappedArgsObj() const {
return !strict() && !function()->hasRest() && !hasDefaults() && !hasDestructuringArgs;
}
// Return whether this or an enclosing function is being parsed and
// validated as asm.js. Note: if asm.js validation fails, this will be false
// while the function is being reparsed. This flag can be used to disable
@ -362,9 +366,9 @@ class FunctionBox : public ObjectBox, public SharedContext
startColumn = tokenStream.getColumn();
}
bool isHeavyweight()
bool needsCallObject()
{
// Note: this should be kept in sync with JSFunction::isHeavyweight().
// Note: this should be kept in sync with JSFunction::needsCallObject().
return bindings.hasAnyAliasedBindings() ||
hasExtensibleScope() ||
needsDeclEnvObject() ||

View File

@ -1182,13 +1182,6 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar
if (!clasp->trace)
return &obj->as<NativeObject>();
// Global objects all have the same trace hook. That hook is safe without barriers
// if the global has no custom trace hook of its own, or has been moved to a different
// compartment, and so can't have one.
MOZ_ASSERT_IF(!(clasp->trace == JS_GlobalObjectTraceHook &&
(!obj->compartment()->options().getTrace() || !obj->isOwnGlobal())),
clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS);
if (clasp->trace == InlineTypedObject::obj_trace) {
Shape** pshape = obj->as<InlineTypedObject>().addressOfShapeFromGC();
f(pshape, mozilla::Forward<Args>(args)...);

View File

@ -0,0 +1,61 @@
// An unmapped arguments object is created for strict functions or functions
// with default/rest/destructuring args.
load(libdir + "asserts.js");
function testDefaults(a, b=3) {
a = 3;
b = 4;
assertEq(arguments.length, 1);
assertEq(arguments[0], 1);
assertEq(arguments[1], undefined);
arguments[0] = 5;
assertEq(a, 3);
assertThrowsInstanceOf(() => arguments.callee, TypeError);
}
testDefaults(1);
function testRest(a, ...rest) {
a = 3;
assertEq(arguments.length, 3);
assertEq(arguments[0], 1);
assertEq(arguments[1], 2);
arguments[0] = 5;
assertEq(a, 3);
arguments[1] = 6;
assertEq(arguments[1], 6);
assertEq(rest.toString(), "2,3");
assertThrowsInstanceOf(() => arguments.callee, TypeError);
}
testRest(1, 2, 3);
function testDestructuring(a, {foo, bar}, b) {
a = 3;
bar = 4;
b = 1;
assertEq(arguments.length, 3);
assertEq(arguments[0], 1);
assertEq(arguments[1].bar, 2);
assertEq(arguments[2], 9);
assertThrowsInstanceOf(() => arguments.callee, TypeError);
}
testDestructuring(1, {foo: 1, bar: 2}, 9);
function testStrict(a) {
"use strict";
a = 3;
assertEq(arguments[0], 1);
arguments[0] = 8;
assertEq(a, 3);
assertThrowsInstanceOf(() => arguments.callee, TypeError);
}
testStrict(1, 2);
function testMapped(a) {
a = 3;
assertEq(arguments[0], 3);
arguments[0] = 5;
assertEq(a, 5);
assertEq(arguments.callee, testMapped);
}
testMapped(1);

View File

@ -1,8 +1,5 @@
// 'arguments' is allowed with rest parameters.
// FIXME: We should create an unmapped arguments object in this case,
// see bug 1175394. This test is not correct until then.
var args;
function restWithArgs(a, b, ...rest) {
@ -11,8 +8,7 @@ function restWithArgs(a, b, ...rest) {
args = restWithArgs(1, 3, 6, 9);
assertEq(args.length, 4);
assertEq(JSON.stringify(args), '{"0":1,"1":3,"2":[6,9],"3":9}',
"Did you just fix bug 1175394?");
assertEq(JSON.stringify(args), '{"0":1,"1":3,"2":6,"3":9}');
args = restWithArgs();
assertEq(args.length, 0);
@ -27,8 +23,7 @@ function restWithArgsEval(a, b, ...rest) {
args = restWithArgsEval(1, 3, 6, 9);
assertEq(args.length, 4);
assertEq(JSON.stringify(args), '{"0":1,"1":3,"2":[6,9],"3":9}',
"Did you just fix bug 1175394?");
assertEq(JSON.stringify(args), '{"0":1,"1":3,"2":6,"3":9}');
function g(...rest) {
h();

View File

@ -9,7 +9,7 @@ function restAndArgs(...rest) {
var args = restAndArgs(1, 2, 3)();
assertEq(args.length, 3);
assertDeepEq(args[0], [1, 2, 3], "This is bogus, see bug 1175394");
assertEq(args[0], 1);
assertEq(args[1], 2);
assertEq(args[2], 3);

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,8 @@
if (!this.SharedArrayBuffer)
quit(0);
load(libdir + "asserts.js");
function m(stdlib, ffi, heap) {
"use asm";
var HEAP32 = new stdlib.SharedInt32Array(heap);
@ -20,4 +22,5 @@ if (isAsmJSCompilationAvailable())
var sab = new SharedArrayBuffer(65536);
var {add_sharedEv} = m(this, {}, sab);
add_sharedEv(sab.byteLength);
assertErrorMessage(() => add_sharedEv(sab.byteLength), RangeError, /out-of-range index/);

View File

@ -5,6 +5,8 @@
//
// These do not test the futex operations.
load(libdir + "asserts.js");
var DEBUG = false; // Set to true for useful printouts
function dprint(...xs) {
@ -204,18 +206,23 @@ function testTypeBinop(a, op) {
op(a, 0);
}
var globlength = 0; // Will be set later
function testRangeCAS(a) {
dprint("Range: " + a.constructor.name);
assertEq(Atomics.compareExchange(a, -1, 0, 1), undefined); // out of range => undefined, no effect
assertEq(a[0], 0);
a[0] = 0;
var msg = /out-of-range index for atomic access/;
assertEq(Atomics.compareExchange(a, "hi", 0, 1), undefined); // invalid => undefined, no effect
assertErrorMessage(() => Atomics.compareExchange(a, -1, 0, 1), RangeError, msg);
assertEq(a[0], 0);
a[0] = 0;
assertEq(Atomics.compareExchange(a, a.length + 5, 0, 1), undefined); // out of range => undefined, no effect
assertErrorMessage(() => Atomics.compareExchange(a, "hi", 0, 1), RangeError, msg);
assertEq(a[0], 0);
assertErrorMessage(() => Atomics.compareExchange(a, a.length + 5, 0, 1), RangeError, msg);
assertEq(a[0], 0);
assertErrorMessage(() => Atomics.compareExchange(a, globlength, 0, 1), RangeError, msg);
assertEq(a[0], 0);
}
@ -479,7 +486,9 @@ function runTests() {
CLONE(testTypeBinop)(v32, Atomics.xor);
// Test out-of-range references
globlength = v8.length + 5;
CLONE(testRangeCAS)(v8);
globlength = v32.length + 5;
CLONE(testRangeCAS)(v32);
// Test extreme values

View File

@ -25,13 +25,14 @@ withJitOptions(Opts_Ion2NoOffthreadCompilation, function () {
}
};
g.eval("" + function f(d, x) { "use strict"; g(d, x); });
g.eval("" + function f(d, x) {
"use strict";
eval("g(d, x)"); // `eval` to avoid inlining g.
});
g.eval("" + function g(d, x) {
"use strict";
for (var i = 0; i < 200; i++);
// Hack to prevent inlining.
function inner() { i = 42; };
toggle(d);
});

View File

@ -0,0 +1,15 @@
function f() {
assertEq(Array.isArray(10), false);
assertEq(Array.isArray([]), true);
assertEq(Array.isArray(Math), false);
var objs = [{}, []];
for (var i=0; i<objs.length; i++)
assertEq(Array.isArray(objs[i]), i === 1);
var arr = [[], [], 1];
for (var i=0; i<arr.length; i++)
assertEq(Array.isArray(arr[i]), i < 2);
}
f();
f();
f();

View File

@ -253,7 +253,7 @@ bool
jit::EnsureHasScopeObjects(JSContext* cx, AbstractFramePtr fp)
{
if (fp.isFunctionFrame() &&
fp.fun()->isHeavyweight() &&
fp.fun()->needsCallObject() &&
!fp.hasCallObj())
{
return fp.initFunctionScopeObjects(cx);

View File

@ -685,7 +685,7 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
Value v = iter.read();
if (v.isObject()) {
scopeChain = &v.toObject();
if (fun && fun->isHeavyweight())
if (fun && fun->needsCallObject())
flags |= BaselineFrame::HAS_CALL_OBJ;
} else {
MOZ_ASSERT(v.isUndefined() || v.isMagic(JS_OPTIMIZED_OUT));

View File

@ -123,7 +123,7 @@ BaselineCompiler::compile()
JSObject* templateScope = nullptr;
if (script->functionNonDelazifying()) {
RootedFunction fun(cx, script->functionNonDelazifying());
if (fun->isHeavyweight()) {
if (fun->needsCallObject()) {
RootedScript scriptRoot(cx, script);
templateScope = CallObject::createTemplateObject(cx, scriptRoot, gc::TenuredHeap);
if (!templateScope)
@ -630,13 +630,13 @@ BaselineCompiler::emitDebugPrologue()
return true;
}
typedef bool (*StrictEvalPrologueFn)(JSContext*, BaselineFrame*);
static const VMFunction StrictEvalPrologueInfo =
FunctionInfo<StrictEvalPrologueFn>(jit::StrictEvalPrologue);
typedef bool (*InitStrictEvalScopeObjectsFn)(JSContext*, BaselineFrame*);
static const VMFunction InitStrictEvalScopeObjectsInfo =
FunctionInfo<InitStrictEvalScopeObjectsFn>(jit::InitStrictEvalScopeObjects);
typedef bool (*HeavyweightFunPrologueFn)(JSContext*, BaselineFrame*);
static const VMFunction HeavyweightFunPrologueInfo =
FunctionInfo<HeavyweightFunPrologueFn>(jit::HeavyweightFunPrologue);
typedef bool (*InitFunctionScopeObjectsFn)(JSContext*, BaselineFrame*);
static const VMFunction InitFunctionScopeObjectsInfo =
FunctionInfo<InitFunctionScopeObjectsFn>(jit::InitFunctionScopeObjects);
bool
BaselineCompiler::initScopeChain()
@ -648,7 +648,7 @@ BaselineCompiler::initScopeChain()
RootedFunction fun(cx, function());
if (fun) {
// Use callee->environment as scope chain. Note that we do
// this also for heavy-weight functions, so that the scope
// this also for needsCallObject functions, so that the scope
// chain slot is properly initialized if the call triggers GC.
Register callee = R0.scratchReg();
Register scope = R1.scratchReg();
@ -656,14 +656,14 @@ BaselineCompiler::initScopeChain()
masm.loadPtr(Address(callee, JSFunction::offsetOfEnvironment()), scope);
masm.storePtr(scope, frame.addressOfScopeChain());
if (fun->isHeavyweight()) {
if (fun->needsCallObject()) {
// Call into the VM to create a new call object.
prepareVMCall();
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
if (!callVMNonOp(HeavyweightFunPrologueInfo, phase))
if (!callVMNonOp(InitFunctionScopeObjectsInfo, phase))
return false;
}
} else {
@ -677,7 +677,7 @@ BaselineCompiler::initScopeChain()
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
if (!callVMNonOp(StrictEvalPrologueInfo, phase))
if (!callVMNonOp(InitStrictEvalScopeObjectsInfo, phase))
return false;
}
}
@ -2621,9 +2621,9 @@ BaselineCompiler::emit_JSOP_SETLOCAL()
bool
BaselineCompiler::emitFormalArgAccess(uint32_t arg, bool get)
{
// Fast path: the script does not use |arguments|, or is strict. In strict
// mode, formals do not alias the arguments object.
if (!script->argumentsHasVarBinding() || script->strict()) {
// Fast path: the script does not use |arguments| or formals don't
// alias the arguments object.
if (!script->argumentsAliasesFormals()) {
if (get) {
frame.pushArg(arg);
} else {

View File

@ -89,7 +89,7 @@ inline CallObject&
BaselineFrame::callObj() const
{
MOZ_ASSERT(hasCallObj());
MOZ_ASSERT(fun()->isHeavyweight());
MOZ_ASSERT(fun()->needsCallObject());
JSObject* obj = scopeChain();
while (!obj->is<CallObject>())

View File

@ -109,7 +109,7 @@ BaselineFrame::copyRawFrameSlots(AutoValueVector* vec) const
}
bool
BaselineFrame::strictEvalPrologue(JSContext* cx)
BaselineFrame::initStrictEvalScopeObjects(JSContext* cx)
{
MOZ_ASSERT(isStrictEvalFrame());
@ -122,17 +122,11 @@ BaselineFrame::strictEvalPrologue(JSContext* cx)
return true;
}
bool
BaselineFrame::heavyweightFunPrologue(JSContext* cx)
{
return initFunctionScopeObjects(cx);
}
bool
BaselineFrame::initFunctionScopeObjects(JSContext* cx)
{
MOZ_ASSERT(isNonEvalFunctionFrame());
MOZ_ASSERT(fun()->isHeavyweight());
MOZ_ASSERT(fun()->needsCallObject());
CallObject* callobj = CallObject::createForFunction(cx, this);
if (!callobj)

View File

@ -279,8 +279,7 @@ class BaselineFrame
inline void popBlock(JSContext* cx);
inline bool freshenBlock(JSContext* cx);
bool strictEvalPrologue(JSContext* cx);
bool heavyweightFunPrologue(JSContext* cx);
bool initStrictEvalScopeObjects(JSContext* cx);
bool initFunctionScopeObjects(JSContext* cx);
void initArgsObjUnchecked(ArgumentsObject& argsobj) {

View File

@ -2838,9 +2838,9 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
// Check for ArgumentsObj[int] accesses
if (obj->is<ArgumentsObject>() && rhs.isInt32()) {
ICGetElem_Arguments::Which which = ICGetElem_Arguments::Normal;
if (obj->is<StrictArgumentsObject>())
which = ICGetElem_Arguments::Strict;
ICGetElem_Arguments::Which which = ICGetElem_Arguments::Mapped;
if (obj->is<UnmappedArgumentsObject>())
which = ICGetElem_Arguments::Unmapped;
if (!ArgumentsGetElemStubExists(stub, which)) {
JitSpew(JitSpew_BaselineIC, " Generating GetElem(ArgsObj[Int32]) stub");
ICGetElem_Arguments::Compiler compiler(
@ -3829,11 +3829,12 @@ ICGetElem_Arguments::Compiler::generateStubCode(MacroAssembler& masm)
return true;
}
MOZ_ASSERT(which_ == ICGetElem_Arguments::Strict ||
which_ == ICGetElem_Arguments::Normal);
MOZ_ASSERT(which_ == ICGetElem_Arguments::Mapped ||
which_ == ICGetElem_Arguments::Unmapped);
bool isStrict = which_ == ICGetElem_Arguments::Strict;
const Class* clasp = isStrict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_;
const Class* clasp = (which_ == ICGetElem_Arguments::Mapped)
? &MappedArgumentsObject::class_
: &UnmappedArgumentsObject::class_;
AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
Register scratchReg = regs.takeAny();
@ -5865,7 +5866,7 @@ TryAttachMagicArgumentsGetPropStub(JSContext* cx, JSScript* script, ICGetProp_Fa
// Try handling arguments.callee on optimized arguments.
if (name == cx->names().callee) {
MOZ_ASSERT(!script->strict());
MOZ_ASSERT(script->hasMappedArgsObj());
JitSpew(JitSpew_BaselineIC, " Generating GetProp(MagicArgs.callee) stub");
@ -5947,10 +5948,10 @@ TryAttachLengthStub(JSContext* cx, JSScript* script, ICGetProp_Fallback* stub, H
if (obj->is<ArgumentsObject>() && res.isInt32()) {
JitSpew(JitSpew_BaselineIC, " Generating GetProp(ArgsObj.length %s) stub",
obj->is<StrictArgumentsObject>() ? "Strict" : "Normal");
ICGetProp_ArgumentsLength::Which which = ICGetProp_ArgumentsLength::Normal;
if (obj->is<StrictArgumentsObject>())
which = ICGetProp_ArgumentsLength::Strict;
obj->is<MappedArgumentsObject>() ? "Mapped" : "Unmapped");
ICGetProp_ArgumentsLength::Which which = ICGetProp_ArgumentsLength::Mapped;
if (obj->is<UnmappedArgumentsObject>())
which = ICGetProp_ArgumentsLength::Unmapped;
ICGetProp_ArgumentsLength::Compiler compiler(cx, which);
ICStub* newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
@ -6479,7 +6480,7 @@ ComputeGetPropResult(JSContext* cx, BaselineFrame* frame, JSOp op, HandlePropert
res.setInt32(frame->numActualArgs());
} else {
MOZ_ASSERT(name == cx->names().callee);
MOZ_ASSERT(!frame->script()->strict());
MOZ_ASSERT(frame->script()->hasMappedArgsObj());
res.setObject(*frame->callee());
}
} else {
@ -7417,11 +7418,12 @@ ICGetProp_ArgumentsLength::Compiler::generateStubCode(MacroAssembler& masm)
EmitStubGuardFailure(masm);
return true;
}
MOZ_ASSERT(which_ == ICGetProp_ArgumentsLength::Strict ||
which_ == ICGetProp_ArgumentsLength::Normal);
MOZ_ASSERT(which_ == ICGetProp_ArgumentsLength::Mapped ||
which_ == ICGetProp_ArgumentsLength::Unmapped);
bool isStrict = which_ == ICGetProp_ArgumentsLength::Strict;
const Class* clasp = isStrict ? &StrictArgumentsObject::class_ : &NormalArgumentsObject::class_;
const Class* clasp = (which_ == ICGetProp_ArgumentsLength::Mapped)
? &MappedArgumentsObject::class_
: &UnmappedArgumentsObject::class_;
Register scratchReg = R1.scratchReg();

View File

@ -1768,7 +1768,7 @@ class ICGetElem_Arguments : public ICMonitoredStub
{
friend class ICStubSpace;
public:
enum Which { Normal, Strict, Magic };
enum Which { Mapped, Unmapped, Magic };
private:
ICGetElem_Arguments(JitCode* stubCode, ICStub* firstMonitorStub, Which which)
@ -3519,7 +3519,7 @@ class ICGetProp_ArgumentsLength : public ICStub
{
friend class ICStubSpace;
public:
enum Which { Normal, Strict, Magic };
enum Which { Mapped, Unmapped, Magic };
protected:
explicit ICGetProp_ArgumentsLength(JitCode* stubCode)

View File

@ -121,8 +121,9 @@ struct BaselineScript
// Code pointer containing the actual method.
RelocatablePtrJitCode method_;
// For heavyweight scripts, template objects to use for the call object and
// decl env object (linked via the call object's enclosing scope).
// For functions with a call object, template objects to use for the call
// object and decl env object (linked via the call object's enclosing
// scope).
RelocatablePtrObject templateScope_;
// Allocated space for fallback stubs.

View File

@ -46,9 +46,10 @@ BytecodeAnalysis::init(TempAllocator& alloc, GSNCache& gsn)
if (!infos_.growByUninitialized(script_->length()))
return false;
// We need a scope chain if the function is heavyweight.
// Initialize the scope chain slot if either the function needs a CallObject
// or the script uses the scope chain. The latter case is handled below.
usesScopeChain_ = (script_->functionDelazifying() &&
script_->functionDelazifying()->isHeavyweight());
script_->functionDelazifying()->needsCallObject());
MOZ_ASSERT_IF(script_->hasAnyAliasedBindings(), usesScopeChain_);
jsbytecode* end = script_->codeEnd();

View File

@ -460,7 +460,7 @@ class CompileInfo
return scriptNeedsArgsObj_;
}
bool argsObjAliasesFormals() const {
return scriptNeedsArgsObj_ && !script()->strict();
return scriptNeedsArgsObj_ && script()->hasMappedArgsObj();
}
AnalysisMode analysisMode() const {
@ -493,7 +493,7 @@ class CompileInfo
if (slot == thisSlot())
return true;
if (funMaybeLazy()->isHeavyweight() && slot == scopeChainSlot())
if (funMaybeLazy()->needsCallObject() && slot == scopeChainSlot())
return true;
// If the function may need an arguments object, then make sure to

View File

@ -3445,10 +3445,11 @@ ArgumentsUseCanBeLazy(JSContext* cx, JSScript* script, MInstruction* ins, size_t
return true;
// arguments.length length can read fp->numActualArgs() directly.
// arguments.callee can read fp->callee() directly in non-strict code.
// arguments.callee can read fp->callee() directly if the arguments object
// is mapped.
if (ins->isCallGetProperty() && index == 0 &&
(ins->toCallGetProperty()->name() == cx->names().length ||
(!script->strict() && ins->toCallGetProperty()->name() == cx->names().callee)))
(script->hasMappedArgsObj() && ins->toCallGetProperty()->name() == cx->names().callee)))
{
return true;
}

View File

@ -524,11 +524,6 @@ IonBuilder::canInlineTarget(JSFunction* target, CallInfo& callInfo)
return DontInline(inlineScript, "Common inlining path");
}
if (target->isHeavyweight()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineHeavyweight);
return DontInline(inlineScript, "Heavyweight function");
}
if (inlineScript->uninlineable()) {
trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
return DontInline(inlineScript, "Uninlineable script");
@ -1223,7 +1218,7 @@ IonBuilder::initScopeChain(MDefinition* callee)
// This reproduce what is done in CallObject::createForFunction. Skip
// this for analyses, as the script might not have a baseline script
// with template objects yet.
if (fun->isHeavyweight() && !info().isAnalysis()) {
if (fun->needsCallObject() && !info().isAnalysis()) {
if (fun->isNamedLambda()) {
scope = createDeclEnvObject(callee, scope);
if (!scope)
@ -10633,7 +10628,7 @@ IonBuilder::getPropTryArgumentsCallee(bool* emitted, MDefinition* obj, PropertyN
if (name != names().callee)
return true;
MOZ_ASSERT(!script()->strict());
MOZ_ASSERT(script()->hasMappedArgsObj());
obj->setImplicitlyUsedUnchecked();
current->push(getCallee());

View File

@ -752,6 +752,7 @@ class IonBuilder
// Array natives.
InliningStatus inlineArray(CallInfo& callInfo);
InliningStatus inlineArrayIsArray(CallInfo& callInfo);
InliningStatus inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode);
InliningStatus inlineArrayPush(CallInfo& callInfo);
InliningStatus inlineArrayConcat(CallInfo& callInfo);

View File

@ -1858,7 +1858,7 @@ GetPropertyIC::tryAttachArgumentsLength(JSContext* cx, HandleScript outerScript,
if (!(outputType == MIRType_Value || outputType == MIRType_Int32))
return true;
if (hasArgumentsLengthStub(obj->is<StrictArgumentsObject>()))
if (hasArgumentsLengthStub(obj->is<MappedArgumentsObject>()))
return true;
*emitted = true;
@ -1878,10 +1878,7 @@ GetPropertyIC::tryAttachArgumentsLength(JSContext* cx, HandleScript outerScript,
}
MOZ_ASSERT(object() != tmpReg);
const Class* clasp = obj->is<StrictArgumentsObject>() ? &StrictArgumentsObject::class_
: &NormalArgumentsObject::class_;
masm.branchTestObjClass(Assembler::NotEqual, object(), tmpReg, clasp, &failures);
masm.branchTestObjClass(Assembler::NotEqual, object(), tmpReg, obj->getClass(), &failures);
// Get initial ArgsObj length value, test if length has been overridden.
masm.unboxInt32(Address(object(), ArgumentsObject::getInitialLengthSlotOffset()), tmpReg);
@ -1901,16 +1898,16 @@ GetPropertyIC::tryAttachArgumentsLength(JSContext* cx, HandleScript outerScript,
masm.bind(&failures);
attacher.jumpNextStub(masm);
if (obj->is<StrictArgumentsObject>()) {
MOZ_ASSERT(!hasStrictArgumentsLengthStub_);
hasStrictArgumentsLengthStub_ = true;
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj length (strict)",
if (obj->is<UnmappedArgumentsObject>()) {
MOZ_ASSERT(!hasUnmappedArgumentsLengthStub_);
hasUnmappedArgumentsLengthStub_ = true;
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj length (unmapped)",
JS::TrackedOutcome::ICGetPropStub_ArgumentsLength);
}
MOZ_ASSERT(!hasNormalArgumentsLengthStub_);
hasNormalArgumentsLengthStub_ = true;
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj length (normal)",
MOZ_ASSERT(!hasMappedArgumentsLengthStub_);
hasMappedArgumentsLengthStub_ = true;
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj length (mapped)",
JS::TrackedOutcome::ICGetPropStub_ArgumentsLength);
}
@ -2028,8 +2025,8 @@ GetPropertyIC::reset(ReprotectCode reprotect)
IonCache::reset(reprotect);
hasTypedArrayLengthStub_ = false;
hasSharedTypedArrayLengthStub_ = false;
hasStrictArgumentsLengthStub_ = false;
hasNormalArgumentsLengthStub_ = false;
hasMappedArgumentsLengthStub_ = false;
hasUnmappedArgumentsLengthStub_ = false;
hasGenericProxyStub_ = false;
}
@ -3931,10 +3928,7 @@ GetElementIC::attachArgumentsElement(JSContext* cx, HandleScript outerScript, Io
Register tmpReg = output().scratchReg().gpr();
MOZ_ASSERT(tmpReg != InvalidReg);
const Class* clasp = obj->is<StrictArgumentsObject>() ? &StrictArgumentsObject::class_
: &NormalArgumentsObject::class_;
masm.branchTestObjClass(Assembler::NotEqual, object(), tmpReg, clasp, &failures);
masm.branchTestObjClass(Assembler::NotEqual, object(), tmpReg, obj->getClass(), &failures);
// Get initial ArgsObj length value, test if length has been overridden.
masm.unboxInt32(Address(object(), ArgumentsObject::getInitialLengthSlotOffset()), tmpReg);
@ -4016,18 +4010,17 @@ GetElementIC::attachArgumentsElement(JSContext* cx, HandleScript outerScript, Io
masm.bind(&failures);
attacher.jumpNextStub(masm);
if (obj->is<StrictArgumentsObject>()) {
MOZ_ASSERT(!hasStrictArgumentsStub_);
hasStrictArgumentsStub_ = true;
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj element (strict)",
JS::TrackedOutcome::ICGetElemStub_ArgsElementStrict);
if (obj->is<UnmappedArgumentsObject>()) {
MOZ_ASSERT(!hasUnmappedArgumentsStub_);
hasUnmappedArgumentsStub_ = true;
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj element (unmapped)",
JS::TrackedOutcome::ICGetElemStub_ArgsElementUnmapped);
}
MOZ_ASSERT(!hasNormalArgumentsStub_);
hasNormalArgumentsStub_ = true;
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj element (normal)",
JS::TrackedOutcome::ICGetElemStub_ArgsElement);
MOZ_ASSERT(!hasMappedArgumentsStub_);
hasMappedArgumentsStub_ = true;
return linkAndAttachStub(cx, masm, attacher, ion, "ArgsObj element (mapped)",
JS::TrackedOutcome::ICGetElemStub_ArgsElementMapped);
}
bool
@ -4058,7 +4051,7 @@ GetElementIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex,
bool attachedStub = false;
if (cache.canAttachStub()) {
if (IsOptimizableArgumentsObjectForGetElem(obj, idval) &&
!cache.hasArgumentsStub(obj->is<StrictArgumentsObject>()) &&
!cache.hasArgumentsStub(obj->is<MappedArgumentsObject>()) &&
(cache.index().hasValue() ||
cache.index().type() == MIRType_Int32) &&
(cache.output().hasValue() || !cache.output().typedReg().isFloat()))
@ -4116,8 +4109,8 @@ GetElementIC::reset(ReprotectCode reprotect)
{
IonCache::reset(reprotect);
hasDenseStub_ = false;
hasStrictArgumentsStub_ = false;
hasNormalArgumentsStub_ = false;
hasMappedArgumentsStub_ = false;
hasUnmappedArgumentsStub_ = false;
}
static bool

View File

@ -392,8 +392,8 @@ class GetPropertyIC : public IonCache
bool monitoredResult_ : 1;
bool hasTypedArrayLengthStub_ : 1;
bool hasSharedTypedArrayLengthStub_ : 1;
bool hasStrictArgumentsLengthStub_ : 1;
bool hasNormalArgumentsLengthStub_ : 1;
bool hasMappedArgumentsLengthStub_ : 1;
bool hasUnmappedArgumentsLengthStub_ : 1;
bool hasGenericProxyStub_ : 1;
public:
@ -410,8 +410,8 @@ class GetPropertyIC : public IonCache
monitoredResult_(monitoredResult),
hasTypedArrayLengthStub_(false),
hasSharedTypedArrayLengthStub_(false),
hasStrictArgumentsLengthStub_(false),
hasNormalArgumentsLengthStub_(false),
hasMappedArgumentsLengthStub_(false),
hasUnmappedArgumentsLengthStub_(false),
hasGenericProxyStub_(false)
{
}
@ -435,8 +435,8 @@ class GetPropertyIC : public IonCache
bool hasAnyTypedArrayLengthStub(HandleObject obj) const {
return obj->is<TypedArrayObject>() ? hasTypedArrayLengthStub_ : hasSharedTypedArrayLengthStub_;
}
bool hasArgumentsLengthStub(bool strict) const {
return strict ? hasStrictArgumentsLengthStub_ : hasNormalArgumentsLengthStub_;
bool hasArgumentsLengthStub(bool mapped) const {
return mapped ? hasMappedArgumentsLengthStub_ : hasUnmappedArgumentsLengthStub_;
}
bool hasGenericProxyStub() const {
return hasGenericProxyStub_;
@ -622,8 +622,8 @@ class GetElementIC : public IonCache
bool monitoredResult_ : 1;
bool allowDoubleResult_ : 1;
bool hasDenseStub_ : 1;
bool hasStrictArgumentsStub_ : 1;
bool hasNormalArgumentsStub_ : 1;
bool hasMappedArgumentsStub_ : 1;
bool hasUnmappedArgumentsStub_ : 1;
size_t failedUpdates_;
@ -639,8 +639,8 @@ class GetElementIC : public IonCache
monitoredResult_(monitoredResult),
allowDoubleResult_(allowDoubleResult),
hasDenseStub_(false),
hasStrictArgumentsStub_(false),
hasNormalArgumentsStub_(false),
hasMappedArgumentsStub_(false),
hasUnmappedArgumentsStub_(false),
failedUpdates_(0)
{
}
@ -667,8 +667,8 @@ class GetElementIC : public IonCache
bool hasDenseStub() const {
return hasDenseStub_;
}
bool hasArgumentsStub(bool strict) const {
return strict ? hasStrictArgumentsStub_ : hasNormalArgumentsStub_;
bool hasArgumentsStub(bool mapped) const {
return mapped ? hasMappedArgumentsStub_ : hasUnmappedArgumentsStub_;
}
void setHasDenseStub() {
MOZ_ASSERT(!hasDenseStub());

View File

@ -2531,19 +2531,19 @@ InlineFrameIterator::computeScopeChain(Value scopeChainValue, MaybeReadFallback&
if (hasCallObj) {
if (fallback.canRecoverResults()) {
RootedObject obj(fallback.maybeCx, &scopeChainValue.toObject());
*hasCallObj = isFunctionFrame() && callee(fallback)->isHeavyweight();
*hasCallObj = isFunctionFrame() && callee(fallback)->needsCallObject();
return obj;
} else {
JS::AutoSuppressGCAnalysis nogc; // If we cannot recover then we cannot GC.
*hasCallObj = isFunctionFrame() && callee(fallback)->isHeavyweight();
*hasCallObj = isFunctionFrame() && callee(fallback)->needsCallObject();
}
}
return &scopeChainValue.toObject();
}
// Note we can hit this case even for heavyweight functions, in case we
// are walking the frame during the function prologue, before the scope
// Note we can hit this case even for functions with a CallObject, in case
// we are walking the frame during the function prologue, before the scope
// chain has been initialized.
if (isFunctionFrame())
return callee(fallback)->environment();

View File

@ -80,6 +80,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
// Array natives.
if (native == ArrayConstructor)
return inlineArray(callInfo);
if (native == js::array_isArray)
return inlineArrayIsArray(callInfo);
if (native == js::array_pop)
return inlineArrayPopShift(callInfo, MArrayPopShift::Pop);
if (native == js::array_shift)
@ -618,6 +620,40 @@ IonBuilder::inlineArray(CallInfo& callInfo)
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineArrayIsArray(CallInfo& callInfo)
{
if (callInfo.constructing() || callInfo.argc() != 1) {
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
return InliningStatus_NotInlined;
}
if (getInlineReturnType() != MIRType_Boolean)
return InliningStatus_NotInlined;
MDefinition* arg = callInfo.getArg(0);
bool isArray;
if (!arg->mightBeType(MIRType_Object)) {
isArray = false;
} else {
if (arg->type() != MIRType_Object)
return InliningStatus_NotInlined;
TemporaryTypeSet* types = arg->resultTypeSet();
const Class* clasp = types ? types->getKnownClass(constraints()) : nullptr;
if (!clasp || clasp->isProxy())
return InliningStatus_NotInlined;
isArray = (clasp == &ArrayObject::class_ || clasp == &UnboxedArrayObject::class_);
}
pushConstant(BooleanValue(isArray));
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
{

View File

@ -13174,11 +13174,19 @@ class MAsmJSHeapAccess
Scalar::Type accessType_ : 8;
bool needsBoundsCheck_;
unsigned numSimdElems_;
MemoryBarrierBits barrierBefore_;
MemoryBarrierBits barrierAfter_;
public:
MAsmJSHeapAccess(Scalar::Type accessType, bool needsBoundsCheck, unsigned numSimdElems = 0)
: offset_(0), accessType_(accessType),
needsBoundsCheck_(needsBoundsCheck), numSimdElems_(numSimdElems)
MAsmJSHeapAccess(Scalar::Type accessType, bool needsBoundsCheck, unsigned numSimdElems = 0,
MemoryBarrierBits barrierBefore = MembarNobits,
MemoryBarrierBits barrierAfter = MembarNobits)
: offset_(0),
accessType_(accessType),
needsBoundsCheck_(needsBoundsCheck),
numSimdElems_(numSimdElems),
barrierBefore_(barrierBefore),
barrierAfter_(barrierAfter)
{
MOZ_ASSERT(numSimdElems <= ScalarTypeToLength(accessType));
}
@ -13198,6 +13206,9 @@ class MAsmJSHeapAccess
MOZ_ASSERT(o >= 0);
offset_ = o;
}
MemoryBarrierBits barrierBefore() const { return barrierBefore_; }
MemoryBarrierBits barrierAfter() const { return barrierAfter_; }
bool isAtomicAccess() const { return (barrierBefore_|barrierAfter_) != MembarNobits; }
};
class MAsmJSLoadHeap
@ -13205,15 +13216,10 @@ class MAsmJSLoadHeap
public MAsmJSHeapAccess,
public NoTypePolicy::Data
{
MemoryBarrierBits barrierBefore_;
MemoryBarrierBits barrierAfter_;
MAsmJSLoadHeap(Scalar::Type accessType, MDefinition* ptr, bool needsBoundsCheck,
unsigned numSimdElems, MemoryBarrierBits before, MemoryBarrierBits after)
: MUnaryInstruction(ptr),
MAsmJSHeapAccess(accessType, needsBoundsCheck, numSimdElems),
barrierBefore_(before),
barrierAfter_(after)
MAsmJSHeapAccess(accessType, needsBoundsCheck, numSimdElems, before, after)
{
if (before|after)
setGuard(); // Not removable
@ -13262,14 +13268,12 @@ class MAsmJSLoadHeap
MDefinition* ptr() const { return getOperand(0); }
void replacePtr(MDefinition* newPtr) { replaceOperand(0, newPtr); }
MemoryBarrierBits barrierBefore() const { return barrierBefore_; }
MemoryBarrierBits barrierAfter() const { return barrierAfter_; }
bool congruentTo(const MDefinition* ins) const override;
AliasSet getAliasSet() const override {
// When a barrier is needed make the instruction effectful by
// giving it a "store" effect.
if (barrierBefore_|barrierAfter_)
if (isAtomicAccess())
return AliasSet::Store(AliasSet::AsmJSHeap);
return AliasSet::Load(AliasSet::AsmJSHeap);
}
@ -13281,15 +13285,10 @@ class MAsmJSStoreHeap
public MAsmJSHeapAccess,
public NoTypePolicy::Data
{
MemoryBarrierBits barrierBefore_;
MemoryBarrierBits barrierAfter_;
MAsmJSStoreHeap(Scalar::Type accessType, MDefinition* ptr, MDefinition* v, bool needsBoundsCheck,
unsigned numSimdElems, MemoryBarrierBits before, MemoryBarrierBits after)
: MBinaryInstruction(ptr, v),
MAsmJSHeapAccess(accessType, needsBoundsCheck, numSimdElems),
barrierBefore_(before),
barrierAfter_(after)
MAsmJSHeapAccess(accessType, needsBoundsCheck, numSimdElems, before, after)
{
if (before|after)
setGuard(); // Not removable
@ -13311,8 +13310,6 @@ class MAsmJSStoreHeap
MDefinition* ptr() const { return getOperand(0); }
void replacePtr(MDefinition* newPtr) { replaceOperand(0, newPtr); }
MDefinition* value() const { return getOperand(1); }
MemoryBarrierBits barrierBefore() const { return barrierBefore_; }
MemoryBarrierBits barrierAfter() const { return barrierAfter_; }
AliasSet getAliasSet() const override {
return AliasSet::Store(AliasSet::AsmJSHeap);

Some files were not shown because too many files have changed in this diff Show More