mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Merge m-c to fx-team. a=merge
This commit is contained in:
commit
75cd780807
@ -225,7 +225,7 @@ DocAccessibleChild::RecvTextSubstring(const uint64_t& aID,
|
||||
bool
|
||||
DocAccessibleChild::RecvGetTextAfterOffset(const uint64_t& aID,
|
||||
const int32_t& aOffset,
|
||||
const AccessibleTextBoundary& aBoundaryType,
|
||||
const int32_t& aBoundaryType,
|
||||
nsString* aText,
|
||||
int32_t* aStartOffset,
|
||||
int32_t* aEndOffset)
|
||||
@ -243,7 +243,7 @@ DocAccessibleChild::RecvGetTextAfterOffset(const uint64_t& aID,
|
||||
bool
|
||||
DocAccessibleChild::RecvGetTextAtOffset(const uint64_t& aID,
|
||||
const int32_t& aOffset,
|
||||
const AccessibleTextBoundary& aBoundaryType,
|
||||
const int32_t& aBoundaryType,
|
||||
nsString* aText,
|
||||
int32_t* aStartOffset,
|
||||
int32_t* aEndOffset)
|
||||
@ -261,7 +261,7 @@ DocAccessibleChild::RecvGetTextAtOffset(const uint64_t& aID,
|
||||
bool
|
||||
DocAccessibleChild::RecvGetTextBeforeOffset(const uint64_t& aID,
|
||||
const int32_t& aOffset,
|
||||
const AccessibleTextBoundary& aBoundaryType,
|
||||
const int32_t& aBoundaryType,
|
||||
nsString* aText,
|
||||
int32_t* aStartOffset,
|
||||
int32_t* aEndOffset)
|
||||
|
@ -70,17 +70,17 @@ public:
|
||||
|
||||
virtual bool RecvGetTextAfterOffset(const uint64_t& aID,
|
||||
const int32_t& aOffset,
|
||||
const AccessibleTextBoundary& aBoundaryType,
|
||||
const int32_t& aBoundaryType,
|
||||
nsString* aText, int32_t* aStartOffset,
|
||||
int32_t* aEndOffset) MOZ_OVERRIDE;
|
||||
virtual bool RecvGetTextAtOffset(const uint64_t& aID,
|
||||
const int32_t& aOffset,
|
||||
const AccessibleTextBoundary& aBoundaryType,
|
||||
const int32_t& aBoundaryType,
|
||||
nsString* aText, int32_t* aStartOffset,
|
||||
int32_t* aEndOffset) MOZ_OVERRIDE;
|
||||
virtual bool RecvGetTextBeforeOffset(const uint64_t& aID,
|
||||
const int32_t& aOffset,
|
||||
const AccessibleTextBoundary& aBoundaryType,
|
||||
const int32_t& aBoundaryType,
|
||||
nsString* aText, int32_t* aStartOffset,
|
||||
int32_t* aEndOffset) MOZ_OVERRIDE;
|
||||
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
include protocol PContent;
|
||||
|
||||
using AccessibleTextBoundary from "nsIAccessibleText.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
@ -69,11 +67,11 @@ child:
|
||||
// TextSubstring is getText in IDL.
|
||||
prio(high) sync TextSubstring(uint64_t aID, int32_t aStartOffset, int32_t
|
||||
aEndOffset) returns(nsString aText);
|
||||
prio(high) sync GetTextAfterOffset(uint64_t aID, int32_t aOffset, AccessibleTextBoundary aBoundaryType)
|
||||
prio(high) sync GetTextAfterOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
|
||||
returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
|
||||
prio(high) sync GetTextAtOffset(uint64_t aID, int32_t aOffset, AccessibleTextBoundary aBoundaryType)
|
||||
prio(high) sync GetTextAtOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
|
||||
returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
|
||||
prio(high) sync GetTextBeforeOffset(uint64_t aID, int32_t aOffset, AccessibleTextBoundary aBoundaryType)
|
||||
prio(high) sync GetTextBeforeOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
|
||||
returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
|
||||
};
|
||||
|
||||
|
@ -688,6 +688,9 @@ pref("ui.useOverlayScrollbars", 1);
|
||||
pref("ui.scrollbarFadeBeginDelay", 450);
|
||||
pref("ui.scrollbarFadeDuration", 200);
|
||||
|
||||
// Scrollbar position follows the document `dir` attribute
|
||||
pref("layout.scrollbar.side", 1);
|
||||
|
||||
// Enable the ProcessPriorityManager, and give processes with no visible
|
||||
// documents a 1s grace period before they're eligible to be marked as
|
||||
// background. Background processes that are perceivable due to playing
|
||||
@ -1114,10 +1117,8 @@ pref("dom.requestSync.enabled", true);
|
||||
pref("gfx.vsync.hw-vsync.enabled", true);
|
||||
pref("gfx.vsync.compositor", true);
|
||||
pref("gfx.touch.resample", true);
|
||||
pref("gfx.vsync.refreshdriver", true);
|
||||
#else
|
||||
pref("gfx.vsync.hw-vsync.enabled", false);
|
||||
pref("gfx.vsync.compositor", false);
|
||||
pref("gfx.touch.resample", false);
|
||||
pref("gfx.vsync.refreshdriver", false);
|
||||
#endif
|
||||
|
@ -36,6 +36,13 @@ xul|scrollbar[orient="vertical"] {
|
||||
max-width: 8px;
|
||||
}
|
||||
|
||||
/* workaround for bug 1119057: as -moz-margin-start may not work as expected,
|
||||
* force a right margin value in RTL mode. */
|
||||
[dir="rtl"] xul|scrollbar[root="true"][orient="vertical"] {
|
||||
-moz-margin-start: unset;
|
||||
margin-right: -8px;
|
||||
}
|
||||
|
||||
xul|scrollbar[orient="vertical"] xul|thumb {
|
||||
max-width: 6px !important;
|
||||
min-width: 6px !important;
|
||||
|
@ -15,11 +15,11 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="cdaa0a4ac28c781709df8c318ed079e9e475503a">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f39e48b95fa00c8669b8707447542024bb55432"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<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"/>
|
||||
|
@ -19,12 +19,12 @@
|
||||
<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="4f39e48b95fa00c8669b8707447542024bb55432"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="2c31ac3a31a340b40ecd9c291df9b9613d3afa72"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
|
@ -17,9 +17,9 @@
|
||||
</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="4f39e48b95fa00c8669b8707447542024bb55432"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
|
@ -15,11 +15,11 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="cdaa0a4ac28c781709df8c318ed079e9e475503a">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f39e48b95fa00c8669b8707447542024bb55432"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<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"/>
|
||||
|
@ -19,12 +19,12 @@
|
||||
<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="4f39e48b95fa00c8669b8707447542024bb55432"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="2c31ac3a31a340b40ecd9c291df9b9613d3afa72"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
|
@ -15,11 +15,11 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="cdaa0a4ac28c781709df8c318ed079e9e475503a">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f39e48b95fa00c8669b8707447542024bb55432"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<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"/>
|
||||
|
@ -17,9 +17,9 @@
|
||||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f39e48b95fa00c8669b8707447542024bb55432"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "4f39e48b95fa00c8669b8707447542024bb55432",
|
||||
"git_revision": "82f286f10a41aab84a0796c89fbefe67b179994b",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "e0816d2581cdc2d0581f625c06811128c87c0c48",
|
||||
"revision": "066f0e84321a010700467d1814ee0048dca7e5e1",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,9 +17,9 @@
|
||||
</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="4f39e48b95fa00c8669b8707447542024bb55432"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
|
@ -15,11 +15,11 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="7f2ee9f4cb926684883fc2a2e407045fd9db2199">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f39e48b95fa00c8669b8707447542024bb55432"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<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"/>
|
||||
|
@ -1809,8 +1809,8 @@ pref("experiments.manifest.uri", "https://telemetry-experiment.cdn.mozilla.net/m
|
||||
// Whether experiments are supported by the current application profile.
|
||||
pref("experiments.supported", true);
|
||||
|
||||
// Enable the OpenH264 plugin support in the addon manager.
|
||||
pref("media.gmp-gmpopenh264.provider.enabled", true);
|
||||
// Enable GMP support in the addon manager.
|
||||
pref("media.gmp-provider.enabled", true);
|
||||
|
||||
pref("browser.apps.URL", "https://marketplace.firefox.com/discovery/");
|
||||
|
||||
|
@ -69,9 +69,16 @@ CallProgressSocket.prototype = {
|
||||
let uri = Services.io.newURI(this._progressUrl, null, null);
|
||||
|
||||
// Allow _websocket to be set for testing.
|
||||
this._websocket = this._websocket ||
|
||||
Cc["@mozilla.org/network/protocol;1?name=" + uri.scheme]
|
||||
.createInstance(Ci.nsIWebSocketChannel);
|
||||
if (!this._websocket) {
|
||||
this._websocket = Cc["@mozilla.org/network/protocol;1?name=" + uri.scheme]
|
||||
.createInstance(Ci.nsIWebSocketChannel);
|
||||
|
||||
this._websocket.initLoadInfo(null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_WEBSOCKET);
|
||||
}
|
||||
|
||||
this._websocket.asyncOpen(uri, this._progressUrl, this, null);
|
||||
},
|
||||
|
@ -61,6 +61,11 @@ PushSocket.prototype = {
|
||||
if (!this._websocket) {
|
||||
this._websocket = Cc["@mozilla.org/network/protocol;1?name=wss"]
|
||||
.createInstance(Ci.nsIWebSocketChannel);
|
||||
this._websocket.initLoadInfo(null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_WEBSOCKET);
|
||||
}
|
||||
|
||||
let uri = Services.io.newURI(pushUri, null, null);
|
||||
|
@ -20,6 +20,7 @@ namespace mozilla {
|
||||
namespace net {
|
||||
class HttpChannelParent;
|
||||
class FTPChannelParent;
|
||||
class WebSocketChannelParent;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,6 +52,7 @@ private:
|
||||
|
||||
friend class net::HttpChannelParent;
|
||||
friend class net::FTPChannelParent;
|
||||
friend class net::WebSocketChannelParent;
|
||||
|
||||
~LoadInfo();
|
||||
|
||||
|
@ -590,7 +590,16 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
|
||||
nsIDocument* doc = aContent->OwnerDoc();
|
||||
|
||||
nsCOMPtr<nsIChannel> chan;
|
||||
aIOService->NewChannelFromURI(aURI, getter_AddRefs(chan));
|
||||
NS_NewChannel(getter_AddRefs(chan),
|
||||
aURI,
|
||||
doc,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_PING,
|
||||
nullptr, // aLoadGroup
|
||||
nullptr, // aCallbacks
|
||||
nsIRequest::LOAD_NORMAL, // aLoadFlags,
|
||||
aIOService);
|
||||
|
||||
if (!chan) {
|
||||
return;
|
||||
}
|
||||
|
@ -90,6 +90,7 @@ public:
|
||||
, mHasFeatureRegistered(false)
|
||||
#endif
|
||||
, mIsMainThread(true)
|
||||
, mMutex("WebSocketImpl::mMutex")
|
||||
, mWorkerShuttingDown(false)
|
||||
{
|
||||
if (!NS_IsMainThread()) {
|
||||
@ -222,6 +223,9 @@ public:
|
||||
nsWeakPtr mWeakLoadGroup;
|
||||
|
||||
bool mIsMainThread;
|
||||
|
||||
// This mutex protects mWorkerShuttingDown.
|
||||
mozilla::Mutex mMutex;
|
||||
bool mWorkerShuttingDown;
|
||||
|
||||
private:
|
||||
@ -422,7 +426,14 @@ public:
|
||||
|
||||
~MaybeDisconnect()
|
||||
{
|
||||
if (mImpl->mWorkerShuttingDown) {
|
||||
bool toDisconnect = false;
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mImpl->mMutex);
|
||||
toDisconnect = mImpl->mWorkerShuttingDown;
|
||||
}
|
||||
|
||||
if (toDisconnect) {
|
||||
mImpl->Disconnect();
|
||||
}
|
||||
}
|
||||
@ -886,7 +897,7 @@ WebSocket::WebSocket(nsPIDOMWindow* aOwnerWindow)
|
||||
, mCheckMustKeepAlive(true)
|
||||
, mOutgoingBufferedAmount(0)
|
||||
, mBinaryType(dom::BinaryType::Blob)
|
||||
, mMutex("WebSocketImpl::mMutex")
|
||||
, mMutex("WebSocket::mMutex")
|
||||
, mReadyState(CONNECTING)
|
||||
{
|
||||
mImpl = new WebSocketImpl(this);
|
||||
@ -1563,15 +1574,11 @@ WebSocketImpl::InitializeConnection()
|
||||
// are not thread-safe.
|
||||
mOriginDocument = nullptr;
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo =
|
||||
new LoadInfo(doc ?
|
||||
doc->NodePrincipal() : mPrincipal.get(),
|
||||
mPrincipal,
|
||||
doc,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_WEBSOCKET);
|
||||
rv = wsChannel->SetLoadInfo(loadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
wsChannel->InitLoadInfo(doc ? doc->AsDOMNode() : nullptr,
|
||||
doc ? doc->NodePrincipal() : mPrincipal.get(),
|
||||
mPrincipal,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_WEBSOCKET);
|
||||
|
||||
if (!mRequestedProtocolList.IsEmpty()) {
|
||||
rv = wsChannel->SetProtocol(mRequestedProtocolList);
|
||||
@ -1982,7 +1989,11 @@ public:
|
||||
MOZ_ASSERT(aStatus > workers::Running);
|
||||
|
||||
if (aStatus >= Canceling) {
|
||||
mWebSocketImpl->mWorkerShuttingDown = true;
|
||||
{
|
||||
MutexAutoLock lock(mWebSocketImpl->mMutex);
|
||||
mWebSocketImpl->mWorkerShuttingDown = true;
|
||||
}
|
||||
|
||||
mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
||||
}
|
||||
|
||||
@ -1991,7 +2002,11 @@ public:
|
||||
|
||||
bool Suspend(JSContext* aCx) MOZ_OVERRIDE
|
||||
{
|
||||
mWebSocketImpl->mWorkerShuttingDown = true;
|
||||
{
|
||||
MutexAutoLock lock(mWebSocketImpl->mMutex);
|
||||
mWebSocketImpl->mWorkerShuttingDown = true;
|
||||
}
|
||||
|
||||
mWebSocketImpl->CloseConnection(nsIWebSocketChannel::CLOSE_GOING_AWAY);
|
||||
return true;
|
||||
}
|
||||
@ -2551,9 +2566,13 @@ namespace {
|
||||
|
||||
class WorkerRunnableDispatcher MOZ_FINAL : public WorkerRunnable
|
||||
{
|
||||
nsRefPtr<WebSocketImpl> mWebSocketImpl;
|
||||
|
||||
public:
|
||||
WorkerRunnableDispatcher(WorkerPrivate* aWorkerPrivate, nsIRunnable* aEvent)
|
||||
WorkerRunnableDispatcher(WebSocketImpl* aImpl, WorkerPrivate* aWorkerPrivate,
|
||||
nsIRunnable* aEvent)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||
, mWebSocketImpl(aImpl)
|
||||
, mEvent(aEvent)
|
||||
{
|
||||
}
|
||||
@ -2561,6 +2580,13 @@ public:
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// No messages when disconnected.
|
||||
if (mWebSocketImpl->mDisconnectingOrDisconnected) {
|
||||
NS_WARNING("Dispatching a WebSocket event after the disconnection!");
|
||||
return true;
|
||||
}
|
||||
|
||||
aWorkerPrivate->ModifyBusyCountFromWorker(aCx, true);
|
||||
return !NS_FAILED(mEvent->Run());
|
||||
}
|
||||
@ -2596,12 +2622,12 @@ WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
return NS_DispatchToMainThread(aEvent);
|
||||
}
|
||||
|
||||
// No messages when disconnected.
|
||||
if (mDisconnectingOrDisconnected) {
|
||||
NS_WARNING("Dispatching a WebSocket event after the disconnection!");
|
||||
return NS_OK;
|
||||
}
|
||||
// If the target is a worker, we have to use a custom WorkerRunnableDispatcher
|
||||
// runnable.
|
||||
nsRefPtr<WorkerRunnableDispatcher> event =
|
||||
new WorkerRunnableDispatcher(this, mWorkerPrivate, aEvent);
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mWorkerShuttingDown) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -2612,10 +2638,6 @@ WebSocketImpl::Dispatch(nsIRunnable* aEvent, uint32_t aFlags)
|
||||
MOZ_ASSERT(HasFeatureRegistered());
|
||||
#endif
|
||||
|
||||
// If the target is a worker, we have to use a custom WorkerRunnableDispatcher
|
||||
// runnable.
|
||||
nsRefPtr<WorkerRunnableDispatcher> event =
|
||||
new WorkerRunnableDispatcher(mWorkerPrivate, aEvent);
|
||||
if (!event->Dispatch(nullptr)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -1667,14 +1667,30 @@ BluetoothServiceBluedroid::BondStateChangedNotification(
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
BluetoothValue(propertiesArray)));
|
||||
|
||||
if (bonded && !sBondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sBondingRunnableArray[0],
|
||||
BluetoothValue(true), EmptyString());
|
||||
sBondingRunnableArray.RemoveElementAt(0);
|
||||
} else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sUnbondingRunnableArray[0],
|
||||
BluetoothValue(true), EmptyString());
|
||||
sUnbondingRunnableArray.RemoveElementAt(0);
|
||||
if (aStatus == STATUS_SUCCESS) {
|
||||
// Resolve existing pair/unpair promise when pair/unpair succeeded
|
||||
if (bonded && !sBondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sBondingRunnableArray[0],
|
||||
BluetoothValue(true), EmptyString());
|
||||
sBondingRunnableArray.RemoveElementAt(0);
|
||||
} else if (!bonded && !sUnbondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sUnbondingRunnableArray[0],
|
||||
BluetoothValue(true), EmptyString());
|
||||
sUnbondingRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
} else {
|
||||
// Reject existing pair/unpair promise when pair/unpair failed
|
||||
if (!bonded && !sBondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sBondingRunnableArray[0],
|
||||
BluetoothValue(),
|
||||
NS_LITERAL_STRING("Pair Error"));
|
||||
sBondingRunnableArray.RemoveElementAt(0);
|
||||
} else if (bonded && !sUnbondingRunnableArray.IsEmpty()) {
|
||||
DispatchBluetoothReply(sUnbondingRunnableArray[0],
|
||||
BluetoothValue(),
|
||||
NS_LITERAL_STRING("Unpair Error"));
|
||||
sUnbondingRunnableArray.RemoveElementAt(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,5 +20,9 @@ mimetype_label=MIME Type
|
||||
description_label=Description
|
||||
suffixes_label=Suffixes
|
||||
|
||||
# GMP Plugins
|
||||
openH264_name=OpenH264 Video Codec provided by Cisco Systems, Inc.
|
||||
openH264_description=Play back web video and use video chats.
|
||||
|
||||
eme-adobe_name=Primetime Content Decryption Module provided by Adobe Systems, Incorporated
|
||||
eme-adobe_description=Play back protected web video.
|
||||
|
@ -2958,7 +2958,7 @@ MediaDecoderStateMachine::FlushDecoding()
|
||||
// The reader is not supposed to put any tasks to deliver samples into
|
||||
// the queue after this runs (unless we request another sample from it).
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode);
|
||||
task = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::ResetDecode);
|
||||
|
||||
// Wait for the ResetDecode to run and for the decoder to abort
|
||||
// decoding operations and run any pending callbacks. This is
|
||||
@ -2979,6 +2979,25 @@ MediaDecoderStateMachine::FlushDecoding()
|
||||
ResetPlayback();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::ResetDecode()
|
||||
{
|
||||
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
|
||||
|
||||
if (!mReader) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (mWaitingForDecoderSeek && !mCancelingSeek) {
|
||||
mReader->CancelSeek();
|
||||
mCancelingSeek = true;
|
||||
}
|
||||
}
|
||||
mReader->ResetDecode();
|
||||
}
|
||||
|
||||
void MediaDecoderStateMachine::RenderVideoFrame(VideoData* aData,
|
||||
TimeStamp aTarget)
|
||||
{
|
||||
|
@ -422,6 +422,9 @@ public:
|
||||
WaitRequestRef(aRejection.mType).Complete();
|
||||
}
|
||||
|
||||
// Resets all state related to decoding, emptying all buffers etc.
|
||||
void ResetDecode();
|
||||
|
||||
private:
|
||||
void AcquireMonitorAndInvokeDecodeError();
|
||||
|
||||
|
@ -805,9 +805,8 @@ RTCPeerConnection.prototype = {
|
||||
},
|
||||
|
||||
removeTrack: function(sender) {
|
||||
// Bug 844295: Not implementing this functionality.
|
||||
throw new this._win.DOMException("removeTrack not yet implemented",
|
||||
"NotSupportedError");
|
||||
this._checkClosed();
|
||||
this._impl.removeTrack(sender.track);
|
||||
},
|
||||
|
||||
_replaceTrack: function(sender, withTrack) {
|
||||
@ -1115,6 +1114,10 @@ PeerConnectionObserver.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
onNegotiationNeeded: function() {
|
||||
this.dispatchEvent(new this._win.Event("negotiationneeded"));
|
||||
},
|
||||
|
||||
|
||||
// This method is primarily responsible for updating iceConnectionState.
|
||||
// This state is defined in the WebRTC specification as follows:
|
||||
|
@ -121,7 +121,7 @@ MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem)
|
||||
if (!IsVistaOrLater()) {
|
||||
return MediaKeySystemStatus::Cdm_not_supported;
|
||||
}
|
||||
if (!Preferences::GetBool("media.eme.adobe-access.enabled", false)) {
|
||||
if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) {
|
||||
return MediaKeySystemStatus::Cdm_disabled;
|
||||
}
|
||||
if (!HaveGMPFor(mps,
|
||||
|
@ -17,154 +17,159 @@ function getBlobContent(blob) {
|
||||
});
|
||||
}
|
||||
|
||||
var commandsCreateDataChannel = [
|
||||
function PC_REMOTE_EXPECT_DATA_CHANNEL(test) {
|
||||
test.pcRemote.expectDataChannel();
|
||||
},
|
||||
|
||||
function PC_LOCAL_CREATE_DATA_CHANNEL(test) {
|
||||
var channel = test.pcLocal.createDataChannel({});
|
||||
is(channel.binaryType, "blob", channel + " is of binary type 'blob'");
|
||||
is(channel.readyState, "connecting", channel + " is in state: 'connecting'");
|
||||
|
||||
is(test.pcLocal.signalingState, STABLE,
|
||||
"Create datachannel does not change signaling state");
|
||||
}
|
||||
];
|
||||
|
||||
var commandsWaitForDataChannel = [
|
||||
function PC_LOCAL_VERIFY_DATA_CHANNEL_STATE(test) {
|
||||
return test.pcLocal.dataChannels[0].opened;
|
||||
},
|
||||
|
||||
function PC_REMOTE_VERIFY_DATA_CHANNEL_STATE(test) {
|
||||
return test.pcRemote.nextDataChannel.then(channel => channel.opened);
|
||||
},
|
||||
];
|
||||
|
||||
var commandsCheckDataChannel = [
|
||||
function SEND_MESSAGE(test) {
|
||||
var message = "Lorem ipsum dolor sit amet";
|
||||
|
||||
return test.send(message).then(result => {
|
||||
is(result.data, message, "Message correctly transmitted from pcLocal to pcRemote.");
|
||||
});
|
||||
},
|
||||
|
||||
function SEND_BLOB(test) {
|
||||
var contents = ["At vero eos et accusam et justo duo dolores et ea rebum."];
|
||||
var blob = new Blob(contents, { "type" : "text/plain" });
|
||||
|
||||
return test.send(blob).then(result => {
|
||||
ok(result.data instanceof Blob, "Received data is of instance Blob");
|
||||
is(result.data.size, blob.size, "Received data has the correct size.");
|
||||
|
||||
return getBlobContent(result.data);
|
||||
}).then(recv_contents =>
|
||||
is(recv_contents, contents, "Received data has the correct content."));
|
||||
},
|
||||
|
||||
function CREATE_SECOND_DATA_CHANNEL(test) {
|
||||
return test.createDataChannel({ }).then(result => {
|
||||
var sourceChannel = result.local;
|
||||
var targetChannel = result.remote;
|
||||
is(sourceChannel.readyState, "open", sourceChannel + " is in state: 'open'");
|
||||
is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
|
||||
|
||||
is(targetChannel.binaryType, "blob", targetChannel + " is of binary type 'blob'");
|
||||
});
|
||||
},
|
||||
|
||||
function SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL(test) {
|
||||
var channels = test.pcRemote.dataChannels;
|
||||
var message = "I am the Omega";
|
||||
|
||||
return test.send(message).then(result => {
|
||||
is(channels.indexOf(result.channel), channels.length - 1, "Last channel used");
|
||||
is(result.data, message, "Received message has the correct content.");
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
function SEND_MESSAGE_THROUGH_FIRST_CHANNEL(test) {
|
||||
var message = "Message through 1st channel";
|
||||
var options = {
|
||||
sourceChannel: test.pcLocal.dataChannels[0],
|
||||
targetChannel: test.pcRemote.dataChannels[0]
|
||||
};
|
||||
|
||||
return test.send(message, options).then(result => {
|
||||
is(test.pcRemote.dataChannels.indexOf(result.channel), 0, "1st channel used");
|
||||
is(result.data, message, "Received message has the correct content.");
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
function SEND_MESSAGE_BACK_THROUGH_FIRST_CHANNEL(test) {
|
||||
var message = "Return a message also through 1st channel";
|
||||
var options = {
|
||||
sourceChannel: test.pcRemote.dataChannels[0],
|
||||
targetChannel: test.pcLocal.dataChannels[0]
|
||||
};
|
||||
|
||||
return test.send(message, options).then(result => {
|
||||
is(test.pcLocal.dataChannels.indexOf(result.channel), 0, "1st channel used");
|
||||
is(result.data, message, "Return message has the correct content.");
|
||||
});
|
||||
},
|
||||
|
||||
function CREATE_NEGOTIATED_DATA_CHANNEL(test) {
|
||||
var options = {
|
||||
negotiated:true,
|
||||
id: 5,
|
||||
protocol: "foo/bar",
|
||||
ordered: false,
|
||||
maxRetransmits: 500
|
||||
};
|
||||
return test.createDataChannel(options).then(result => {
|
||||
var sourceChannel2 = result.local;
|
||||
var targetChannel2 = result.remote;
|
||||
is(sourceChannel2.readyState, "open", sourceChannel2 + " is in state: 'open'");
|
||||
is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
|
||||
|
||||
is(targetChannel2.binaryType, "blob", targetChannel2 + " is of binary type 'blob'");
|
||||
|
||||
is(sourceChannel2.id, options.id, sourceChannel2 + " id is:" + sourceChannel2.id);
|
||||
var reliable = !options.ordered ? false : (options.maxRetransmits || options.maxRetransmitTime);
|
||||
is(sourceChannel2.protocol, options.protocol, sourceChannel2 + " protocol is:" + sourceChannel2.protocol);
|
||||
is(sourceChannel2.reliable, reliable, sourceChannel2 + " reliable is:" + sourceChannel2.reliable);
|
||||
/*
|
||||
These aren't exposed by IDL yet
|
||||
is(sourceChannel2.ordered, options.ordered, sourceChannel2 + " ordered is:" + sourceChannel2.ordered);
|
||||
is(sourceChannel2.maxRetransmits, options.maxRetransmits, sourceChannel2 + " maxRetransmits is:" +
|
||||
sourceChannel2.maxRetransmits);
|
||||
is(sourceChannel2.maxRetransmitTime, options.maxRetransmitTime, sourceChannel2 + " maxRetransmitTime is:" +
|
||||
sourceChannel2.maxRetransmitTime);
|
||||
*/
|
||||
|
||||
is(targetChannel2.id, options.id, targetChannel2 + " id is:" + targetChannel2.id);
|
||||
is(targetChannel2.protocol, options.protocol, targetChannel2 + " protocol is:" + targetChannel2.protocol);
|
||||
is(targetChannel2.reliable, reliable, targetChannel2 + " reliable is:" + targetChannel2.reliable);
|
||||
/*
|
||||
These aren't exposed by IDL yet
|
||||
is(targetChannel2.ordered, options.ordered, targetChannel2 + " ordered is:" + targetChannel2.ordered);
|
||||
is(targetChannel2.maxRetransmits, options.maxRetransmits, targetChannel2 + " maxRetransmits is:" +
|
||||
targetChannel2.maxRetransmits);
|
||||
is(targetChannel2.maxRetransmitTime, options.maxRetransmitTime, targetChannel2 + " maxRetransmitTime is:" +
|
||||
targetChannel2.maxRetransmitTime);
|
||||
*/
|
||||
});
|
||||
},
|
||||
|
||||
function SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL2(test) {
|
||||
var channels = test.pcRemote.dataChannels;
|
||||
var message = "I am the walrus; Goo goo g'joob";
|
||||
|
||||
return test.send(message).then(result => {
|
||||
is(channels.indexOf(result.channel), channels.length - 1, "Last channel used");
|
||||
is(result.data, message, "Received message has the correct content.");
|
||||
});
|
||||
}
|
||||
];
|
||||
|
||||
function addInitialDataChannel(chain) {
|
||||
chain.insertBefore('PC_LOCAL_CREATE_OFFER', [
|
||||
function PC_REMOTE_EXPECT_DATA_CHANNEL(test) {
|
||||
test.pcRemote.expectDataChannel();
|
||||
},
|
||||
|
||||
function PC_LOCAL_CREATE_DATA_CHANNEL(test) {
|
||||
var channel = test.pcLocal.createDataChannel({});
|
||||
is(channel.binaryType, "blob", channel + " is of binary type 'blob'");
|
||||
is(channel.readyState, "connecting", channel + " is in state: 'connecting'");
|
||||
|
||||
is(test.pcLocal.signalingState, STABLE,
|
||||
"Create datachannel does not change signaling state");
|
||||
}
|
||||
]);
|
||||
|
||||
chain.insertBefore('PC_LOCAL_CHECK_MEDIA_TRACKS', [
|
||||
function PC_LOCAL_VERIFY_DATA_CHANNEL_STATE(test) {
|
||||
return test.pcLocal.dataChannels[0].opened;
|
||||
},
|
||||
|
||||
function PC_REMOTE_VERIFY_DATA_CHANNEL_STATE(test) {
|
||||
return test.pcRemote.nextDataChannel.then(channel => channel.opened);
|
||||
}
|
||||
]);
|
||||
chain.insertBefore('PC_LOCAL_CREATE_OFFER', commandsCreateDataChannel);
|
||||
chain.insertBefore('PC_LOCAL_CHECK_MEDIA_TRACKS', commandsWaitForDataChannel);
|
||||
chain.removeAfter('PC_REMOTE_CHECK_ICE_CONNECTIONS');
|
||||
chain.append([
|
||||
function SEND_MESSAGE(test) {
|
||||
var message = "Lorem ipsum dolor sit amet";
|
||||
|
||||
return test.send(message).then(result => {
|
||||
is(result.data, message, "Message correctly transmitted from pcLocal to pcRemote.");
|
||||
});
|
||||
},
|
||||
|
||||
function SEND_BLOB(test) {
|
||||
var contents = ["At vero eos et accusam et justo duo dolores et ea rebum."];
|
||||
var blob = new Blob(contents, { "type" : "text/plain" });
|
||||
|
||||
return test.send(blob).then(result => {
|
||||
ok(result.data instanceof Blob, "Received data is of instance Blob");
|
||||
is(result.data.size, blob.size, "Received data has the correct size.");
|
||||
|
||||
return getBlobContent(result.data);
|
||||
}).then(recv_contents =>
|
||||
is(recv_contents, contents, "Received data has the correct content."));
|
||||
},
|
||||
|
||||
function CREATE_SECOND_DATA_CHANNEL(test) {
|
||||
return test.createDataChannel({ }).then(result => {
|
||||
var sourceChannel = result.local;
|
||||
var targetChannel = result.remote;
|
||||
is(sourceChannel.readyState, "open", sourceChannel + " is in state: 'open'");
|
||||
is(targetChannel.readyState, "open", targetChannel + " is in state: 'open'");
|
||||
|
||||
is(targetChannel.binaryType, "blob", targetChannel + " is of binary type 'blob'");
|
||||
});
|
||||
},
|
||||
|
||||
function SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL(test) {
|
||||
var channels = test.pcRemote.dataChannels;
|
||||
var message = "I am the Omega";
|
||||
|
||||
return test.send(message).then(result => {
|
||||
is(channels.indexOf(result.channel), channels.length - 1, "Last channel used");
|
||||
is(result.data, message, "Received message has the correct content.");
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
function SEND_MESSAGE_THROUGH_FIRST_CHANNEL(test) {
|
||||
var message = "Message through 1st channel";
|
||||
var options = {
|
||||
sourceChannel: test.pcLocal.dataChannels[0],
|
||||
targetChannel: test.pcRemote.dataChannels[0]
|
||||
};
|
||||
|
||||
return test.send(message, options).then(result => {
|
||||
is(test.pcRemote.dataChannels.indexOf(result.channel), 0, "1st channel used");
|
||||
is(result.data, message, "Received message has the correct content.");
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
function SEND_MESSAGE_BACK_THROUGH_FIRST_CHANNEL(test) {
|
||||
var message = "Return a message also through 1st channel";
|
||||
var options = {
|
||||
sourceChannel: test.pcRemote.dataChannels[0],
|
||||
targetChannel: test.pcLocal.dataChannels[0]
|
||||
};
|
||||
|
||||
return test.send(message, options).then(result => {
|
||||
is(test.pcLocal.dataChannels.indexOf(result.channel), 0, "1st channel used");
|
||||
is(result.data, message, "Return message has the correct content.");
|
||||
});
|
||||
},
|
||||
|
||||
function CREATE_NEGOTIATED_DATA_CHANNEL(test) {
|
||||
var options = {
|
||||
negotiated:true,
|
||||
id: 5,
|
||||
protocol: "foo/bar",
|
||||
ordered: false,
|
||||
maxRetransmits: 500
|
||||
};
|
||||
return test.createDataChannel(options).then(result => {
|
||||
var sourceChannel2 = result.local;
|
||||
var targetChannel2 = result.remote;
|
||||
is(sourceChannel2.readyState, "open", sourceChannel2 + " is in state: 'open'");
|
||||
is(targetChannel2.readyState, "open", targetChannel2 + " is in state: 'open'");
|
||||
|
||||
is(targetChannel2.binaryType, "blob", targetChannel2 + " is of binary type 'blob'");
|
||||
|
||||
is(sourceChannel2.id, options.id, sourceChannel2 + " id is:" + sourceChannel2.id);
|
||||
var reliable = !options.ordered ? false : (options.maxRetransmits || options.maxRetransmitTime);
|
||||
is(sourceChannel2.protocol, options.protocol, sourceChannel2 + " protocol is:" + sourceChannel2.protocol);
|
||||
is(sourceChannel2.reliable, reliable, sourceChannel2 + " reliable is:" + sourceChannel2.reliable);
|
||||
/*
|
||||
These aren't exposed by IDL yet
|
||||
is(sourceChannel2.ordered, options.ordered, sourceChannel2 + " ordered is:" + sourceChannel2.ordered);
|
||||
is(sourceChannel2.maxRetransmits, options.maxRetransmits, sourceChannel2 + " maxRetransmits is:" +
|
||||
sourceChannel2.maxRetransmits);
|
||||
is(sourceChannel2.maxRetransmitTime, options.maxRetransmitTime, sourceChannel2 + " maxRetransmitTime is:" +
|
||||
sourceChannel2.maxRetransmitTime);
|
||||
*/
|
||||
|
||||
is(targetChannel2.id, options.id, targetChannel2 + " id is:" + targetChannel2.id);
|
||||
is(targetChannel2.protocol, options.protocol, targetChannel2 + " protocol is:" + targetChannel2.protocol);
|
||||
is(targetChannel2.reliable, reliable, targetChannel2 + " reliable is:" + targetChannel2.reliable);
|
||||
/*
|
||||
These aren't exposed by IDL yet
|
||||
is(targetChannel2.ordered, options.ordered, targetChannel2 + " ordered is:" + targetChannel2.ordered);
|
||||
is(targetChannel2.maxRetransmits, options.maxRetransmits, targetChannel2 + " maxRetransmits is:" +
|
||||
targetChannel2.maxRetransmits);
|
||||
is(targetChannel2.maxRetransmitTime, options.maxRetransmitTime, targetChannel2 + " maxRetransmitTime is:" +
|
||||
targetChannel2.maxRetransmitTime);
|
||||
*/
|
||||
});
|
||||
},
|
||||
|
||||
function SEND_MESSAGE_THROUGH_LAST_OPENED_CHANNEL2(test) {
|
||||
var channels = test.pcRemote.dataChannels;
|
||||
var message = "I am the walrus; Goo goo g'joob";
|
||||
|
||||
return test.send(message).then(result => {
|
||||
is(channels.indexOf(result.channel), channels.length - 1, "Last channel used");
|
||||
is(result.data, message, "Received message has the correct content.");
|
||||
});
|
||||
}
|
||||
]);
|
||||
chain.append(commandsCheckDataChannel);
|
||||
}
|
||||
|
@ -363,12 +363,19 @@ CommandChain.prototype = {
|
||||
|
||||
/**
|
||||
* Returns the index of the specified command in the chain.
|
||||
* @param {start} Optional param specifying the index at which the search will
|
||||
* start. If not specified, the search starts at index 0.
|
||||
*/
|
||||
indexOf: function(functionOrName) {
|
||||
indexOf: function(functionOrName, start) {
|
||||
start = start || 0;
|
||||
if (typeof functionOrName === 'string') {
|
||||
return this.commands.findIndex(f => f.name === functionOrName);
|
||||
var index = this.commands.slice(start).findIndex(f => f.name === functionOrName);
|
||||
if (index !== -1) {
|
||||
index += start;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
return this.commands.indexOf(functionOrName);
|
||||
return this.commands.indexOf(functionOrName, start);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -379,20 +386,35 @@ CommandChain.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts the new commands before the specified command.
|
||||
* Inserts the new commands after every occurrence of the specified command
|
||||
*/
|
||||
insertBefore: function(functionOrName, commands) {
|
||||
this._insertHelper(functionOrName, commands, 0);
|
||||
insertAfterEach: function(functionOrName, commands) {
|
||||
this._insertHelper(functionOrName, commands, 1, true);
|
||||
},
|
||||
|
||||
_insertHelper: function(functionOrName, commands, delta) {
|
||||
var index = this.indexOf(functionOrName);
|
||||
/**
|
||||
* Inserts the new commands before the specified command.
|
||||
*/
|
||||
insertBefore: function(functionOrName, commands, all, start) {
|
||||
this._insertHelper(functionOrName, commands, 0, all, start);
|
||||
},
|
||||
|
||||
if (index >= 0) {
|
||||
this.commands = [].concat(
|
||||
this.commands.slice(0, index + delta),
|
||||
commands,
|
||||
this.commands.slice(index + delta));
|
||||
_insertHelper: function(functionOrName, commands, delta, all, start) {
|
||||
var index = this.indexOf(functionOrName);
|
||||
start = start || 0;
|
||||
for (; index !== -1; index = this.indexOf(functionOrName, index)) {
|
||||
if (!start) {
|
||||
this.commands = [].concat(
|
||||
this.commands.slice(0, index + delta),
|
||||
commands,
|
||||
this.commands.slice(index + delta));
|
||||
if (!all) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
start -= 1;
|
||||
}
|
||||
index += (commands.length + 1);
|
||||
}
|
||||
},
|
||||
|
||||
@ -460,7 +482,7 @@ CommandChain.prototype = {
|
||||
*/
|
||||
filterOut: function (id_match) {
|
||||
this.commands = this.commands.filter(c => !id_match.test(c.name));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
@ -150,8 +150,32 @@ skip-if = (toolkit == 'gonk' || (e10s && debug)) # b2g (Bug 1059867) or fd exhau
|
||||
skip-if = (toolkit == 'gonk' || (e10s && debug)) # b2g (Bug 1059867) or fd exhaustion on e10s debug intermittent (Bug 1126078)
|
||||
[test_peerConnection_twoVideoStreams.html]
|
||||
skip-if = (toolkit == 'gonk' || (e10s && debug)) # b2g (Bug 1059867) or fd exhaustion on e10s debug intermittent (Bug 1126078)
|
||||
# Renegotiation is not yet supported (bug 1017888)
|
||||
#[test_peerConnection_addSecondAudioStream.html]
|
||||
[test_peerConnection_addSecondAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_answererAddSecondAudioStream.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_removeAudioTrack.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_removeThenAddAudioTrack.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_addSecondVideoStream.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_removeVideoTrack.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_removeThenAddVideoTrack.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_addSecondAudioStreamNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_removeThenAddAudioTrackNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_addSecondVideoStreamNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_removeThenAddVideoTrackNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_addDataChannel.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
[test_peerConnection_addDataChannelNoBundle.html]
|
||||
skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
|
||||
|
||||
# Bug 950317: Hack for making a cleanup hook after finishing all WebRTC cases
|
||||
[test_zmedia_cleanup.html]
|
||||
|
@ -121,6 +121,12 @@ function removeVP8(sdp) {
|
||||
return updated_sdp;
|
||||
}
|
||||
|
||||
var makeDefaultCommands = () => {
|
||||
return [].concat(commandsPeerConnectionInitial,
|
||||
commandsGetUserMedia,
|
||||
commandsPeerConnectionOfferAnswer);
|
||||
};
|
||||
|
||||
/**
|
||||
* This class handles tests for peer connections.
|
||||
*
|
||||
@ -142,7 +148,7 @@ function removeVP8(sdp) {
|
||||
function PeerConnectionTest(options) {
|
||||
// If no options are specified make it an empty object
|
||||
options = options || { };
|
||||
options.commands = options.commands || commandsPeerConnection;
|
||||
options.commands = options.commands || makeDefaultCommands();
|
||||
options.is_local = "is_local" in options ? options.is_local : true;
|
||||
options.is_remote = "is_remote" in options ? options.is_remote : true;
|
||||
|
||||
@ -740,8 +746,6 @@ function PeerConnectionWrapper(label, configuration, h264) {
|
||||
|
||||
this.dataChannels = [ ];
|
||||
|
||||
this.addStreamCounter = {audio: 0, video: 0 };
|
||||
|
||||
this._local_ice_candidates = [];
|
||||
this._remote_ice_candidates = [];
|
||||
this.holdIceCandidates = new Promise(r => this.releaseIceCandidates = r);
|
||||
@ -749,6 +753,16 @@ function PeerConnectionWrapper(label, configuration, h264) {
|
||||
this.remoteRequiresTrickleIce = false;
|
||||
this.localMediaElements = [];
|
||||
|
||||
this.expectedLocalTrackTypesById = {};
|
||||
this.expectedRemoteTrackTypesById = {};
|
||||
this.observedRemoteTrackTypesById = {};
|
||||
|
||||
this.disableRtpCountChecking = false;
|
||||
|
||||
this.negotiationNeededFired = false;
|
||||
|
||||
this.iceCheckingRestartExpected = false;
|
||||
|
||||
this.h264 = typeof h264 !== "undefined" ? true : false;
|
||||
|
||||
info("Creating " + this);
|
||||
@ -769,27 +783,6 @@ function PeerConnectionWrapper(label, configuration, h264) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback for native peer connection 'onaddstream' events.
|
||||
*
|
||||
* @param {Object} event
|
||||
* Event data which includes the stream to be added
|
||||
*/
|
||||
this._pc.onaddstream = event => {
|
||||
info(this + ": 'onaddstream' event fired for " + JSON.stringify(event.stream));
|
||||
|
||||
var type = '';
|
||||
if (event.stream.getAudioTracks().length > 0) {
|
||||
type = 'audio';
|
||||
this.addStreamCounter.audio += this.countTracksInStreams('audio', [event.stream]);
|
||||
}
|
||||
if (event.stream.getVideoTracks().length > 0) {
|
||||
type += 'video';
|
||||
this.addStreamCounter.video += this.countTracksInStreams('video', [event.stream]);
|
||||
}
|
||||
this.attachMedia(event.stream, type, 'remote');
|
||||
};
|
||||
|
||||
createOneShotEventWrapper(this, this._pc, 'datachannel');
|
||||
this._pc.addEventListener('datachannel', e => {
|
||||
var wrapper = new DataChannelWrapper(e.channel, this);
|
||||
@ -797,6 +790,7 @@ function PeerConnectionWrapper(label, configuration, h264) {
|
||||
});
|
||||
|
||||
createOneShotEventWrapper(this, this._pc, 'signalingstatechange');
|
||||
createOneShotEventWrapper(this, this._pc, 'negotiationneeded');
|
||||
}
|
||||
|
||||
PeerConnectionWrapper.prototype = {
|
||||
@ -888,6 +882,12 @@ PeerConnectionWrapper.prototype = {
|
||||
is(sender.track, track, "addTrack returns sender");
|
||||
});
|
||||
}
|
||||
|
||||
stream.getTracks().forEach(track => {
|
||||
ok(track.id, "track has id");
|
||||
ok(track.kind, "track has kind");
|
||||
this.expectedLocalTrackTypesById[track.id] = track.kind;
|
||||
});
|
||||
}
|
||||
|
||||
var element = createMediaElement(type, this.label + '_' + side + this.streams.length);
|
||||
@ -902,6 +902,12 @@ PeerConnectionWrapper.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
removeSender : function(index) {
|
||||
var sender = this._pc.getSenders()[index];
|
||||
delete this.expectedLocalTrackTypesById[sender.track.id];
|
||||
this._pc.removeTrack(sender);
|
||||
},
|
||||
|
||||
/**
|
||||
* Requests all the media streams as specified in the constrains property.
|
||||
*
|
||||
@ -1068,6 +1074,59 @@ PeerConnectionWrapper.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks whether a given track is expected, has not been observed yet, and
|
||||
* is of the correct type. Then, moves the track from
|
||||
* |expectedTrackTypesById| to |observedTrackTypesById|.
|
||||
*/
|
||||
checkTrackIsExpected : function(track,
|
||||
expectedTrackTypesById,
|
||||
observedTrackTypesById) {
|
||||
ok(expectedTrackTypesById[track.id], "track id " + track.id + " was expected");
|
||||
ok(!observedTrackTypesById[track.id], "track id " + track.id + " was not yet observed");
|
||||
var observedKind = track.kind;
|
||||
var expectedKind = expectedTrackTypesById[track.id];
|
||||
is(observedKind, expectedKind,
|
||||
"track id " + track.id + " was of kind " +
|
||||
observedKind + ", which matches " + expectedKind);
|
||||
observedTrackTypesById[track.id] = expectedTrackTypesById[track.id];
|
||||
delete expectedTrackTypesById[track.id];
|
||||
},
|
||||
|
||||
setupAddStreamEventHandler: function() {
|
||||
var resolveAllAddStreamEventsDone;
|
||||
|
||||
// checkMediaTracks waits on this promise later on in the test.
|
||||
this.allAddStreamEventsDonePromise =
|
||||
new Promise(resolve => resolveAllAddStreamEventsDone = resolve);
|
||||
|
||||
this._pc.addEventListener('addstream', event => {
|
||||
info(this + ": 'onaddstream' event fired for " + JSON.stringify(event.stream));
|
||||
|
||||
// TODO(bug 1130185): We need to handle addtrack events once we start
|
||||
// testing addTrack on pre-existing streams.
|
||||
|
||||
event.stream.getTracks().forEach(track => {
|
||||
this.checkTrackIsExpected(track,
|
||||
this.expectedRemoteTrackTypesById,
|
||||
this.observedRemoteTrackTypesById);
|
||||
});
|
||||
|
||||
if (Object.keys(this.expectedRemoteTrackTypesById).length === 0) {
|
||||
resolveAllAddStreamEventsDone();
|
||||
}
|
||||
|
||||
var type = '';
|
||||
if (event.stream.getAudioTracks().length > 0) {
|
||||
type = 'audio';
|
||||
}
|
||||
if (event.stream.getVideoTracks().length > 0) {
|
||||
type += 'video';
|
||||
}
|
||||
this.attachMedia(event.stream, type, 'remote');
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Either adds a given ICE candidate right away or stores it to be added
|
||||
* later, depending on the state of the PeerConnection.
|
||||
@ -1148,7 +1207,14 @@ PeerConnectionWrapper.prototype = {
|
||||
var newstate = this._pc.iceConnectionState;
|
||||
var oldstate = this.iceConnectionLog[this.iceConnectionLog.length - 1]
|
||||
if (Object.keys(iceStateTransitions).indexOf(oldstate) != -1) {
|
||||
ok(iceStateTransitions[oldstate].indexOf(newstate) != -1, this + ": legal ICE state transition from " + oldstate + " to " + newstate);
|
||||
if (this.iceCheckingRestartExpected) {
|
||||
is(newstate, "checking",
|
||||
"iceconnectionstate event \'" + newstate +
|
||||
"\' matches expected state \'checking\'");
|
||||
this.iceCheckingRestartExpected = false;
|
||||
} else {
|
||||
ok(iceStateTransitions[oldstate].indexOf(newstate) != -1, this + ": legal ICE state transition from " + oldstate + " to " + newstate);
|
||||
}
|
||||
} else {
|
||||
ok(false, this + ": old ICE state " + oldstate + " missing in ICE transition array");
|
||||
}
|
||||
@ -1284,23 +1350,25 @@ PeerConnectionWrapper.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Counts the amount of tracks of the given type in a set of streams.
|
||||
*
|
||||
* @param type audio|video
|
||||
* @param streams
|
||||
* An array of streams (as returned by getLocalStreams()) to be
|
||||
* examined.
|
||||
*/
|
||||
countTracksInStreams: function(type, streams) {
|
||||
if (!Array.isArray(streams)) {
|
||||
return 0;
|
||||
}
|
||||
var f = (type === 'video') ? "getVideoTracks" : "getAudioTracks";
|
||||
checkLocalMediaTracks : function() {
|
||||
var observedLocalTrackTypesById = {};
|
||||
// We do not want to empty out this.expectedLocalTrackTypesById, so make a
|
||||
// copy.
|
||||
var expectedLocalTrackTypesById =
|
||||
JSON.parse(JSON.stringify((this.expectedLocalTrackTypesById)));
|
||||
info(this + " Checking local tracks " +
|
||||
JSON.stringify(expectedLocalTrackTypesById));
|
||||
this._pc.getLocalStreams().forEach(stream => {
|
||||
stream.getTracks().forEach(track => {
|
||||
this.checkTrackIsExpected(track,
|
||||
expectedLocalTrackTypesById,
|
||||
observedLocalTrackTypesById);
|
||||
});
|
||||
});
|
||||
|
||||
return streams.reduce((count, st) => {
|
||||
return count + st[f]().length;
|
||||
}, 0);
|
||||
Object.keys(expectedLocalTrackTypesById).forEach(id => {
|
||||
ok(false, this + " local id " + id + " was observed");
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1309,42 +1377,18 @@ PeerConnectionWrapper.prototype = {
|
||||
* @param {object} constraints
|
||||
* The media constraints of the remote peer connection object
|
||||
*/
|
||||
checkMediaTracks : function(remoteConstraints) {
|
||||
var waitForExpectedTracks = type => {
|
||||
var outstandingCount = this.countTracksInConstraint(type, remoteConstraints);
|
||||
outstandingCount -= this.addStreamCounter[type];
|
||||
if (outstandingCount <= 0) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
checkMediaTracks : function() {
|
||||
this.checkLocalMediaTracks();
|
||||
|
||||
return new Promise(resolve => {
|
||||
this._pc.addEventListener('addstream', e => {
|
||||
outstandingCount -= this.countTracksInStreams(type, [e.stream]);
|
||||
if (outstandingCount <= 0) {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
info(this + " Checking remote tracks " +
|
||||
JSON.stringify(this.expectedRemoteTrackTypesById));
|
||||
|
||||
var checkTrackCounts = (side, streams, constraints) => {
|
||||
['audio', 'video'].forEach(type => {
|
||||
var actual = this.countTracksInStreams(type, streams);
|
||||
var expected = this.countTracksInConstraint(type, constraints);
|
||||
is(actual, expected, this + ' has ' + actual + ' ' +
|
||||
side + ' ' + type + ' tracks');
|
||||
});
|
||||
};
|
||||
// No tracks are expected
|
||||
if (Object.keys(this.expectedRemoteTrackTypesById).length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
info(this + " checkMediaTracks() got called before onAddStream fired");
|
||||
var checkPromise = Promise.all([
|
||||
waitForExpectedTracks('audio'),
|
||||
waitForExpectedTracks('video')
|
||||
]).then(() => {
|
||||
checkTrackCounts('local', this._pc.getLocalStreams(), this.constraints);
|
||||
checkTrackCounts('remote', this._pc.getRemoteStreams(), remoteConstraints);
|
||||
});
|
||||
return timerGuard(checkPromise, 60000, "onaddstream never fired");
|
||||
return timerGuard(this.allAddStreamEventsDonePromise, 60000, "onaddstream never fired");
|
||||
},
|
||||
|
||||
checkMsids: function() {
|
||||
@ -1515,10 +1559,12 @@ PeerConnectionWrapper.prototype = {
|
||||
if(res.type == "outboundrtp") {
|
||||
ok(rem.type == "inboundrtp", "Rtcp is inbound");
|
||||
ok(rem.packetsReceived !== undefined, "Rtcp packetsReceived");
|
||||
ok(rem.packetsReceived <= res.packetsSent, "No more than sent");
|
||||
ok(rem.packetsLost !== undefined, "Rtcp packetsLost");
|
||||
ok(rem.bytesReceived >= rem.packetsReceived, "Rtcp bytesReceived");
|
||||
ok(rem.bytesReceived <= res.bytesSent, "No more than sent bytes");
|
||||
if (!this.disableRtpCountChecking) {
|
||||
ok(rem.packetsReceived <= res.packetsSent, "No more than sent packets");
|
||||
ok(rem.bytesReceived <= res.bytesSent, "No more than sent bytes");
|
||||
}
|
||||
ok(rem.jitter !== undefined, "Rtcp jitter");
|
||||
ok(rem.mozRtt !== undefined, "Rtcp rtt");
|
||||
ok(rem.mozRtt >= 0, "Rtcp rtt " + rem.mozRtt + " >= 0");
|
||||
|
@ -63,17 +63,19 @@ function dumpSdp(test) {
|
||||
}
|
||||
|
||||
function waitForIceConnected(test, pc) {
|
||||
if (pc.isIceConnected()) {
|
||||
info(pc + ": ICE connection state log: " + pc.iceConnectionLog);
|
||||
ok(true, pc + ": ICE is in connected state");
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!pc.iceCheckingRestartExpected) {
|
||||
if (pc.isIceConnected()) {
|
||||
info(pc + ": ICE connection state log: " + pc.iceConnectionLog);
|
||||
ok(true, pc + ": ICE is in connected state");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (!pc.isIceConnectionPending()) {
|
||||
dumpSdp(test);
|
||||
var details = pc + ": ICE is already in bad state: " + pc.iceConnectionState;
|
||||
ok(false, details);
|
||||
return Promise.reject(new Error(details));
|
||||
if (!pc.isIceConnectionPending()) {
|
||||
dumpSdp(test);
|
||||
var details = pc + ": ICE is already in bad state: " + pc.iceConnectionState;
|
||||
ok(false, details);
|
||||
return Promise.reject(new Error(details));
|
||||
}
|
||||
}
|
||||
|
||||
return pc.waitForIceConnected()
|
||||
@ -135,7 +137,9 @@ function checkTrackStats(pc, audio, outbound) {
|
||||
var checkAllTrackStats = pc =>
|
||||
Promise.all([0, 1, 2, 3].map(i => checkTrackStats(pc, i & 1, i & 2)));
|
||||
|
||||
var commandsPeerConnection = [
|
||||
// Commands run once at the beginning of each test, even when performing a
|
||||
// renegotiation test.
|
||||
var commandsPeerConnectionInitial = [
|
||||
function PC_SETUP_SIGNALING_CLIENT(test) {
|
||||
if (test.steeplechase) {
|
||||
setTimeout(() => {
|
||||
@ -169,12 +173,12 @@ var commandsPeerConnection = [
|
||||
test.pcRemote.logSignalingState();
|
||||
},
|
||||
|
||||
function PC_LOCAL_GUM(test) {
|
||||
return test.pcLocal.getAllUserMedia(test.pcLocal.constraints);
|
||||
function PC_LOCAL_SETUP_ADDSTREAM_HANDLER(test) {
|
||||
test.pcLocal.setupAddStreamEventHandler();
|
||||
},
|
||||
|
||||
function PC_REMOTE_GUM(test) {
|
||||
return test.pcRemote.getAllUserMedia(test.pcRemote.constraints);
|
||||
function PC_REMOTE_SETUP_ADDSTREAM_HANDLER(test) {
|
||||
test.pcRemote.setupAddStreamEventHandler();
|
||||
},
|
||||
|
||||
function PC_LOCAL_CHECK_INITIAL_SIGNALINGSTATE(test) {
|
||||
@ -197,6 +201,34 @@ var commandsPeerConnection = [
|
||||
"Initial remote ICE connection state is 'new'");
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
var commandsGetUserMedia = [
|
||||
function PC_LOCAL_GUM(test) {
|
||||
return test.pcLocal.getAllUserMedia(test.pcLocal.constraints);
|
||||
},
|
||||
|
||||
function PC_REMOTE_GUM(test) {
|
||||
return test.pcRemote.getAllUserMedia(test.pcRemote.constraints);
|
||||
},
|
||||
];
|
||||
|
||||
var commandsBeforeRenegotiation = [
|
||||
function PC_LOCAL_SETUP_NEGOTIATION_CALLBACK(test) {
|
||||
test.pcLocal.onnegotiationneeded = event => {
|
||||
test.pcLocal.negotiationNeededFired = true;
|
||||
};
|
||||
},
|
||||
];
|
||||
|
||||
var commandsAfterRenegotiation = [
|
||||
function PC_LOCAL_CHECK_NEGOTIATION_CALLBACK(test) {
|
||||
ok(test.pcLocal.negotiationNeededFired, "Expected negotiationneeded event");
|
||||
test.pcLocal.negotiationNeededFired = false;
|
||||
},
|
||||
];
|
||||
|
||||
var commandsPeerConnectionOfferAnswer = [
|
||||
function PC_LOCAL_SETUP_ICE_HANDLER(test) {
|
||||
test.pcLocal.setupIceCandidateHandler(test);
|
||||
if (test.steeplechase) {
|
||||
@ -215,6 +247,56 @@ var commandsPeerConnection = [
|
||||
}
|
||||
},
|
||||
|
||||
function PC_LOCAL_STEEPLECHASE_SIGNAL_EXPECTED_LOCAL_TRACKS(test) {
|
||||
if (test.steeplechase) {
|
||||
send_message({"type": "local_expected_tracks",
|
||||
"expected_tracks": test.pcLocal.expectedLocalTrackTypesById});
|
||||
}
|
||||
},
|
||||
|
||||
function PC_REMOTE_STEEPLECHASE_SIGNAL_EXPECTED_LOCAL_TRACKS(test) {
|
||||
if (test.steeplechase) {
|
||||
send_message({"type": "remote_expected_tracks",
|
||||
"expected_tracks": test.pcRemote.expectedLocalTrackTypesById});
|
||||
}
|
||||
},
|
||||
|
||||
function PC_LOCAL_GET_EXPECTED_REMOTE_TRACKS(test) {
|
||||
if (test.steeplechase) {
|
||||
return test.getSignalingMessage("remote_expected_tracks").then(
|
||||
message => {
|
||||
test.pcLocal.expectedRemoteTrackTypesById = message.expected_tracks;
|
||||
});
|
||||
} else {
|
||||
// Deep copy, as similar to steeplechase as possible
|
||||
test.pcLocal.expectedRemoteTrackTypesById =
|
||||
JSON.parse(JSON.stringify((test.pcRemote.expectedLocalTrackTypesById)));
|
||||
}
|
||||
|
||||
// Remove what we've already observed
|
||||
Object.keys(test.pcLocal.observedRemoteTrackTypesById).forEach(id => {
|
||||
delete test.pcLocal.expectedRemoteTrackTypesById[id];
|
||||
});
|
||||
},
|
||||
|
||||
function PC_LOCAL_GET_EXPECTED_REMOTE_TRACKS(test) {
|
||||
if (test.steeplechase) {
|
||||
return test.getSignalingMessage("local_expected_tracks").then(
|
||||
message => {
|
||||
test.pcRemote.expectedRemoteTrackTypesById = message.expected_tracks;
|
||||
});
|
||||
} else {
|
||||
// Deep copy, as similar to steeplechase as possible
|
||||
test.pcRemote.expectedRemoteTrackTypesById =
|
||||
JSON.parse(JSON.stringify((test.pcLocal.expectedLocalTrackTypesById)));
|
||||
}
|
||||
|
||||
// Remove what we've already observed
|
||||
Object.keys(test.pcRemote.observedRemoteTrackTypesById).forEach(id => {
|
||||
delete test.pcRemote.expectedRemoteTrackTypesById[id];
|
||||
});
|
||||
},
|
||||
|
||||
function PC_LOCAL_CREATE_OFFER(test) {
|
||||
return test.createOffer(test.pcLocal).then(offer => {
|
||||
is(test.pcLocal.signalingState, STABLE,
|
||||
@ -390,11 +472,11 @@ var commandsPeerConnection = [
|
||||
},
|
||||
|
||||
function PC_LOCAL_CHECK_MEDIA_TRACKS(test) {
|
||||
return test.pcLocal.checkMediaTracks(test._answer_constraints);
|
||||
return test.pcLocal.checkMediaTracks();
|
||||
},
|
||||
|
||||
function PC_REMOTE_CHECK_MEDIA_TRACKS(test) {
|
||||
return test.pcRemote.checkMediaTracks(test._offer_constraints);
|
||||
return test.pcRemote.checkMediaTracks();
|
||||
},
|
||||
|
||||
function PC_LOCAL_CHECK_MEDIA_FLOW_PRESENT(test) {
|
||||
@ -468,3 +550,32 @@ var commandsPeerConnection = [
|
||||
return checkAllTrackStats(test.pcRemote);
|
||||
}
|
||||
];
|
||||
|
||||
function PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER(test) {
|
||||
test.originalOffer.sdp = test.originalOffer.sdp.replace(
|
||||
/a=group:BUNDLE .*\r\n/g,
|
||||
""
|
||||
);
|
||||
info("Updated no bundle offer: " + JSON.stringify(test.originalOffer));
|
||||
};
|
||||
|
||||
var addRenegotiation = (chain, commands, checks) => {
|
||||
chain.append(commandsBeforeRenegotiation);
|
||||
chain.append(commands);
|
||||
chain.append(commandsAfterRenegotiation);
|
||||
chain.append(commandsPeerConnectionOfferAnswer);
|
||||
if (checks) {
|
||||
chain.append(checks);
|
||||
}
|
||||
};
|
||||
|
||||
var addRenegotiationAnswerer = (chain, commands, checks) => {
|
||||
chain.append(function SWAP_PC_LOCAL_PC_REMOTE(test) {
|
||||
var temp = test.pcLocal;
|
||||
test.pcLocal = test.pcRemote;
|
||||
test.pcRemote = temp;
|
||||
});
|
||||
addRenegotiation(chain, commands, checks);
|
||||
};
|
||||
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: add DataChannel"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
commandsCreateDataChannel,
|
||||
commandsCheckDataChannel);
|
||||
|
||||
// Insert before the second PC_LOCAL_CHECK_MEDIA_TRACKS
|
||||
test.chain.insertBefore('PC_LOCAL_CHECK_MEDIA_TRACKS',
|
||||
commandsWaitForDataChannel,
|
||||
false,
|
||||
1);
|
||||
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,46 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: add DataChannel"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
commandsCreateDataChannel.concat(
|
||||
[
|
||||
function PC_LOCAL_EXPECT_ICE_CHECKING(test) {
|
||||
test.pcLocal.iceCheckingRestartExpected = true;
|
||||
},
|
||||
function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
|
||||
test.pcRemote.iceCheckingRestartExpected = true;
|
||||
},
|
||||
]
|
||||
),
|
||||
commandsCheckDataChannel);
|
||||
|
||||
test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER',
|
||||
PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
|
||||
|
||||
// Insert before the second PC_LOCAL_CHECK_MEDIA_TRACKS
|
||||
test.chain.insertBefore('PC_LOCAL_CHECK_MEDIA_TRACKS',
|
||||
commandsWaitForDataChannel,
|
||||
false,
|
||||
1);
|
||||
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -7,49 +7,24 @@
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1091242",
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: add second audio stream"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
test.chain.append([
|
||||
function PC_LOCAL_SETUP_NEGOTIATION_CALLBACK(test) {
|
||||
test.pcLocal.onNegotiationneededFired = false;
|
||||
test.pcLocal._pc.onnegotiationneeded = anEvent => {
|
||||
info("pcLocal.onnegotiationneeded fired");
|
||||
test.pcLocal.onNegotiationneededFired = true;
|
||||
};
|
||||
},
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
return test.pcLocal.getAllUserMedia([{audio: true}]);
|
||||
},
|
||||
function PC_LOCAL_CREATE_NEW_OFFER(test) {
|
||||
ok(test.pcLocal.onNegotiationneededFired, "onnegotiationneeded");
|
||||
return test.createOffer(test.pcLocal).then(offer => {
|
||||
test._new_offer = offer;
|
||||
});
|
||||
},
|
||||
function PC_LOCAL_SET_NEW_LOCAL_DESCRIPTION(test) {
|
||||
return test.setLocalDescription(test.pcLocal, test._new_offer, HAVE_LOCAL_OFFER);
|
||||
},
|
||||
function PC_REMOTE_SET_NEW_REMOTE_DESCRIPTION(test) {
|
||||
return test.setRemoteDescription(test.pcRemote, test._new_offer, HAVE_REMOTE_OFFER);
|
||||
},
|
||||
function PC_REMOTE_CREATE_NEW_ANSWER(test) {
|
||||
return test.createAnswer(test.pcRemote).then(answer => {
|
||||
test._new_answer = answer;
|
||||
});
|
||||
},
|
||||
function PC_REMOTE_SET_NEW_LOCAL_DESCRIPTION(test) {
|
||||
return test.setLocalDescription(test.pcRemote, test._new_answer, STABLE);
|
||||
},
|
||||
function PC_LOCAL_SET_NEW_REMOTE_DESCRIPTION(test) {
|
||||
return test.setRemoteDescription(test.pcLocal, test._new_answer, STABLE);
|
||||
}
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
]);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
test.setMediaConstraints([{audio: true}, {audio: true}],
|
||||
[{audio: true}]);
|
||||
return test.pcLocal.getAllUserMedia([{audio: true}]);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
|
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: add second audio stream, no bundle"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
test.setMediaConstraints([{audio: true}, {audio: true}],
|
||||
[{audio: true}]);
|
||||
// Since this is a NoBundle variant, adding a track will cause us to
|
||||
// go back to checking.
|
||||
test.pcLocal.iceCheckingRestartExpected = true;
|
||||
return test.pcLocal.getAllUserMedia([{audio: true}]);
|
||||
},
|
||||
function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
|
||||
test.pcRemote.iceCheckingRestartExpected = true;
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER',
|
||||
PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,34 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: add second video stream"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
test.setMediaConstraints([{video: true}, {video: true}],
|
||||
[{video: true}]);
|
||||
return test.pcLocal.getAllUserMedia([{video: true}]);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,43 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: add second video stream, no bundle"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
test.setMediaConstraints([{video: true}, {video: true}],
|
||||
[{video: true}]);
|
||||
// Since this is a NoBundle variant, adding a track will cause us to
|
||||
// go back to checking.
|
||||
test.pcLocal.iceCheckingRestartExpected = true;
|
||||
return test.pcLocal.getAllUserMedia([{video: true}]);
|
||||
},
|
||||
function PC_REMOTE_EXPECT_ICE_CHECKING(test) {
|
||||
test.pcRemote.iceCheckingRestartExpected = true;
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER',
|
||||
PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,34 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: answerer adds second audio stream"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiationAnswerer(test.chain,
|
||||
[
|
||||
function PC_LOCAL_ADD_SECOND_STREAM(test) {
|
||||
test.setMediaConstraints([{audio: true}, {audio: true}],
|
||||
[{audio: true}]);
|
||||
return test.pcLocal.getAllUserMedia([{audio: true}]);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -15,15 +15,7 @@
|
||||
var test = new PeerConnectionTest(options);
|
||||
test.chain.insertAfter(
|
||||
'PC_LOCAL_CREATE_OFFER',
|
||||
[
|
||||
function PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER(test) {
|
||||
test.originalOffer.sdp = test.originalOffer.sdp.replace(
|
||||
/a=group:BUNDLE .*\r\n/g,
|
||||
""
|
||||
);
|
||||
info("Updated no bundle offer: " + JSON.stringify(test.originalOffer));
|
||||
}
|
||||
]);
|
||||
[PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER]);
|
||||
test.setMediaConstraints([{audio: true}, {video: true}],
|
||||
[{audio: true}, {video: true}]);
|
||||
test.run();
|
||||
|
@ -31,7 +31,10 @@ runNetworkTest(function() {
|
||||
.then(() => {
|
||||
var stream = v1.mozCaptureStreamUntilEnded();
|
||||
is(stream.getTracks().length, 2, "Captured stream has 2 tracks");
|
||||
stream.getTracks().forEach(tr => test.pcLocal._pc.addTrack(tr, stream));
|
||||
stream.getTracks().forEach(tr => {
|
||||
test.pcLocal._pc.addTrack(tr, stream);
|
||||
test.pcLocal.expectedLocalTrackTypesById[tr.id] = tr.kind;
|
||||
});
|
||||
test.pcLocal.constraints = [{ video: true, audio:true }]; // fool tests
|
||||
});
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: remove audio track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
test.setOfferOptions({ offerToReceiveAudio: true });
|
||||
test.setMediaConstraints([], [{audio: true}]);
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify that media stopped flowing from pcLocal
|
||||
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,39 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: remove then add audio track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
function PC_LOCAL_ADD_AUDIO_TRACK(test) {
|
||||
// The new track's pipeline will start with a packet count of
|
||||
// 0, but the remote side will keep its old pipeline and packet
|
||||
// count.
|
||||
test.pcLocal.disableRtpCountChecking = true;
|
||||
return test.pcLocal.getAllUserMedia([{audio: true}]);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,42 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: remove then add audio track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
// The new track's pipeline will start with a packet count of
|
||||
// 0, but the remote side will keep its old pipeline and packet
|
||||
// count.
|
||||
test.pcLocal.disableRtpCountChecking = true;
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
function PC_LOCAL_ADD_AUDIO_TRACK(test) {
|
||||
return test.pcLocal.getAllUserMedia([{audio: true}]);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER',
|
||||
PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{audio: true}], [{audio: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,39 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: remove then add video track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
// The new track's pipeline will start with a packet count of
|
||||
// 0, but the remote side will keep its old pipeline and packet
|
||||
// count.
|
||||
test.pcLocal.disableRtpCountChecking = true;
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
function PC_LOCAL_ADD_AUDIO_TRACK(test) {
|
||||
return test.pcLocal.getAllUserMedia([{video: true}]);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,42 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: remove then add video track, no bundle"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_REMOVE_AUDIO_TRACK(test) {
|
||||
// The new track's pipeline will start with a packet count of
|
||||
// 0, but the remote side will keep its old pipeline and packet
|
||||
// count.
|
||||
test.pcLocal.disableRtpCountChecking = true;
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
function PC_LOCAL_ADD_AUDIO_TRACK(test) {
|
||||
return test.pcLocal.getAllUserMedia([{video: true}]);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
test.chain.insertAfterEach('PC_LOCAL_CREATE_OFFER',
|
||||
PC_LOCAL_REMOVE_BUNDLE_FROM_OFFER);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify if media flows through the new stream
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<script type="application/javascript" src="pc.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
createHTML({
|
||||
bug: "1017888",
|
||||
title: "Renegotiation: remove video track"
|
||||
});
|
||||
|
||||
var test;
|
||||
runNetworkTest(function (options) {
|
||||
test = new PeerConnectionTest(options);
|
||||
addRenegotiation(test.chain,
|
||||
[
|
||||
function PC_LOCAL_REMOVE_VIDEO_TRACK(test) {
|
||||
test.setOfferOptions({ offerToReceiveVideo: true });
|
||||
test.setMediaConstraints([], [{video: true}]);
|
||||
return test.pcLocal.removeSender(0);
|
||||
},
|
||||
]
|
||||
);
|
||||
|
||||
// TODO(bug 1093835): figure out how to verify that media stopped flowing from pcLocal
|
||||
|
||||
test.setMediaConstraints([{video: true}], [{video: true}]);
|
||||
test.run();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -23,6 +23,8 @@
|
||||
#include "gfxSharedImageSurface.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#ifdef MOZ_X11
|
||||
#include "gfxXlibSurface.h"
|
||||
#endif
|
||||
@ -45,10 +47,6 @@
|
||||
#include "mozilla/plugins/PluginSurfaceParent.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
// Plugin focus event for widget.
|
||||
extern const wchar_t* kOOPPPluginFocusEventId;
|
||||
UINT gOOPPPluginFocusEvent =
|
||||
RegisterWindowMessage(kOOPPPluginFocusEventId);
|
||||
extern const wchar_t* kFlashFullscreenClass;
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
#include <gdk/gdk.h>
|
||||
@ -1789,7 +1787,6 @@ PluginInstanceParent::SubclassPluginWindow(HWND aWnd)
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
if (!aWnd) {
|
||||
NS_WARNING("PluginInstanceParent::SubclassPluginWindow unexpected null window");
|
||||
@ -1802,7 +1799,6 @@ PluginInstanceParent::SubclassPluginWindow(HWND aWnd)
|
||||
sPluginInstanceList->Put((void*)mPluginHWND, this);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSERTION(!(mPluginHWND && aWnd != mPluginHWND),
|
||||
"PluginInstanceParent::SubclassPluginWindow hwnd is not our window!");
|
||||
@ -1821,7 +1817,6 @@ PluginInstanceParent::SubclassPluginWindow(HWND aWnd)
|
||||
void
|
||||
PluginInstanceParent::UnsubclassPluginWindow()
|
||||
{
|
||||
#if defined(XP_WIN)
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Content) {
|
||||
if (mPluginHWND) {
|
||||
// Remove 'this' from the plugin list safely
|
||||
@ -1837,7 +1832,6 @@ PluginInstanceParent::UnsubclassPluginWindow()
|
||||
mPluginHWND = nullptr;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mPluginHWND && mPluginWndProc) {
|
||||
::SetWindowLongPtrA(mPluginHWND, GWLP_WNDPROC,
|
||||
@ -1980,14 +1974,21 @@ PluginInstanceParent::AnswerPluginFocusChange(const bool& gotFocus)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
|
||||
|
||||
// Currently only in use on windows - an rpc event we receive from the
|
||||
// child when it's plugin window (or one of it's children) receives keyboard
|
||||
// focus. We forward the event down to widget so the dom/focus manager can
|
||||
// be updated.
|
||||
// Currently only in use on windows - an event we receive from the child
|
||||
// when it's plugin window (or one of it's children) receives keyboard
|
||||
// focus. We detect this and forward a notification here so we can update
|
||||
// focus.
|
||||
#if defined(OS_WIN)
|
||||
// XXX This needs to go to PuppetWidget. bug ???
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||
::SendMessage(mPluginHWND, gOOPPPluginFocusEvent, gotFocus ? 1 : 0, 0);
|
||||
if (gotFocus) {
|
||||
nsPluginInstanceOwner* owner = GetOwner();
|
||||
if (owner) {
|
||||
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
nsCOMPtr<nsIDOMElement> element;
|
||||
owner->GetDOMElement(getter_AddRefs(element));
|
||||
if (fm && element) {
|
||||
fm->SetFocus(element, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
|
@ -819,6 +819,12 @@ this.PushService = {
|
||||
if (uri.scheme === "wss") {
|
||||
this._ws = Cc["@mozilla.org/network/protocol;1?name=wss"]
|
||||
.createInstance(Ci.nsIWebSocketChannel);
|
||||
|
||||
this._ws.initLoadInfo(null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_WEBSOCKET);
|
||||
}
|
||||
else if (uri.scheme === "ws") {
|
||||
debug("Push over an insecure connection (ws://) is not allowed!");
|
||||
|
@ -23,6 +23,7 @@ interface PeerConnectionObserver
|
||||
void onAddIceCandidateSuccess();
|
||||
void onAddIceCandidateError(unsigned long name, DOMString message);
|
||||
void onIceCandidate(unsigned short level, DOMString mid, DOMString candidate);
|
||||
void onNegotiationNeeded();
|
||||
|
||||
/* Stats callbacks */
|
||||
void onGetStatsSuccess(optional RTCStatsReportInternal report);
|
||||
@ -40,7 +41,7 @@ interface PeerConnectionObserver
|
||||
|
||||
/* Changes to MediaStreamTracks */
|
||||
void onAddStream(MediaStream stream);
|
||||
void onRemoveStream();
|
||||
void onRemoveStream(MediaStream stream);
|
||||
void onAddTrack(MediaStreamTrack track);
|
||||
void onRemoveTrack();
|
||||
void onRemoveTrack(MediaStreamTrack track);
|
||||
};
|
||||
|
@ -130,7 +130,6 @@ ServiceWorkerRegistrationInfo::Clear()
|
||||
mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
|
||||
// Fire statechange.
|
||||
mWaitingWorker = nullptr;
|
||||
mWaitingToActivate = false;
|
||||
}
|
||||
|
||||
if (mActiveWorker) {
|
||||
@ -199,8 +198,6 @@ ServiceWorkerManager::~ServiceWorkerManager()
|
||||
mServiceWorkerRegistrationInfos.Clear();
|
||||
}
|
||||
|
||||
class ServiceWorkerRegisterJob;
|
||||
|
||||
class ContinueLifecycleTask : public nsISupports
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
@ -216,6 +213,8 @@ public:
|
||||
|
||||
NS_IMPL_ISUPPORTS0(ContinueLifecycleTask);
|
||||
|
||||
class ServiceWorkerRegisterJob;
|
||||
|
||||
class ContinueInstallTask MOZ_FINAL : public ContinueLifecycleTask
|
||||
{
|
||||
nsRefPtr<ServiceWorkerRegisterJob> mJob;
|
||||
@ -238,10 +237,7 @@ public:
|
||||
{ }
|
||||
|
||||
void
|
||||
ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately /* unused */) MOZ_OVERRIDE
|
||||
{
|
||||
mRegistration->FinishActivate(aSuccess);
|
||||
}
|
||||
ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately /* unused */) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
class ContinueLifecycleRunnable MOZ_FINAL : public nsRunnable
|
||||
@ -571,6 +567,7 @@ public:
|
||||
getter_AddRefs(serviceWorker));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
swm->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope);
|
||||
Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
return rv;
|
||||
}
|
||||
@ -585,6 +582,7 @@ public:
|
||||
jsapi.Init();
|
||||
bool ok = r->Dispatch(jsapi.cx());
|
||||
if (NS_WARN_IF(!ok)) {
|
||||
swm->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope);
|
||||
Fail(NS_ERROR_DOM_ABORT_ERR);
|
||||
return rv;
|
||||
}
|
||||
@ -608,6 +606,10 @@ public:
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
MOZ_ASSERT(swm->mSetOfScopesBeingUpdated.Contains(mRegistration->mScope));
|
||||
swm->mSetOfScopesBeingUpdated.Remove(mRegistration->mScope);
|
||||
// This is effectively the end of Step 4.3 of the [[Update]] algorithm.
|
||||
// The invocation of [[Install]] is not part of the atomic block.
|
||||
|
||||
// Begin [[Install]] atomic step 4.
|
||||
if (mRegistration->mInstallingWorker) {
|
||||
// FIXME(nsm): Terminate and stuff
|
||||
mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
|
||||
@ -620,15 +622,13 @@ public:
|
||||
|
||||
Succeed();
|
||||
|
||||
// Step 4.6 "Queue a task..." for updatefound.
|
||||
nsCOMPtr<nsIRunnable> upr =
|
||||
NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>(swm,
|
||||
&ServiceWorkerManager::FireUpdateFound,
|
||||
mRegistration);
|
||||
NS_DispatchToMainThread(upr);
|
||||
|
||||
nsMainThreadPtrHandle<ContinueLifecycleTask> handle(
|
||||
new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueInstallTask(this)));
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
nsresult rv =
|
||||
swm->CreateServiceWorker(mRegistration->mPrincipal,
|
||||
@ -637,15 +637,21 @@ public:
|
||||
getter_AddRefs(serviceWorker));
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
ContinueAfterInstallEvent(false /* success */, false /* activate immediately */);
|
||||
ContinueAfterInstallEvent(false /* aSuccess */, false /* aActivateImmediately */);
|
||||
return;
|
||||
}
|
||||
|
||||
nsMainThreadPtrHandle<ContinueLifecycleTask> handle(
|
||||
new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueInstallTask(this)));
|
||||
|
||||
nsRefPtr<LifecycleEventWorkerRunnable> r =
|
||||
new LifecycleEventWorkerRunnable(serviceWorker->GetWorkerPrivate(), NS_LITERAL_STRING("install"), handle);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
|
||||
// This triggers Step 4.7 "Queue a task to run the following substeps..."
|
||||
// which sends the install event to the worker.
|
||||
r->Dispatch(jsapi.cx());
|
||||
}
|
||||
|
||||
@ -727,7 +733,8 @@ private:
|
||||
FailCommon(nsresult aRv)
|
||||
{
|
||||
mCallback = nullptr;
|
||||
MaybeRemoveRegistration();
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
swm->MaybeRemoveRegistration(mRegistration);
|
||||
// Ensures that the job can't do anything useful from this point on.
|
||||
mRegistration = nullptr;
|
||||
Done(aRv);
|
||||
@ -745,23 +752,8 @@ private:
|
||||
}
|
||||
|
||||
void
|
||||
MaybeRemoveRegistration()
|
||||
ContinueAfterInstallEvent(bool aInstallEventSuccess, bool aActivateImmediately)
|
||||
{
|
||||
MOZ_ASSERT(mRegistration);
|
||||
nsRefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
|
||||
if (!newest) {
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
swm->RemoveRegistration(mRegistration);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContinueAfterInstallEvent(bool aSuccess, bool aActivateImmediately)
|
||||
{
|
||||
// By this point the callback should've been notified about success or fail
|
||||
// and nulled.
|
||||
MOZ_ASSERT(!mCallback);
|
||||
|
||||
if (!mRegistration->mInstallingWorker) {
|
||||
NS_WARNING("mInstallingWorker was null.");
|
||||
return Done(NS_ERROR_DOM_ABORT_ERR);
|
||||
@ -770,12 +762,12 @@ private:
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
|
||||
// "If installFailed is true"
|
||||
if (!aSuccess) {
|
||||
if (!aInstallEventSuccess) {
|
||||
mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
|
||||
mRegistration->mInstallingWorker = nullptr;
|
||||
swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
|
||||
WhichServiceWorker::INSTALLING_WORKER);
|
||||
MaybeRemoveRegistration();
|
||||
swm->MaybeRemoveRegistration(mRegistration);
|
||||
return Done(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
|
||||
@ -792,14 +784,14 @@ private:
|
||||
// swapping it with waiting worker.
|
||||
mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installed);
|
||||
mRegistration->mWaitingWorker = mRegistration->mInstallingWorker.forget();
|
||||
mRegistration->mWaitingToActivate = false;
|
||||
swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
|
||||
WhichServiceWorker::INSTALLING_WORKER | WhichServiceWorker::WAITING_WORKER);
|
||||
|
||||
// FIXME(nsm): Bug 982711 Deal with activateImmediately.
|
||||
NS_WARN_IF_FALSE(!aActivateImmediately, "Immediate activation using replace() is not supported yet");
|
||||
mRegistration->TryToActivate();
|
||||
Done(NS_OK);
|
||||
// Activate() is invoked out of band of atomic.
|
||||
mRegistration->TryToActivate();
|
||||
}
|
||||
};
|
||||
|
||||
@ -818,6 +810,8 @@ ContinueUpdateRunnable::Run()
|
||||
void
|
||||
ContinueInstallTask::ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately)
|
||||
{
|
||||
// This does not start the job immediately if there are other jobs in the
|
||||
// queue, which captures the "atomic" behaviour we want.
|
||||
mJob->ContinueAfterInstallEvent(aSuccess, aActivateImmediately);
|
||||
}
|
||||
|
||||
@ -1100,18 +1094,20 @@ LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx, WorkerPriva
|
||||
void
|
||||
ServiceWorkerRegistrationInfo::TryToActivate()
|
||||
{
|
||||
mWaitingToActivate = true;
|
||||
if (!IsControllingDocuments()) {
|
||||
Activate();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ContinueActivateTask::ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately /* unused */)
|
||||
{
|
||||
mRegistration->FinishActivate(aSuccess);
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerRegistrationInfo::Activate()
|
||||
{
|
||||
MOZ_ASSERT(mWaitingToActivate);
|
||||
mWaitingToActivate = false;
|
||||
|
||||
nsRefPtr<ServiceWorkerInfo> activatingWorker = mWaitingWorker;
|
||||
nsRefPtr<ServiceWorkerInfo> exitingWorker = mActiveWorker;
|
||||
|
||||
@ -1132,18 +1128,18 @@ ServiceWorkerRegistrationInfo::Activate()
|
||||
mWaitingWorker = nullptr;
|
||||
mActiveWorker->UpdateState(ServiceWorkerState::Activating);
|
||||
|
||||
// FIXME(nsm): Unlink appcache if there is one.
|
||||
|
||||
swm->CheckPendingReadyPromises();
|
||||
swm->StoreRegistration(mPrincipal, this);
|
||||
|
||||
// "Queue a task to fire a simple event named controllerchange..."
|
||||
nsCOMPtr<nsIRunnable> controllerChangeRunnable =
|
||||
NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>(swm, &ServiceWorkerManager::FireControllerChange, this);
|
||||
NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>(swm,
|
||||
&ServiceWorkerManager::FireControllerChange,
|
||||
this);
|
||||
NS_DispatchToMainThread(controllerChangeRunnable);
|
||||
|
||||
// XXXnsm I have my doubts about this. Leaving the main thread means that
|
||||
// subsequent calls to Activate() not from a Register() call, i.e. due to all
|
||||
// controlled documents going away, may lead to two or more calls being
|
||||
// interleaved.
|
||||
MOZ_ASSERT(mActiveWorker);
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
nsresult rv =
|
||||
@ -1152,7 +1148,11 @@ ServiceWorkerRegistrationInfo::Activate()
|
||||
mScope,
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
FinishActivate(false /* success */);
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
NS_NewRunnableMethodWithArg<bool>(this,
|
||||
&ServiceWorkerRegistrationInfo::FinishActivate,
|
||||
false /* success */);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1688,7 +1688,10 @@ ServiceWorkerManager::HandleError(JSContext* aCx,
|
||||
void
|
||||
ServiceWorkerRegistrationInfo::FinishActivate(bool aSuccess)
|
||||
{
|
||||
MOZ_ASSERT(mActiveWorker);
|
||||
if (mPendingUninstall || !mActiveWorker) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSuccess) {
|
||||
mActiveWorker->UpdateState(ServiceWorkerState::Activated);
|
||||
} else {
|
||||
@ -1933,10 +1936,6 @@ void
|
||||
ServiceWorkerManager::MaybeStartControlling(nsIDocument* aDoc)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
if (!Preferences::GetBool("dom.serviceWorkers.enabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
|
||||
GetServiceWorkerRegistrationInfo(aDoc);
|
||||
if (registration) {
|
||||
@ -1952,10 +1951,6 @@ void
|
||||
ServiceWorkerManager::MaybeStopControlling(nsIDocument* aDoc)
|
||||
{
|
||||
MOZ_ASSERT(aDoc);
|
||||
if (!Preferences::GetBool("dom.serviceWorkers.enabled")) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||
mControlledDocuments.Remove(aDoc, getter_AddRefs(registration));
|
||||
// A document which was uncontrolled does not maintain that state itself, so
|
||||
@ -1963,6 +1958,14 @@ ServiceWorkerManager::MaybeStopControlling(nsIDocument* aDoc)
|
||||
// associated registration. So this check is required.
|
||||
if (registration) {
|
||||
registration->StopControllingADocument();
|
||||
if (!registration->IsControllingDocuments()) {
|
||||
if (registration->mPendingUninstall) {
|
||||
registration->Clear();
|
||||
RemoveRegistration(registration);
|
||||
} else {
|
||||
registration->TryToActivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2410,4 +2413,14 @@ ServiceWorkerManager::CreateNewRegistration(const nsCString& aScope,
|
||||
return registration;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerManager::MaybeRemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration)
|
||||
{
|
||||
MOZ_ASSERT(aRegistration);
|
||||
nsRefPtr<ServiceWorkerInfo> newest = aRegistration->Newest();
|
||||
if (!newest) {
|
||||
RemoveRegistration(aRegistration);
|
||||
}
|
||||
}
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
@ -49,6 +49,7 @@ class ServiceWorkerJobQueue;
|
||||
|
||||
class ServiceWorkerJob : public nsISupports
|
||||
{
|
||||
protected:
|
||||
// The queue keeps the jobs alive, so they can hold a rawptr back to the
|
||||
// queue.
|
||||
ServiceWorkerJobQueue* mQueue;
|
||||
@ -151,7 +152,6 @@ public:
|
||||
// removed since documents may be controlled. It is marked as
|
||||
// pendingUninstall and when all controlling documents go away, removed.
|
||||
bool mPendingUninstall;
|
||||
bool mWaitingToActivate;
|
||||
|
||||
explicit ServiceWorkerRegistrationInfo(const nsACString& aScope,
|
||||
nsIPrincipal* aPrincipal);
|
||||
@ -289,13 +289,11 @@ class ServiceWorkerManager MOZ_FINAL
|
||||
: public nsIServiceWorkerManager
|
||||
, public nsIIPCBackgroundChildCreateCallback
|
||||
{
|
||||
friend class ActivationRunnable;
|
||||
friend class ServiceWorkerRegistrationInfo;
|
||||
friend class ServiceWorkerRegisterJob;
|
||||
friend class GetReadyPromiseRunnable;
|
||||
friend class GetRegistrationsRunnable;
|
||||
friend class GetRegistrationRunnable;
|
||||
friend class QueueFireUpdateFoundRunnable;
|
||||
friend class ServiceWorkerRegisterJob;
|
||||
friend class ServiceWorkerRegistrationInfo;
|
||||
friend class ServiceWorkerUnregisterJob;
|
||||
|
||||
public:
|
||||
@ -349,6 +347,8 @@ public:
|
||||
void
|
||||
RemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration)
|
||||
{
|
||||
MOZ_ASSERT(aRegistration);
|
||||
MOZ_ASSERT(!aRegistration->IsControllingDocuments());
|
||||
MOZ_ASSERT(mServiceWorkerRegistrationInfos.Contains(aRegistration->mScope));
|
||||
ServiceWorkerManager::RemoveScope(mOrderedScopes, aRegistration->mScope);
|
||||
mServiceWorkerRegistrationInfos.Remove(aRegistration->mScope);
|
||||
@ -491,6 +491,9 @@ private:
|
||||
void* aUnused);
|
||||
|
||||
nsClassHashtable<nsISupportsHashKey, PendingReadyPromise> mPendingReadyPromises;
|
||||
|
||||
void
|
||||
MaybeRemoveRegistration(ServiceWorkerRegistrationInfo* aRegistration);
|
||||
|
||||
mozilla::ipc::PBackgroundChild* mActor;
|
||||
|
||||
|
@ -17,11 +17,11 @@
|
||||
|
||||
// Make sure to use good, unique messages, since the actual expression will not show up in test results.
|
||||
function my_ok(result, msg) {
|
||||
window.opener.postMessage({status: "ok", result: result, message: msg}, "*");
|
||||
parent.postMessage({status: "ok", result: result, message: msg}, "*");
|
||||
}
|
||||
|
||||
function finish() {
|
||||
window.opener.postMessage({status: "done"}, "*");
|
||||
parent.postMessage({status: "done"}, "*");
|
||||
}
|
||||
|
||||
navigator.serviceWorker.ready.then(function(swr) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Worker that errors on receiving an install event.
|
||||
oninstall = function(e) {
|
||||
undefined.doSomething;
|
||||
}
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
[DEFAULT]
|
||||
skip-if = buildapp == 'b2g' || android_version == "10" # bug 1056702
|
||||
skip-if = buildapp == 'b2g'
|
||||
support-files =
|
||||
worker.js
|
||||
worker2.js
|
||||
@ -22,18 +22,16 @@ support-files =
|
||||
message_posting_worker.js
|
||||
|
||||
[test_unregister.html]
|
||||
skip-if = true # bug 1094375
|
||||
skip-if = true # Bug 1133805
|
||||
[test_installation_simple.html]
|
||||
skip-if = true # bug 1094375
|
||||
[test_get_serviced.html]
|
||||
[test_install_event.html]
|
||||
[test_navigator.html]
|
||||
[test_scopes.html]
|
||||
skip-if = true # bug 1126470 and many others
|
||||
[test_controller.html]
|
||||
[test_workerUpdate.html]
|
||||
skip-if = true # Enable after Bug 982726 postMessage is landed.
|
||||
skip-if = true # Bug 1133805
|
||||
[test_workerUnregister.html]
|
||||
skip-if = true # Enable after Bug 982726 postMessage is landed.
|
||||
skip-if = true # Bug 1133805
|
||||
[test_post_message.html]
|
||||
[test_post_message_advanced.html]
|
||||
|
@ -3,13 +3,11 @@
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
|
||||
window.addEventListener('message', function(evt) {
|
||||
navigator.serviceWorker.ready.then(function() {
|
||||
navigator.serviceWorker.oncontrollerchange = function(e) {
|
||||
evt.ports[0].postMessage("WOW!");
|
||||
}
|
||||
});
|
||||
}, false);
|
||||
window.addEventListener('message', function(evt) {
|
||||
navigator.serviceWorker.ready.then(function() {
|
||||
evt.ports[0].postMessage("WOW!");
|
||||
});
|
||||
}, false);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
@ -15,6 +15,9 @@
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var content;
|
||||
var iframe;
|
||||
|
||||
function simpleRegister() {
|
||||
// We use the control scope for the less specific registration. The window will register a worker on controller/
|
||||
return navigator.serviceWorker.register("worker.js", { scope: "./control" });
|
||||
@ -27,17 +30,23 @@
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "done") {
|
||||
window.onmessage = null;
|
||||
w.close();
|
||||
content.removeChild(iframe);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var w = window.open("controller/index.html");
|
||||
content = document.getElementById("content");
|
||||
ok(content, "Parent exists.");
|
||||
|
||||
iframe = document.createElement("iframe");
|
||||
iframe.setAttribute('src', "controller/index.html");
|
||||
content.appendChild(iframe);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// This document just flips the prefs and opens the window for the actual test.
|
||||
// This document just flips the prefs and opens the iframe for the actual test.
|
||||
function runTest() {
|
||||
simpleRegister()
|
||||
.then(testController)
|
||||
|
@ -38,9 +38,10 @@
|
||||
|
||||
function installError() {
|
||||
// Silence worker errors so they don't cause the test to fail.
|
||||
window.onerror = function() { }
|
||||
window.onerror = function(e) {}
|
||||
return navigator.serviceWorker.register("install_event_error_worker.js", { scope: "./install_event" })
|
||||
.then(function(swr) {
|
||||
ok(swr.installing instanceof ServiceWorker, "There should be an installing worker if promise resolves.");
|
||||
ok(swr.installing.state == "installing", "Installing worker's state should be 'installing'");
|
||||
return new Promise(function(resolve, reject) {
|
||||
swr.installing.onstatechange = function(e) {
|
||||
@ -85,7 +86,8 @@
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
simpleRegister()
|
||||
Promise.resolve()
|
||||
.then(simpleRegister)
|
||||
.then(nextRegister)
|
||||
.then(installError)
|
||||
.then(activateError)
|
||||
|
@ -75,25 +75,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
function abortPrevious() {
|
||||
var p = navigator.serviceWorker.register("worker2.js", { scope: "foo/" });
|
||||
var q = navigator.serviceWorker.register("worker3.js", { scope: "foo/" });
|
||||
|
||||
return Promise.all([
|
||||
p.then(function(wr) {
|
||||
ok(false, "First registration should fail with AbortError");
|
||||
}, function(e) {
|
||||
ok(e.name === "AbortError", "First registration should fail with AbortError");
|
||||
}),
|
||||
|
||||
q.then(function(wr) {
|
||||
ok(wr instanceof ServiceWorkerRegistration, "Second registration should succeed");
|
||||
}, function(e) {
|
||||
ok(false, "Second registration should succeed");
|
||||
})
|
||||
]);
|
||||
}
|
||||
|
||||
function networkError404() {
|
||||
return navigator.serviceWorker.register("404.js", { scope: "network_error/"}).then(function(w) {
|
||||
ok(false, "Should fail with NetworkError");
|
||||
@ -111,7 +92,6 @@
|
||||
is(swr, undefined, "A failed registration for a scope with no prior controllers should clear itself");
|
||||
});
|
||||
}, function(e) {
|
||||
info("NSM " + e.name);
|
||||
ok(e instanceof Error, "Registration should fail with parse error");
|
||||
});
|
||||
}
|
||||
@ -140,8 +120,7 @@
|
||||
window.onmessage = null;
|
||||
// We have to make frame navigate away, otherwise it will call
|
||||
// MaybeStopControlling() when this document is unloaded. At that point
|
||||
// the pref has been disabled, and so MaybeStopControlling() will just
|
||||
// return since it is currently gated.
|
||||
// the pref has been disabled, so the ServiceWorkerManager is not available.
|
||||
frame.setAttribute("src", new URL("about:blank").href);
|
||||
resolve();
|
||||
} else if (e.data.type == "check") {
|
||||
@ -183,7 +162,6 @@
|
||||
.then(sameOriginScope)
|
||||
.then(httpsOnly)
|
||||
.then(realWorker)
|
||||
.then(abortPrevious)
|
||||
.then(networkError404)
|
||||
.then(parseError)
|
||||
.then(updatefound)
|
||||
|
@ -62,7 +62,7 @@
|
||||
ok(getScope(p("sub/dir/afoo")) === p("sub/dir/a"), "Scope should match");
|
||||
ok(getScope(p("star*wars")) === p("star*"), "Scope should match");
|
||||
ok(getScope(p("star/a.html")) === p(""), "Scope should match");
|
||||
resolve(true);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -19,22 +19,19 @@
|
||||
info("unregister/index.html should not to be launched directly!");
|
||||
}
|
||||
|
||||
SimpleTest.requestFlakyTimeout("Unfortunately we have no way to test for a page being uncontrolled except waiting for ready to not resolve");
|
||||
var tId = setTimeout(function() {
|
||||
info("tId timeout!");
|
||||
parent.postMessage({ controlled: false }, "*");
|
||||
tId = null;
|
||||
}, 2000);
|
||||
|
||||
navigator.serviceWorker.ready.then(function() {
|
||||
info("Got ready");
|
||||
if (tId == null) {
|
||||
info("tId was null");
|
||||
parent.postMessage("FAIL!!!", "*");
|
||||
return;
|
||||
}
|
||||
|
||||
clearTimeout(tId);
|
||||
info("tId was non-null");
|
||||
parent.postMessage({ controlled: true }, "*");
|
||||
});
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
|
||||
#include "nsIURI.h"
|
||||
#include "nsIIOService.h"
|
||||
#include "nsIFileChannel.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsGkAtoms.h"
|
||||
@ -27,6 +26,7 @@
|
||||
#include "mozIStorageService.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
@ -212,11 +212,13 @@ nsXULTemplateQueryProcessorStorage::GetDatasource(nsIArray* aDataSources,
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsCOMPtr<nsIIOService> ioservice =
|
||||
do_GetService("@mozilla.org/network/io-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aRootNode);
|
||||
|
||||
rv = ioservice->NewChannelFromURI(uri, getter_AddRefs(channel));
|
||||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
uri,
|
||||
node,
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_OTHER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(channel, &rv);
|
||||
|
@ -3628,11 +3628,11 @@ nsWebBrowserPersist::CreateChannelFromURI(nsIURI *aURI, nsIChannel **aChannel)
|
||||
nsresult rv = NS_OK;
|
||||
*aChannel = nullptr;
|
||||
|
||||
nsCOMPtr<nsIIOService> ioserv;
|
||||
ioserv = do_GetIOService(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = ioserv->NewChannelFromURI(aURI, aChannel);
|
||||
rv = NS_NewChannel(aChannel,
|
||||
aURI,
|
||||
nsContentUtils::GetSystemPrincipal(),
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_OTHER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_ARG_POINTER(*aChannel);
|
||||
|
||||
|
@ -1895,18 +1895,16 @@ nsPermissionManager::ImportDefaults()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIIOService> ioservice =
|
||||
do_GetService("@mozilla.org/network/io-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> defaultsURI;
|
||||
rv = NS_NewURI(getter_AddRefs(defaultsURI), defaultsURL,
|
||||
nullptr, nullptr, ioservice);
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(defaultsURI), defaultsURL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = ioservice->NewChannelFromURI(defaultsURI, getter_AddRefs(channel));
|
||||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
defaultsURI,
|
||||
nsContentUtils::GetSystemPrincipal(),
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_OTHER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "nsCRT.h"
|
||||
#include "nspr.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
extern PRLogModuleInfo *MCD;
|
||||
|
||||
@ -253,26 +254,23 @@ nsresult nsReadConfig::openAndEvaluateJSFile(const char *aFileName, int32_t obsc
|
||||
return rv;
|
||||
|
||||
} else {
|
||||
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsAutoCString location("resource://gre/defaults/autoconfig/");
|
||||
location += aFileName;
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = ioService->NewURI(location, nullptr, nullptr, getter_AddRefs(uri));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
rv = NS_NewURI(getter_AddRefs(uri), location);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = ioService->NewChannelFromURI(uri, getter_AddRefs(channel));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
rv = NS_NewChannel(getter_AddRefs(channel),
|
||||
uri,
|
||||
nsContentUtils::GetSystemPrincipal(),
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_OTHER);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = channel->Open(getter_AddRefs(inStr));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
uint64_t fs64;
|
||||
|
@ -418,36 +418,20 @@ ClientTiledPaintedLayer::RenderLayer()
|
||||
ToClientLayer(GetMaskLayer())->RenderLayer();
|
||||
}
|
||||
|
||||
// For more complex cases we need to calculate a bunch of metrics before we
|
||||
// can do the paint.
|
||||
BeginPaint();
|
||||
if (mPaintData.mPaintFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In some cases we can take a fast path and just be done with it.
|
||||
if (UseFastPath()) {
|
||||
TILING_LOG("TILING %p: Taking fast-path\n", this);
|
||||
mValidRegion = neededRegion;
|
||||
|
||||
// Make sure that tiles that fall outside of the visible region or outside of the
|
||||
// critical displayport are discarded on the first update. Also make sure that we
|
||||
// only draw stuff inside the critical displayport on the first update.
|
||||
if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
|
||||
mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
|
||||
invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
|
||||
}
|
||||
|
||||
if (invalidRegion.IsEmpty()) {
|
||||
EndPaint();
|
||||
return;
|
||||
}
|
||||
|
||||
mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution);
|
||||
mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, callback, data);
|
||||
ClientManager()->Hold(this);
|
||||
mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
|
||||
EndPaint();
|
||||
return;
|
||||
}
|
||||
|
||||
// For more complex cases we need to calculate a bunch of metrics before we
|
||||
// can do the paint.
|
||||
BeginPaint();
|
||||
if (mPaintData.mPaintFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2137,13 +2137,8 @@ IsCoercionCall(ModuleCompiler &m, ParseNode *pn, AsmJSCoercion *coercion, ParseN
|
||||
return true;
|
||||
}
|
||||
|
||||
if (global->isSimdCtor() ||
|
||||
(global->isSimdOperation() && global->simdOperation() == AsmJSSimdOperation_check))
|
||||
{
|
||||
AsmJSSimdType type = global->isSimdCtor()
|
||||
? global->simdCtorType()
|
||||
: global->simdOperationType();
|
||||
switch (type) {
|
||||
if (global->isSimdOperation() && global->simdOperation() == AsmJSSimdOperation_check) {
|
||||
switch (global->simdOperationType()) {
|
||||
case AsmJSSimdType_int32x4:
|
||||
*coercion = AsmJS_ToInt32x4;
|
||||
return true;
|
||||
@ -5572,12 +5567,7 @@ class CheckSimdVectorScalarArgs
|
||||
}
|
||||
|
||||
// Second argument is the scalar
|
||||
Type coercedFormalType = SimdToCoercedScalarType(formalSimdType_);
|
||||
if (!(actualType <= coercedFormalType)) {
|
||||
return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
|
||||
coercedFormalType.toChars());
|
||||
}
|
||||
return true;
|
||||
return CheckSimdScalarArgs(formalSimdType_)(f, arg, argIndex, actualType, def);
|
||||
}
|
||||
};
|
||||
|
||||
@ -5981,11 +5971,6 @@ CheckSimdCtorCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Gl
|
||||
{
|
||||
MOZ_ASSERT(call->isKind(PNK_CALL));
|
||||
|
||||
AsmJSCoercion coercion;
|
||||
ParseNode *argNode;
|
||||
if (IsCoercionCall(f.m(), call, &coercion, &argNode))
|
||||
return CheckCoercionArg(f, argNode, coercion, def, type);
|
||||
|
||||
AsmJSSimdType simdType = global->simdCtorType();
|
||||
unsigned length = SimdTypeToLength(simdType);
|
||||
DefinitionVector defs;
|
||||
|
@ -350,17 +350,6 @@ SimdTypeDescr::call(JSContext *cx, unsigned argc, Value *vp)
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
Rooted<SimdTypeDescr*> descr(cx, &args.callee().as<SimdTypeDescr>());
|
||||
if (args.length() == 1) {
|
||||
// SIMD type used as a coercion
|
||||
if (!CheckVectorObject(args[0], descr->type())) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR);
|
||||
return false;
|
||||
}
|
||||
|
||||
args.rval().setObject(args[0].toObject());
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(size_t(static_cast<TypeDescr*>(descr)->size()) <= InlineTypedObject::MaximumSize,
|
||||
"inline storage is needed for using InternalHandle belows");
|
||||
|
||||
@ -733,27 +722,18 @@ FuncWith(JSContext *cx, unsigned argc, Value *vp)
|
||||
typedef typename V::Elem Elem;
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 2 || !IsVectorObject<V>(args[0]) ||
|
||||
(!args[1].isNumber() && !args[1].isBoolean()))
|
||||
{
|
||||
if (args.length() != 2 || !IsVectorObject<V>(args[0]))
|
||||
return ErrorBadArgs(cx);
|
||||
}
|
||||
|
||||
Elem *val = TypedObjectMemory<Elem *>(args[0]);
|
||||
Elem *vec = TypedObjectMemory<Elem *>(args[0]);
|
||||
Elem result[V::lanes];
|
||||
|
||||
if (args[1].isNumber()) {
|
||||
Elem withAsNumber;
|
||||
if (!V::toType(cx, args[1], &withAsNumber))
|
||||
return false;
|
||||
for (unsigned i = 0; i < V::lanes; i++)
|
||||
result[i] = OpWith<Elem>::apply(i, withAsNumber, val[i]);
|
||||
} else {
|
||||
MOZ_ASSERT(args[1].isBoolean());
|
||||
bool withAsBool = args[1].toBoolean();
|
||||
for (unsigned i = 0; i < V::lanes; i++)
|
||||
result[i] = OpWith<Elem>::apply(i, withAsBool, val[i]);
|
||||
}
|
||||
Elem value;
|
||||
if (!V::toType(cx, args[1], &value))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < V::lanes; i++)
|
||||
result[i] = OpWith<Elem>::apply(i, value, vec[i]);
|
||||
return StoreResult<V>(cx, args, result);
|
||||
}
|
||||
|
||||
@ -827,7 +807,7 @@ Int32x4BinaryScalar(JSContext *cx, unsigned argc, Value *vp)
|
||||
return ErrorBadArgs(cx);
|
||||
|
||||
int32_t result[4];
|
||||
if (!IsVectorObject<Int32x4>(args[0]) || !args[1].isNumber())
|
||||
if (!IsVectorObject<Int32x4>(args[0]))
|
||||
return ErrorBadArgs(cx);
|
||||
|
||||
int32_t *val = TypedObjectMemory<int32_t *>(args[0]);
|
||||
@ -922,7 +902,7 @@ FuncSplat(JSContext *cx, unsigned argc, Value *vp)
|
||||
typedef typename Vret::Elem RetElem;
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (args.length() != 1 || !args[0].isNumber())
|
||||
if (args.length() != 1)
|
||||
return ErrorBadArgs(cx);
|
||||
|
||||
RetElem arg;
|
||||
|
@ -273,7 +273,10 @@ struct Float32x4 {
|
||||
return a;
|
||||
}
|
||||
static bool toType(JSContext *cx, JS::HandleValue v, Elem *out) {
|
||||
*out = v.toNumber();
|
||||
double d;
|
||||
if (!ToNumber(cx, v, &d))
|
||||
return false;
|
||||
*out = float(d);
|
||||
return true;
|
||||
}
|
||||
static void setReturn(CallArgs &args, Elem value) {
|
||||
@ -293,8 +296,7 @@ struct Float64x2 {
|
||||
return a;
|
||||
}
|
||||
static bool toType(JSContext *cx, JS::HandleValue v, Elem *out) {
|
||||
*out = v.toNumber();
|
||||
return true;
|
||||
return ToNumber(cx, v, out);
|
||||
}
|
||||
static void setReturn(CallArgs &args, Elem value) {
|
||||
args.rval().setDouble(JS::CanonicalizeNaN(value));
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -28,8 +28,10 @@ function assertEqX4(real, expected, assertFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// Load / Store
|
||||
var IMPORTS = USE_ASM + 'var H=new glob.Uint8Array(heap); var i4=glob.SIMD.int32x4; var load=i4.load; var store=i4.store;';
|
||||
var IMPORTS = USE_ASM + 'var H=new glob.Uint8Array(heap); var i4=glob.SIMD.int32x4; var ci4=i4.check; var load=i4.load; var store=i4.store;';
|
||||
|
||||
// Bad number of args
|
||||
assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load();} return f");
|
||||
@ -63,9 +65,9 @@ assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load(H, " + (IN
|
||||
assertAsmTypeFail('glob', 'ffi', 'heap', IMPORTS + "function f(){load(H, " + (INT32_MAX + 1 - 15) + ");} return f");
|
||||
asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f(){load(H, " + (INT32_MAX + 1 - 16) + ");} return f");
|
||||
|
||||
assertAsmLinkFail(asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f() {return i4(load(H, " + (BUF_MIN - 15) + "));} return f"), this, {}, buf);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f() {return i4(load(H, " + (BUF_MIN - 16) + "));} return f"), this, {}, buf)(), [4, 3, 2, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f() {return i4(load(H, " + BUF_MIN + " - 16 | 0));} return f"), this, {}, buf)(), [4, 3, 2, 1]);
|
||||
assertAsmLinkFail(asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f() {return ci4(load(H, " + (BUF_MIN - 15) + "));} return f"), this, {}, buf);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f() {return ci4(load(H, " + (BUF_MIN - 16) + "));} return f"), this, {}, buf)(), [4, 3, 2, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', IMPORTS + "function f() {return ci4(load(H, " + BUF_MIN + " - 16 | 0));} return f"), this, {}, buf)(), [4, 3, 2, 1]);
|
||||
|
||||
var CONSTANT_INDEX = 42;
|
||||
var CONSTANT_BYTE_INDEX = CONSTANT_INDEX << 2;
|
||||
@ -78,33 +80,35 @@ var loadStoreCode = `
|
||||
var i4 = glob.SIMD.int32x4;
|
||||
var i4load = i4.load;
|
||||
var i4store = i4.store;
|
||||
var ci4 = i4.check;
|
||||
|
||||
var f4 = glob.SIMD.float32x4;
|
||||
var f4load = f4.load;
|
||||
var f4store = f4.store;
|
||||
var cf4 = f4.check;
|
||||
|
||||
function f32l(i) { i=i|0; return f4(f4load(H, i|0)); }
|
||||
function f32lcst() { return f4(f4load(H, ${CONSTANT_BYTE_INDEX})); }
|
||||
function f32s(i, vec) { i=i|0; vec=f4(vec); f4store(H, i|0, vec); }
|
||||
function f32scst(vec) { vec=f4(vec); f4store(H, ${CONSTANT_BYTE_INDEX}, vec); }
|
||||
function f32l(i) { i=i|0; return cf4(f4load(H, i|0)); }
|
||||
function f32lcst() { return cf4(f4load(H, ${CONSTANT_BYTE_INDEX})); }
|
||||
function f32s(i, vec) { i=i|0; vec=cf4(vec); f4store(H, i|0, vec); }
|
||||
function f32scst(vec) { vec=cf4(vec); f4store(H, ${CONSTANT_BYTE_INDEX}, vec); }
|
||||
|
||||
function i32l(i) { i=i|0; return i4(i4load(H, i|0)); }
|
||||
function i32lcst() { return i4(i4load(H, ${CONSTANT_BYTE_INDEX})); }
|
||||
function i32s(i, vec) { i=i|0; vec=i4(vec); i4store(H, i|0, vec); }
|
||||
function i32scst(vec) { vec=i4(vec); i4store(H, ${CONSTANT_BYTE_INDEX}, vec); }
|
||||
function i32l(i) { i=i|0; return ci4(i4load(H, i|0)); }
|
||||
function i32lcst() { return ci4(i4load(H, ${CONSTANT_BYTE_INDEX})); }
|
||||
function i32s(i, vec) { i=i|0; vec=ci4(vec); i4store(H, i|0, vec); }
|
||||
function i32scst(vec) { vec=ci4(vec); i4store(H, ${CONSTANT_BYTE_INDEX}, vec); }
|
||||
|
||||
function f32lbndcheck(i) {
|
||||
i=i|0;
|
||||
if ((i|0) > ${CONSTANT_BYTE_INDEX}) i=${CONSTANT_BYTE_INDEX};
|
||||
if ((i|0) < 0) i = 0;
|
||||
return f4(f4load(H, i|0));
|
||||
return cf4(f4load(H, i|0));
|
||||
}
|
||||
function f32sbndcheck(i, vec) {
|
||||
i=i|0;
|
||||
vec=f4(vec);
|
||||
vec=cf4(vec);
|
||||
if ((i|0) > ${CONSTANT_BYTE_INDEX}) i=${CONSTANT_BYTE_INDEX};
|
||||
if ((i|0) < 0) i = 0;
|
||||
return f4(f4store(H, i|0, vec));
|
||||
return cf4(f4store(H, i|0, vec));
|
||||
}
|
||||
|
||||
return {
|
||||
@ -169,12 +173,12 @@ var code = `
|
||||
x = (x>>0) < 0 ? 0 : x;
|
||||
// ptr value gets a precise range but the bounds check shouldn't get
|
||||
// eliminated.
|
||||
return f4(f4l(u8, 0xFFFA + x | 0));
|
||||
return f4l(u8, 0xFFFA + x | 0);
|
||||
}
|
||||
|
||||
return g;
|
||||
`;
|
||||
assertThrowsInstanceOf(() =>asmLink(asmCompile('glob', 'ffi', 'heap', code), this, {}, new ArrayBuffer(0x10000))(0), RangeError);
|
||||
assertThrowsInstanceOf(() => asmLink(asmCompile('glob', 'ffi', 'heap', code), this, {}, new ArrayBuffer(0x10000))(0), RangeError);
|
||||
|
||||
// Float32x4.store
|
||||
function f32s(n, v) { return m.f32s((n|0) << 2 | 0, v); };
|
||||
@ -274,6 +278,7 @@ function MakeCodeFor(typeName) {
|
||||
return `
|
||||
"use asm";
|
||||
var type = glob.SIMD.${typeName};
|
||||
var c = type.check;
|
||||
|
||||
var lx = type.loadX;
|
||||
var lxy = type.loadXY;
|
||||
@ -293,13 +298,13 @@ function MakeCodeFor(typeName) {
|
||||
function loadCstXY() { return lxy(u8, 41 << 2); }
|
||||
function loadCstXYZ() { return lxyz(u8, 41 << 2); }
|
||||
|
||||
function storeX(i, x) { i=i|0; x=type(x); return sx(u8, i, x); }
|
||||
function storeXY(i, x) { i=i|0; x=type(x); return sxy(u8, i, x); }
|
||||
function storeXYZ(i, x) { i=i|0; x=type(x); return sxyz(u8, i, x); }
|
||||
function storeX(i, x) { i=i|0; x=c(x); return sx(u8, i, x); }
|
||||
function storeXY(i, x) { i=i|0; x=c(x); return sxy(u8, i, x); }
|
||||
function storeXYZ(i, x) { i=i|0; x=c(x); return sxyz(u8, i, x); }
|
||||
|
||||
function storeCstX(x) { x=type(x); return sx(u8, 41 << 2, x); }
|
||||
function storeCstXY(x) { x=type(x); return sxy(u8, 41 << 2, x); }
|
||||
function storeCstXYZ(x) { x=type(x); return sxyz(u8, 41 << 2, x); }
|
||||
function storeCstX(x) { x=c(x); return sx(u8, 41 << 2, x); }
|
||||
function storeCstXY(x) { x=c(x); return sxy(u8, 41 << 2, x); }
|
||||
function storeCstXYZ(x) { x=c(x); return sxyz(u8, 41 << 2, x); }
|
||||
|
||||
return {
|
||||
loadX: loadX,
|
||||
@ -505,3 +510,5 @@ TestPartialLoads(mint32x4, i32,
|
||||
TestPartialStores(mint32x4, i32, 'int32x4', 42, -3, 13, 37);
|
||||
|
||||
})();
|
||||
|
||||
} catch (e) { print('stack: ', e.stack); throw e }
|
||||
|
@ -10,10 +10,12 @@ if (!isSimdAvailable() || typeof SIMD === 'undefined') {
|
||||
}
|
||||
|
||||
const I32 = 'var i4 = glob.SIMD.int32x4;'
|
||||
const CI32 = 'var ci4 = i4.check;'
|
||||
const I32A = 'var i4a = i4.add;'
|
||||
const I32S = 'var i4s = i4.sub;'
|
||||
const I32M = 'var i4m = i4.mul;'
|
||||
const F32 = 'var f4 = glob.SIMD.float32x4;'
|
||||
const CF32 = 'var cf4 = f4.check;'
|
||||
const F32A = 'var f4a = f4.add;'
|
||||
const F32S = 'var f4s = f4.sub;'
|
||||
const F32M = 'var f4m = f4.mul;'
|
||||
@ -37,15 +39,15 @@ function assertEqX4(real, expected, assertFunc) {
|
||||
|
||||
function CheckI4(header, code, expected) {
|
||||
// code needs to contain a local called x
|
||||
header = USE_ASM + I32 + F32 + header;
|
||||
var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return i4(x)} return f'), this)();
|
||||
header = USE_ASM + I32 + CI32 + F32 + header;
|
||||
var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return ci4(x)} return f'), this)();
|
||||
assertEqX4(observed, expected);
|
||||
}
|
||||
|
||||
function CheckF4(header, code, expected) {
|
||||
// code needs to contain a local called x
|
||||
header = USE_ASM + F32 + header;
|
||||
var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return f4(x)} return f'), this)();
|
||||
header = USE_ASM + F32 + CF32 + header;
|
||||
var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return cf4(x)} return f'), this)();
|
||||
assertEqX4(observed, expected.map(Math.fround));
|
||||
}
|
||||
|
||||
@ -119,27 +121,27 @@ assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(i) {var x=f4(1,2,3,i
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {return +i4(1,2,3,4)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {return i4(1,2,3,4)|0} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f() {return f32(i4(1,2,3,4))} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f() {return f4(i4(1,2,3,4))} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + "function f() {return cf4(i4(1,2,3,4))} return f");
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {return +f4(1,2,3,4)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {return f4(1,2,3,4)|0} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + FROUND + "function f() {return f32(f4(1,2,3,4))} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f() {return i4(f4(1,2,3,4))} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + "function f() {return ci4(f4(1,2,3,4))} return f");
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {return i4(1,2,3,4);} return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {return i4(i4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f() {return ci4(i4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {return f4(1,2,3,4);} return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {return f4(f4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f() {return cf4(f4(1,2,3,4));} return f"), this)(), [1, 2, 3, 4]);
|
||||
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {i4(1,2,3,4);} return f"), this)(), undefined);
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {f4(1,2,3,4);} return f"), this)(), undefined);
|
||||
|
||||
// Int32x4 ctor should accept int?
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + "var i32=new glob.Int32Array(heap); function f(i) {i=i|0; return i4(i4(i32[i>>2], 2, 3, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [0, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + CI32 + "var i32=new glob.Int32Array(heap); function f(i) {i=i|0; return ci4(i4(i32[i>>2], 2, 3, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [0, 2, 3, 4]);
|
||||
// Float32x4 ctor should accept floatish (i.e. float || float? || floatish) and doublit
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + FROUND + "var h=new glob.Float32Array(heap); function f(i) {i=i|0; return f4(f4(h[i>>2], f32(2), f32(3), f32(4)))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [NaN, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + "function f(i) {i=i|0; return f4(f4(f32(1) + f32(2), f32(2), f32(3), f32(4)))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + FROUND + "function f(i) {i=i|0; return f4(f4(f32(1) + f32(2), 2.0, 3.0, 4.0))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + CF32 + FROUND + "var h=new glob.Float32Array(heap); function f(i) {i=i|0; return cf4(f4(h[i>>2], f32(2), f32(3), f32(4)))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [NaN, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + FROUND + "function f(i) {i=i|0; return cf4(f4(f32(1) + f32(2), f32(2), f32(3), f32(4)))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + FROUND + "function f(i) {i=i|0; return cf4(f4(f32(1) + f32(2), 2.0, 3.0, 4.0))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]);
|
||||
|
||||
// 1.3.2 Reading values out of lanes
|
||||
assertAsmTypeFail('glob', USE_ASM + "function f() {var x=1; return x.y | 0;} return f");
|
||||
@ -240,73 +242,63 @@ assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4)
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f");
|
||||
|
||||
CheckF4('', 'var x=f4(1,2,3,4); var y=f4(4,3,2,1); x=3?y:x', [4, 3, 2, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=x|0; var v=f4(1,2,3,4); var w=f4(5,6,7,8); return f4(x?w:v);} return f"), this)(1), [5,6,7,8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(v) {v=f4(v); var w=f4(5,6,7,8); return f4(4?w:v);} return f"), this)(SIMD.float32x4(1,2,3,4)), [5,6,7,8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(v, x) {v=f4(v); x=x|0; var w=f4(5,6,7,8); return f4(x?w:v);} return f"), this)(SIMD.float32x4(1,2,3,4), 0), [1,2,3,4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=x|0; var v=f4(1,2,3,4); var w=f4(5,6,7,8); return cf4(x?w:v);} return f"), this)(1), [5,6,7,8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(v) {v=cf4(v); var w=f4(5,6,7,8); return cf4(4?w:v);} return f"), this)(SIMD.float32x4(1,2,3,4)), [5,6,7,8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(v, x) {v=cf4(v); x=x|0; var w=f4(5,6,7,8); return cf4(x?w:v);} return f"), this)(SIMD.float32x4(1,2,3,4), 0), [1,2,3,4]);
|
||||
|
||||
CheckI4('', 'var x=i4(1,2,3,4); var y=i4(4,3,2,1); x=(x.x|0)?y:x', [4, 3, 2, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=x|0; var v=i4(1,2,3,4); var w=i4(5,6,7,8); return i4(x?w:v);} return f"), this)(1), [5,6,7,8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(v) {v=i4(v); var w=i4(5,6,7,8); return i4(4?w:v);} return f"), this)(SIMD.int32x4(1,2,3,4)), [5,6,7,8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(v, x) {v=i4(v); x=x|0; var w=i4(5,6,7,8); return i4(x?w:v);} return f"), this)(SIMD.int32x4(1,2,3,4), 0), [1,2,3,4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=x|0; var v=i4(1,2,3,4); var w=i4(5,6,7,8); return ci4(x?w:v);} return f"), this)(1), [5,6,7,8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v) {v=ci4(v); var w=i4(5,6,7,8); return ci4(4?w:v);} return f"), this)(SIMD.int32x4(1,2,3,4)), [5,6,7,8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(v, x) {v=ci4(v); x=x|0; var w=i4(5,6,7,8); return ci4(x?w:v);} return f"), this)(SIMD.int32x4(1,2,3,4), 0), [1,2,3,4]);
|
||||
|
||||
// 1.3.4 Return values
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1; return i4(x)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1; return i4(x + x)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1.; return i4(x)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f() {var x=f32(1.); return i4(x)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {var x=1; return ci4(x)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {var x=1; return ci4(x + x)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {var x=1.; return ci4(x)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + "function f() {var x=f32(1.); return ci4(x)} return f");
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return i4(x)} return f"), this)(), [1,2,3,4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); return f4(x)} return f"), this)(), [1,2,3,4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f() {var x=i4(1,2,3,4); return ci4(x)} return f"), this)(), [1,2,3,4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f() {var x=f4(1,2,3,4); return cf4(x)} return f"), this)(), [1,2,3,4]);
|
||||
|
||||
// 1.3.5 Coerce and pass arguments
|
||||
// Via check
|
||||
const CHECK_I32 = 'var c=i4.check;';
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f() {c();} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f(x) {x=i4(x); c(x, x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f() {c(1);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f() {c(1.);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + FROUND + "function f() {c(f32(1.));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + F32 + "function f(x) {x=f4(x); c(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f(x) {x=i4(x); return 1 + c(x) | 0;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {ci4();} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); ci4(x, x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {ci4(1);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f() {ci4(1.);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + "function f() {ci4(f32(1.));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + CF32 + "function f(x) {x=cf4(x); ci4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return 1 + ci4(x) | 0;} return f");
|
||||
|
||||
var i32x4 = SIMD.int32x4(1, 3, 3, 7);
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + CHECK_I32 + "function f(x) {x=c(x)} return f"), this)(i32x4), undefined);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CHECK_I32 + "function f(x) {x=i4(x); return c(x);} return f"), this)(i32x4), [1,3,3,7]);
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x)} return f"), this)(i32x4), undefined);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return ci4(x);} return f"), this)(i32x4), [1,3,3,7]);
|
||||
|
||||
const CHECK_F32 = 'var c=f4.check;';
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f() {c();} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f(x) {x=f4(x); c(x, x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f() {c(1);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f() {c(1.);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + FROUND + "function f() {c(f32(1.));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + I32 + "function f(x) {x=i4(x); c(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f(x) {x=f4(x); return 1 + c(x) | 0;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f() {cf4();} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); cf4(x, x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f() {cf4(1);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f() {cf4(1.);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + FROUND + "function f() {cf4(f32(1.));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + F32 + CF32 + "function f(x) {x=cf4(x); cf4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return 1 + cf4(x) | 0;} return f");
|
||||
|
||||
var f32x4 = SIMD.float32x4(13.37, 42.42, -0, NaN);
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + CHECK_F32 + "function f(x) {x=c(x)} return f"), this)(f32x4), undefined);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CHECK_F32 + "function f(x) {x=c(x); return c(x);} return f"), this)(f32x4),
|
||||
[Math.fround(13.37), Math.fround(42.42), -0, NaN]);
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x)} return f"), this)(f32x4), undefined);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return cf4(x);} return f"), this)(f32x4), [13.37, 42.42, -0, NaN].map(Math.fround));
|
||||
|
||||
// Legacy coercions
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4();} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4(1,2,3,4);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x,y) {x=i4(y);y=+y} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return i4(x);} return f");
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {return +i4(1,2,3,4)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {return 0|i4(1,2,3,4)} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f(x) {return f32(i4(1,2,3,4))} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(x) {return f4(i4(1,2,3,4))} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return f4(x);} return f");
|
||||
|
||||
var i32x4 = SIMD.int32x4(1, 3, 3, 7);
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=i4(x)} return f"), this)(i32x4), undefined);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=i4(x); return i4(x);} return f"), this)(i32x4), [1,3,3,7]);
|
||||
|
||||
var f32x4 = SIMD.float32x4(13.37, 42.42, -0, NaN);
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=f4(x)} return f"), this)(f32x4), undefined);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=f4(x); return f4(x);} return f"), this)(f32x4),
|
||||
[Math.fround(13.37), Math.fround(42.42), -0, NaN]);
|
||||
|
||||
function assertCaught(f) {
|
||||
var caught = false;
|
||||
@ -320,14 +312,14 @@ function assertCaught(f) {
|
||||
assertEq(caught, true);
|
||||
}
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + F32 + "function f(x) {x=f4(x); return f4(x);} return f"), this);
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return cf4(x);} return f"), this);
|
||||
assertCaught(f);
|
||||
assertCaught(f, 1);
|
||||
assertCaught(f, {});
|
||||
assertCaught(f, "I sincerely am a SIMD typed object.");
|
||||
assertCaught(f, SIMD.int32x4(1,2,3,4));
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + "function f(x) {x=i4(x); return i4(x);} return f"), this);
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return ci4(x);} return f"), this);
|
||||
assertCaught(f);
|
||||
assertCaught(f, 1);
|
||||
assertCaught(f, {});
|
||||
@ -345,8 +337,8 @@ assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f(
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4.; x=+g;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); var f32=glob.Math.fround; function f() {var x=f32(4.); x=f32(g);} return f");
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); x=i4(g);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); x=f4(g);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32 + CI32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); x=ci4(g);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); x=cf4(g);} return f");
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0; function f() {var x=i4(1,2,3,4); x=g|0;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "var g=0.; function f() {var x=i4(1,2,3,4); x=+g;} return f");
|
||||
@ -372,10 +364,10 @@ assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f(
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); function f() {var x=4.; g=+x;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + "var g=f4(1., 2., 3., 4.); var f32=glob.Math.fround; function f() {var x=f32(4.); g=f32(x);} return f");
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=i4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=f4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=f4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=i4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32 + CI32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=ci4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32 + CF32 + "var g=f4(1., 2., 3., 4.); function f() {var x=i4(1,2,3,4); g=cf4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=cf4(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + "var g=i4(1,2,3,4); function f() {var x=f4(1.,2.,3.,4.); g=ci4(x);} return f");
|
||||
|
||||
CheckI4('var x=i4(0,0,0,0);', 'x=i4(1,2,3,4)', [1,2,3,4]);
|
||||
CheckF4('var x=f4(0.,0.,0.,0.);', 'x=f4(5.,3.,4.,2.)', [5,3,4,2]);
|
||||
@ -385,32 +377,32 @@ CheckF4('var x=f4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=f4(1,2,3,4); y
|
||||
|
||||
// 1.3.6.2 Imported globals
|
||||
// Read
|
||||
var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + "var g=i4(ffi.g); function f() {return i4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})();
|
||||
var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {return ci4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})();
|
||||
assertEq(int32x4.x, 1);
|
||||
assertEq(int32x4.y, 2);
|
||||
assertEq(int32x4.z, 3);
|
||||
assertEq(int32x4.w, 4);
|
||||
|
||||
for (var v of [1, {}, "totally legit SIMD variable", SIMD.float32x4(1,2,3,4)])
|
||||
assertCaught(asmCompile('glob', 'ffi', USE_ASM + I32 + "var g=i4(ffi.g); function f() {return i4(g)} return f"), this, {g: v});
|
||||
assertCaught(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {return ci4(g)} return f"), this, {g: v});
|
||||
|
||||
var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + "var g=f4(ffi.g); function f() {return f4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})();
|
||||
var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {return cf4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})();
|
||||
assertEq(float32x4.x, 1);
|
||||
assertEq(float32x4.y, 2);
|
||||
assertEq(float32x4.z, 3);
|
||||
assertEq(float32x4.w, 4);
|
||||
|
||||
for (var v of [1, {}, "totally legit SIMD variable", SIMD.int32x4(1,2,3,4)])
|
||||
assertCaught(asmCompile('glob', 'ffi', USE_ASM + F32 + "var g=f4(ffi.g); function f() {return f4(g)} return f"), this, {g: v});
|
||||
assertCaught(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {return cf4(g)} return f"), this, {g: v});
|
||||
|
||||
// Write
|
||||
var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + "var g=i4(ffi.g); function f() {g=i4(4,5,6,7); return i4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})();
|
||||
var int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {g=i4(4,5,6,7); return ci4(g)} return f"), this, {g: SIMD.int32x4(1,2,3,4)})();
|
||||
assertEq(int32x4.x, 4);
|
||||
assertEq(int32x4.y, 5);
|
||||
assertEq(int32x4.z, 6);
|
||||
assertEq(int32x4.w, 7);
|
||||
|
||||
var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + "var g=f4(ffi.g); function f() {g=f4(4.,5.,6.,7.); return f4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})();
|
||||
var float32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {g=f4(4.,5.,6.,7.); return cf4(g)} return f"), this, {g: SIMD.float32x4(1,2,3,4)})();
|
||||
assertEq(float32x4.x, 4);
|
||||
assertEq(float32x4.y, 5);
|
||||
assertEq(float32x4.z, 6);
|
||||
@ -458,31 +450,31 @@ assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); y=f4a(x, y);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32A + "function f() {var x=i4(0,0,0,0); var y=f4(4,3,2,1); x=f4a(y, y);} return f");
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0; y=i4(x,x)|0} return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0.; y=+i4(x,x)} return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0; y=i4a(x,x)|0} return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + I32A + 'function f() {var x=i4(1,2,3,4); var y=0.; y=+i4a(x,x)} return f');
|
||||
|
||||
CheckI4(I32A, 'var z=i4(1,2,3,4); var y=i4(0,1,0,3); var x=i4(0,0,0,0); x=i4a(z,y)', [1,3,3,7]);
|
||||
CheckI4(I32A, 'var x=i4(2,3,4,5); var y=i4(0,1,0,3); x=i4a(x,y)', [2,4,4,8]);
|
||||
CheckI4(I32A, 'var x=i4(1,2,3,4); x=i4a(x,x)', [2,4,6,8]);
|
||||
CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=i4a(x,y)', [INT32_MIN,3,3,7]);
|
||||
CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=i4(i4a(x,y))', [INT32_MIN,3,3,7]);
|
||||
CheckI4(I32A, 'var x=i4(' + INT32_MAX + ',2,3,4); var y=i4(1,1,0,3); x=ci4(i4a(x,y))', [INT32_MIN,3,3,7]);
|
||||
|
||||
CheckF4(F32A, 'var x=f4(1,2,3,4); x=f4a(x,x)', [2,4,6,8]);
|
||||
CheckF4(F32A, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [5,5,8,6]);
|
||||
CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4a(x,y)', [Math.fround(13.37) + 4,5,8,6]);
|
||||
CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4a(x,y))', [Math.fround(13.37) + 4,5,8,6]);
|
||||
CheckF4(F32A, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=cf4(f4a(x,y))', [Math.fround(13.37) + 4,5,8,6]);
|
||||
|
||||
// 2.3.2. Subtracts
|
||||
CheckI4(I32S, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=i4s(x,y)', [2,1,3,2]);
|
||||
CheckI4(I32S, 'var x=i4(5,4,3,2); var y=i4(1,2,3,4); x=i4s(x,y)', [4,2,0,-2]);
|
||||
CheckI4(I32S, 'var x=i4(1,2,3,4); x=i4s(x,x)', [0,0,0,0]);
|
||||
CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=i4s(x,y)', [INT32_MAX,1,3,1]);
|
||||
CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=i4(i4s(x,y))', [INT32_MAX,1,3,1]);
|
||||
CheckI4(I32S, 'var x=i4(' + INT32_MIN + ',2,3,4); var y=i4(1,1,0,3); x=ci4(i4s(x,y))', [INT32_MAX,1,3,1]);
|
||||
|
||||
CheckF4(F32S, 'var x=f4(1,2,3,4); x=f4s(x,x)', [0,0,0,0]);
|
||||
CheckF4(F32S, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [-3,-1,-2,2]);
|
||||
CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4s(x,y)', [Math.fround(13.37) - 4,-1,-2,2]);
|
||||
CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4s(x,y))', [Math.fround(13.37) - 4,-1,-2,2]);
|
||||
CheckF4(F32S, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=cf4(f4s(x,y))', [Math.fround(13.37) - 4,-1,-2,2]);
|
||||
|
||||
// 2.3.3. Multiplications / Divisions
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "var f4d=i4.div; function f() {} return f");
|
||||
@ -501,11 +493,11 @@ CheckI4(I32M, 'var x=i4(1,2,3,4); x=i4m(x,x)', [1,4,9,16]);
|
||||
CheckF4(F32M, 'var x=f4(1,2,3,4); x=f4m(x,x)', [1,4,9,16]);
|
||||
CheckF4(F32M, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [4,6,15,8]);
|
||||
CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [Math.fround(13.37) * 4,6,15,8]);
|
||||
CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4m(x,y))', [Math.fround(13.37) * 4,6,15,8]);
|
||||
CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=cf4(f4m(x,y))', [Math.fround(13.37) * 4,6,15,8]);
|
||||
|
||||
var f32x4 = SIMD.float32x4(0, NaN, -0, NaN);
|
||||
var another = SIMD.float32x4(NaN, -1, -0, NaN);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32M + "function f(x, y) {x=f4(x); y=f4(y); x=f4m(x,y); return f4(x);} return f"), this)(f32x4, another), [NaN, NaN, 0, NaN]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32M + CF32 + "function f(x, y) {x=cf4(x); y=cf4(y); x=f4m(x,y); return cf4(x);} return f"), this)(f32x4, another), [NaN, NaN, 0, NaN]);
|
||||
|
||||
CheckF4(F32D, 'var x=f4(1,2,3,4); x=f4d(x,x)', [1,1,1,1]);
|
||||
CheckF4(F32D, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4d(x,y)', [1/4,2/3,3/5,2]);
|
||||
@ -513,11 +505,11 @@ CheckF4(F32D, 'var x=f4(13.37,1,1,4); var y=f4(4,0,-0.,2); x=f4d(x,y)', [Math.fr
|
||||
|
||||
var f32x4 = SIMD.float32x4(0, 0, -0, NaN);
|
||||
var another = SIMD.float32x4(0, -0, 0, 0);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32D + "function f(x,y) {x=f4(x); y=f4(y); x=f4d(x,y); return f4(x);} return f"), this)(f32x4, another), [NaN, NaN, NaN, NaN]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32D + CF32 + "function f(x,y) {x=cf4(x); y=cf4(y); x=f4d(x,y); return cf4(x);} return f"), this)(f32x4, another), [NaN, NaN, NaN, NaN]);
|
||||
|
||||
// Unary arithmetic operators
|
||||
function CheckUnaryF4(op, checkFunc, assertFunc) {
|
||||
var _ = asmLink(asmCompile('glob', USE_ASM + F32 + 'var op=f4.' + op + '; function f(x){x=f4(x); return f4(op(x)); } return f'), this);
|
||||
var _ = asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + 'var op=f4.' + op + '; function f(x){x=cf4(x); return cf4(op(x)); } return f'), this);
|
||||
return function(input) {
|
||||
var simd = SIMD.float32x4(input[0], input[1], input[2], input[3]);
|
||||
|
||||
@ -528,7 +520,7 @@ function CheckUnaryF4(op, checkFunc, assertFunc) {
|
||||
}
|
||||
|
||||
function CheckUnaryI4(op, checkFunc) {
|
||||
var _ = asmLink(asmCompile('glob', USE_ASM + I32 + 'var op=i4.' + op + '; function f(x){x=i4(x); return i4(op(x)); } return f'), this);
|
||||
var _ = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + 'var op=i4.' + op + '; function f(x){x=ci4(x); return ci4(op(x)); } return f'), this);
|
||||
return function(input) {
|
||||
var simd = SIMD.int32x4(input[0], input[1], input[2], input[3]);
|
||||
assertEqX4(_(simd), input.map(checkFunc).map(function(x) { return x | 0}));
|
||||
@ -622,7 +614,6 @@ const WZF = 'var w = f4.withZ;';
|
||||
const WWF = 'var w = f4.withW;';
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, 1);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, 1.0);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + "function f() {var x = f4(1,2,3,4); x = w(x, x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(1, f32(1));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + WXF + FROUND + "function f() {var x = f4(1,2,3,4); x = w(1., f32(1));} return f");
|
||||
@ -635,6 +626,11 @@ CheckF4(WZF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, 2, Math.
|
||||
CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37));', [1, 2, 3, Math.fround(13.37)]);
|
||||
CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, f32(13.37) + f32(6.63));', [1, 2, 3, Math.fround(Math.fround(13.37) + Math.fround(6.63))]);
|
||||
|
||||
CheckF4(WXF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [Math.fround(13.37), 2, 3, 4]);
|
||||
CheckF4(WYF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [1, Math.fround(13.37), 3, 4]);
|
||||
CheckF4(WZF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [1, 2, Math.fround(13.37), 4]);
|
||||
CheckF4(WWF + FROUND, 'var x = f4(1,2,3,4); x = w(x, 13.37);', [1, 2, 3, Math.fround(13.37)]);
|
||||
|
||||
const WXI = 'var w = i4.withX;';
|
||||
const WYI = 'var w = i4.withY;';
|
||||
const WZI = 'var w = i4.withZ;';
|
||||
@ -729,7 +725,7 @@ assertAsmTypeFail('glob', USE_ASM + F32 + "var cvt=f4.fromFloat32x4; return {}")
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=i4(1,2,3,4); x=cvt(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIF + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f");
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTIF + 'function f(x){x=i4(x); var y=f4(0,0,0,0); y=cvt(x); return f4(y);} return f'), this);
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + CI32 + CVTIF + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); y=cvt(x); return cf4(y);} return f'), this);
|
||||
assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4]);
|
||||
assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, Math.fround(INT32_MIN), Math.fround(INT32_MAX), -1]);
|
||||
|
||||
@ -738,7 +734,7 @@ assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, Math.fround(INT32_MIN)
|
||||
// tests, we assume x86/x64, so a conversion which failed will return the
|
||||
// undefined int32 value. See also bug 1068028.
|
||||
const UNDEFINED_INT32 = 0x80000000 | 0;
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTFI + 'function f(x){x=f4(x); var y=i4(0,0,0,0); y=cvt(x); return i4(y);} return f'), this);
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + CVTFI + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); y=cvt(x); return ci4(y);} return f'), this);
|
||||
assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4]);
|
||||
assertEqX4(f(SIMD.float32x4(NaN,Infinity,-Infinity,-0)), [UNDEFINED_INT32, UNDEFINED_INT32, UNDEFINED_INT32, 0]);
|
||||
|
||||
@ -771,19 +767,19 @@ assertAsmTypeFail('glob', USE_ASM + F32 + "var cvt=f4.fromFloat32x4; return {}")
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=i4(1,2,3,4); x=cvt(x);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f");
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTIFB + 'function f(x){x=i4(x); var y=f4(0,0,0,0); y=cvt(x); return f4(y);} return f'), this);
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTIFB + CF32 + CI32 + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); y=cvt(x); return cf4(y);} return f'), this);
|
||||
assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits));
|
||||
assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits));
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32A + CVTIFB + 'function f(x){x=i4(x); var y=f4(0,0,0,0); var z=f4(1,1,1,1); y=cvt(x); y=f4a(y, z); return f4(y)} return f'), this);
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32A + CVTIFB + CF32 + CI32 + 'function f(x){x=ci4(x); var y=f4(0,0,0,0); var z=f4(1,1,1,1); y=cvt(x); y=f4a(y, z); return cf4(y)} return f'), this);
|
||||
assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits).map((x) => x+1));
|
||||
assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits).map((x) => x+1));
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTFIB + 'function f(x){x=f4(x); var y=i4(0,0,0,0); y=cvt(x); return i4(y);} return f'), this);
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + CVTFIB + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); y=cvt(x); return ci4(y);} return f'), this);
|
||||
assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits));
|
||||
assertEqX4(f(SIMD.float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits));
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + I32A + CVTFIB + 'function f(x){x=f4(x); var y=i4(0,0,0,0); var z=i4(1,1,1,1); y=cvt(x); y=i4a(y,z); return i4(y);} return f'), this);
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + F32 + CF32 + I32A + CVTFIB + 'function f(x){x=cf4(x); var y=i4(0,0,0,0); var z=i4(1,1,1,1); y=cvt(x); y=i4a(y,z); return ci4(y);} return f'), this);
|
||||
assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits).map((x) => x+1));
|
||||
assertEqX4(f(SIMD.float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits).map((x) => x+1));
|
||||
|
||||
@ -826,10 +822,10 @@ const LSHI = 'var lsh=i4.shiftLeftByScalar;'
|
||||
const RSHI = 'var rsh=i4.shiftRightArithmeticByScalar;'
|
||||
const URSHI = 'var ursh=i4.shiftRightLogicalByScalar;'
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return i4(lsh(x,f32(42)));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return i4(lsh(x,42));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return i4(lsh(x,42.0));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return i4(lsh(x,f32(42)));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return ci4(lsh(x,f32(42)));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return ci4(lsh(x,42));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return ci4(lsh(x,42.0));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return ci4(lsh(x,f32(42)));} return f");
|
||||
|
||||
var input = 'i4(0, 1, ' + INT32_MIN + ', ' + INT32_MAX + ')';
|
||||
var vinput = [0, 1, INT32_MIN, INT32_MAX];
|
||||
@ -841,9 +837,9 @@ function Lsh(i) { if (i > 31) return () => 0; return function(x) { return (x <<
|
||||
function Rsh(i) { if (i > 31) return (x) => (x<0)?-1:0; return function(x) { return (x >> i) | 0 } }
|
||||
function Ursh(i) { if (i > 31) return () => 0; return function(x) { return (x >>> i) | 0 } }
|
||||
|
||||
var asmLsh = asmLink(asmCompile('glob', USE_ASM + I32 + LSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return i4(lsh(v, x+y))} return f;'), this)
|
||||
var asmRsh = asmLink(asmCompile('glob', USE_ASM + I32 + RSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return i4(rsh(v, x+y))} return f;'), this)
|
||||
var asmUrsh = asmLink(asmCompile('glob', USE_ASM + I32 + URSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return i4(ursh(v, x+y))} return f;'), this)
|
||||
var asmLsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + LSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(lsh(v, x+y))} return f;'), this)
|
||||
var asmRsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + RSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(rsh(v, x+y))} return f;'), this)
|
||||
var asmUrsh = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + URSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return ci4(ursh(v, x+y))} return f;'), this)
|
||||
|
||||
for (var i = 1; i < 64; i++) {
|
||||
CheckI4(LSHI, 'var x=' + input + '; x=lsh(x, ' + i + ')', vinput.map(Lsh(i)));
|
||||
@ -861,51 +857,51 @@ const F32SEL = 'var f4sel = f4.select;'
|
||||
const I32BSEL = 'var i4sel = i4.bitselect;'
|
||||
const F32BSEL = 'var f4sel = f4.bitselect;'
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32SEL + "function f() {var x=f4(1,2,3,4); return i4(i4sel(x,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return i4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=f4(1,2,3,4); return i4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); return i4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=i4(1,2,3,4); var y=f4(5,6,7,8); return i4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return i4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var x=f4(1,2,3,4); return ci4(i4sel(x,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=i4(1,2,3,4); var y=f4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + F32SEL + "function f() {var m=f4(1,2,3,4); return f4(f4sel(x,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return f4(f4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=f4(1,2,3,4); var x=f4(1,2,3,4); return f4(f4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=i4(5,6,7,8); return f4(f4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(1,2,3,4); var x=i4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + F32SEL + "function f() {var m=f4(1,2,3,4); return cf4(f4sel(x,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return cf4(f4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=f4(1,2,3,4); var x=f4(1,2,3,4); return cf4(f4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=i4(5,6,7,8); return cf4(f4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(1,2,3,4); var x=i4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y));} return f");
|
||||
|
||||
// These pass with select but not bitselect
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SEL + "function f() {var m=i4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SEL + "function f() {var m=i4(-1,-2,-3,-42); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SEL + "function f() {var m=i4(1,-1,2,-2); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SEL + "function f() {var m=i4(42,45,-42,-47); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(-1,-2,-3,-42); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(1,-1,2,-2); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(42,45,-42,-47); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(-1,-2,-3,-42); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(1,-1,2,-2); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(42,45,-42,-47); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(-1,-2,-3,-42); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(1,-1,2,-2); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(42,45,-42,-47); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
// These pass for both select and bitselect
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SEL + "function f() {var m=i4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32BSEL + "function f() {var m=i4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32BSEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32BSEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32BSEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return i4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f() {var m=i4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32BSEL + "function f() {var m=i4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32BSEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32BSEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32BSEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32BSEL + "function f() {var m=i4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32BSEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32BSEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32BSEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
// Specific bitselect tests
|
||||
var masks = [
|
||||
@ -921,7 +917,7 @@ var inputs = [
|
||||
[SIMD.int32x4(-1, 2, INT32_MAX, INT32_MIN), SIMD.int32x4(INT32_MAX, -4, INT32_MIN, 42)]
|
||||
];
|
||||
|
||||
var i32bsel = asmLink(asmCompile('glob', USE_ASM + I32 + I32BSEL + "function f(mask, ifTrue, ifFalse) {mask=i4(mask); ifTrue=i4(ifTrue); ifFalse=i4(ifFalse); return i4(i4sel(mask,ifTrue,ifFalse)); } return f"), this)
|
||||
var i32bsel = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f(mask, ifTrue, ifFalse) {mask=ci4(mask); ifTrue=ci4(ifTrue); ifFalse=ci4(ifFalse); return ci4(i4sel(mask,ifTrue,ifFalse)); } return f"), this)
|
||||
|
||||
for (var mask of masks) {
|
||||
for (var [x, y] of inputs) {
|
||||
@ -935,7 +931,7 @@ inputs = [
|
||||
[SIMD.float32x4(1.5,2.75,NaN,Infinity), SIMD.float32x4(-NaN,-Infinity,9.75,16.125)]
|
||||
];
|
||||
|
||||
var f32bsel = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32BSEL + "function f(mask, ifTrue, ifFalse) {mask=i4(mask); ifTrue=f4(ifTrue); ifFalse=f4(ifFalse); return f4(f4sel(mask,ifTrue,ifFalse)); } return f"), this)
|
||||
var f32bsel = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CI32 + CF32 + F32BSEL + "function f(mask, ifTrue, ifFalse) {mask=ci4(mask); ifTrue=cf4(ifTrue); ifFalse=cf4(ifFalse); return cf4(f4sel(mask,ifTrue,ifFalse)); } return f"), this)
|
||||
|
||||
for (var mask of masks)
|
||||
for (var [x, y] of inputs)
|
||||
@ -953,28 +949,28 @@ assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat(1.0);} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + FROUND + "function f() {var m=i4(1,2,3,4); m=splat(f32(1.0));} return f");
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SPLAT + 'function f(){return i4(splat(42));} return f'), this)(), [42, 42, 42, 42]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SPLAT + 'function f(){return ci4(splat(42));} return f'), this)(), [42, 42, 42, 42]);
|
||||
|
||||
const l33t = Math.fround(13.37);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(f32(1)));} return f'), this)(), [1, 1, 1, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(1.0));} return f'), this)(), [1, 1, 1, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(f32(1 >>> 0)));} return f'), this)(), [1, 1, 1, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(f32(13.37)));} return f'), this)(), [l33t, l33t, l33t, l33t]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(13.37));} return f'), this)(), [l33t, l33t, l33t, l33t]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(1)));} return f'), this)(), [1, 1, 1, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(1.0));} return f'), this)(), [1, 1, 1, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(1 >>> 0)));} return f'), this)(), [1, 1, 1, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(13.37)));} return f'), this)(), [l33t, l33t, l33t, l33t]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(13.37));} return f'), this)(), [l33t, l33t, l33t, l33t]);
|
||||
|
||||
var i32view = new Int32Array(heap);
|
||||
var f32view = new Float32Array(heap);
|
||||
i32view[0] = 42;
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + I32SPLAT + 'var i32=new glob.Int32Array(heap); function f(){return i4(splat(i32[0]));} return f'), this, {}, heap)(), [42, 42, 42, 42]);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + CI32 + I32SPLAT + 'var i32=new glob.Int32Array(heap); function f(){return ci4(splat(i32[0]));} return f'), this, {}, heap)(), [42, 42, 42, 42]);
|
||||
f32view[0] = 42;
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + F32SPLAT + 'var f32=new glob.Float32Array(heap); function f(){return f4(splat(f32[0]));} return f'), this, {}, heap)(), [42, 42, 42, 42]);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(f32(1) + f32(2)));} return f'), this, {}, heap)(), [3, 3, 3, 3]);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + CF32 + F32SPLAT + 'var f32=new glob.Float32Array(heap); function f(){return cf4(splat(f32[0]));} return f'), this, {}, heap)(), [42, 42, 42, 42]);
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(1) + f32(2)));} return f'), this, {}, heap)(), [3, 3, 3, 3]);
|
||||
|
||||
// Dead code
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); return i4(x); x=i4(5,6,7,8); return i4(x);} return f'), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); c=x.x|0; return i4(x);} return f'), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32A + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); x=i4a(x,x); return i4(x);} return f'), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32S + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); x=i4s(x,x); return i4(x);} return f'), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + 'function f(){var x=i4(1,2,3,4); return ci4(x); x=i4(5,6,7,8); return ci4(x);} return f'), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + 'function f(){var x=i4(1,2,3,4); var c=0; return ci4(x); c=x.x|0; return ci4(x);} return f'), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32A + 'function f(){var x=i4(1,2,3,4); var c=0; return ci4(x); x=i4a(x,x); return ci4(x);} return f'), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32S + 'function f(){var x=i4(1,2,3,4); var c=0; return ci4(x); x=i4s(x,x); return ci4(x);} return f'), this)(), [1, 2, 3, 4]);
|
||||
|
||||
// Swizzle
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x, -1, 0, 0, 0);} return f");
|
||||
@ -1093,7 +1089,7 @@ assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f(
|
||||
// 3.3 Internal calls
|
||||
// asm.js -> asm.js
|
||||
// Retrieving values from asm.js
|
||||
var code = USE_ASM + I32 + I32A + `
|
||||
var code = USE_ASM + I32 + CI32 + I32A + `
|
||||
var check = ffi.check;
|
||||
|
||||
function g() {
|
||||
@ -1105,15 +1101,15 @@ var code = USE_ASM + I32 + I32A + `
|
||||
y = i4a(z, y);
|
||||
y = i4a(w, y);
|
||||
check(y.x | 0, y.y | 0, y.z | 0, y.w | 0);
|
||||
return i4(y);
|
||||
return ci4(y);
|
||||
}
|
||||
|
||||
function f(x) {
|
||||
x = i4(x);
|
||||
x = ci4(x);
|
||||
var y = i4(0,0,0,0);
|
||||
y = i4(g());
|
||||
y = ci4(g());
|
||||
check(y.x | 0, y.y | 0, y.z | 0, y.w | 0);
|
||||
return i4(x);
|
||||
return ci4(x);
|
||||
}
|
||||
return f;
|
||||
`;
|
||||
@ -1130,7 +1126,7 @@ assertEqX4(asmLink(asmCompile('glob', 'ffi', code), this, ffi)(v4), [1,2,3,4]);
|
||||
|
||||
// Passing arguments from asm.js to asm.js
|
||||
// TODO make this code look better with templatized strings
|
||||
var code = USE_ASM + I32 + I32A + `
|
||||
var code = USE_ASM + I32 + CI32 + I32A + `
|
||||
var assertEq = ffi.assertEq;
|
||||
|
||||
function internal([args]) {
|
||||
@ -1156,7 +1152,7 @@ for (var i = 1; i < 10; ++i) {
|
||||
var j = i;
|
||||
args += ((i > 1) ? ', ':'') + 'x' + i;
|
||||
decls += 'var x' + i + ' = i4(' + j++ + ', ' + j++ + ', ' + j++ + ', ' + j++ + ');\n';
|
||||
coerc += 'x' + i + ' = i4(x' + i + ');\n';
|
||||
coerc += 'x' + i + ' = ci4(x' + i + ');\n';
|
||||
last = 'x' + i;
|
||||
var c = code.replace(/\[args\]/g, args)
|
||||
.replace(/\[last\]/g, last)
|
||||
@ -1232,6 +1228,7 @@ asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)();
|
||||
var code = `
|
||||
"use asm";
|
||||
var i4 = glob.SIMD.int32x4;
|
||||
var ci4 = i4.check;
|
||||
function h(
|
||||
// In registers:
|
||||
gpr1, gpr2, gpr3, gpr4, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8,
|
||||
@ -1254,13 +1251,13 @@ asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)();
|
||||
xmm8=+xmm8;
|
||||
|
||||
sint1=sint1|0;
|
||||
ssimd1=i4(ssimd1);
|
||||
ssimd1=ci4(ssimd1);
|
||||
sdouble1=+sdouble1;
|
||||
ssimd2=i4(ssimd2);
|
||||
ssimd2=ci4(ssimd2);
|
||||
sint2=sint2|0;
|
||||
sint3=sint3|0;
|
||||
sint4=sint4|0;
|
||||
ssimd3=i4(ssimd3);
|
||||
ssimd3=ci4(ssimd3);
|
||||
sdouble2=+sdouble2;
|
||||
|
||||
return (ssimd1.x|0) + (ssimd2.y|0) + (ssimd3.z|0) + sint2 + gpr3 | 0;
|
||||
@ -1290,6 +1287,7 @@ asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)();
|
||||
"use asm";
|
||||
var i4 = glob.SIMD.int32x4;
|
||||
var i4a = i4.add;
|
||||
var ci4 = i4.check;
|
||||
function _() {
|
||||
var i = 0;
|
||||
var n = i4(0,0,0,0);
|
||||
@ -1297,7 +1295,7 @@ asmLink(asmCompile('glob', 'ffi', code), this, assertEqFFI)();
|
||||
for (; (i>>>0) < ` + iters + `; i=(i+1)>>>0) {
|
||||
n = i4a(n, one);
|
||||
}
|
||||
return i4(n);
|
||||
return ci4(n);
|
||||
}
|
||||
return _;`;
|
||||
// This test relies on the fact that setting the timeout will call the
|
||||
|
@ -665,17 +665,26 @@ CodeGenerator::getJumpLabelForBranch(MBasicBlock *block)
|
||||
void
|
||||
CodeGenerator::visitTestOAndBranch(LTestOAndBranch *lir)
|
||||
{
|
||||
MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(),
|
||||
"Objects which can't emulate undefined should have been constant-folded");
|
||||
|
||||
OutOfLineTestObject *ool = new(alloc()) OutOfLineTestObject();
|
||||
addOutOfLineCode(ool, lir->mir());
|
||||
MIRType inputType = lir->mir()->input()->type();
|
||||
MOZ_ASSERT(inputType == MIRType_ObjectOrNull || lir->mir()->operandMightEmulateUndefined(),
|
||||
"If the object couldn't emulate undefined, this should have been folded.");
|
||||
|
||||
Label *truthy = getJumpLabelForBranch(lir->ifTruthy());
|
||||
Label *falsy = getJumpLabelForBranch(lir->ifFalsy());
|
||||
Register input = ToRegister(lir->input());
|
||||
|
||||
testObjectEmulatesUndefined(ToRegister(lir->input()), falsy, truthy,
|
||||
ToRegister(lir->temp()), ool);
|
||||
if (lir->mir()->operandMightEmulateUndefined()) {
|
||||
if (inputType == MIRType_ObjectOrNull)
|
||||
masm.branchTestPtr(Assembler::Zero, input, input, falsy);
|
||||
|
||||
OutOfLineTestObject *ool = new(alloc()) OutOfLineTestObject();
|
||||
addOutOfLineCode(ool, lir->mir());
|
||||
|
||||
testObjectEmulatesUndefined(input, falsy, truthy, ToRegister(lir->temp()), ool);
|
||||
} else {
|
||||
MOZ_ASSERT(inputType == MIRType_ObjectOrNull);
|
||||
testZeroEmitBranch(Assembler::NotEqual, input, lir->ifTruthy(), lir->ifFalsy());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -2553,14 +2562,23 @@ CodeGenerator::visitTypeBarrierV(LTypeBarrierV *lir)
|
||||
void
|
||||
CodeGenerator::visitTypeBarrierO(LTypeBarrierO *lir)
|
||||
{
|
||||
MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly);
|
||||
|
||||
Register obj = ToRegister(lir->object());
|
||||
Register scratch = ToTempRegisterOrInvalid(lir->temp());
|
||||
Label miss, ok;
|
||||
|
||||
if (lir->mir()->type() == MIRType_ObjectOrNull) {
|
||||
Label *nullTarget = lir->mir()->resultTypeSet()->mightBeMIRType(MIRType_Null) ? &ok : &miss;
|
||||
masm.branchTestPtr(Assembler::Zero, obj, obj, nullTarget);
|
||||
} else {
|
||||
MOZ_ASSERT(lir->mir()->type() == MIRType_Object);
|
||||
MOZ_ASSERT(lir->mir()->barrierKind() != BarrierKind::TypeTagOnly);
|
||||
}
|
||||
|
||||
if (lir->mir()->barrierKind() != BarrierKind::TypeTagOnly)
|
||||
masm.guardObjectType(obj, lir->mir()->resultTypeSet(), scratch, &miss);
|
||||
|
||||
Label miss;
|
||||
masm.guardObjectType(obj, lir->mir()->resultTypeSet(), scratch, &miss);
|
||||
bailoutFrom(&miss, lir->snapshot());
|
||||
masm.bind(&ok);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2519,11 +2519,18 @@ TryEliminateTypeBarrier(MTypeBarrier *barrier, bool *eliminated)
|
||||
}
|
||||
|
||||
static bool
|
||||
TryOptimizeLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull *def, MDefinitionVector *peliminateList)
|
||||
TryOptimizeLoadObjectOrNull(MDefinition *def, MDefinitionVector *peliminateList)
|
||||
{
|
||||
if (def->type() != MIRType_Value)
|
||||
return true;
|
||||
|
||||
// Check if this definition can only produce object or null values.
|
||||
TemporaryTypeSet *types = def->resultTypeSet();
|
||||
if (!types)
|
||||
return true;
|
||||
if (types->baseFlags() & ~(TYPE_FLAG_NULL | TYPE_FLAG_ANYOBJECT))
|
||||
return true;
|
||||
|
||||
MDefinitionVector eliminateList(def->block()->graph().alloc());
|
||||
|
||||
for (MUseDefIterator iter(def); iter; ++iter) {
|
||||
@ -2533,6 +2540,8 @@ TryOptimizeLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull *def, MDefinitionVec
|
||||
if (ndef->toCompare()->compareType() != MCompare::Compare_Null)
|
||||
return true;
|
||||
break;
|
||||
case MDefinition::Op_Test:
|
||||
break;
|
||||
case MDefinition::Op_PostWriteBarrier:
|
||||
break;
|
||||
case MDefinition::Op_StoreFixedSlot:
|
||||
@ -2546,13 +2555,42 @@ TryOptimizeLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull *def, MDefinitionVec
|
||||
case MDefinition::Op_Unbox:
|
||||
MOZ_ASSERT(ndef->type() == MIRType_Object);
|
||||
break;
|
||||
case MDefinition::Op_TypeBarrier:
|
||||
// For now, only handle type barriers which are not consumed
|
||||
// anywhere and only test that the value is null.
|
||||
if (ndef->hasUses() || ndef->resultTypeSet()->getKnownMIRType() != MIRType_Null)
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// On punboxing systems we are better off leaving the value boxed if it
|
||||
// is only stored back to the heap.
|
||||
#ifdef JS_PUNBOX64
|
||||
bool foundUse = false;
|
||||
for (MUseDefIterator iter(def); iter; ++iter) {
|
||||
MDefinition *ndef = iter.def();
|
||||
if (!ndef->isStoreFixedSlot() && !ndef->isStoreSlot()) {
|
||||
foundUse = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundUse)
|
||||
return true;
|
||||
#endif // JS_PUNBOX64
|
||||
|
||||
def->setResultType(MIRType_ObjectOrNull);
|
||||
|
||||
// Fixup the result type of MTypeBarrier uses.
|
||||
for (MUseDefIterator iter(def); iter; ++iter) {
|
||||
MDefinition *ndef = iter.def();
|
||||
if (ndef->isTypeBarrier())
|
||||
ndef->setResultType(MIRType_ObjectOrNull);
|
||||
}
|
||||
|
||||
// Eliminate MToObjectOrNull instruction uses.
|
||||
for (size_t i = 0; i < eliminateList.length(); i++) {
|
||||
MDefinition *ndef = eliminateList[i];
|
||||
ndef->replaceAllUsesWith(def);
|
||||
@ -2627,21 +2665,28 @@ jit::EliminateRedundantChecks(MIRGraph &graph)
|
||||
|
||||
bool eliminated = false;
|
||||
|
||||
if (def->isBoundsCheck()) {
|
||||
switch (def->op()) {
|
||||
case MDefinition::Op_BoundsCheck:
|
||||
if (!TryEliminateBoundsCheck(checks, index, def->toBoundsCheck(), &eliminated))
|
||||
return false;
|
||||
} else if (def->isTypeBarrier()) {
|
||||
break;
|
||||
case MDefinition::Op_TypeBarrier:
|
||||
if (!TryEliminateTypeBarrier(def->toTypeBarrier(), &eliminated))
|
||||
return false;
|
||||
} else if (def->isLoadUnboxedObjectOrNull()) {
|
||||
if (!TryOptimizeLoadUnboxedObjectOrNull(def->toLoadUnboxedObjectOrNull(), &eliminateList))
|
||||
break;
|
||||
case MDefinition::Op_LoadFixedSlot:
|
||||
case MDefinition::Op_LoadSlot:
|
||||
case MDefinition::Op_LoadUnboxedObjectOrNull:
|
||||
if (!TryOptimizeLoadObjectOrNull(def, &eliminateList))
|
||||
return false;
|
||||
} else {
|
||||
break;
|
||||
default:
|
||||
// Now that code motion passes have finished, replace
|
||||
// instructions which pass through one of their operands
|
||||
// (and perform additional checks) with that operand.
|
||||
if (MDefinition *passthrough = PassthroughOperand(def))
|
||||
def->replaceAllUsesWith(passthrough);
|
||||
break;
|
||||
}
|
||||
|
||||
if (eliminated)
|
||||
|
@ -658,6 +658,12 @@ LIRGenerator::visitTest(MTest *test)
|
||||
return;
|
||||
}
|
||||
|
||||
if (opd->type() == MIRType_ObjectOrNull) {
|
||||
LDefinition temp0 = test->operandMightEmulateUndefined() ? temp() : LDefinition::BogusTemp();
|
||||
add(new(alloc()) LTestOAndBranch(useRegister(opd), ifTrue, ifFalse, temp0), test);
|
||||
return;
|
||||
}
|
||||
|
||||
// Objects are truthy, except if it might emulate undefined.
|
||||
if (opd->type() == MIRType_Object) {
|
||||
if (test->operandMightEmulateUndefined())
|
||||
@ -2327,10 +2333,18 @@ LIRGenerator::visitTypeBarrier(MTypeBarrier *ins)
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle typebarrier with specific ObjectGroup/SingleObjects.
|
||||
// The payload needs to be tested if it either might be null or might have
|
||||
// an object that should be excluded from the barrier.
|
||||
bool needsObjectBarrier = false;
|
||||
if (inputType == MIRType_ObjectOrNull)
|
||||
needsObjectBarrier = true;
|
||||
if (inputType == MIRType_Object && !types->hasType(TypeSet::AnyObjectType()) &&
|
||||
ins->barrierKind() != BarrierKind::TypeTagOnly)
|
||||
{
|
||||
needsObjectBarrier = true;
|
||||
}
|
||||
|
||||
if (needsObjectBarrier) {
|
||||
LDefinition tmp = needTemp ? temp() : LDefinition::BogusTemp();
|
||||
LTypeBarrierO *barrier = new(alloc()) LTypeBarrierO(useRegister(ins->getOperand(0)), tmp);
|
||||
assignSnapshot(barrier, Bailout_TypeBarrierO);
|
||||
|
@ -3348,7 +3348,7 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
|
||||
cache.lookupGlobal(&ArrayObject::class_, cx->global(), allocKind, &entry))
|
||||
{
|
||||
gc::InitialHeap heap = GetInitialHeap(newKind, &ArrayObject::class_);
|
||||
JSObject *obj = cache.newObjectFromHit<NoGC>(cx, entry, heap);
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry, heap);
|
||||
if (obj) {
|
||||
/* Fixup the elements pointer and length, which may be incorrect. */
|
||||
ArrayObject *arr = &obj->as<ArrayObject>();
|
||||
@ -3360,9 +3360,6 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
|
||||
return nullptr;
|
||||
}
|
||||
return arr;
|
||||
} else {
|
||||
obj = cache.newObjectFromHit<CanGC>(cx, entry, heap);
|
||||
MOZ_ASSERT(!obj);
|
||||
}
|
||||
} else {
|
||||
gcNumber = rt->gc.gcNumber();
|
||||
|
@ -1251,13 +1251,9 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext *cxArg, const Class *clasp,
|
||||
!proto.toObject()->is<GlobalObject>())
|
||||
{
|
||||
if (cache.lookupProto(clasp, proto.toObject(), allocKind, &entry)) {
|
||||
JSObject *obj = cache.newObjectFromHit<NoGC>(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
if (obj) {
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
if (obj)
|
||||
return obj;
|
||||
} else {
|
||||
obj = cache.newObjectFromHit<CanGC>(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
MOZ_ASSERT(!obj);
|
||||
}
|
||||
} else {
|
||||
gcNumber = rt->gc.gcNumber();
|
||||
}
|
||||
@ -1424,13 +1420,9 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg, const Class *clasp,
|
||||
!cx->compartment()->hasObjectMetadataCallback())
|
||||
{
|
||||
if (cache.lookupGlobal(clasp, &parent->as<GlobalObject>(), allocKind, &entry)) {
|
||||
JSObject *obj = cache.newObjectFromHit<NoGC>(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
if (obj) {
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
if (obj)
|
||||
return obj;
|
||||
} else {
|
||||
obj = cache.newObjectFromHit<CanGC>(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
MOZ_ASSERT(!obj);
|
||||
}
|
||||
} else {
|
||||
gcNumber = rt->gc.gcNumber();
|
||||
}
|
||||
@ -1478,6 +1470,7 @@ js::NewObjectWithGroupCommon(JSContext *cx, HandleObjectGroup group, HandleObjec
|
||||
NewObjectCache &cache = cx->runtime()->newObjectCache;
|
||||
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
uint64_t gcNumber = 0;
|
||||
if (group->proto().isObject() &&
|
||||
parent == group->proto().toObject()->getParent() &&
|
||||
newKind == GenericObject &&
|
||||
@ -1486,13 +1479,12 @@ js::NewObjectWithGroupCommon(JSContext *cx, HandleObjectGroup group, HandleObjec
|
||||
!cx->compartment()->hasObjectMetadataCallback())
|
||||
{
|
||||
if (cache.lookupGroup(group, allocKind, &entry)) {
|
||||
JSObject *obj = cache.newObjectFromHit<NoGC>(cx, entry, GetInitialHeap(newKind, group->clasp()));
|
||||
if (obj) {
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry,
|
||||
GetInitialHeap(newKind, group->clasp()));
|
||||
if (obj)
|
||||
return obj;
|
||||
} else {
|
||||
obj = cache.newObjectFromHit<CanGC>(cx, entry, GetInitialHeap(newKind, group->clasp()));
|
||||
MOZ_ASSERT(!obj);
|
||||
}
|
||||
} else {
|
||||
gcNumber = cx->runtime()->gc.gcNumber();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1500,8 +1492,11 @@ js::NewObjectWithGroupCommon(JSContext *cx, HandleObjectGroup group, HandleObjec
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
if (entry != -1 && !obj->as<NativeObject>().hasDynamicSlots())
|
||||
if (entry != -1 && !obj->as<NativeObject>().hasDynamicSlots() &&
|
||||
cx->runtime()->gc.gcNumber() == gcNumber)
|
||||
{
|
||||
cache.fillGroup(entry, group, allocKind, &obj->as<NativeObject>());
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
@ -9,85 +9,31 @@ function TestInt32x4Ctor() {
|
||||
assertEqX4(int32x4(1, 2, 3, 4), [1,2,3,4]);
|
||||
assertEqX4(int32x4(1, 2, 3), [1,2,3,0]);
|
||||
assertEqX4(int32x4(1, 2), [1,2,0,0]);
|
||||
// The 1-argument form is reserved for coercions.
|
||||
assertEqX4(int32x4(1), [1,0,0,0]);
|
||||
assertEqX4(int32x4(), [0,0,0,0]);
|
||||
assertEqX4(int32x4(1, 2, 3, 4, 5), [1,2,3,4]);
|
||||
assertEqX4(int32x4(1, 2, 3, 4, 5, 6), [1,2,3,4]);
|
||||
|
||||
// Constructors used as coercion.
|
||||
var x = int32x4(1, 2, 3, 4);
|
||||
var y = int32x4(x);
|
||||
|
||||
assertEq(x, y);
|
||||
|
||||
assertEq(y.x, x.x);
|
||||
assertEq(y.x, 1);
|
||||
assertEq(y.y, x.y);
|
||||
assertEq(y.y, 2);
|
||||
assertEq(y.z, x.z);
|
||||
assertEq(y.z, 3);
|
||||
assertEq(y.w, x.w);
|
||||
assertEq(y.w, 4);
|
||||
|
||||
assertThrowsInstanceOf(() => int32x4(3), TypeError);
|
||||
assertThrowsInstanceOf(() => int32x4(float32x4(1,2,3,4)), TypeError);
|
||||
assertThrowsInstanceOf(() => int32x4(float64x2(1,2)), TypeError);
|
||||
assertThrowsInstanceOf(() => int32x4('pony x 4'), TypeError);
|
||||
}
|
||||
|
||||
function TestFloat32x4Ctor() {
|
||||
assertEqX4(float32x4(1, 2, 3, 4), [1,2,3,4]);
|
||||
assertEqX4(float32x4(1, 2, 3), [1,2,3,NaN]);
|
||||
assertEqX4(float32x4(1, 2), [1,2,NaN,NaN]);
|
||||
// The 1-argument form is reserved for coercions.
|
||||
assertEqX4(float32x4(1), [1,NaN,NaN,NaN]);
|
||||
assertEqX4(float32x4(), [NaN,NaN,NaN,NaN]);
|
||||
assertEqX4(float32x4(1, 2, 3, 4, 5), [1,2,3,4]);
|
||||
assertEqX4(float32x4(1, 2, 3, 4, 5, 6), [1,2,3,4]);
|
||||
|
||||
var x = float32x4(NaN, 13.37, -Infinity, 4);
|
||||
var y = float32x4(x);
|
||||
|
||||
assertEq(x, y);
|
||||
|
||||
assertEq(y.x, x.x);
|
||||
assertEq(y.x, Math.fround(NaN));
|
||||
assertEq(y.y, x.y);
|
||||
assertEq(y.y, Math.fround(13.37));
|
||||
assertEq(y.z, x.z);
|
||||
assertEq(y.z, Math.fround(-Infinity));
|
||||
assertEq(y.w, x.w);
|
||||
assertEq(y.w, Math.fround(4));
|
||||
|
||||
assertThrowsInstanceOf(() => float32x4(3), TypeError);
|
||||
assertThrowsInstanceOf(() => float32x4(int32x4(1,2,3,4)), TypeError);
|
||||
assertThrowsInstanceOf(() => float32x4(float64x2(1,2)), TypeError);
|
||||
assertThrowsInstanceOf(() => float32x4('pony x 4'), TypeError);
|
||||
}
|
||||
|
||||
function TestFloat64x2Ctor() {
|
||||
assertEqX2(float64x2(1, 2), [1,2]);
|
||||
// The 1-argument form is reserved for coercions.
|
||||
assertEqX2(float64x2(1), [1,NaN]);
|
||||
assertEqX2(float64x2(), [NaN,NaN]);
|
||||
assertEqX2(float64x2(1, 2, 3), [1,2]);
|
||||
assertEqX2(float64x2(1, 2, 3, 4), [1,2]);
|
||||
assertEqX2(float64x2(1, 2, 3, 4, 5), [1,2]);
|
||||
assertEqX2(float64x2(1, 2, 3, 4, 5), [1,2]);
|
||||
assertEqX2(float64x2(1, 2, 3, 4, 5, 6), [1,2]);
|
||||
|
||||
var x = float64x2(NaN, 13.37);
|
||||
var y = float64x2(x);
|
||||
|
||||
assertEq(x, y);
|
||||
|
||||
assertEq(y.x, x.x);
|
||||
assertEq(y.x, NaN);
|
||||
assertEq(y.y, x.y);
|
||||
assertEq(y.y, 13.37);
|
||||
|
||||
assertThrowsInstanceOf(() => float64x2(3), TypeError);
|
||||
assertThrowsInstanceOf(() => float64x2(int32x4(1,2,3,4)), TypeError);
|
||||
assertThrowsInstanceOf(() => float64x2(float32x4(1,2,3,4)), TypeError);
|
||||
assertThrowsInstanceOf(() => float64x2('pony x 4'), TypeError);
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
@ -1,91 +0,0 @@
|
||||
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
|
||||
var BUGNUMBER = 946042;
|
||||
var float32x4 = SIMD.float32x4;
|
||||
var int32x4 = SIMD.int32x4;
|
||||
|
||||
var summary = 'float32x4 with';
|
||||
|
||||
function test() {
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
var a = float32x4(1, 2, 3, 4);
|
||||
var x = SIMD.float32x4.withX(a, 5);
|
||||
var y = SIMD.float32x4.withY(a, 5);
|
||||
var z = SIMD.float32x4.withZ(a, 5);
|
||||
var w = SIMD.float32x4.withW(a, 5);
|
||||
assertEq(x.x, 5);
|
||||
assertEq(x.y, 2);
|
||||
assertEq(x.z, 3);
|
||||
assertEq(x.w, 4);
|
||||
|
||||
assertEq(y.x, 1);
|
||||
assertEq(y.y, 5);
|
||||
assertEq(y.z, 3);
|
||||
assertEq(y.w, 4);
|
||||
|
||||
assertEq(z.x, 1);
|
||||
assertEq(z.y, 2);
|
||||
assertEq(z.z, 5);
|
||||
assertEq(z.w, 4);
|
||||
|
||||
assertEq(w.x, 1);
|
||||
assertEq(w.y, 2);
|
||||
assertEq(w.z, 3);
|
||||
assertEq(w.w, 5);
|
||||
|
||||
var b = float32x4(1.87, 2.08, 3.84, 4.17);
|
||||
var x1 = SIMD.float32x4.withX(b, 5.38);
|
||||
var y1 = SIMD.float32x4.withY(b, 5.19);
|
||||
var z1 = SIMD.float32x4.withZ(b, 5.11);
|
||||
var w1 = SIMD.float32x4.withW(b, 5.07);
|
||||
assertEq(x1.x, Math.fround(5.38));
|
||||
assertEq(x1.y, Math.fround(2.08));
|
||||
assertEq(x1.z, Math.fround(3.84));
|
||||
assertEq(x1.w, Math.fround(4.17));
|
||||
|
||||
assertEq(y1.x, Math.fround(1.87));
|
||||
assertEq(y1.y, Math.fround(5.19));
|
||||
assertEq(y1.z, Math.fround(3.84));
|
||||
assertEq(y1.w, Math.fround(4.17));
|
||||
|
||||
assertEq(z1.x, Math.fround(1.87));
|
||||
assertEq(z1.y, Math.fround(2.08));
|
||||
assertEq(z1.z, Math.fround(5.11));
|
||||
assertEq(z1.w, Math.fround(4.17));
|
||||
|
||||
assertEq(w1.x, Math.fround(1.87));
|
||||
assertEq(w1.y, Math.fround(2.08));
|
||||
assertEq(w1.z, Math.fround(3.84));
|
||||
assertEq(w1.w, Math.fround(5.07));
|
||||
|
||||
var c = float32x4(NaN, -0, Infinity, -Infinity);
|
||||
var x2 = SIMD.float32x4.withX(c, 0);
|
||||
var y2 = SIMD.float32x4.withY(c, 0);
|
||||
var z2 = SIMD.float32x4.withZ(c, 0);
|
||||
var w2 = SIMD.float32x4.withW(c, 0);
|
||||
assertEq(x2.x, 0);
|
||||
assertEq(x2.y, -0);
|
||||
assertEq(x2.z, Infinity);
|
||||
assertEq(x2.w, -Infinity);
|
||||
|
||||
assertEq(y2.x, NaN);
|
||||
assertEq(y2.y, 0);
|
||||
assertEq(y2.z, Infinity);
|
||||
assertEq(y2.w, -Infinity);
|
||||
|
||||
assertEq(z2.x, NaN);
|
||||
assertEq(z2.y, -0);
|
||||
assertEq(z2.z, 0);
|
||||
assertEq(z2.w, -Infinity);
|
||||
|
||||
assertEq(w2.x, NaN);
|
||||
assertEq(w2.y, -0);
|
||||
assertEq(w2.z, Infinity);
|
||||
assertEq(w2.w, 0);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
}
|
||||
|
||||
test();
|
||||
|
@ -1,36 +0,0 @@
|
||||
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
|
||||
var BUGNUMBER = 1031203;
|
||||
var float64x2 = SIMD.float64x2;
|
||||
|
||||
var summary = 'float64x2 with';
|
||||
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
function test() {
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
var a = float64x2(1, 2);
|
||||
var x = float64x2.withX(a, 5);
|
||||
var y = float64x2.withY(a, 5);
|
||||
assertEq(x.x, 5);
|
||||
assertEq(x.y, 2);
|
||||
assertEq(y.x, 1);
|
||||
assertEq(y.y, 5);
|
||||
|
||||
var b = float64x2(NaN, -0);
|
||||
var x1 = float64x2.withX(b, Infinity);
|
||||
var y1 = float64x2.withY(b, -Infinity);
|
||||
assertEq(x1.x, Infinity);
|
||||
assertEq(x1.y, -0);
|
||||
assertEq(y1.x, NaN);
|
||||
assertEq(y1.y, -Infinity);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
}
|
||||
|
||||
test();
|
||||
|
@ -1,28 +0,0 @@
|
||||
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
|
||||
var BUGNUMBER = 946042;
|
||||
var float32x4 = SIMD.float32x4;
|
||||
var int32x4 = SIMD.int32x4;
|
||||
|
||||
var summary = 'int32x4 with';
|
||||
|
||||
function test() {
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
var INT32_MAX = Math.pow(2, 31) - 1;
|
||||
|
||||
var a = int32x4(1, 2, 3, 4);
|
||||
var x = SIMD.int32x4.withX(a, 5);
|
||||
var y = SIMD.int32x4.withY(a, 5);
|
||||
var z = SIMD.int32x4.withZ(a, 5);
|
||||
var w = SIMD.int32x4.withW(a, INT32_MAX + 1);
|
||||
assertEq(x.x, 5);
|
||||
assertEq(y.y, 5);
|
||||
assertEq(z.z, 5);
|
||||
assertEq(w.w, (INT32_MAX + 1) | 0);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
}
|
||||
|
||||
test();
|
||||
|
@ -18,6 +18,11 @@ function ursh(a, b) {
|
||||
}
|
||||
|
||||
function test() {
|
||||
function TestError() {};
|
||||
|
||||
var good = {valueOf: () => 21};
|
||||
var bad = {valueOf: () => {throw new TestError(); }};
|
||||
|
||||
for (var v of [
|
||||
int32x4(-1, 2, -3, 4),
|
||||
int32x4(INT32_MAX, INT32_MIN, INT32_MAX - 1, INT32_MIN + 1)
|
||||
@ -28,8 +33,17 @@ function test() {
|
||||
testBinaryScalarFunc(v, bits, int32x4.shiftRightArithmeticByScalar, rsh);
|
||||
testBinaryScalarFunc(v, bits, int32x4.shiftRightLogicalByScalar, ursh);
|
||||
}
|
||||
// Test that the shift count is coerced to an int32.
|
||||
testBinaryScalarFunc(v, undefined, int32x4.shiftLeftByScalar, lsh);
|
||||
testBinaryScalarFunc(v, 3.5, int32x4.shiftLeftByScalar, lsh);
|
||||
testBinaryScalarFunc(v, good, int32x4.shiftLeftByScalar, lsh);
|
||||
}
|
||||
|
||||
var v = SIMD.int32x4(1,2,3,4);
|
||||
assertThrowsInstanceOf(() => SIMD.int32x4.shiftLeftByScalar(v, bad), TestError);
|
||||
assertThrowsInstanceOf(() => SIMD.int32x4.shiftRightArithmeticByScalar(v, bad), TestError);
|
||||
assertThrowsInstanceOf(() => SIMD.int32x4.shiftRightLogicalByScalar(v, bad), TestError);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
}
|
||||
|
38
js/src/tests/ecma_7/SIMD/splat.js
Normal file
38
js/src/tests/ecma_7/SIMD/splat.js
Normal file
@ -0,0 +1,38 @@
|
||||
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
|
||||
|
||||
var float64x2 = SIMD.float64x2;
|
||||
var float32x4 = SIMD.float32x4;
|
||||
var int32x4 = SIMD.int32x4;
|
||||
|
||||
function TestSplatX4(type, inputs, coerceFunc) {
|
||||
for (var x of inputs) {
|
||||
assertEqX4(SIMD[type].splat(x), [x, x, x, x].map(coerceFunc));
|
||||
}
|
||||
}
|
||||
|
||||
function TestSplatX2(type, inputs, coerceFunc) {
|
||||
for (var x of inputs) {
|
||||
assertEqX2(SIMD[type].splat(x), [x, x].map(coerceFunc));
|
||||
}
|
||||
}
|
||||
|
||||
function test() {
|
||||
function TestError(){};
|
||||
|
||||
var good = {valueOf: () => 19.89};
|
||||
var bad = {valueOf: () => { throw new TestError(); }};
|
||||
|
||||
TestSplatX4('int32x4', [0, undefined, 3.5, 42, -1337, INT32_MAX, INT32_MAX + 1, good], (x) => x | 0);
|
||||
assertThrowsInstanceOf(() => SIMD.int32x4.splat(bad), TestError);
|
||||
|
||||
TestSplatX4('float32x4', [0, undefined, 3.5, 42, -13.37, Infinity, NaN, -0, good], (x) => Math.fround(x));
|
||||
assertThrowsInstanceOf(() => SIMD.float32x4.splat(bad), TestError);
|
||||
|
||||
TestSplatX2('float64x2', [0, undefined, 3.5, 42, -13.37, Infinity, NaN, -0, good], (x) => +x);
|
||||
assertThrowsInstanceOf(() => SIMD.float64x2.splat(bad), TestError);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
}
|
||||
|
||||
test();
|
90
js/src/tests/ecma_7/SIMD/with.js
Normal file
90
js/src/tests/ecma_7/SIMD/with.js
Normal file
@ -0,0 +1,90 @@
|
||||
// |reftest| skip-if(!this.hasOwnProperty("SIMD"))
|
||||
var BUGNUMBER = 946042;
|
||||
var float32x4 = SIMD.float32x4;
|
||||
var int32x4 = SIMD.int32x4;
|
||||
var float64x2 = SIMD.float64x2;
|
||||
|
||||
var summary = 'with{X,Y,Z,W}';
|
||||
|
||||
function withX(arr, x) {
|
||||
if (arr.length == 2)
|
||||
return [x, arr[1]];
|
||||
return [x, arr[1], arr[2], arr[3]];
|
||||
}
|
||||
function withY(arr, x) {
|
||||
if (arr.length == 2)
|
||||
return [arr[0], x];
|
||||
return [arr[0], x, arr[2], arr[3]];
|
||||
}
|
||||
function withZ(arr, x) {
|
||||
return [arr[0], arr[1], x, arr[3]];
|
||||
}
|
||||
function withW(arr, x) {
|
||||
return [arr[0], arr[1], arr[2], x];
|
||||
}
|
||||
|
||||
function testWith(vec, scalar, simdFunc, func) {
|
||||
var varr = simdToArray(vec);
|
||||
var observed = simdToArray(simdFunc(vec, scalar));
|
||||
var expected = func(varr, scalar);
|
||||
for (var i = 0; i < observed.length; i++)
|
||||
assertEq(observed[i], expected[i]);
|
||||
}
|
||||
|
||||
function test() {
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
function testType(type, inputs) {
|
||||
var length = simdToArray(inputs[0][0]).length;
|
||||
for (var [vec, s] of inputs) {
|
||||
testWith(vec, s, SIMD[type].withX, withX);
|
||||
testWith(vec, s, SIMD[type].withY, withY);
|
||||
if (length <= 2)
|
||||
continue;
|
||||
testWith(vec, s, SIMD[type].withZ, withZ);
|
||||
testWith(vec, s, SIMD[type].withW, withW);
|
||||
}
|
||||
}
|
||||
|
||||
function TestError(){};
|
||||
var good = {valueOf: () => 42};
|
||||
var bad = {valueOf: () => {throw new TestError(); }};
|
||||
|
||||
var float32x4inputs = [
|
||||
[float32x4(1, 2, 3, 4), 5],
|
||||
[float32x4(1.87, 2.08, 3.84, 4.17), Math.fround(13.37)],
|
||||
[float32x4(NaN, -0, Infinity, -Infinity), 0]
|
||||
];
|
||||
testType('float32x4', float32x4inputs);
|
||||
|
||||
var v = float32x4inputs[1][0];
|
||||
assertEqX4(float32x4.withX(v, good), withX(simdToArray(v), good | 0));
|
||||
assertThrowsInstanceOf(() => float32x4.withX(v, bad), TestError);
|
||||
|
||||
var float64x2inputs = [
|
||||
[float64x2(1, 2), 5],
|
||||
[float64x2(1.87, 2.08), Math.fround(13.37)],
|
||||
[float64x2(NaN, -0), 0]
|
||||
];
|
||||
testType('float64x2', float64x2inputs);
|
||||
|
||||
var v = float64x2inputs[1][0];
|
||||
assertEqX4(float64x2.withX(v, good), withX(simdToArray(v), good | 0));
|
||||
assertThrowsInstanceOf(() => float64x2.withX(v, bad), TestError);
|
||||
|
||||
var int32x4inputs = [
|
||||
[int32x4(1, 2, 3, 4), 5],
|
||||
[int32x4(INT32_MIN, INT32_MAX, 3, 4), INT32_MIN],
|
||||
];
|
||||
testType('int32x4', int32x4inputs);
|
||||
|
||||
var v = int32x4inputs[1][0];
|
||||
assertEqX4(int32x4.withX(v, good), withX(simdToArray(v), good | 0));
|
||||
assertThrowsInstanceOf(() => int32x4.withX(v, bad), TestError);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
}
|
||||
|
||||
test();
|
||||
|
@ -38,15 +38,14 @@ NewObjectCache::fillGlobal(EntryIndex entry, const Class *clasp, js::GlobalObjec
|
||||
return fill(entry, clasp, global, kind, obj);
|
||||
}
|
||||
|
||||
template <AllowGC allowGC>
|
||||
inline JSObject *
|
||||
NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::InitialHeap heap)
|
||||
NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entryIndex, js::gc::InitialHeap heap)
|
||||
{
|
||||
// The new object cache does not account for metadata attached via callbacks.
|
||||
MOZ_ASSERT(!cx->compartment()->hasObjectMetadataCallback());
|
||||
|
||||
MOZ_ASSERT(unsigned(entry_) < mozilla::ArrayLength(entries));
|
||||
Entry *entry = &entries[entry_];
|
||||
MOZ_ASSERT(unsigned(entryIndex) < mozilla::ArrayLength(entries));
|
||||
Entry *entry = &entries[entryIndex];
|
||||
|
||||
JSObject *templateObj = reinterpret_cast<JSObject *>(&entry->templateObject);
|
||||
|
||||
@ -60,16 +59,6 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi
|
||||
if (cx->runtime()->gc.upcomingZealousGC())
|
||||
return nullptr;
|
||||
|
||||
// Trigger an identical allocation to the one that notified us of OOM
|
||||
// so that we trigger the right kind of GC automatically.
|
||||
if (allowGC) {
|
||||
mozilla::DebugOnly<JSObject *> obj =
|
||||
js::gc::AllocateObjectForCacheHit<allowGC>(cx, entry->kind, heap, group->clasp());
|
||||
MOZ_ASSERT(!obj);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(allowGC == NoGC);
|
||||
JSObject *obj = js::gc::AllocateObjectForCacheHit<NoGC>(cx, entry->kind, heap, group->clasp());
|
||||
if (obj) {
|
||||
copyCachedToObject(obj, templateObj, entry->kind);
|
||||
@ -78,6 +67,11 @@ NewObjectCache::newObjectFromHit(JSContext *cx, EntryIndex entry_, js::gc::Initi
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Trigger an identical allocation to the one that notified us of OOM
|
||||
// so that we trigger the right kind of GC automatically.
|
||||
mozilla::DebugOnly<JSObject *> obj2 =
|
||||
js::gc::AllocateObjectForCacheHit<CanGC>(cx, entry->kind, heap, group->clasp());
|
||||
MOZ_ASSERT(!obj2);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,6 @@ class NewObjectCache
|
||||
* nullptr if returning the object could possibly trigger GC (does not
|
||||
* indicate failure).
|
||||
*/
|
||||
template <AllowGC allowGC>
|
||||
inline JSObject *newObjectFromHit(JSContext *cx, EntryIndex entry, js::gc::InitialHeap heap);
|
||||
|
||||
/* Fill an entry after a cache miss. */
|
||||
|
@ -237,7 +237,15 @@ class MOZ_STACK_CLASS ComponentLoaderInfo {
|
||||
nsIChannel* ScriptChannel() { MOZ_ASSERT(mScriptChannel); return mScriptChannel; }
|
||||
nsresult EnsureScriptChannel() {
|
||||
BEGIN_ENSURE(ScriptChannel, IOService, URI);
|
||||
return mIOService->NewChannelFromURI(mURI, getter_AddRefs(mScriptChannel));
|
||||
return NS_NewChannel(getter_AddRefs(mScriptChannel),
|
||||
mURI,
|
||||
nsContentUtils::GetSystemPrincipal(),
|
||||
nsILoadInfo::SEC_NORMAL,
|
||||
nsIContentPolicy::TYPE_SCRIPT,
|
||||
nullptr, // aLoadGroup
|
||||
nullptr, // aCallbacks
|
||||
nsIRequest::LOAD_NORMAL,
|
||||
mIOService);
|
||||
}
|
||||
|
||||
nsIURI* ResolvedURI() { MOZ_ASSERT(mResolvedURI); return mResolvedURI; }
|
||||
|
@ -696,6 +696,7 @@ static void UnmarkFrameForDisplay(nsIFrame* aFrame) {
|
||||
/* static */ FrameMetrics
|
||||
nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame,
|
||||
nsIFrame* aScrollFrame,
|
||||
nsIContent* aContent,
|
||||
const nsIFrame* aReferenceFrame,
|
||||
Layer* aLayer,
|
||||
ViewID aScrollParentId,
|
||||
@ -711,20 +712,19 @@ nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame,
|
||||
metrics.SetViewport(CSSRect::FromAppUnits(aViewport));
|
||||
|
||||
ViewID scrollId = FrameMetrics::NULL_SCROLL_ID;
|
||||
nsIContent* content = aScrollFrame ? aScrollFrame->GetContent() : nullptr;
|
||||
if (content) {
|
||||
scrollId = nsLayoutUtils::FindOrCreateIDFor(content);
|
||||
if (aContent) {
|
||||
scrollId = nsLayoutUtils::FindOrCreateIDFor(aContent);
|
||||
nsRect dp;
|
||||
if (nsLayoutUtils::GetDisplayPort(content, &dp)) {
|
||||
if (nsLayoutUtils::GetDisplayPort(aContent, &dp)) {
|
||||
metrics.SetDisplayPort(CSSRect::FromAppUnits(dp));
|
||||
nsLayoutUtils::LogTestDataForPaint(aLayer->Manager(), scrollId, "displayport",
|
||||
metrics.GetDisplayPort());
|
||||
}
|
||||
if (nsLayoutUtils::GetCriticalDisplayPort(content, &dp)) {
|
||||
if (nsLayoutUtils::GetCriticalDisplayPort(aContent, &dp)) {
|
||||
metrics.SetCriticalDisplayPort(CSSRect::FromAppUnits(dp));
|
||||
}
|
||||
DisplayPortMarginsPropertyData* marginsData =
|
||||
static_cast<DisplayPortMarginsPropertyData*>(content->GetProperty(nsGkAtoms::DisplayPortMargins));
|
||||
static_cast<DisplayPortMarginsPropertyData*>(aContent->GetProperty(nsGkAtoms::DisplayPortMargins));
|
||||
if (marginsData) {
|
||||
metrics.SetDisplayPortMargins(marginsData->mMargins);
|
||||
}
|
||||
@ -1634,15 +1634,31 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
|
||||
root->SetEventRegionsOverride(EventRegionsOverride::ForceDispatchToContent);
|
||||
}
|
||||
|
||||
if (gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
// If we're using containerless scrolling, there is still one case where we
|
||||
// want the root container layer to have metrics. If the parent process is
|
||||
// using XUL windows, there is no root scrollframe, and without explicitly
|
||||
// creating metrics there will be no guaranteed top-level APZC.
|
||||
if (gfxPrefs::LayoutUseContainersForRootFrames() ||
|
||||
(XRE_IsParentProcess() && !presShell->GetRootScrollFrame()))
|
||||
{
|
||||
bool isRoot = presContext->IsRootContentDocument();
|
||||
|
||||
nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
|
||||
|
||||
nsRect viewport(aBuilder->ToReferenceFrame(frame), frame->GetSize());
|
||||
|
||||
nsIFrame* scrollFrame = presShell->GetRootScrollFrame();
|
||||
nsIContent* content = nullptr;
|
||||
if (scrollFrame) {
|
||||
content = scrollFrame->GetContent();
|
||||
} else if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
|
||||
// If there is no root scroll frame, and we're using containerless
|
||||
// scrolling, pick the document element instead.
|
||||
content = document->GetDocumentElement();
|
||||
}
|
||||
|
||||
root->SetFrameMetrics(
|
||||
nsDisplayScrollLayer::ComputeFrameMetrics(frame, rootScrollFrame,
|
||||
nsDisplayScrollLayer::ComputeFrameMetrics(frame,
|
||||
presShell->GetRootScrollFrame(),
|
||||
content,
|
||||
aBuilder->FindReferenceFrameFor(frame),
|
||||
root, FrameMetrics::NULL_SCROLL_ID, viewport,
|
||||
isRoot, containerParameters));
|
||||
@ -4121,9 +4137,10 @@ nsDisplaySubDocument::ComputeFrameMetrics(Layer* aLayer,
|
||||
mFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
||||
|
||||
return MakeUnique<FrameMetrics>(
|
||||
nsDisplayScrollLayer::ComputeFrameMetrics(mFrame, rootScrollFrame, ReferenceFrame(),
|
||||
aLayer, mScrollParentId, viewport,
|
||||
isRootContentDocument, params));
|
||||
nsDisplayScrollLayer::ComputeFrameMetrics(
|
||||
mFrame, rootScrollFrame, rootScrollFrame->GetContent(), ReferenceFrame(),
|
||||
aLayer, mScrollParentId, viewport,
|
||||
isRootContentDocument, params));
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -4456,8 +4473,10 @@ nsDisplayScrollLayer::ComputeFrameMetrics(Layer* aLayer,
|
||||
mScrollFrame->GetOffsetToCrossDoc(ReferenceFrame());
|
||||
|
||||
return UniquePtr<FrameMetrics>(new FrameMetrics(
|
||||
ComputeFrameMetrics(mScrolledFrame, mScrollFrame, ReferenceFrame(), aLayer,
|
||||
mScrollParentId, viewport, false, params)));
|
||||
ComputeFrameMetrics(
|
||||
mScrolledFrame, mScrollFrame, mScrollFrame->GetContent(),
|
||||
ReferenceFrame(), aLayer,
|
||||
mScrollParentId, viewport, false, params)));
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3175,6 +3175,7 @@ public:
|
||||
|
||||
static FrameMetrics ComputeFrameMetrics(nsIFrame* aForFrame,
|
||||
nsIFrame* aScrollFrame,
|
||||
nsIContent* aContent,
|
||||
const nsIFrame* aReferenceFrame,
|
||||
Layer* aLayer,
|
||||
ViewID aScrollParentId,
|
||||
|
@ -867,6 +867,11 @@ GetDisplayPortFromMarginsData(nsIContent* aContent,
|
||||
// We want the scroll frame, the root scroll frame differs from all
|
||||
// others in that the primary frame is not the scroll frame.
|
||||
frame = frame->PresContext()->PresShell()->GetRootScrollFrame();
|
||||
if (!frame) {
|
||||
// If there is no root scrollframe, just exit.
|
||||
return ApplyRectMultiplier(base, aMultiplier);
|
||||
}
|
||||
|
||||
isRoot = true;
|
||||
}
|
||||
|
||||
|
@ -3177,7 +3177,8 @@ ScrollFrameHelper::ComputeFrameMetrics(Layer* aLayer,
|
||||
bool isRoot = mIsRoot && mOuter->PresContext()->IsRootContentDocument();
|
||||
|
||||
*aOutput->AppendElement() =
|
||||
nsDisplayScrollLayer::ComputeFrameMetrics(mScrolledFrame, mOuter,
|
||||
nsDisplayScrollLayer::ComputeFrameMetrics(
|
||||
mScrolledFrame, mOuter, mOuter->GetContent(),
|
||||
aContainerReferenceFrame, aLayer, mScrollParentID,
|
||||
scrollport, isRoot, aParameters);
|
||||
}
|
||||
|
@ -649,8 +649,8 @@ nsChangeHint nsStyleOutline::CalcDifference(const nsStyleOutline& aOther) const
|
||||
(outlineIsVisible && (mOutlineOffset != aOther.mOutlineOffset ||
|
||||
mOutlineWidth != aOther.mOutlineWidth ||
|
||||
mTwipsPerPixel != aOther.mTwipsPerPixel))) {
|
||||
return NS_CombineHint(nsChangeHint_AllReflowHints,
|
||||
nsChangeHint_RepaintFrame);
|
||||
return NS_CombineHint(nsChangeHint_UpdateOverflow,
|
||||
nsChangeHint_SchedulePaint);
|
||||
}
|
||||
|
||||
if ((mOutlineStyle != aOther.mOutlineStyle) ||
|
||||
|
@ -1065,15 +1065,15 @@ struct nsStyleOutline {
|
||||
void RecalcData(nsPresContext* aContext);
|
||||
nsChangeHint CalcDifference(const nsStyleOutline& aOther) const;
|
||||
static nsChangeHint MaxDifference() {
|
||||
return NS_CombineHint(nsChangeHint_AllReflowHints,
|
||||
return NS_CombineHint(NS_CombineHint(nsChangeHint_UpdateOverflow,
|
||||
nsChangeHint_SchedulePaint),
|
||||
NS_CombineHint(nsChangeHint_RepaintFrame,
|
||||
nsChangeHint_NeutralChange));
|
||||
}
|
||||
static nsChangeHint MaxDifferenceNeverInherited() {
|
||||
// CalcDifference never returns nsChangeHint_NeedReflow or
|
||||
// nsChangeHint_ClearAncestorIntrinsics as inherited hints.
|
||||
return NS_CombineHint(nsChangeHint_NeedReflow,
|
||||
nsChangeHint_ClearAncestorIntrinsics);
|
||||
// nsChangeHint_ClearAncestorIntrinsics at all.
|
||||
return nsChangeHint(0);
|
||||
}
|
||||
|
||||
nsStyleCorners mOutlineRadius; // [reset] coord, percent, calc
|
||||
|
@ -131,6 +131,7 @@ skip-if = toolkit == 'android' #bug 536603
|
||||
[test_descriptor_storage.html]
|
||||
[test_descriptor_syntax_errors.html]
|
||||
[test_dont_use_document_colors.html]
|
||||
[test_dynamic_change_causing_reflow.html]
|
||||
[test_exposed_prop_accessors.html]
|
||||
[test_extra_inherit_initial.html]
|
||||
[test_flexbox_align_self_auto.html]
|
||||
|
143
layout/style/test/test_dynamic_change_causing_reflow.html
Normal file
143
layout/style/test/test_dynamic_change_causing_reflow.html
Normal file
@ -0,0 +1,143 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1131371
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1131371</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1131371">Mozilla Bug 1131371</a>
|
||||
<div id="display">
|
||||
<div id="content">
|
||||
</div>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
/** Test for Bug 1131371 **/
|
||||
|
||||
/**
|
||||
* This test verifies that certain style changes do or don't cause reflow
|
||||
* and/or frame construction. We do this by checking the framesReflowed &
|
||||
* framesConstructed counts, before & after a style-change, and verifying
|
||||
* that any change to these counts is in line with our expectations.
|
||||
*
|
||||
* Each entry in gTestcases contains these member-values:
|
||||
* - beforeStyle (optional): initial value to use for "style" attribute.
|
||||
* - afterStyle: value to change the "style" attribute to.
|
||||
*
|
||||
* Testcases may also include two optional member-values to express that reflow
|
||||
* and/or frame construction *are* in fact expected:
|
||||
* - expectConstruction (optional): if set to something truthy, then we expect
|
||||
* frame construction to occur when afterStyle is set. Otherwise, we
|
||||
* expect that frame construction should *not* occur.
|
||||
* - expectReflow (optional): if set to something truthy, then we expect
|
||||
* reflow to occur when afterStyle is set. Otherwise, we expect that
|
||||
* reflow should *not* occur.
|
||||
*/
|
||||
const gTestcases = [
|
||||
// Things that shouldn't cause reflow:
|
||||
// -----------------------------------
|
||||
// * Adding an outline (e.g. for focus ring).
|
||||
{
|
||||
afterStyle: "outline: 1px dotted black",
|
||||
},
|
||||
|
||||
// * Changing between completely-different outlines.
|
||||
{
|
||||
beforeStyle: "outline: 2px solid black",
|
||||
afterStyle: "outline: 6px dashed yellow",
|
||||
},
|
||||
|
||||
// Things that *should* cause reflow:
|
||||
// ----------------------------------
|
||||
// (e.g. to make sure our counts are actually measuring something)
|
||||
|
||||
// * Changing 'height' should cause reflow, but not frame construction.
|
||||
{
|
||||
beforeStyle: "height: 10px",
|
||||
afterStyle: "height: 15px",
|
||||
expectReflow: true,
|
||||
},
|
||||
|
||||
// * Changing 'display' should cause frame construction and reflow.
|
||||
{
|
||||
beforeStyle: "display: inline",
|
||||
afterStyle: "display: table",
|
||||
expectConstruction: true,
|
||||
expectReflow: true,
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
// Helper function to let us call either "is" or "isnot" & assemble
|
||||
// the failure message, based on the provided parameters.
|
||||
function checkFinalCount(aFinalCount, aExpectedCount,
|
||||
aExpectChange, aMsgPrefix, aCountDescription)
|
||||
{
|
||||
let compareFunc;
|
||||
let msg = aMsgPrefix;
|
||||
if (aExpectChange) {
|
||||
compareFunc = isnot;
|
||||
msg += "should cause " + aCountDescription;
|
||||
} else {
|
||||
compareFunc = is;
|
||||
msg += "should not cause " + aCountDescription;
|
||||
}
|
||||
|
||||
compareFunc(aFinalCount, aExpectedCount, msg);
|
||||
}
|
||||
|
||||
// Vars used in runOneTest that we really only have to look up once:
|
||||
const gUtils = SpecialPowers.getDOMWindowUtils(window);
|
||||
const gElem = document.getElementById("content");
|
||||
|
||||
function runOneTest(aTestcase)
|
||||
{
|
||||
// sanity-check that we have the one main thing we need:
|
||||
if (!aTestcase.afterStyle) {
|
||||
ok(false, "testcase is missing an 'afterStyle' to change to");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the "before" style, and compose the first part of the message
|
||||
// to be used in our "is"/"isnot" invocations:
|
||||
let msgPrefix = "Changing style ";
|
||||
if (aTestcase.beforeStyle) {
|
||||
gElem.setAttribute("style", aTestcase.beforeStyle);
|
||||
msgPrefix += "from '" + aTestcase.beforeStyle + "' ";
|
||||
}
|
||||
msgPrefix += "to '" + aTestcase.afterStyle + "' ";
|
||||
|
||||
// Establish initial counts:
|
||||
let unusedVal = gElem.offsetHeight; // flush layout
|
||||
let origFramesConstructed = gUtils.framesConstructed;
|
||||
let origFramesReflowed = gUtils.framesReflowed;
|
||||
|
||||
// Make the change and flush:
|
||||
gElem.setAttribute("style", aTestcase.afterStyle);
|
||||
unusedVal = gElem.offsetHeight; // flush layout
|
||||
|
||||
// Make our is/isnot assertions about whether things should have changed:
|
||||
checkFinalCount(gUtils.framesConstructed, origFramesConstructed,
|
||||
aTestcase.expectConstruction, msgPrefix,
|
||||
"frame construction");
|
||||
checkFinalCount(gUtils.framesReflowed, origFramesReflowed,
|
||||
aTestcase.expectReflow, msgPrefix,
|
||||
"reflow");
|
||||
|
||||
// Clean up!
|
||||
gElem.removeAttribute("style");
|
||||
}
|
||||
|
||||
gTestcases.forEach(runOneTest);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -366,8 +366,10 @@ void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx,
|
||||
NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
|
||||
RefPtr<NrIceMediaStream> s = ctx->FindStream(stream);
|
||||
|
||||
// Streams which do not exist shouldn't have candidates.
|
||||
MOZ_ASSERT(s);
|
||||
if (!s) {
|
||||
// This stream has been removed because it is inactive
|
||||
return;
|
||||
}
|
||||
|
||||
// Format the candidate.
|
||||
char candidate_str[NR_ICE_MAX_ATTRIBUTE_SIZE];
|
||||
@ -668,32 +670,26 @@ abort:
|
||||
|
||||
nsresult NrIceCtx::StartGathering() {
|
||||
ASSERT_ON_THREAD(sts_target_);
|
||||
MOZ_ASSERT(connection_state_ == ICE_CTX_INIT);
|
||||
if (connection_state_ != ICE_CTX_INIT) {
|
||||
MOZ_MTLOG(ML_ERROR, "ICE ctx in the wrong state for gathering: '"
|
||||
<< name_ << "' state: " << connection_state_);
|
||||
// This might start gathering for the first time, or again after
|
||||
// renegotiation, or might do nothing at all if gathering has already
|
||||
// finished.
|
||||
int r = nr_ice_gather(ctx_, &NrIceCtx::gather_cb, this);
|
||||
|
||||
if (r && (r != R_WOULDBLOCK)) {
|
||||
MOZ_MTLOG(ML_ERROR, "Couldn't gather ICE candidates for '"
|
||||
<< name_ << "', error=" << r);
|
||||
SetConnectionState(ICE_CTX_FAILED);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int r = nr_ice_initialize(ctx_, &NrIceCtx::initialized_cb, this);
|
||||
|
||||
if (r && r != R_WOULDBLOCK) {
|
||||
MOZ_MTLOG(ML_ERROR, "Couldn't gather ICE candidates for '"
|
||||
<< name_ << "'");
|
||||
SetConnectionState(ICE_CTX_FAILED);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
SetGatheringState(ICE_CTX_GATHER_STARTED);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<NrIceMediaStream> NrIceCtx::FindStream(
|
||||
nr_ice_media_stream *stream) {
|
||||
for (size_t i=0; i<streams_.size(); ++i) {
|
||||
if (streams_[i]->stream() == stream) {
|
||||
if (streams_[i] && (streams_[i]->stream() == stream)) {
|
||||
return streams_[i];
|
||||
}
|
||||
}
|
||||
@ -771,7 +767,7 @@ nsresult NrIceCtx::StartChecks() {
|
||||
}
|
||||
|
||||
|
||||
void NrIceCtx::initialized_cb(NR_SOCKET s, int h, void *arg) {
|
||||
void NrIceCtx::gather_cb(NR_SOCKET s, int h, void *arg) {
|
||||
NrIceCtx *ctx = static_cast<NrIceCtx *>(arg);
|
||||
|
||||
ctx->SetGatheringState(ICE_CTX_GATHER_COMPLETE);
|
||||
|
@ -225,7 +225,7 @@ class NrIceCtx {
|
||||
|
||||
// Create a media stream
|
||||
RefPtr<NrIceMediaStream> CreateStream(const std::string& name,
|
||||
int components);
|
||||
int components);
|
||||
|
||||
RefPtr<NrIceMediaStream> GetStream(size_t index) {
|
||||
if (index < streams_.size()) {
|
||||
@ -234,6 +234,11 @@ class NrIceCtx {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void RemoveStream(size_t index)
|
||||
{
|
||||
streams_[index] = nullptr;
|
||||
}
|
||||
|
||||
// The name of the ctx
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
@ -325,7 +330,7 @@ class NrIceCtx {
|
||||
DISALLOW_COPY_ASSIGN(NrIceCtx);
|
||||
|
||||
// Callbacks for nICEr
|
||||
static void initialized_cb(NR_SOCKET s, int h, void *arg); // ICE initialized
|
||||
static void gather_cb(NR_SOCKET s, int h, void *arg); // ICE gather complete
|
||||
|
||||
// Handler implementation
|
||||
static int select_pair(void *obj,nr_ice_media_stream *stream,
|
||||
|
@ -209,6 +209,7 @@ nsresult NrIceMediaStream::ParseAttributes(std::vector<std::string>&
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
has_parsed_attrs_ = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -142,6 +142,7 @@ class NrIceMediaStream {
|
||||
|
||||
// Parse remote attributes
|
||||
nsresult ParseAttributes(std::vector<std::string>& candidates);
|
||||
bool HasParsedAttributes() const { return has_parsed_attrs_; }
|
||||
|
||||
// Parse trickle ICE candidate
|
||||
nsresult ParseTrickleCandidate(const std::string& candidate);
|
||||
@ -198,7 +199,8 @@ class NrIceMediaStream {
|
||||
name_(name),
|
||||
components_(components),
|
||||
stream_(nullptr),
|
||||
level_(0) {}
|
||||
level_(0),
|
||||
has_parsed_attrs_(false) {}
|
||||
|
||||
~NrIceMediaStream();
|
||||
|
||||
@ -210,6 +212,7 @@ class NrIceMediaStream {
|
||||
const size_t components_;
|
||||
nr_ice_media_stream *stream_;
|
||||
uint16_t level_;
|
||||
bool has_parsed_attrs_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -265,7 +265,7 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
PR_Sleep(1000);
|
||||
}
|
||||
|
||||
void AddStream(int components) {
|
||||
void AddStream_s(int components) {
|
||||
char name[100];
|
||||
snprintf(name, sizeof(name), "%s:stream%d", name_.c_str(),
|
||||
(int)streams_.size());
|
||||
@ -281,6 +281,14 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
stream->SignalPacketReceived.connect(this, &IceTestPeer::PacketReceived);
|
||||
}
|
||||
|
||||
void AddStream(int components)
|
||||
{
|
||||
test_utils->sts_target()->Dispatch(WrapRunnable(this,
|
||||
&IceTestPeer::AddStream_s,
|
||||
components),
|
||||
NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
void SetStunServer(const std::string addr, uint16_t port) {
|
||||
if (addr.empty()) {
|
||||
// Happens when MOZ_DISABLE_NONLOCAL_CONNECTIONS is set
|
||||
@ -410,9 +418,17 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
|
||||
bool gathering_complete() { return gathering_complete_; }
|
||||
int ready_ct() { return ready_ct_; }
|
||||
bool is_ready(size_t stream) {
|
||||
bool is_ready_s(size_t stream) {
|
||||
return streams_[stream]->state() == NrIceMediaStream::ICE_OPEN;
|
||||
}
|
||||
bool is_ready(size_t stream)
|
||||
{
|
||||
bool result;
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnableRet(this, &IceTestPeer::is_ready_s, stream, &result),
|
||||
NS_DISPATCH_SYNC);
|
||||
return result;
|
||||
}
|
||||
bool ice_complete() { return ice_complete_; }
|
||||
bool ice_reached_checking() { return ice_reached_checking_; }
|
||||
size_t received() { return received_; }
|
||||
@ -426,12 +442,16 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
remote_ = remote;
|
||||
|
||||
trickle_mode_ = trickle_mode;
|
||||
ice_complete_ = false;
|
||||
res = ice_ctx_->ParseGlobalAttributes(remote->GetGlobalAttributes());
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
|
||||
if (trickle_mode == TRICKLE_NONE ||
|
||||
trickle_mode == TRICKLE_REAL) {
|
||||
for (size_t i=0; i<streams_.size(); ++i) {
|
||||
if (streams_[i]->HasParsedAttributes()) {
|
||||
continue;
|
||||
}
|
||||
std::vector<std::string> candidates =
|
||||
remote->GetCandidates(i);
|
||||
|
||||
@ -444,7 +464,11 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
} else {
|
||||
// Parse empty attributes and then trickle them out later
|
||||
for (size_t i=0; i<streams_.size(); ++i) {
|
||||
if (streams_[i]->HasParsedAttributes()) {
|
||||
continue;
|
||||
}
|
||||
std::vector<std::string> empty_attrs;
|
||||
std::cout << "Calling ParseAttributes on stream " << i << std::endl;
|
||||
res = streams_[i]->ParseAttributes(empty_attrs);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
}
|
||||
@ -470,6 +494,8 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
// If we are in trickle deferred mode, now trickle in the candidates
|
||||
// for |stream|
|
||||
|
||||
// The size of streams_ is not going to change out from under us, so should
|
||||
// be safe here.
|
||||
ASSERT_GT(remote_->streams_.size(), stream);
|
||||
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates =
|
||||
@ -602,6 +628,16 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
}
|
||||
|
||||
ice_ctx_ = nullptr;
|
||||
|
||||
if (remote_) {
|
||||
remote_->UnsetRemote();
|
||||
remote_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void UnsetRemote()
|
||||
{
|
||||
remote_ = nullptr;
|
||||
}
|
||||
|
||||
void StartChecks() {
|
||||
@ -649,7 +685,7 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
|
||||
// If we are connected, then try to trickle to the
|
||||
// other side.
|
||||
if (remote_ && remote_->remote_) {
|
||||
if (remote_ && remote_->remote_ && (trickle_mode_ != TRICKLE_SIMULATE)) {
|
||||
std::vector<mozilla::RefPtr<NrIceMediaStream> >::iterator it =
|
||||
std::find(streams_.begin(), streams_.end(), stream);
|
||||
ASSERT_NE(streams_.end(), it);
|
||||
@ -663,8 +699,9 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
}
|
||||
}
|
||||
|
||||
nsresult GetCandidatePairs(size_t stream_index,
|
||||
std::vector<NrIceCandidatePair>* pairs) {
|
||||
nsresult GetCandidatePairs_s(size_t stream_index,
|
||||
std::vector<NrIceCandidatePair>* pairs)
|
||||
{
|
||||
MOZ_ASSERT(pairs);
|
||||
if (stream_index >= streams_.size()) {
|
||||
// Is there a better error for "no such index"?
|
||||
@ -672,14 +709,20 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsresult res;
|
||||
return streams_[stream_index]->GetCandidatePairs(pairs);
|
||||
}
|
||||
|
||||
nsresult GetCandidatePairs(size_t stream_index,
|
||||
std::vector<NrIceCandidatePair>* pairs) {
|
||||
nsresult v;
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnableRet(streams_[stream_index],
|
||||
&NrIceMediaStream::GetCandidatePairs,
|
||||
WrapRunnableRet(this,
|
||||
&IceTestPeer::GetCandidatePairs_s,
|
||||
stream_index,
|
||||
pairs,
|
||||
&res),
|
||||
&v),
|
||||
NS_DISPATCH_SYNC);
|
||||
return res;
|
||||
return v;
|
||||
}
|
||||
|
||||
void DumpCandidatePair(const NrIceCandidatePair& pair) {
|
||||
@ -693,7 +736,7 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
<< " codeword = " << pair.codeword << std::endl;
|
||||
}
|
||||
|
||||
void DumpCandidatePairs(NrIceMediaStream *stream) {
|
||||
void DumpCandidatePairs_s(NrIceMediaStream *stream) {
|
||||
std::vector<NrIceCandidatePair> pairs;
|
||||
nsresult res = stream->GetCandidatePairs(&pairs);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
@ -707,10 +750,10 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
std::cerr << "]" << std::endl;
|
||||
}
|
||||
|
||||
void DumpCandidatePairs() {
|
||||
void DumpCandidatePairs_s() {
|
||||
std::cerr << "Dumping candidate pairs for all streams [" << std::endl;
|
||||
for (size_t s = 0; s < streams_.size(); ++s) {
|
||||
DumpCandidatePairs(streams_[s]);
|
||||
DumpCandidatePairs_s(streams_[s]);
|
||||
}
|
||||
std::cerr << "]" << std::endl;
|
||||
}
|
||||
@ -790,11 +833,11 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
void StreamReady(NrIceMediaStream *stream) {
|
||||
++ready_ct_;
|
||||
std::cerr << "Stream ready " << stream->name() << " ct=" << ready_ct_ << std::endl;
|
||||
DumpCandidatePairs(stream);
|
||||
DumpCandidatePairs_s(stream);
|
||||
}
|
||||
void StreamFailed(NrIceMediaStream *stream) {
|
||||
std::cerr << "Stream failed " << stream->name() << " ct=" << ready_ct_ << std::endl;
|
||||
DumpCandidatePairs(stream);
|
||||
DumpCandidatePairs_s(stream);
|
||||
}
|
||||
|
||||
void ConnectionStateChange(NrIceCtx* ctx,
|
||||
@ -834,20 +877,39 @@ class IceTestPeer : public sigslot::has_slots<> {
|
||||
candidate_filter_ = filter;
|
||||
}
|
||||
|
||||
// Allow us to parse candidates directly on the current thread.
|
||||
void ParseCandidate(size_t i, const std::string& candidate) {
|
||||
void ParseCandidate_s(size_t i, const std::string& candidate) {
|
||||
std::vector<std::string> attributes;
|
||||
|
||||
attributes.push_back(candidate);
|
||||
streams_[i]->ParseAttributes(attributes);
|
||||
}
|
||||
|
||||
void DisableComponent(size_t stream, int component_id) {
|
||||
void ParseCandidate(size_t i, const std::string& candidate)
|
||||
{
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnable(this,
|
||||
&IceTestPeer::ParseCandidate_s,
|
||||
i,
|
||||
candidate),
|
||||
NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
void DisableComponent_s(size_t stream, int component_id) {
|
||||
ASSERT_LT(stream, streams_.size());
|
||||
nsresult res = streams_[stream]->DisableComponent(component_id);
|
||||
ASSERT_TRUE(NS_SUCCEEDED(res));
|
||||
}
|
||||
|
||||
void DisableComponent(size_t stream, int component_id)
|
||||
{
|
||||
test_utils->sts_target()->Dispatch(
|
||||
WrapRunnable(this,
|
||||
&IceTestPeer::DisableComponent_s,
|
||||
stream,
|
||||
component_id),
|
||||
NS_DISPATCH_SYNC);
|
||||
}
|
||||
|
||||
int trickled() { return trickled_; }
|
||||
|
||||
void SetControlling(NrIceCtx::Controlling controlling) {
|
||||
@ -1612,6 +1674,64 @@ TEST_F(IceConnectTest, TestConnectTrickleTwoStreamsOneComponent) {
|
||||
AssertCheckingReached();
|
||||
}
|
||||
|
||||
void RealisticTrickleDelay(
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates) {
|
||||
for (size_t i = 0; i < candidates.size(); ++i) {
|
||||
SchedulableTrickleCandidate* cand = candidates[i];
|
||||
if (cand->IsHost()) {
|
||||
cand->Schedule(i*10);
|
||||
} else if (cand->IsReflexive()) {
|
||||
cand->Schedule(i*10 + 100);
|
||||
} else if (cand->IsRelay()) {
|
||||
cand->Schedule(i*10 + 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DelayRelayCandidates(
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates,
|
||||
unsigned int ms) {
|
||||
for (auto i = candidates.begin(); i != candidates.end(); ++i) {
|
||||
if ((*i)->IsRelay()) {
|
||||
(*i)->Schedule(ms);
|
||||
} else {
|
||||
(*i)->Schedule(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestConnectTrickleAddStreamDuringICE) {
|
||||
AddStream("first", 1);
|
||||
ASSERT_TRUE(Gather());
|
||||
ConnectTrickle();
|
||||
RealisticTrickleDelay(p1_->ControlTrickle(0));
|
||||
RealisticTrickleDelay(p2_->ControlTrickle(0));
|
||||
AddStream("second", 1);
|
||||
RealisticTrickleDelay(p1_->ControlTrickle(1));
|
||||
RealisticTrickleDelay(p2_->ControlTrickle(1));
|
||||
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
|
||||
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
|
||||
AssertCheckingReached();
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestConnectTrickleAddStreamAfterICE) {
|
||||
AddStream("first", 1);
|
||||
ASSERT_TRUE(Gather());
|
||||
ConnectTrickle();
|
||||
RealisticTrickleDelay(p1_->ControlTrickle(0));
|
||||
RealisticTrickleDelay(p2_->ControlTrickle(0));
|
||||
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
|
||||
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
|
||||
AddStream("second", 1);
|
||||
ASSERT_TRUE(Gather());
|
||||
ConnectTrickle();
|
||||
RealisticTrickleDelay(p1_->ControlTrickle(1));
|
||||
RealisticTrickleDelay(p2_->ControlTrickle(1));
|
||||
ASSERT_TRUE_WAIT(p1_->ice_complete(), 1000);
|
||||
ASSERT_TRUE_WAIT(p2_->ice_complete(), 1000);
|
||||
AssertCheckingReached();
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestConnectRealTrickleOneStreamOneComponent) {
|
||||
AddStream("first", 1);
|
||||
AddStream("second", 1);
|
||||
@ -1657,32 +1777,6 @@ TEST_F(IceConnectTest, TestConnectTurnWithDelay) {
|
||||
WaitForComplete();
|
||||
}
|
||||
|
||||
void RealisticTrickleDelay(
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates) {
|
||||
for (size_t i = 0; i < candidates.size(); ++i) {
|
||||
SchedulableTrickleCandidate* cand = candidates[i];
|
||||
if (cand->IsHost()) {
|
||||
cand->Schedule(i*10);
|
||||
} else if (cand->IsReflexive()) {
|
||||
cand->Schedule(i*10 + 100);
|
||||
} else if (cand->IsRelay()) {
|
||||
cand->Schedule(i*10 + 200);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DelayRelayCandidates(
|
||||
std::vector<SchedulableTrickleCandidate*>& candidates,
|
||||
unsigned int ms) {
|
||||
for (auto i = candidates.begin(); i != candidates.end(); ++i) {
|
||||
if ((*i)->IsRelay()) {
|
||||
(*i)->Schedule(ms);
|
||||
} else {
|
||||
(*i)->Schedule(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(IceConnectTest, TestConnectTurnWithNormalTrickleDelay) {
|
||||
if (g_turn_server.empty())
|
||||
return;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user