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

This commit is contained in:
Ryan VanderMeulen 2015-02-17 21:24:49 -05:00
commit 75cd780807
212 changed files with 11012 additions and 6180 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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);
};

View File

@ -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

View File

@ -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;

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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"
}

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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/");

View File

@ -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);
},

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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.

View File

@ -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)
{

View File

@ -422,6 +422,9 @@ public:
WaitRequestRef(aRejection.mType).Complete();
}
// Resets all state related to decoding, emptying all buffers etc.
void ResetDecode();
private:
void AcquireMonitorAndInvokeDecodeError();

View File

@ -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:

View File

@ -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,

View File

@ -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);
}

View File

@ -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));
}
},
};

View File

@ -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]

View File

@ -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");

View File

@ -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);
};

View File

@ -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>

View File

@ -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>

View File

@ -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();
});

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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();

View File

@ -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
});
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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!");

View File

@ -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);
};

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -1,4 +1,4 @@
// Worker that errors on receiving an install event.
oninstall = function(e) {
undefined.doSomething;
}
};

View File

@ -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]

View File

@ -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>

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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();
});
}

View File

@ -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 }, "*");
});

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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 }

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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() {

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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);
}

View 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();

View 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();

View File

@ -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;
}

View File

@ -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. */

View File

@ -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; }

View File

@ -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

View File

@ -3175,6 +3175,7 @@ public:
static FrameMetrics ComputeFrameMetrics(nsIFrame* aForFrame,
nsIFrame* aScrollFrame,
nsIContent* aContent,
const nsIFrame* aReferenceFrame,
Layer* aLayer,
ViewID aScrollParentId,

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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) ||

View File

@ -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

View File

@ -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]

View 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>

View File

@ -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);

View File

@ -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,

View File

@ -209,6 +209,7 @@ nsresult NrIceMediaStream::ParseAttributes(std::vector<std::string>&
return NS_ERROR_FAILURE;
}
has_parsed_attrs_ = true;
return NS_OK;
}

View File

@ -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_;
};

View File

@ -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