mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-18 14:56:07 +00:00
Merge m-c to fx-team. a=merge
This commit is contained in:
commit
9688a15055
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -5,5 +5,12 @@
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -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"/>
|
||||
|
@ -5,5 +5,12 @@
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -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"/>
|
||||
|
@ -5,5 +5,12 @@
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -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"/>
|
||||
|
@ -5,5 +5,12 @@
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -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"/>
|
||||
|
@ -5,5 +5,12 @@
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -5,5 +5,12 @@
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": 6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -5,5 +5,12 @@
|
||||
"algorithm": "sha512",
|
||||
"filename": "gcc.tar.xz",
|
||||
"unpack": "True"
|
||||
},
|
||||
{
|
||||
"size": 12057960,
|
||||
"digest": "6105d6432943141cffb40020dc5ba3a793650bdeb3af9bd5e56d3796c5f03df9962a73e521646cd71fbfb5e266c1e74716ad722fb6055589dfb7d35175bca89e",
|
||||
"algorithm": "sha512",
|
||||
"filename": "gtk3.tar.xz",
|
||||
"unpack": true
|
||||
}
|
||||
]
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"
|
||||
}
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"
|
||||
|
@ -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();
|
||||
|
@ -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":
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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() {
|
||||
|
@ -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.
|
||||
|
160
dom/media/mediasink/AudioSinkWrapper.cpp
Normal file
160
dom/media/mediasink/AudioSinkWrapper.cpp
Normal 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
|
||||
|
93
dom/media/mediasink/AudioSinkWrapper.h
Normal file
93
dom/media/mediasink/AudioSinkWrapper.h
Normal 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_
|
115
dom/media/mediasink/MediaSink.h
Normal file
115
dom/media/mediasink/MediaSink.h
Normal 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_
|
@ -5,6 +5,7 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'AudioSinkWrapper.cpp',
|
||||
'DecodedAudioDataSink.cpp',
|
||||
]
|
||||
|
||||
|
@ -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')
|
||||
|
44
dom/media/test/test_streams_capture_origin.html
Normal file
44
dom/media/test/test_streams_capture_origin.html
Normal 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>
|
@ -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>
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -56,6 +56,7 @@ MobileMessageDatabaseService::CreateMessageCursor(bool aHasStartDate,
|
||||
const nsAString& aDelivery,
|
||||
bool aHasRead,
|
||||
bool aRead,
|
||||
bool aHasThreadId,
|
||||
uint64_t aThreadId,
|
||||
bool aReverse,
|
||||
nsIMobileMessageCursorCallback* aCallback,
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -847,6 +847,7 @@ MobileMessageCursorParent::DoRequest(const CreateMessageCursorRequest& aRequest)
|
||||
filter.delivery(),
|
||||
filter.hasRead(),
|
||||
filter.read(),
|
||||
filter.hasThreadId(),
|
||||
filter.threadId(),
|
||||
aRequest.reverse(),
|
||||
this,
|
||||
|
@ -85,6 +85,7 @@ struct SmsFilterData
|
||||
nsString delivery;
|
||||
bool hasRead;
|
||||
bool read;
|
||||
bool hasThreadId;
|
||||
uint64_t threadId;
|
||||
};
|
||||
|
||||
|
@ -341,6 +341,7 @@ function createMessageCursor(aMmdb, aStartDate = null, aEndDate = null,
|
||||
aDelivery || null,
|
||||
aRead !== null,
|
||||
aRead || false,
|
||||
aThreadId !== null,
|
||||
aThreadId || 0,
|
||||
aReverse || false);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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) \
|
||||
|
@ -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 */
|
||||
|
@ -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
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 */ \
|
||||
|
@ -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)
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -273,7 +273,8 @@ function isRootedGCPointerTypeName(name)
|
||||
name == "WrappableJSErrorResult" ||
|
||||
name == "frontend::TokenStream" ||
|
||||
name == "frontend::TokenStream::Position" ||
|
||||
name == "ModuleCompiler")
|
||||
name == "ModuleCompiler" ||
|
||||
name == "ModuleValidator")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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();
|
||||
|
@ -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() ||
|
||||
|
@ -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)...);
|
||||
|
61
js/src/jit-test/tests/arguments/mapped-unmapped-args.js
Normal file
61
js/src/jit-test/tests/arguments/mapped-unmapped-args.js
Normal 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);
|
@ -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();
|
||||
|
@ -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
@ -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/);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
15
js/src/jit-test/tests/ion/isArray.js
Normal file
15
js/src/jit-test/tests/ion/isArray.js
Normal 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();
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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 {
|
||||
|
@ -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>())
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user