mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to fx-team
This commit is contained in:
commit
f7a74303f9
@ -163,26 +163,26 @@ public:
|
||||
const int32_t& aY) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvReplaceText(const uint64_t& aID,
|
||||
const nsString& aText);
|
||||
const nsString& aText) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvInsertText(const uint64_t& aID,
|
||||
const nsString& aText,
|
||||
const int32_t& aPosition);
|
||||
const int32_t& aPosition) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvCopyText(const uint64_t& aID,
|
||||
const int32_t& aStartPos,
|
||||
const int32_t& aEndPos);
|
||||
const int32_t& aEndPos) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvCutText(const uint64_t& aID,
|
||||
const int32_t& aStartPos,
|
||||
const int32_t& aEndPos);
|
||||
const int32_t& aEndPos) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvDeleteText(const uint64_t& aID,
|
||||
const int32_t& aStartPos,
|
||||
const int32_t& aEndPos);
|
||||
const int32_t& aEndPos) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvPasteText(const uint64_t& aID,
|
||||
const int32_t& aPosition);
|
||||
const int32_t& aPosition) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
bool PersistentPropertiesToArray(nsIPersistentProperties* aProps,
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
@ -134,10 +134,10 @@
|
||||
<project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
|
||||
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
|
||||
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
|
||||
<project name="kernel/common" path="kernel" revision="855c239879b1d0ba2dc783e64c32cf8a0afadfc4"/>
|
||||
<project name="kernel/common" path="kernel" revision="737e6b490870911879b80d0961297cd03e0a9028"/>
|
||||
<project name="platform/system/core" path="system/core" revision="a626f6c0ef9e88586569331bd7387b569eaa5ed2"/>
|
||||
<project name="u-boot" path="u-boot" revision="f1502910977ac88f43da7bf9277c3523ad4b0b2f"/>
|
||||
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="6974f8e771d4d8e910357a6739ab124768891e8f"/>
|
||||
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="4c59900937dc2e978b7b14b7f1ea617e3d5d550e"/>
|
||||
<project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="cce8a36e1ec3d136f5eb8ec4b767d9c6ef08c427"/>
|
||||
<project name="vendor/sprd/partner" path="vendor/sprd/partner" revision="8649c7145972251af11b0639997edfecabfc7c2e"/>
|
||||
<project name="vendor/sprd/proprietories" path="vendor/sprd/proprietories" revision="d2466593022f7078aaaf69026adf3367c2adb7bb"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</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="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ddf33f81e9a60f8110fcfd6b51b5dff2db676183"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</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="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ddf33f81e9a60f8110fcfd6b51b5dff2db676183"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "943c8b4039f59b08ba100390e164a076a20c892e",
|
||||
"git_revision": "2b87ee8e7e2ec30a9851b6b59a899006a98767ab",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "c8f9d4bbb0ab4ddfb272c0ee955e640b9d122b54",
|
||||
"revision": "a3f060d46f5e179164fe9435f30878ebdf58eb49",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
</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="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="ddf33f81e9a60f8110fcfd6b51b5dff2db676183"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="943c8b4039f59b08ba100390e164a076a20c892e"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="2b87ee8e7e2ec30a9851b6b59a899006a98767ab"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="c82a532ee1f14b9733214022b1e2d55a0b030be8"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -1,4 +1,6 @@
|
||||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=0
|
||||
. "$topsrcdir/browser/config/mozconfigs/linux64/nightly"
|
||||
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
@ -1,5 +1,7 @@
|
||||
MOZ_AUTOMATION_BUILD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_PACKAGE_TESTS=0
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=0
|
||||
. $topsrcdir/build/macosx/mozconfig.common
|
||||
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
@ -2,6 +2,8 @@ MOZ_AUTOMATION_BUILD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
MOZ_AUTOMATION_PACKAGE_TESTS=0
|
||||
MOZ_AUTOMATION_INSTALLER=0
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=0
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=0
|
||||
. "$topsrcdir/browser/config/mozconfigs/win32/nightly"
|
||||
|
||||
ac_add_options --enable-application=b2g/dev
|
||||
|
@ -68,13 +68,14 @@ AboutGeneric.prototype = {
|
||||
return Ci.nsIAboutModule.ALLOW_SCRIPT;
|
||||
},
|
||||
|
||||
newChannel: function(aURI) {
|
||||
newChannel: function(aURI, aLoadInfo) {
|
||||
let moduleInfo = this._getModuleInfo(aURI);
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
|
||||
var channel = ios.newChannel(moduleInfo.uri, null, null);
|
||||
var newURI = ios.newURI(moduleInfo.uri, null, null);
|
||||
var channel = ios.newChannelFromURIWithLoadInfo(newURI, aLoadInfo);
|
||||
|
||||
if (!moduleInfo.privileged) {
|
||||
// Setting the owner to null means that we'll go through the normal
|
||||
|
@ -843,7 +843,15 @@ SessionStore.prototype = {
|
||||
}
|
||||
|
||||
try {
|
||||
let channel = NetUtil.newChannel(this._sessionFileBackup);
|
||||
let channel = NetUtil.newChannel2(this._sessionFileBackup,
|
||||
null,
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
|
||||
channel.contentType = "application/json";
|
||||
NetUtil.asyncFetch(channel, function(aStream, aResult) {
|
||||
if (!Components.isSuccessCode(aResult)) {
|
||||
|
@ -5,8 +5,9 @@
|
||||
MOZ_AUTOMATION_L10N_CHECK=0
|
||||
|
||||
if [ "x$IS_NIGHTLY" = "xyes" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
# Some nightlies (eg: Mulet) don't want these set.
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
|
||||
fi
|
||||
. "$topsrcdir/build/mozconfig.common"
|
||||
|
||||
|
@ -3,8 +3,9 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if [ "x$IS_NIGHTLY" = "xyes" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
# Some nightlies (eg: Mulet) don't want these set.
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
|
||||
fi
|
||||
|
||||
# Some builds (eg: Mulet) don't want the installer, so only set this if it
|
||||
|
@ -1,6 +1,7 @@
|
||||
if [ "x$IS_NIGHTLY" = "xyes" ]; then
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=1
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=1
|
||||
# Some nightlies (eg: Mulet) don't want these set.
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS=${MOZ_AUTOMATION_UPLOAD_SYMBOLS-1}
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING=${MOZ_AUTOMATION_UPDATE_PACKAGING-1}
|
||||
fi
|
||||
|
||||
. "$topsrcdir/build/mozconfig.common"
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "nsIGlobalHistory2.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIURI.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsDownloadHistory
|
||||
@ -42,7 +43,7 @@ nsDownloadHistory::AddDownload(nsIURI* aSource,
|
||||
|
||||
if (!visited) {
|
||||
nsCOMPtr<nsIObserverService> os =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
mozilla::services::GetObserverService();
|
||||
if (os) {
|
||||
os->NotifyObservers(aSource, NS_LINK_VISITED_EVENT_TOPIC, nullptr);
|
||||
}
|
||||
|
@ -19,10 +19,11 @@
|
||||
</style>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script src="../testcommon.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="log"></div>
|
||||
<script type="text/javascript;version=1.8">
|
||||
<script type="text/javascript">
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -41,13 +42,42 @@
|
||||
const CSS_ANIM_EVENTS = ['animationstart', 'animationiteration', 'animationend'];
|
||||
const ANIM_DELAY_MS = 1000000; // 1000s
|
||||
const ANIM_DUR_MS = 1000000; // 1000s
|
||||
const ANIM_PROPERTY_VAL = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
|
||||
/**
|
||||
* These helpers get the value that the startTime needs to be set to, to put an
|
||||
* animation that uses the above ANIM_DELAY_MS and ANIM_DUR_MS values into the
|
||||
* middle of various phases or points through the active duration.
|
||||
*/
|
||||
function startTimeForBeforePhase(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS / 2;
|
||||
}
|
||||
function startTimeForActivePhase(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS / 2;
|
||||
}
|
||||
function startTimeForAfterPhase(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS - ANIM_DELAY_MS / 2;
|
||||
}
|
||||
function startTimeForStartOfActiveInterval(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS;
|
||||
}
|
||||
function startTimeForFiftyPercentThroughActiveInterval(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5;
|
||||
}
|
||||
function startTimeForNinetyPercentThroughActiveInterval(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.9;
|
||||
}
|
||||
function startTimeForEndOfActiveInterval(timeline) {
|
||||
return timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS;
|
||||
}
|
||||
|
||||
|
||||
// Expected computed 'margin-left' values at points during the active interval:
|
||||
// When we assert_between_inclusive using these values we could in theory cause
|
||||
// intermittent failure due to long refresh driver delays, but since the active
|
||||
// duration is 1000s long, a delay would need to be around 100s to cause that.
|
||||
// If that's happening than we have issues that we should solve anyway, so a
|
||||
// failure to make us look into that seems like a good thing.
|
||||
// intermittent failure due to very long delays between paints, but since the
|
||||
// active duration is 1000s long, a delay would need to be around 100s to cause
|
||||
// that. If that's happening then there are likely other issues that should be
|
||||
// fixed, so a failure to make us look into that seems like a good thing.
|
||||
const UNANIMATED_POSITION = 10;
|
||||
const INITIAL_POSITION = 100;
|
||||
const TEN_PCT_POSITION = 110;
|
||||
@ -55,17 +85,6 @@ const FIFTY_PCT_POSITION = 150;
|
||||
const NINETY_PCT_POSITION = 190;
|
||||
const END_POSITION = 200;
|
||||
|
||||
function addDiv(id)
|
||||
{
|
||||
var div = document.createElement('div');
|
||||
div.setAttribute('class', 'animated-div');
|
||||
if (id) {
|
||||
div.setAttribute('id', id);
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
return div;
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS animation events fire asynchronously after we set 'startTime'. This
|
||||
* helper class allows us to handle such events using Promises.
|
||||
@ -84,7 +103,7 @@ function addDiv(id)
|
||||
* eventWatcher.stopWatching(); // all done - stop listening for events
|
||||
* });
|
||||
*
|
||||
* This class will assert_true(false) if an event occurs when there is no
|
||||
* This class will assert_unreached() if an event occurs when there is no
|
||||
* Promise created by a waitForEvent() call waiting to be fulfilled, or if the
|
||||
* event is of a different type to the type passed to waitForEvent. This helps
|
||||
* provide test coverage to ensure that only events that are expected occur, in
|
||||
@ -102,13 +121,13 @@ function EventWatcher(watchedNode, eventTypes)
|
||||
|
||||
function eventHandler(evt) {
|
||||
if (!waitingFor) {
|
||||
assert_true(false, 'Not expecting event, but got: ' + evt.type +
|
||||
assert_unreached('Not expecting event, but got: ' + evt.type +
|
||||
' targeting element #' + evt.target.getAttribute('id'));
|
||||
return;
|
||||
}
|
||||
if (evt.type != waitingFor.types[0]) {
|
||||
assert_true(false, 'Expected ' + waitingFor.types[0] + ' event but got ' +
|
||||
evt.type + ' event');
|
||||
assert_unreached('Expected ' + waitingFor.types[0] + ' event but got ' +
|
||||
evt.type + ' event');
|
||||
return;
|
||||
}
|
||||
if (waitingFor.types.length > 1) {
|
||||
@ -124,8 +143,8 @@ function EventWatcher(watchedNode, eventTypes)
|
||||
resolveFunc(evt);
|
||||
}
|
||||
|
||||
for (let event of eventTypes) {
|
||||
watchedNode.addEventListener(event, eventHandler);
|
||||
for (var i = 0; i < eventTypes.length; i++) {
|
||||
watchedNode.addEventListener(eventTypes[i], eventHandler);
|
||||
}
|
||||
|
||||
this.waitForEvent = function(type) {
|
||||
@ -164,8 +183,8 @@ function EventWatcher(watchedNode, eventTypes)
|
||||
};
|
||||
|
||||
this.stopWatching = function() {
|
||||
for (let event of eventTypes) {
|
||||
watchedNode.removeEventListener(event, eventHandler);
|
||||
for (var i = 0; i < eventTypes.length; i++) {
|
||||
watchedNode.removeEventListener(eventTypes[i], eventHandler);
|
||||
}
|
||||
};
|
||||
|
||||
@ -206,7 +225,7 @@ function checkStateOnSettingStartTimeToAnimationCreationTime(player)
|
||||
// Called when the ready Promise's callbacks should happen
|
||||
function checkStateOnReadyPromiseResolved(player)
|
||||
{
|
||||
assert_less_than_equal(player.startTime, document.timeline.currentTime,
|
||||
assert_less_than_equal(player.startTime, player.timeline.currentTime,
|
||||
'AnimationPlayer.startTime should be less than the timeline\'s ' +
|
||||
'currentTime on the first paint tick after animation creation');
|
||||
|
||||
@ -288,11 +307,11 @@ function checkStateAtActiveIntervalEndTime(player)
|
||||
}
|
||||
|
||||
|
||||
test(function()
|
||||
test(function(t)
|
||||
{
|
||||
var div = addDiv();
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
|
||||
div.style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
@ -315,48 +334,45 @@ test(function()
|
||||
// will be called (async) regardless of whether the Promise was resolved in
|
||||
// the past or is resolved in the future.
|
||||
|
||||
var currentTime = document.timeline.currentTime;
|
||||
player.startTime = document.timeline.currentTime;
|
||||
var currentTime = player.timeline.currentTime;
|
||||
player.startTime = currentTime;
|
||||
assert_approx_equals(player.startTime, currentTime, 0.0001, // rounding error
|
||||
'Check setting of startTime actually works');
|
||||
|
||||
checkStateOnSettingStartTimeToAnimationCreationTime(player);
|
||||
|
||||
div.parentNode.removeChild(div);
|
||||
}, 'Examine newly created Animation');
|
||||
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv();
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
|
||||
div.style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
player.ready.then(t.step_func(function() {
|
||||
checkStateOnReadyPromiseResolved(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS; // jump to start of active interval
|
||||
player.startTime = startTimeForStartOfActiveInterval(player.timeline);
|
||||
return eventWatcher.waitForEvent('animationstart');
|
||||
})).then(t.step_func(function() {
|
||||
checkStateAtActiveIntervalStartTime(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5; // 50% through active interval
|
||||
player.startTime = startTimeForFiftyPercentThroughActiveInterval(player.timeline);
|
||||
checkStateAtFiftyPctOfActiveInterval(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.9; // 90% through active interval
|
||||
player.startTime = startTimeForNinetyPercentThroughActiveInterval(player.timeline);
|
||||
checkStateAtNinetyPctOfActiveInterval(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS; // end of active interval
|
||||
player.startTime = startTimeForEndOfActiveInterval(player.timeline);
|
||||
return eventWatcher.waitForEvent('animationend');
|
||||
})).then(t.step_func(function() {
|
||||
checkStateAtActiveIntervalEndTime(player);
|
||||
|
||||
eventWatcher.stopWatching();
|
||||
div.parentNode.removeChild(div);
|
||||
})).catch(t.step_func(function(reason) {
|
||||
assert_true(false, reason);
|
||||
assert_unreached(reason);
|
||||
})).then(function() {
|
||||
t.done();
|
||||
});
|
||||
@ -364,14 +380,14 @@ async_test(function(t) {
|
||||
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv();
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
|
||||
div.style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS; // end of active interval
|
||||
player.startTime = startTimeForEndOfActiveInterval(player.timeline);
|
||||
|
||||
// Skipping over the active interval will dispatch an 'animationstart' then
|
||||
// an 'animationend' event. We need to wait for these events before we start
|
||||
@ -382,7 +398,7 @@ async_test(function(t) {
|
||||
// that after the events we're still in the same end time state:
|
||||
checkStateAtActiveIntervalEndTime(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.9; // 90% through active interval
|
||||
player.startTime = startTimeForNinetyPercentThroughActiveInterval(player.timeline);
|
||||
|
||||
// Despite going backwards from after the end of the animation to just
|
||||
// before the end of the animation, we now expect an animationstart event
|
||||
@ -391,13 +407,13 @@ async_test(function(t) {
|
||||
})).then(t.step_func(function() {
|
||||
checkStateAtNinetyPctOfActiveInterval(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS * 0.5; // 50% through active interval
|
||||
player.startTime = startTimeForFiftyPercentThroughActiveInterval(player.timeline);
|
||||
checkStateAtFiftyPctOfActiveInterval(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime - ANIM_DELAY_MS; // jump to start of active interval
|
||||
player.startTime = startTimeForStartOfActiveInterval(player.timeline);
|
||||
checkStateAtActiveIntervalStartTime(player);
|
||||
|
||||
player.startTime = document.timeline.currentTime;
|
||||
player.startTime = player.timeline.currentTime;
|
||||
// Despite going backwards from just after the active interval starts to
|
||||
// the animation start time, we now expect an animationend event
|
||||
// because we went from inside to outside the active interval.
|
||||
@ -406,9 +422,8 @@ async_test(function(t) {
|
||||
checkStateOnReadyPromiseResolved(player);
|
||||
|
||||
eventWatcher.stopWatching();
|
||||
div.parentNode.removeChild(div);
|
||||
})).catch(t.step_func(function(reason) {
|
||||
assert_true(false, reason);
|
||||
assert_unreached(reason);
|
||||
})).then(function() {
|
||||
t.done();
|
||||
});
|
||||
@ -421,102 +436,133 @@ async_test(function(t) {
|
||||
}, 'Skipping backwards through animation');
|
||||
|
||||
|
||||
// Here we have multiple tests to check that redundant startTime changes do NOT
|
||||
// Next we have multiple tests to check that redundant startTime changes do NOT
|
||||
// dispatch events. It's impossible to distinguish between events not being
|
||||
// dispatched and events just taking an incredibly long time to dispatch
|
||||
// without some sort of risk of creating intermittent failure. We have a short
|
||||
// timeout here since we don't want to delay the completion of this test file
|
||||
// waiting for a long time to make "more sure" events weren't dispatched rather
|
||||
// than being late.
|
||||
//
|
||||
// We test:
|
||||
//
|
||||
// * before -> active, then back
|
||||
// * before -> after, then back
|
||||
// * active -> before, then back
|
||||
// * active -> after, then back
|
||||
// * after -> before, then back
|
||||
// * after -> active, then back
|
||||
//
|
||||
// We do all these tests in a single async_test since that allows us to share
|
||||
// the timeout that we use to wait so that this test file isn't delayed by the
|
||||
// timeout time multiplied by number of tests.
|
||||
// without waiting an infinitely long time. Obviously we don't want to do that
|
||||
// (block this test from finishing forever), so instead we just listen for
|
||||
// events until two animation frames (i.e. requestAnimationFrame callbacks)
|
||||
// have happened, then assume that no events will ever be dispatched for the
|
||||
// redundant changes if no events were detected in that time.
|
||||
|
||||
async_test(function(t) {
|
||||
var divs = new Array(6);
|
||||
var eventWatchers = new Array(6);
|
||||
var players = new Array(6);
|
||||
for (let i = 0; i < 6; i++) {
|
||||
divs[i] = addDiv();
|
||||
eventWatchers[i] = new EventWatcher(divs[i], CSS_ANIM_EVENTS);
|
||||
divs[i].style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
players[i] = divs[i].getAnimationPlayers()[0];
|
||||
}
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
var beforeTime = document.timeline.currentTime - ANIM_DELAY_MS / 2;
|
||||
var activeTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS / 2;
|
||||
var afterTime = document.timeline.currentTime - ANIM_DELAY_MS - ANIM_DUR_MS - ANIM_DELAY_MS / 2;
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
player.startTime = startTimeForBeforePhase(player.timeline);
|
||||
|
||||
// before -> active, then back:
|
||||
players[0].startTime = activeTime;
|
||||
players[0].startTime = beforeTime;
|
||||
|
||||
// before -> after, then back:
|
||||
players[1].startTime = afterTime;
|
||||
players[1].startTime = beforeTime;
|
||||
|
||||
// active -> before, then back:
|
||||
eventWatchers[2].waitForEvent('animationstart').then(function() {
|
||||
players[2].startTime = beforeTime;
|
||||
players[2].startTime = activeTime;
|
||||
});
|
||||
players[2].startTime = activeTime; // get us into the initial state
|
||||
|
||||
// active -> after, then back:
|
||||
eventWatchers[3].waitForEvent('animationstart').then(function() {
|
||||
players[3].startTime = afterTime;
|
||||
players[3].startTime = activeTime;
|
||||
});
|
||||
players[3].startTime = activeTime; // get us into the initial state
|
||||
|
||||
// after -> before, then back:
|
||||
eventWatchers[4].waitForEvents(['animationstart', 'animationend']).then(function() {
|
||||
players[4].startTime = beforeTime;
|
||||
players[4].startTime = afterTime;
|
||||
});
|
||||
players[4].startTime = afterTime; // get us into the initial state
|
||||
|
||||
// after -> active, then back:
|
||||
eventWatchers[5].waitForEvents(['animationstart', 'animationend']).then(function() {
|
||||
players[5].startTime = activeTime;
|
||||
players[5].startTime = afterTime;
|
||||
});
|
||||
players[5].startTime = afterTime; // get us into the initial state
|
||||
|
||||
// See the long comment documenting this async_test for an explanation of
|
||||
// why we have this timeout and its relationship to intermittent failure.
|
||||
setTimeout(function() {
|
||||
for (let i = 0; i < 6; i++) {
|
||||
eventWatchers[i].stopWatching();
|
||||
divs[i].parentNode.removeChild(divs[i]);
|
||||
}
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
}, 1000);
|
||||
}, 'Redundant changes');
|
||||
});
|
||||
}, 'Redundant change, before -> active, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
player.startTime = startTimeForBeforePhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
}, 'Redundant change, before -> after, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
eventWatcher.waitForEvent('animationstart').then(function() {
|
||||
player.startTime = startTimeForBeforePhase(player.timeline);
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
});
|
||||
// get us into the initial state:
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
}, 'Redundant change, active -> before, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
eventWatcher.waitForEvent('animationstart').then(function() {
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
});
|
||||
// get us into the initial state:
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
}, 'Redundant change, active -> after, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
eventWatcher.waitForEvents(['animationstart', 'animationend']).then(function() {
|
||||
player.startTime = startTimeForBeforePhase(player.timeline);
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
});
|
||||
// get us into the initial state:
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
}, 'Redundant change, after -> before, then back');
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
var eventWatcher = new EventWatcher(div, CSS_ANIM_EVENTS);
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
eventWatcher.waitForEvents(['animationstart', 'animationend']).then(function() {
|
||||
player.startTime = startTimeForActivePhase(player.timeline);
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
|
||||
waitForTwoAnimationFrames().then(function() {
|
||||
eventWatcher.stopWatching();
|
||||
t.done();
|
||||
});
|
||||
});
|
||||
// get us into the initial state:
|
||||
player.startTime = startTimeForAfterPhase(player.timeline);
|
||||
}, 'Redundant change, after -> active, then back');
|
||||
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv();
|
||||
div.style.animation = 'anim ' + ANIM_DUR_MS + 'ms ' + ANIM_DELAY_MS + 'ms';
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
div.style.animation = ANIM_PROPERTY_VAL;
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
|
||||
player.ready.then(t.step_func(function() {
|
||||
player.startTime = null;
|
||||
return player.ready;
|
||||
})).then(t.step_func(function() {
|
||||
div.parentNode.removeChild(div);
|
||||
})).catch(t.step_func(function(reason) {
|
||||
assert_true(false, reason);
|
||||
assert_unreached(reason);
|
||||
})).then(function() {
|
||||
t.done();
|
||||
});
|
||||
@ -524,7 +570,7 @@ async_test(function(t) {
|
||||
|
||||
|
||||
async_test(function(t) {
|
||||
var div = addDiv();
|
||||
var div = addDiv(t, {'class': 'animated-div'});
|
||||
div.style.animation = 'anim 100s';
|
||||
|
||||
var player = div.getAnimationPlayers()[0];
|
||||
@ -540,10 +586,8 @@ async_test(function(t) {
|
||||
'AnimationPlayer.startTime is null after paused');
|
||||
assert_equals(player.playState, 'paused',
|
||||
'AnimationPlayer.playState is "paused" after pause() call');
|
||||
|
||||
div.parentNode.removeChild(div);
|
||||
})).catch(t.step_func(function(reason) {
|
||||
assert_true(false, reason);
|
||||
assert_unreached(reason);
|
||||
})).then(function() {
|
||||
t.done();
|
||||
});
|
||||
|
@ -7,12 +7,24 @@
|
||||
* @param t The testharness.js Test object. If provided, this will be used
|
||||
* to register a cleanup callback to remove the div when the test
|
||||
* finishes.
|
||||
*
|
||||
* @param attrs A dictionary object with attribute names and values to set on
|
||||
* the div.
|
||||
*/
|
||||
function addDiv(t) {
|
||||
function addDiv(t, attrs) {
|
||||
var div = document.createElement('div');
|
||||
if (attrs) {
|
||||
for (var attrName in attrs) {
|
||||
div.setAttribute(attrName, attrs[attrName]);
|
||||
}
|
||||
}
|
||||
document.body.appendChild(div);
|
||||
if (t && typeof t.add_cleanup === 'function') {
|
||||
t.add_cleanup(function() { div.remove(); });
|
||||
t.add_cleanup(function() {
|
||||
if (div.parentNode) {
|
||||
div.parentNode.removeChild(div);
|
||||
}
|
||||
});
|
||||
}
|
||||
return div;
|
||||
}
|
||||
@ -34,3 +46,19 @@ function waitForFrame() {
|
||||
function waitForAllPlayers(players) {
|
||||
return Promise.all(players.map(function(player) { return player.ready; }));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Promise that is resolved after the next two animation frames have
|
||||
* occured (that is, after two consecutive requestAnimationFrame callbacks
|
||||
* have been called).
|
||||
*/
|
||||
function waitForTwoAnimationFrames() {
|
||||
return new Promise(function(resolve, reject) {
|
||||
window.requestAnimationFrame(function() {
|
||||
window.requestAnimationFrame(function() {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "nsIApplicationCacheContainer.h"
|
||||
#include "nsIApplicationCacheChannel.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
#include "nsICookieService.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
@ -686,6 +687,10 @@ nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
|
||||
PrefetchDNS(aHref);
|
||||
}
|
||||
|
||||
if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::ePRECONNECT)) {
|
||||
Preconnect(aHref);
|
||||
}
|
||||
|
||||
// is it a stylesheet link?
|
||||
if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) {
|
||||
return NS_OK;
|
||||
@ -857,6 +862,26 @@ nsContentSink::PrefetchDNS(const nsAString &aHref)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsContentSink::Preconnect(const nsAString &aHref)
|
||||
{
|
||||
nsCOMPtr<nsISpeculativeConnect>
|
||||
speculator(do_QueryInterface(nsContentUtils::GetIOService()));
|
||||
if (!speculator) {
|
||||
return;
|
||||
}
|
||||
|
||||
// construct URI using document charset
|
||||
const nsACString& charset = mDocument->GetDocumentCharacterSet();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
NS_NewURI(getter_AddRefs(uri), aHref,
|
||||
charset.IsEmpty() ? nullptr : PromiseFlatCString(charset).get(),
|
||||
mDocument->GetDocBaseURI());
|
||||
if (uri) {
|
||||
speculator->SpeculativeConnect(uri, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentSink::SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
|
||||
nsIURI *aManifestURI,
|
||||
|
@ -164,9 +164,10 @@ protected:
|
||||
void PrefetchHref(const nsAString &aHref, nsINode *aSource,
|
||||
bool aExplicit);
|
||||
|
||||
// aHref can either be the usual URI format or of the form "//www.hostname.com"
|
||||
// without a scheme.
|
||||
// For both PrefetchDNS() and Preconnect() aHref can either be the usual
|
||||
// URI format or of the form "//www.hostname.com" without a scheme.
|
||||
void PrefetchDNS(const nsAString &aHref);
|
||||
void Preconnect(const nsAString &aHref);
|
||||
|
||||
// Gets the cache key (used to identify items in a cache) of the channel.
|
||||
nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey);
|
||||
|
@ -8846,7 +8846,7 @@ public:
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
services::GetObserverService();
|
||||
if (observerService) {
|
||||
nsCOMPtr<nsISupportsPRUint64> wrapper =
|
||||
do_CreateInstance(NS_SUPPORTS_PRUINT64_CONTRACTID);
|
||||
|
@ -150,6 +150,8 @@ static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal)
|
||||
else if (aLink.EqualsLiteral("import") &&
|
||||
nsStyleLinkElement::IsImportEnabled())
|
||||
return nsStyleLinkElement::eHTMLIMPORT;
|
||||
else if (aLink.EqualsLiteral("preconnect"))
|
||||
return nsStyleLinkElement::ePRECONNECT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
@ -59,7 +59,8 @@ public:
|
||||
eSTYLESHEET = 0x00000004,
|
||||
eNEXT = 0x00000008,
|
||||
eALTERNATE = 0x00000010,
|
||||
eHTMLIMPORT = 0x00000020
|
||||
eHTMLIMPORT = 0x00000020,
|
||||
ePRECONNECT = 0x00000040
|
||||
};
|
||||
|
||||
// The return value is a bitwise or of 0 or more RelValues.
|
||||
|
@ -2044,11 +2044,15 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
|
||||
}
|
||||
nsCOMPtr<nsIFile> jarFile;
|
||||
jarChannel->GetJarFile(getter_AddRefs(jarFile));
|
||||
rv = mArrayBufferBuilder.mapToFileInPackage(file, jarFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (!jarFile) {
|
||||
mIsMappedArrayBuffer = false;
|
||||
} else {
|
||||
channel->SetContentType(NS_LITERAL_CSTRING("application/mem-mapped"));
|
||||
rv = mArrayBufferBuilder.mapToFileInPackage(file, jarFile);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mIsMappedArrayBuffer = false;
|
||||
} else {
|
||||
channel->SetContentType(NS_LITERAL_CSTRING("application/mem-mapped"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
support-files =
|
||||
file_url.jsm
|
||||
file_empty.html
|
||||
file_bug945152.jar
|
||||
file_bug945152_worker.js
|
||||
file_bug1008126_worker.js
|
||||
|
||||
[test_anonymousContent_xul_window.xul]
|
||||
[test_bug715041.xul]
|
||||
@ -18,3 +21,7 @@ support-files =
|
||||
[test_messagemanager_principal.html]
|
||||
[test_messagemanager_send_principal.html]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[test_bug945152.html]
|
||||
run-if = os == 'linux'
|
||||
[test_bug1008126.html]
|
||||
run-if = os == 'linux'
|
||||
|
@ -206,13 +206,31 @@
|
||||
function recvDomTest(message) {
|
||||
savedElement = message.objects.element;
|
||||
|
||||
is(savedElement.QueryInterface(Components.interfaces.nsISupports), savedElement,
|
||||
"QI to nsISupports works");
|
||||
is(savedElement.QueryInterface(Components.interfaces.nsIDOMNode), savedElement,
|
||||
"QI to a random (implemented) interface works");
|
||||
|
||||
function testNoInterface(savedElement, i) {
|
||||
try {
|
||||
savedElement.QueryInterface(i);
|
||||
ok(false, "should have thrown an exception");
|
||||
} catch (e) {
|
||||
is(e.result, Components.results.NS_ERROR_NO_INTERFACE, "threw the right exception");
|
||||
}
|
||||
}
|
||||
|
||||
testNoInterface(savedElement, Components.interfaces.nsIDOMAttr);
|
||||
testNoInterface(savedElement, Components.interfaces.nsIClassInfo);
|
||||
|
||||
// Test to ensure that we don't pass CPOWs to C++-implemented interfaces.
|
||||
// See bug 1072980.
|
||||
if (test_state == "remote") {
|
||||
// This doesn't work because we intercept toString specially
|
||||
// This doesn't work because we intercept toString and QueryInterface specially
|
||||
// and don't cache the function pointer.
|
||||
// See bug 1140636.
|
||||
todo_is(savedElement.toString, savedElement.toString, "toString identity works");
|
||||
todo_is(savedElement.QueryInterface, savedElement.QueryInterface, "toString identity works");
|
||||
|
||||
// This does work because we create a CPOW for isEqualNode that stays
|
||||
// alive as long as we have a reference to the first CPOW (so as long
|
||||
|
@ -3,9 +3,9 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
var gJar1 = "jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_1.txt";
|
||||
var gJar2 = "jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_2.txt";
|
||||
var gJar3 = "jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_big.txt";
|
||||
var gEntry1 = "data_1.txt";
|
||||
var gEntry2 = "data_2.txt";
|
||||
var gEntry3 = "data_big.txt";
|
||||
var gPaddingChar = ".";
|
||||
var gPaddingSize = 10000;
|
||||
var gPadding = "";
|
||||
@ -37,6 +37,11 @@ function checkData(xhr, data, mapped, cb) {
|
||||
}
|
||||
|
||||
self.onmessage = function onmessage(event) {
|
||||
var jar = event.data;
|
||||
|
||||
function makeJarURL(entry) {
|
||||
return "jar:" + jar + "!/" + entry;
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
|
||||
@ -71,7 +76,7 @@ self.onmessage = function onmessage(event) {
|
||||
}
|
||||
};
|
||||
xhr.onload = runTests;
|
||||
xhr.open("GET", gJar3, true);
|
||||
xhr.open("GET", makeJarURL(gEntry3), true);
|
||||
xhr.responseType = "moz-chunked-arraybuffer";
|
||||
xhr.send();
|
||||
}
|
||||
@ -104,7 +109,7 @@ self.onmessage = function onmessage(event) {
|
||||
loadendCount++;
|
||||
checkData(xhr, gData2, false, function() {} );
|
||||
};
|
||||
xhr.open("GET", gJar2, false);
|
||||
xhr.open("GET", makeJarURL(gEntry2), false);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
checkEventCount(runTests);
|
||||
@ -112,7 +117,7 @@ self.onmessage = function onmessage(event) {
|
||||
|
||||
function test_sync_xhr_data1() {
|
||||
ok(true, "Test sync XHR with data1");
|
||||
xhr.open("GET", gJar1, false);
|
||||
xhr.open("GET", makeJarURL(gEntry1), false);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
checkData(xhr, gData1, true, runTests);
|
||||
@ -120,7 +125,7 @@ self.onmessage = function onmessage(event) {
|
||||
|
||||
function test_sync_xhr_data2() {
|
||||
ok(true, "Test sync XHR with data2");
|
||||
xhr.open("GET", gJar2, false);
|
||||
xhr.open("GET", makeJarURL(gEntry2), false);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
checkData(xhr, gData2, false, runTests);
|
||||
@ -131,7 +136,7 @@ self.onmessage = function onmessage(event) {
|
||||
xhr.onload = function() {
|
||||
checkData(xhr, gData1, true, runTests);
|
||||
};
|
||||
xhr.open("GET", gJar1, true);
|
||||
xhr.open("GET", makeJarURL(gEntry1), true);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
}
|
||||
@ -141,7 +146,7 @@ self.onmessage = function onmessage(event) {
|
||||
xhr.onload = function() {
|
||||
checkData(xhr, gData2, false, runTests);
|
||||
};
|
||||
xhr.open("GET", gJar2, true);
|
||||
xhr.open("GET", makeJarURL(gEntry2), true);
|
||||
xhr.responseType = "arraybuffer";
|
||||
xhr.send();
|
||||
}
|
||||
|
@ -26,10 +26,15 @@ function checkData(response, data_head, cb) {
|
||||
}
|
||||
|
||||
self.onmessage = function onmessage(event) {
|
||||
var jar = event.data;
|
||||
|
||||
function makeJarURL(entry) {
|
||||
return "jar:" + jar + "!/" + entry;
|
||||
}
|
||||
|
||||
function test_mapped_sync() {
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('GET', 'jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_1.txt', false);
|
||||
xhr.open('GET', makeJarURL('data_1.txt'), false);
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.send();
|
||||
if (xhr.status) {
|
||||
@ -42,7 +47,7 @@ self.onmessage = function onmessage(event) {
|
||||
|
||||
function test_mapped_async() {
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('GET', 'jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_1.txt');
|
||||
xhr.open('GET', makeJarURL('data_1.txt'));
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState !== xhr.DONE) {
|
||||
@ -62,7 +67,7 @@ self.onmessage = function onmessage(event) {
|
||||
// handled by memory allocation instead of memory mapping.
|
||||
function test_non_mapped() {
|
||||
var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
|
||||
xhr.open('GET', 'jar:http://example.org/tests/dom/base/test/file_bug945152.jar!/data_2.txt');
|
||||
xhr.open('GET', makeJarURL('data_2.txt'));
|
||||
xhr.responseType = 'arraybuffer';
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState !== xhr.DONE) {
|
||||
|
@ -162,8 +162,6 @@ support-files =
|
||||
file_bug902350_frame.html
|
||||
file_bug907892.html
|
||||
file_bug945152.jar
|
||||
file_bug945152_worker.js
|
||||
file_bug1008126_worker.js
|
||||
file_general_document.html
|
||||
file_html_in_xhr.html
|
||||
file_html_in_xhr.sjs
|
||||
@ -659,11 +657,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
|
||||
[test_bug907892.html]
|
||||
[test_bug922681.html]
|
||||
[test_bug927196.html]
|
||||
[test_bug945152.html]
|
||||
skip-if = os != 'linux'
|
||||
[test_bug982153.html]
|
||||
[test_bug1008126.html]
|
||||
skip-if = os != 'linux'
|
||||
[test_bug1057176.html]
|
||||
[test_bug1070015.html]
|
||||
[test_bug1075702.html]
|
||||
|
@ -10,8 +10,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1008126
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1008126</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1008126">Mozilla Bug 1008126</a>
|
||||
@ -20,10 +20,16 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1008126
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
<script type="application/javascript;version=1.7">
|
||||
function translateChrome(uriStr) {
|
||||
const { Cc, Ci } = SpecialPowers;
|
||||
let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
|
||||
let uri = ios.newURI(uriStr, null, ios.newURI(document.baseURI, null, null));
|
||||
return chromeReg.convertChromeURL(uri).spec;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
|
||||
var worker = new Worker("file_bug1008126_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
@ -36,11 +42,11 @@ function runTest() {
|
||||
|
||||
worker.onerror = function(event) {
|
||||
is(event.target, worker);
|
||||
ok(false, "Worker had an error: " + event.message);
|
||||
ok(false, "Worker had an error: " + event.filename + ":" + event.lineno + ":" + event.colno + ": " + event.message);
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
worker.postMessage(true);
|
||||
worker.postMessage(translateChrome("file_bug945152.jar"));
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -6,8 +6,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 945152</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=945152">Mozilla Bug 945152</a>
|
||||
@ -16,7 +16,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=945152
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
<script type="application/javascript;version=1.7">
|
||||
function translateChrome(uriStr) {
|
||||
const { Cc, Ci } = SpecialPowers;
|
||||
let ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIChromeRegistry);
|
||||
let uri = ios.newURI(uriStr, null, ios.newURI(document.baseURI, null, null));
|
||||
return chromeReg.convertChromeURL(uri).spec;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var worker = new Worker("file_bug945152_worker.js");
|
||||
@ -31,11 +38,11 @@ function runTest() {
|
||||
|
||||
worker.onerror = function(event) {
|
||||
is(event.target, worker);
|
||||
ok(false, "Worker had an error: " + event.data);
|
||||
ok(false, "Worker had an error: " + event.filename + ":" + event.lineno + ":" + event.colno + ": " + event.message);
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
worker.postMessage(true);
|
||||
worker.postMessage(translateChrome("file_bug945152.jar"));
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -25,6 +25,9 @@
|
||||
#include "mozilla/layers/TextureClient.h"
|
||||
#include "CameraPreferences.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
|
||||
#include "GonkBufferQueueProducer.h"
|
||||
#endif
|
||||
#include "GonkCameraControl.h"
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "CameraCommon.h"
|
||||
@ -187,6 +190,7 @@ GonkCameraHardware::Init()
|
||||
sp<IGraphicBufferProducer> producer;
|
||||
sp<IGonkGraphicBufferConsumer> consumer;
|
||||
GonkBufferQueue::createBufferQueue(&producer, &consumer);
|
||||
static_cast<GonkBufferQueueProducer*>(producer.get())->setSynchronousMode(false);
|
||||
mNativeWindow = new GonkNativeWindow(consumer, GonkCameraHardware::MIN_UNDEQUEUED_BUFFERS);
|
||||
mCamera->setPreviewTarget(producer);
|
||||
#elif ANDROID_VERSION >= 19
|
||||
|
@ -31,6 +31,9 @@ public:
|
||||
NetworkError()
|
||||
{
|
||||
nsRefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
|
||||
ErrorResult result;
|
||||
response->Headers()->SetGuard(HeadersGuardEnum::Immutable, result);
|
||||
MOZ_ASSERT(!result.Failed());
|
||||
response->mType = ResponseType::Error;
|
||||
return response.forget();
|
||||
}
|
||||
|
@ -112,6 +112,8 @@ Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
r->GetInternalHeaders()->SetGuard(HeadersGuardEnum::Immutable, aRv);
|
||||
MOZ_ASSERT(!aRv.Failed());
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
@ -419,7 +419,8 @@ HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
// SetAttr handles setting src since it needs to catch img.src =
|
||||
// img.src, so we only need to handle the unset case
|
||||
if (InResponsiveMode()) {
|
||||
if (mResponsiveSelector->Content() == this) {
|
||||
if (mResponsiveSelector &&
|
||||
mResponsiveSelector->Content() == this) {
|
||||
mResponsiveSelector->SetDefaultSource(NullString());
|
||||
}
|
||||
QueueImageLoadTask();
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMStyleSheet.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
#include "nsIStyleSheet.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "nsIURL.h"
|
||||
@ -147,6 +148,10 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
aDocument->RegisterPendingLinkUpdate(this);
|
||||
}
|
||||
|
||||
if (IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
}
|
||||
|
||||
void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
|
||||
nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update));
|
||||
|
||||
@ -292,6 +297,30 @@ HTMLLinkElement::UpdateImport()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::UpdatePreconnect()
|
||||
{
|
||||
// rel type should be preconnect
|
||||
nsAutoString rel;
|
||||
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel, NodePrincipal());
|
||||
if (!(linkTypes & ePRECONNECT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISpeculativeConnect>
|
||||
speculator(do_QueryInterface(nsContentUtils::GetIOService()));
|
||||
if (speculator) {
|
||||
nsCOMPtr<nsIURI> uri = GetHrefURI();
|
||||
if (uri) {
|
||||
speculator->SpeculativeConnect(uri, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
@ -326,11 +355,16 @@ HTMLLinkElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET);
|
||||
} else if (linkTypes & eHTMLIMPORT) {
|
||||
UpdateImport();
|
||||
} else if ((linkTypes & ePRECONNECT) && IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
}
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::href) {
|
||||
UpdateImport();
|
||||
if (IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStyleSheetInternal(nullptr, nullptr,
|
||||
|
@ -43,6 +43,7 @@ public:
|
||||
void LinkRemoved();
|
||||
|
||||
void UpdateImport();
|
||||
void UpdatePreconnect();
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
|
||||
|
@ -11,10 +11,6 @@
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "nsCycleCollector.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace indexedDB {
|
||||
@ -76,7 +72,7 @@ IDBWrapperCache::SetScriptOwner(JSObject* aScriptOwner)
|
||||
void
|
||||
IDBWrapperCache::AssertIsRooted() const
|
||||
{
|
||||
MOZ_ASSERT(cyclecollector::IsJSHolder(const_cast<IDBWrapperCache*>(this)),
|
||||
MOZ_ASSERT(IsJSHolder(const_cast<IDBWrapperCache*>(this)),
|
||||
"Why aren't we rooted?!");
|
||||
}
|
||||
#endif
|
||||
|
@ -1609,7 +1609,7 @@ void MediaDecoder::Invalidate()
|
||||
// Constructs the time ranges representing what segments of the media
|
||||
// are buffered and playable.
|
||||
nsresult MediaDecoder::GetBuffered(dom::TimeRanges* aBuffered) {
|
||||
NS_ENSURE_TRUE(mDecoderStateMachine, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(mDecoderStateMachine && !mShuttingDown, NS_ERROR_FAILURE);
|
||||
return mDecoderStateMachine->GetBuffered(aBuffered);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
#include "mozilla/Base64.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -51,6 +54,8 @@ MediaKeySession::MediaKeySession(JSContext* aCx,
|
||||
, mUninitialized(true)
|
||||
, mKeyStatusMap(new MediaKeyStatusMap(aCx, aParent, aRv))
|
||||
{
|
||||
EME_LOG("MediaKeySession[%p,''] session Id set", this);
|
||||
|
||||
MOZ_ASSERT(aParent);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
@ -60,6 +65,9 @@ MediaKeySession::MediaKeySession(JSContext* aCx,
|
||||
|
||||
void MediaKeySession::SetSessionId(const nsAString& aSessionId)
|
||||
{
|
||||
EME_LOG("MediaKeySession[%p,'%s'] session Id set",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
|
||||
if (NS_WARN_IF(!mSessionId.IsEmpty())) {
|
||||
return;
|
||||
}
|
||||
@ -129,6 +137,25 @@ MediaKeySession::UpdateKeyStatusMap()
|
||||
}
|
||||
|
||||
mKeyStatusMap->Update(keyStatuses);
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
nsAutoCString message(
|
||||
nsPrintfCString("MediaKeySession[%p,'%s'] key statuses change {",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get()));
|
||||
for (const CDMCaps::KeyStatus& status : keyStatuses) {
|
||||
nsAutoCString base64KeyId;
|
||||
nsDependentCSubstring rawKeyId(reinterpret_cast<const char*>(status.mId.Elements()),
|
||||
status.mId.Length());
|
||||
nsresult rv = Base64Encode(rawKeyId, base64KeyId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
continue;
|
||||
}
|
||||
message.Append(nsPrintfCString(" (%s,%s)", base64KeyId.get(),
|
||||
MediaKeyStatusValues::strings[status.mStatus].value));
|
||||
}
|
||||
message.Append(" }");
|
||||
EME_LOG(message.get());
|
||||
#endif
|
||||
}
|
||||
|
||||
MediaKeyStatusMap*
|
||||
@ -148,6 +175,8 @@ MediaKeySession::GenerateRequest(const nsAString& aInitDataType,
|
||||
}
|
||||
|
||||
if (!mUninitialized) {
|
||||
EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, uninitialized",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
@ -158,15 +187,37 @@ MediaKeySession::GenerateRequest(const nsAString& aInitDataType,
|
||||
if (aInitDataType.IsEmpty() ||
|
||||
!CopyArrayBufferViewOrArrayBufferData(aInitData, data)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, "
|
||||
"invalid initData or initDataType",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
// Convert initData to base64 for easier logging.
|
||||
// Note: UpdateSession() Move()s the data out of the array, so we have
|
||||
// to copy it here.
|
||||
nsAutoCString base64InitData;
|
||||
nsDependentCSubstring rawInitData(reinterpret_cast<const char*>(data.Elements()),
|
||||
data.Length());
|
||||
if (NS_FAILED(Base64Encode(rawInitData, base64InitData))) {
|
||||
NS_WARNING("Failed to base64 encode initData for logging");
|
||||
}
|
||||
#endif
|
||||
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->CreateSession(Token(),
|
||||
mSessionType,
|
||||
pid,
|
||||
aInitDataType, data);
|
||||
|
||||
EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() sent, "
|
||||
"promiseId=%d initData(base64)='%s'",
|
||||
this,
|
||||
NS_ConvertUTF16toUTF8(mSessionId).get(),
|
||||
pid,
|
||||
base64InitData.get());
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@ -181,11 +232,14 @@ MediaKeySession::Load(const nsAString& aSessionId, ErrorResult& aRv)
|
||||
if (aSessionId.IsEmpty()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
// "The sessionId parameter is empty."
|
||||
EME_LOG("MediaKeySession[%p,''] Load() failed, no sessionId", this);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
if (!mUninitialized) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Load() failed, uninitialized",
|
||||
this, NS_ConvertUTF16toUTF8(aSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@ -199,7 +253,11 @@ MediaKeySession::Load(const nsAString& aSessionId, ErrorResult& aRv)
|
||||
// Associate with the known sessionId.
|
||||
SetSessionId(aSessionId);
|
||||
|
||||
mKeys->GetCDMProxy()->LoadSession(mKeys->StorePromise(promise), aSessionId);
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->LoadSession(pid, aSessionId);
|
||||
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Load() sent to CDM, promiseId=%d",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
@ -216,11 +274,36 @@ MediaKeySession::Update(const ArrayBufferViewOrArrayBuffer& aResponse, ErrorResu
|
||||
!mKeys->GetCDMProxy() ||
|
||||
!CopyArrayBufferViewOrArrayBufferData(aResponse, data)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Update() failed, invalid response buffer",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
// Convert response to base64 for easier logging.
|
||||
// Note: UpdateSession() Move()s the data out of the array, so we have
|
||||
// to copy it here.
|
||||
nsAutoCString base64Response;
|
||||
nsDependentCSubstring rawResponse(reinterpret_cast<const char*>(data.Elements()),
|
||||
data.Length());
|
||||
if (NS_FAILED(Base64Encode(rawResponse, base64Response))) {
|
||||
NS_WARNING("Failed to base64 encode response for logging");
|
||||
}
|
||||
#endif
|
||||
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->UpdateSession(mSessionId,
|
||||
mKeys->StorePromise(promise),
|
||||
pid,
|
||||
data);
|
||||
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Update() sent to CDM, "
|
||||
"promiseId=%d Response(base64)='%s'",
|
||||
this,
|
||||
NS_ConvertUTF16toUTF8(mSessionId).get(),
|
||||
pid,
|
||||
base64Response.get());
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@ -232,11 +315,17 @@ MediaKeySession::Close(ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
if (IsClosed() || !mKeys->GetCDMProxy()) {
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Close() already closed",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->CloseSession(mSessionId, mKeys->StorePromise(promise));
|
||||
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Close() sent to CDM, promiseId=%d",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@ -246,6 +335,8 @@ MediaKeySession::OnClosed()
|
||||
if (IsClosed()) {
|
||||
return;
|
||||
}
|
||||
EME_LOG("MediaKeySession[%p,'%s'] session close operation complete.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
mIsClosed = true;
|
||||
mKeys->OnSessionClosed(this);
|
||||
mKeys = nullptr;
|
||||
@ -268,14 +359,22 @@ MediaKeySession::Remove(ErrorResult& aRv)
|
||||
if (mSessionType != SessionType::Persistent) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
// "The operation is not supported on session type sessions."
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Remove() failed, sesion not persisrtent.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
if (IsClosed() || !mKeys->GetCDMProxy()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
// "The session is closed."
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Remove() failed, already session closed.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get());
|
||||
return promise.forget();
|
||||
}
|
||||
mKeys->GetCDMProxy()->RemoveSession(mSessionId, mKeys->StorePromise(promise));
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->RemoveSession(mSessionId, pid);
|
||||
EME_LOG("MediaKeySession[%p,'%s'] Remove() sent to CDM, promiseId=%d.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@ -283,6 +382,19 @@ void
|
||||
MediaKeySession::DispatchKeyMessage(MediaKeyMessageType aMessageType,
|
||||
const nsTArray<uint8_t>& aMessage)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
nsAutoCString base64MsgData;
|
||||
nsDependentCSubstring rawMsgData(reinterpret_cast<const char*>(aMessage.Elements()),
|
||||
aMessage.Length());
|
||||
if (NS_FAILED(Base64Encode(rawMsgData, base64MsgData))) {
|
||||
NS_WARNING("Failed to base64 encode message for logging");
|
||||
}
|
||||
EME_LOG("MediaKeySession[%p,'%s'] DispatchKeyMessage() type=%s message(base64)='%s'",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(),
|
||||
MediaKeyMessageTypeValues::strings[uint32_t(aMessageType)].value,
|
||||
base64MsgData.get());
|
||||
#endif
|
||||
|
||||
nsRefPtr<MediaKeyMessageEvent> event(
|
||||
MediaKeyMessageEvent::Constructor(this, aMessageType, aMessage));
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
@ -293,6 +405,9 @@ MediaKeySession::DispatchKeyMessage(MediaKeyMessageType aMessageType,
|
||||
void
|
||||
MediaKeySession::DispatchKeyError(uint32_t aSystemCode)
|
||||
{
|
||||
EME_LOG("MediaKeySession[%p,'%s'] DispatchKeyError() systemCode=%u.",
|
||||
this, NS_ConvertUTF16toUTF8(mSessionId).get(), aSystemCode);
|
||||
|
||||
RefPtr<MediaKeyError> event(new MediaKeyError(this, aSystemCode));
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, event);
|
||||
|
@ -52,6 +52,8 @@ MediaKeys::MediaKeys(nsPIDOMWindow* aParent, const nsAString& aKeySystem)
|
||||
, mKeySystem(aKeySystem)
|
||||
, mCreatePromiseId(0)
|
||||
{
|
||||
EME_LOG("MediaKeys[%p] constructed keySystem=%s",
|
||||
this, NS_ConvertUTF16toUTF8(mKeySystem).get());
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
@ -67,6 +69,7 @@ RejectPromises(const uint32_t& aKey,
|
||||
MediaKeys::~MediaKeys()
|
||||
{
|
||||
Shutdown();
|
||||
EME_LOG("MediaKeys[%p] destroyed", this);
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
@ -91,6 +94,8 @@ CloseSessions(const nsAString& aKey,
|
||||
void
|
||||
MediaKeys::Terminated()
|
||||
{
|
||||
EME_LOG("MediaKeys[%p] CDM crashed unexpectedly", this);
|
||||
|
||||
KeySessionHashMap keySessions;
|
||||
// Remove entries during iteration will screw it. Make a copy first.
|
||||
mKeySessions.Enumerate(&CopySessions, &keySessions);
|
||||
@ -385,6 +390,8 @@ MediaKeys::CreateSession(JSContext* aCx,
|
||||
SessionType aSessionType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
EME_LOG("MediaKeys[%p] Creating session", this);
|
||||
|
||||
nsRefPtr<MediaKeySession> session = new MediaKeySession(aCx,
|
||||
GetParentObject(),
|
||||
this,
|
||||
|
@ -20,18 +20,6 @@ const TEST_DATA = [
|
||||
relSignalStrength: null
|
||||
}
|
||||
},
|
||||
// Valid rxlev with max value.
|
||||
{
|
||||
input: {
|
||||
rxlev: 63,
|
||||
rsrp: 65535,
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: -48,
|
||||
relSignalStrength: 100
|
||||
}
|
||||
},
|
||||
// Valid rxlev.
|
||||
{
|
||||
input: {
|
||||
@ -40,7 +28,7 @@ const TEST_DATA = [
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: -99,
|
||||
signalStrength: null,
|
||||
relSignalStrength: 100
|
||||
}
|
||||
},
|
||||
@ -52,9 +40,57 @@ const TEST_DATA = [
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: -111,
|
||||
signalStrength: null,
|
||||
relSignalStrength: 0
|
||||
}
|
||||
},
|
||||
// Valid rxlev with max value.
|
||||
{
|
||||
input: {
|
||||
rxlev: 63,
|
||||
rsrp: 65535,
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: null,
|
||||
relSignalStrength: 100
|
||||
}
|
||||
},
|
||||
// Valid rsrp.
|
||||
{
|
||||
input: {
|
||||
rxlev: 31,
|
||||
rsrp: 50,
|
||||
rssnr: 65535
|
||||
},
|
||||
expect: {
|
||||
signalStrength: 50,
|
||||
relSignalStrength: 100
|
||||
}
|
||||
},
|
||||
// Valid rssnr.
|
||||
{
|
||||
input: {
|
||||
rxlev: 31,
|
||||
rsrp: 65535,
|
||||
rssnr: 100
|
||||
},
|
||||
expect: {
|
||||
signalStrength: null,
|
||||
relSignalStrength: 81
|
||||
}
|
||||
},
|
||||
// Valid rsrp and rssnr.
|
||||
{
|
||||
input: {
|
||||
rxlev: 31,
|
||||
rsrp: 100,
|
||||
rssnr: 30
|
||||
},
|
||||
expect: {
|
||||
signalStrength: 100,
|
||||
relSignalStrength: 37
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -47,6 +47,9 @@ let RILQUIRKS_RADIO_OFF_WO_CARD =
|
||||
let RILQUIRKS_HAVE_IPV6 =
|
||||
libcutils.property_get("ro.moz.ril.ipv6", "false") == "true";
|
||||
|
||||
let RILQUIRKS_SIGNAL_EXTRA_INT32 =
|
||||
libcutils.property_get("ro.moz.ril.signal_extra_int", "false") == "true";
|
||||
|
||||
const RADIOINTERFACELAYER_CID =
|
||||
Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
|
||||
const RADIOINTERFACE_CID =
|
||||
@ -1512,7 +1515,8 @@ WorkerMessenger.prototype = {
|
||||
sendStkProfileDownload:
|
||||
libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true",
|
||||
dataRegistrationOnDemand: RILQUIRKS_DATA_REGISTRATION_ON_DEMAND,
|
||||
subscriptionControl: RILQUIRKS_SUBSCRIPTION_CONTROL
|
||||
subscriptionControl: RILQUIRKS_SUBSCRIPTION_CONTROL,
|
||||
signalExtraInt: RILQUIRKS_SIGNAL_EXTRA_INT32
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -82,6 +82,8 @@ let RILQUIRKS_DATA_REGISTRATION_ON_DEMAND;
|
||||
// Ril quirk to control the uicc/data subscription.
|
||||
let RILQUIRKS_SUBSCRIPTION_CONTROL;
|
||||
|
||||
let RILQUIRKS_SIGNAL_EXTRA_INT32;
|
||||
|
||||
const TELEPHONY_REQUESTS = [
|
||||
REQUEST_GET_CURRENT_CALLS,
|
||||
REQUEST_ANSWER,
|
||||
@ -3376,15 +3378,12 @@ RilObject.prototype = {
|
||||
*
|
||||
* @return The object of signal strength info.
|
||||
* Or null if invalid signal input.
|
||||
*
|
||||
* TODO: Bug 982013: reconsider the format of signal strength APIs for
|
||||
* GSM/CDMA/LTE to expose details, such as rsrp and rsnnr,
|
||||
* individually.
|
||||
*/
|
||||
_processLteSignal: function(signal) {
|
||||
// Valid values are 0-63 as defined in TS 27.007 clause 8.69.
|
||||
if (signal.lteSignalStrength === undefined ||
|
||||
signal.lteSignalStrength < 0 ||
|
||||
signal.lteSignalStrength > 63) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let info = {
|
||||
voice: {
|
||||
signalStrength: null,
|
||||
@ -3396,16 +3395,51 @@ RilObject.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: Bug 982013: reconsider signalStrength/relSignalStrength APIs for
|
||||
// GSM/CDMA/LTE, and take rsrp/rssnr into account for LTE case then.
|
||||
let signalStrength = -111 + signal.lteSignalStrength;
|
||||
// Referring to AOSP, use lteRSRP for signalStrength in dBm.
|
||||
let signalStrength = (signal.lteRSRP === undefined || signal.lteRSRP === 0x7FFFFFFF) ?
|
||||
null : signal.lteRSRP;
|
||||
info.voice.signalStrength = info.data.signalStrength = signalStrength;
|
||||
// 0 and 12 are referred to AOSP's implementation. These values are not
|
||||
// constants and can be customized based on different requirements.
|
||||
let signalLevel = this._processSignalLevel(signal.lteSignalStrength, 0, 12);
|
||||
info.voice.relSignalStrength = info.data.relSignalStrength = signalLevel;
|
||||
|
||||
return info;
|
||||
// Referring to AOSP, first determine signalLevel based on RSRP and RSSNR,
|
||||
// then on lteSignalStrength if RSRP and RSSNR are invalid.
|
||||
let rsrpLevel = -1;
|
||||
let rssnrLevel = -1;
|
||||
if (signal.lteRSRP !== undefined &&
|
||||
signal.lteRSRP !== 0x7FFFFFFF &&
|
||||
signal.lteRSRP >= 44 &&
|
||||
signal.lteRSRP <= 140) {
|
||||
rsrpLevel = this._processSignalLevel(signal.lteRSRP * -1, -115, -85);
|
||||
}
|
||||
|
||||
if (signal.lteRSSNR !== undefined &&
|
||||
signal.lteRSSNR !== 0x7FFFFFFF &&
|
||||
signal.lteRSSNR >= -200 &&
|
||||
signal.lteRSSNR <= 300) {
|
||||
rssnrLevel = this._processSignalLevel(signal.lteRSSNR, -30, 130);
|
||||
}
|
||||
|
||||
if (rsrpLevel !== -1 && rssnrLevel !== -1) {
|
||||
info.voice.relSignalStrength = info.data.relSignalStrength =
|
||||
Math.min(rsrpLevel, rssnrLevel);
|
||||
return info;
|
||||
}
|
||||
|
||||
let level = Math.max(rsrpLevel, rssnrLevel);
|
||||
if (level !== -1) {
|
||||
info.voice.relSignalStrength = info.data.relSignalStrength = level;
|
||||
return info;
|
||||
}
|
||||
|
||||
// Valid values are 0-63 as defined in TS 27.007 clause 8.69.
|
||||
if (signal.lteSignalStrength !== undefined &&
|
||||
signal.lteSignalStrength >= 0 &&
|
||||
signal.lteSignalStrength <= 63) {
|
||||
level = this._processSignalLevel(signal.lteSignalStrength, 0, 12);
|
||||
info.voice.relSignalStrength = info.data.relSignalStrength = level;
|
||||
return info;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
_processSignalStrength: function(signal) {
|
||||
@ -5323,15 +5357,18 @@ RilObject.prototype[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH(
|
||||
}
|
||||
|
||||
let Buf = this.context.Buf;
|
||||
let signal = {
|
||||
gsmSignalStrength: Buf.readInt32(),
|
||||
gsmBitErrorRate: Buf.readInt32(),
|
||||
cdmaDBM: Buf.readInt32(),
|
||||
cdmaECIO: Buf.readInt32(),
|
||||
evdoDBM: Buf.readInt32(),
|
||||
evdoECIO: Buf.readInt32(),
|
||||
evdoSNR: Buf.readInt32()
|
||||
};
|
||||
let signal = {};
|
||||
|
||||
signal.gsmSignalStrength = Buf.readInt32();
|
||||
signal.gsmBitErrorRate = Buf.readInt32();
|
||||
if (RILQUIRKS_SIGNAL_EXTRA_INT32) {
|
||||
Buf.readInt32();
|
||||
}
|
||||
signal.cdmaDBM = Buf.readInt32();
|
||||
signal.cdmaECIO = Buf.readInt32();
|
||||
signal.evdoDBM = Buf.readInt32();
|
||||
signal.evdoECIO = Buf.readInt32();
|
||||
signal.evdoSNR = Buf.readInt32();
|
||||
|
||||
if (!this.v5Legacy) {
|
||||
signal.lteSignalStrength = Buf.readInt32();
|
||||
@ -16093,6 +16130,7 @@ let ContextPool = {
|
||||
RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = quirks.sendStkProfileDownload;
|
||||
RILQUIRKS_DATA_REGISTRATION_ON_DEMAND = quirks.dataRegistrationOnDemand;
|
||||
RILQUIRKS_SUBSCRIPTION_CONTROL = quirks.subscriptionControl;
|
||||
RILQUIRKS_SIGNAL_EXTRA_INT32 = quirks.signalExtraInt;
|
||||
},
|
||||
|
||||
setDebugFlag: function(aOptions) {
|
||||
|
@ -265,14 +265,23 @@ GetWorkerPref(const nsACString& aPref,
|
||||
return result;
|
||||
}
|
||||
|
||||
// This function creates a key for a SharedWorker composed by "name|scriptSpec".
|
||||
// This function creates a key for a SharedWorker composed by "shared|name|scriptSpec"
|
||||
// and a key for a ServiceWorker composed by "service|scope|scriptSpec".
|
||||
// If the name contains a '|', this will be replaced by '||'.
|
||||
void
|
||||
GenerateSharedWorkerKey(const nsACString& aScriptSpec, const nsACString& aName,
|
||||
nsCString& aKey)
|
||||
WorkerType aWorkerType, nsCString& aKey)
|
||||
{
|
||||
aKey.Truncate();
|
||||
aKey.SetCapacity(aScriptSpec.Length() + aName.Length() + 1);
|
||||
NS_NAMED_LITERAL_CSTRING(sharedPrefix, "shared|");
|
||||
NS_NAMED_LITERAL_CSTRING(servicePrefix, "service|");
|
||||
MOZ_ASSERT(servicePrefix.Length() > sharedPrefix.Length());
|
||||
MOZ_ASSERT(aWorkerType == WorkerTypeShared ||
|
||||
aWorkerType == WorkerTypeService);
|
||||
aKey.SetCapacity(servicePrefix.Length() + aScriptSpec.Length() +
|
||||
aName.Length() + 1);
|
||||
|
||||
aKey.Append(aWorkerType == WorkerTypeService ? servicePrefix : sharedPrefix);
|
||||
|
||||
nsACString::const_iterator start, end;
|
||||
aName.BeginReading(start);
|
||||
@ -1463,7 +1472,8 @@ RuntimeService::RegisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
const nsCString& sharedWorkerName = aWorkerPrivate->SharedWorkerName();
|
||||
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(sharedWorkerScriptSpec, sharedWorkerName, key);
|
||||
GenerateSharedWorkerKey(sharedWorkerScriptSpec, sharedWorkerName,
|
||||
aWorkerPrivate->Type(), key);
|
||||
MOZ_ASSERT(!domainInfo->mSharedWorkerInfos.Get(key));
|
||||
|
||||
SharedWorkerInfo* sharedWorkerInfo =
|
||||
@ -1568,7 +1578,8 @@ RuntimeService::UnregisterWorker(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
if (match.mSharedWorkerInfo) {
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(match.mSharedWorkerInfo->mScriptSpec,
|
||||
match.mSharedWorkerInfo->mName, key);
|
||||
match.mSharedWorkerInfo->mName,
|
||||
aWorkerPrivate->Type(), key);
|
||||
domainInfo->mSharedWorkerInfos.Remove(key);
|
||||
}
|
||||
}
|
||||
@ -2297,7 +2308,7 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(scriptSpec, aName, key);
|
||||
GenerateSharedWorkerKey(scriptSpec, aName, aType, key);
|
||||
|
||||
if (mDomainMap.Get(aLoadInfo->mDomain, &domainInfo) &&
|
||||
domainInfo->mSharedWorkerInfos.Get(key, &sharedWorkerInfo)) {
|
||||
@ -2372,7 +2383,8 @@ RuntimeService::ForgetSharedWorker(WorkerPrivate* aWorkerPrivate)
|
||||
if (match.mSharedWorkerInfo) {
|
||||
nsAutoCString key;
|
||||
GenerateSharedWorkerKey(match.mSharedWorkerInfo->mScriptSpec,
|
||||
match.mSharedWorkerInfo->mName, key);
|
||||
match.mSharedWorkerInfo->mName,
|
||||
aWorkerPrivate->Type(), key);
|
||||
domainInfo->mSharedWorkerInfos.Remove(key);
|
||||
}
|
||||
}
|
||||
|
@ -77,11 +77,28 @@ function testClone() {
|
||||
});
|
||||
}
|
||||
|
||||
function testError() {
|
||||
var res = Response.error();
|
||||
is(res.status, 0, "Error response status should be 0");
|
||||
try {
|
||||
res.headers.set("someheader", "not allowed");
|
||||
ok(false, "Error response should have immutable headers");
|
||||
} catch(e) {
|
||||
ok(true, "Error response should have immutable headers");
|
||||
}
|
||||
}
|
||||
|
||||
function testRedirect() {
|
||||
var res = Response.redirect("./redirect.response");
|
||||
is(res.status, 302, "Default redirect has status code 302");
|
||||
var h = res.headers.get("location");
|
||||
ok(h === (new URL("./redirect.response", self.location.href)).href, "Location header should be correct absolute URL");
|
||||
try {
|
||||
res.headers.set("someheader", "not allowed");
|
||||
ok(false, "Redirects should have immutable headers");
|
||||
} catch(e) {
|
||||
ok(true, "Redirects should have immutable headers");
|
||||
}
|
||||
|
||||
var successStatus = [301, 302, 303, 307, 308];
|
||||
for (var i = 0; i < successStatus.length; ++i) {
|
||||
@ -217,6 +234,7 @@ onmessage = function() {
|
||||
var done = function() { postMessage({ type: 'finish' }) }
|
||||
|
||||
testDefaultCtor();
|
||||
testError();
|
||||
testRedirect();
|
||||
testOk();
|
||||
testFinalURL();
|
||||
|
@ -30,6 +30,7 @@ support-files =
|
||||
serviceworker_wrapper.js
|
||||
message_receiver.html
|
||||
close_test.js
|
||||
serviceworker_not_sharedworker.js
|
||||
|
||||
[test_unregister.html]
|
||||
[test_installation_simple.html]
|
||||
@ -46,3 +47,4 @@ support-files =
|
||||
[test_match_all_client_properties.html]
|
||||
[test_close.html]
|
||||
[test_serviceworker_interfaces.html]
|
||||
[test_serviceworker_not_sharedworker.html]
|
||||
|
@ -0,0 +1,21 @@
|
||||
function OnMessage(e)
|
||||
{
|
||||
if (e.data.msg == "whoareyou") {
|
||||
if ("ServiceWorker" in self) {
|
||||
self.clients.matchAll().then(function(clients) {
|
||||
clients[0].postMessage({result: "serviceworker"});
|
||||
});
|
||||
} else {
|
||||
port.postMessage({result: "sharedworker"});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var port;
|
||||
onconnect = function(e) {
|
||||
port = e.ports[0];
|
||||
port.onmessage = OnMessage;
|
||||
port.start();
|
||||
};
|
||||
|
||||
onmessage = OnMessage;
|
@ -0,0 +1,72 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1141274 - test that service workers and shared workers are separate</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var iframe;
|
||||
const SCOPE = "http://mochi.test:8888/tests/dom/workers/test/serviceworkers/";
|
||||
function runTest() {
|
||||
navigator.serviceWorker.register("serviceworker_not_sharedworker.js",
|
||||
{scope: SCOPE})
|
||||
.then(function(registration) {
|
||||
if (registration.installing) {
|
||||
registration.installing.onstatechange = function(e) {
|
||||
e.target.onstatechange = null;
|
||||
setupSW(registration);
|
||||
};
|
||||
} else {
|
||||
setupSW(registration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var sw, worker;
|
||||
function setupSW(registration) {
|
||||
sw = registration.waiting || registration.active;
|
||||
worker = new SharedWorker("serviceworker_not_sharedworker.js", SCOPE);
|
||||
worker.port.start();
|
||||
iframe = document.querySelector("iframe");
|
||||
iframe.src = "message_receiver.html";
|
||||
iframe.onload = function() {
|
||||
window.onmessage = function(e) {
|
||||
is(e.data.result, "serviceworker", "We should be talking to a service worker");
|
||||
window.onmessage = null;
|
||||
worker.port.onmessage = function(e) {
|
||||
is(e.data.result, "sharedworker", "We should be talking to a shared worker");
|
||||
registration.unregister().then(function(success) {
|
||||
ok(success, "unregister should succeed");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
};
|
||||
worker.port.postMessage({msg: "whoareyou"});
|
||||
};
|
||||
sw.postMessage({msg: "whoareyou"});
|
||||
};
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
onload = function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true]
|
||||
]}, runTest);
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -15,7 +15,7 @@
|
||||
#include "mozilla/gfx/BasePoint.h" // for BasePoint
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
#include "mozilla/layers/LayersMessages.h" // for TargetConfig
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsISupportsImpl.h" // for LayerManager::AddRef, etc
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "mozilla/layers/Effects.h" // for EffectChain
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
#include "nsString.h" // for nsAutoCString
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "TiledContentHost.h" // for TiledContentHost
|
||||
#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
|
||||
#include "mozilla/layers/TextureHost.h" // for TextureHost, etc
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsDebug.h" // for NS_WARNING
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "gfxPlatform.h" // for gfxPlatform
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform
|
||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||
#include "mozilla/mozalloc.h" // for operator delete, etc
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "mozilla/layers/TextureHost.h" // for TextureHost, etc
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
|
@ -44,7 +44,7 @@
|
||||
#include "ipc/ShadowLayerUtils.h"
|
||||
#include "mozilla/mozalloc.h" // for operator new, etc
|
||||
#include "nsAppRunner.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_WARNING, NS_RUNTIMEABORT, etc
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsCOMPtr.h" // for already_AddRefed
|
||||
#include "nsDebug.h" // for NS_ASSERTION
|
||||
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "mozilla/layers/Effects.h" // for EffectChain
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
|
||||
#include "nsMathUtils.h" // for NS_lround
|
||||
#include "nsPoint.h" // for nsIntPoint
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
||||
#include "mozilla/layers/YCbCrImageDataSerializer.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsRefPtr.h" // for nsRefPtr
|
||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||
#include "mozilla/layers/PTextureParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
@ -37,6 +37,7 @@ struct RemoteObject
|
||||
uint64_t serializedId;
|
||||
bool isCallable;
|
||||
bool isConstructor;
|
||||
bool isDOMObject;
|
||||
nsCString objectTag;
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "jsfriendapi.h"
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "xpcprivate.h"
|
||||
#include "CPOWTimer.h"
|
||||
#include "WrapperFactory.h"
|
||||
@ -26,15 +27,21 @@ struct AuxCPOWData
|
||||
ObjectId id;
|
||||
bool isCallable;
|
||||
bool isConstructor;
|
||||
bool isDOMObject;
|
||||
|
||||
// The object tag is just some auxilliary information that clients can use
|
||||
// however they see fit.
|
||||
nsCString objectTag;
|
||||
|
||||
AuxCPOWData(ObjectId id, bool isCallable, bool isConstructor, const nsACString &objectTag)
|
||||
AuxCPOWData(ObjectId id,
|
||||
bool isCallable,
|
||||
bool isConstructor,
|
||||
bool isDOMObject,
|
||||
const nsACString &objectTag)
|
||||
: id(id),
|
||||
isCallable(isCallable),
|
||||
isConstructor(isConstructor),
|
||||
isDOMObject(isDOMObject),
|
||||
objectTag(objectTag)
|
||||
{}
|
||||
};
|
||||
@ -153,7 +160,7 @@ CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, Handl
|
||||
|
||||
bool
|
||||
WrapperOwner::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc)
|
||||
MutableHandle<JSPropertyDescriptor> desc)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
@ -183,7 +190,7 @@ CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, Ha
|
||||
|
||||
bool
|
||||
WrapperOwner::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc)
|
||||
MutableHandle<JSPropertyDescriptor> desc)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
|
||||
@ -214,7 +221,7 @@ CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
|
||||
bool
|
||||
WrapperOwner::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
MutableHandle<JSPropertyDescriptor> desc,
|
||||
ObjectOpResult &result)
|
||||
{
|
||||
ObjectId objId = idOf(proxy);
|
||||
@ -338,6 +345,19 @@ CPOWProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
FORWARD(get, (cx, proxy, receiver, id, vp));
|
||||
}
|
||||
|
||||
static bool
|
||||
CPOWDOMQI(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (!args.thisv().isObject() || !IsCPOW(&args.thisv().toObject())) {
|
||||
JS_ReportError(cx, "bad this object passed to special QI");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject proxy(cx, &args.thisv().toObject());
|
||||
FORWARD(DOMQI, (cx, proxy, args));
|
||||
}
|
||||
|
||||
static bool
|
||||
CPOWToString(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -392,6 +412,49 @@ WrapperOwner::toString(JSContext *cx, HandleObject cpow, JS::CallArgs &args)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperOwner::DOMQI(JSContext *cx, JS::HandleObject proxy, JS::CallArgs &args)
|
||||
{
|
||||
// Someone's calling us, handle nsISupports specially to avoid unnecessary
|
||||
// CPOW traffic.
|
||||
HandleValue id = args[0];
|
||||
if (id.isObject()) {
|
||||
RootedObject idobj(cx, &id.toObject());
|
||||
nsCOMPtr<nsIJSID> jsid;
|
||||
|
||||
nsresult rv = UnwrapArg<nsIJSID>(idobj, getter_AddRefs(jsid));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MOZ_ASSERT(jsid, "bad wrapJS");
|
||||
const nsID *idptr = jsid->GetID();
|
||||
if (idptr->Equals(NS_GET_IID(nsISupports))) {
|
||||
args.rval().set(args.thisv());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Webidl-implemented DOM objects never have nsIClassInfo.
|
||||
if (idptr->Equals(NS_GET_IID(nsIClassInfo)))
|
||||
return Throw(cx, NS_ERROR_NO_INTERFACE);
|
||||
}
|
||||
}
|
||||
|
||||
// It wasn't nsISupports, call into the other process to do the QI for us
|
||||
// (since we don't know what other interfaces our object supports). Note
|
||||
// that we have to use JS_GetPropertyDescriptor here to avoid infinite
|
||||
// recursion back into CPOWDOMQI via WrapperOwner::get().
|
||||
// We could stash the actual QI function on our own function object to avoid
|
||||
// if we're called multiple times, but since we're transient, there's no
|
||||
// point right now.
|
||||
JS::Rooted<JSPropertyDescriptor> propDesc(cx);
|
||||
if (!JS_GetPropertyDescriptor(cx, proxy, "QueryInterface", &propDesc))
|
||||
return false;
|
||||
|
||||
if (!propDesc.value().isObject()) {
|
||||
MOZ_ASSERT_UNREACHABLE("We didn't get QueryInterface off a node");
|
||||
return Throw(cx, NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
return JS_CallFunctionValue(cx, proxy, propDesc.value(), args, args.rval());
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
HandleId id, MutableHandleValue vp)
|
||||
@ -406,6 +469,22 @@ WrapperOwner::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
|
||||
if (!toJSIDVariant(cx, id, &idVar))
|
||||
return false;
|
||||
|
||||
AuxCPOWData *data = AuxCPOWDataOf(proxy);
|
||||
if (data->isDOMObject &&
|
||||
idVar.type() == JSIDVariant::TnsString &&
|
||||
idVar.get_nsString().EqualsLiteral("QueryInterface"))
|
||||
{
|
||||
// Handle QueryInterface on DOM Objects specially since we can assume
|
||||
// certain things about their implementation.
|
||||
RootedFunction qi(cx, JS_NewFunction(cx, CPOWDOMQI, 1, 0,
|
||||
"QueryInterface"));
|
||||
if (!qi)
|
||||
return false;
|
||||
|
||||
vp.set(ObjectValue(*JS_GetFunctionObject(qi)));
|
||||
return true;
|
||||
}
|
||||
|
||||
JSVariant val;
|
||||
ReturnStatus status;
|
||||
if (!SendGet(objId, receiverVar, idVar, &status, &val))
|
||||
@ -967,6 +1046,7 @@ MakeRemoteObject(JSContext *cx, ObjectId id, HandleObject obj)
|
||||
return RemoteObject(id.serialize(),
|
||||
JS::IsCallable(obj),
|
||||
JS::IsConstructor(obj),
|
||||
dom::IsDOMObject(obj),
|
||||
objectTag);
|
||||
}
|
||||
|
||||
@ -1051,6 +1131,7 @@ WrapperOwner::fromRemoteObjectVariant(JSContext *cx, RemoteObject objVar)
|
||||
AuxCPOWData *aux = new AuxCPOWData(objId,
|
||||
objVar.isCallable(),
|
||||
objVar.isConstructor(),
|
||||
objVar.isDOMObject(),
|
||||
objVar.objectTag());
|
||||
|
||||
SetProxyExtra(obj, 0, PrivateValue(this));
|
||||
|
@ -63,6 +63,7 @@ class WrapperOwner : public virtual JavaScriptShared
|
||||
nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
|
||||
|
||||
bool toString(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args);
|
||||
bool DOMQI(JSContext *cx, JS::HandleObject callee, JS::CallArgs &args);
|
||||
|
||||
/*
|
||||
* Check that |obj| is a DOM wrapper whose prototype chain contains
|
||||
|
@ -214,6 +214,9 @@ $(LIBRARY_NAME).pc: js.pc
|
||||
install:: $(LIBRARY_NAME).pc
|
||||
$(SYSINSTALL) $^ $(DESTDIR)$(libdir)/pkgconfig
|
||||
|
||||
install:: js-config.h
|
||||
$(SYSINSTALL) $^ $(DESTDIR)$(includedir)
|
||||
|
||||
######################################################
|
||||
# BEGIN SpiderMonkey header installation
|
||||
#
|
||||
|
@ -889,7 +889,6 @@ class GCRuntime
|
||||
void markGrayReferencesInCurrentGroup(gcstats::Phase phase);
|
||||
void markAllWeakReferences(gcstats::Phase phase);
|
||||
void markAllGrayReferences(gcstats::Phase phase);
|
||||
void markJitcodeGlobalTable();
|
||||
|
||||
void beginSweepPhase(bool lastGC);
|
||||
void findZoneGroups();
|
||||
|
@ -337,7 +337,6 @@ static const PhaseInfo phases[] = {
|
||||
{ PHASE_SWEEP_MARK_INCOMING_GRAY, "Mark Incoming Gray Pointers", PHASE_SWEEP_MARK },
|
||||
{ PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK },
|
||||
{ PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK },
|
||||
{ PHASE_SWEEP_MARK_JITCODE_GLOBAL_TABLE, "Mark JitcodeGlobalTable", PHASE_SWEEP_MARK },
|
||||
{ PHASE_FINALIZE_START, "Finalize Start Callback", PHASE_SWEEP },
|
||||
{ PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP },
|
||||
{ PHASE_SWEEP_SYMBOL_REGISTRY, "Sweep Symbol Registry", PHASE_SWEEP },
|
||||
|
@ -43,7 +43,6 @@ enum Phase {
|
||||
PHASE_SWEEP_MARK_INCOMING_GRAY,
|
||||
PHASE_SWEEP_MARK_GRAY,
|
||||
PHASE_SWEEP_MARK_GRAY_WEAK,
|
||||
PHASE_SWEEP_MARK_JITCODE_GLOBAL_TABLE,
|
||||
PHASE_FINALIZE_START,
|
||||
PHASE_SWEEP_ATOMS,
|
||||
PHASE_SWEEP_SYMBOL_REGISTRY,
|
||||
|
@ -177,325 +177,78 @@ function loadModule_int32(stdlib, foreign, heap) {
|
||||
cas2_i: do_cas2_i };
|
||||
}
|
||||
|
||||
function loadModule_int8(stdlib, foreign, heap) {
|
||||
"use asm";
|
||||
|
||||
var atomic_load = stdlib.Atomics.load;
|
||||
var atomic_store = stdlib.Atomics.store;
|
||||
var atomic_cmpxchg = stdlib.Atomics.compareExchange;
|
||||
var atomic_add = stdlib.Atomics.add;
|
||||
var atomic_sub = stdlib.Atomics.sub;
|
||||
var atomic_and = stdlib.Atomics.and;
|
||||
var atomic_or = stdlib.Atomics.or;
|
||||
var atomic_xor = stdlib.Atomics.xor;
|
||||
|
||||
var i8a = new stdlib.SharedInt8Array(heap);
|
||||
|
||||
// Load element 0
|
||||
function do_load() {
|
||||
var v = 0;
|
||||
v = atomic_load(i8a, 0);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Load element i
|
||||
function do_load_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_load(i8a, i);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Store 37 in element 0
|
||||
function do_store() {
|
||||
var v = 0;
|
||||
v = atomic_store(i8a, 0, 37);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Store 37 in element i
|
||||
function do_store_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_store(i8a, i, 37);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Add 37 to element 10
|
||||
function do_add() {
|
||||
var v = 0;
|
||||
v = atomic_add(i8a, 10, 37);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Add 37 to element i
|
||||
function do_add_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_add(i8a, i, 37);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Subtract 108 from element 20
|
||||
function do_sub() {
|
||||
var v = 0;
|
||||
v = atomic_sub(i8a, 20, 108);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// Subtract 108 from element i
|
||||
function do_sub_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_sub(i8a, i, 108);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// AND 0x33 into element 30
|
||||
function do_and() {
|
||||
var v = 0;
|
||||
v = atomic_and(i8a, 30, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// AND 0x33 into element i
|
||||
function do_and_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_and(i8a, i, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// OR 0x33 into element 40
|
||||
function do_or() {
|
||||
var v = 0;
|
||||
v = atomic_or(i8a, 40, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// OR 0x33 into element i
|
||||
function do_or_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_or(i8a, i, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// XOR 0x33 into element 50
|
||||
function do_xor() {
|
||||
var v = 0;
|
||||
v = atomic_xor(i8a, 50, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// XOR 0x33 into element i
|
||||
function do_xor_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_xor(i8a, i, 0x33);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// CAS element 100: 0 -> -1
|
||||
function do_cas1() {
|
||||
var v = 0;
|
||||
v = atomic_cmpxchg(i8a, 100, 0, -1);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// CAS element 100: -1 -> 0x5A
|
||||
function do_cas2() {
|
||||
var v = 0;
|
||||
v = atomic_cmpxchg(i8a, 100, -1, 0x5A);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// CAS element i: 0 -> -1
|
||||
function do_cas1_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_cmpxchg(i8a, i, 0, -1);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
// CAS element i: -1 -> 0x5A
|
||||
function do_cas2_i(i) {
|
||||
i = i|0;
|
||||
var v = 0;
|
||||
v = atomic_cmpxchg(i8a, i, -1, 0x5A);
|
||||
return v|0;
|
||||
}
|
||||
|
||||
return { load: do_load,
|
||||
load_i: do_load_i,
|
||||
store: do_store,
|
||||
store_i: do_store_i,
|
||||
add: do_add,
|
||||
add_i: do_add_i,
|
||||
sub: do_sub,
|
||||
sub_i: do_sub_i,
|
||||
and: do_and,
|
||||
and_i: do_and_i,
|
||||
or: do_or,
|
||||
or_i: do_or_i,
|
||||
xor: do_xor,
|
||||
xor_i: do_xor_i,
|
||||
cas1: do_cas1,
|
||||
cas2: do_cas2,
|
||||
cas1_i: do_cas1_i,
|
||||
cas2_i: do_cas2_i };
|
||||
}
|
||||
|
||||
// TODO: byte arrays
|
||||
// TODO: halfword arrays
|
||||
// TODO: signed vs unsigned; negative results
|
||||
|
||||
var heap = new SharedArrayBuffer(65536);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// int32 tests
|
||||
|
||||
var i32a = new SharedInt32Array(heap);
|
||||
var i32m = loadModule_int32(this, {}, heap);
|
||||
var module = loadModule_int32(this, {}, heap);
|
||||
|
||||
var size = 4;
|
||||
|
||||
i32m.fence();
|
||||
module.fence();
|
||||
|
||||
i32a[0] = 12345;
|
||||
assertEq(i32m.load(), 12345);
|
||||
assertEq(i32m.load_i(size*0), 12345);
|
||||
assertEq(module.load(), 12345);
|
||||
assertEq(module.load_i(size*0), 12345);
|
||||
|
||||
assertEq(i32m.store(), 37);
|
||||
assertEq(module.store(), 37);
|
||||
assertEq(i32a[0], 37);
|
||||
assertEq(i32m.store_i(size*0), 37);
|
||||
assertEq(module.store_i(size*0), 37);
|
||||
|
||||
i32a[10] = 18;
|
||||
assertEq(i32m.add(), 18);
|
||||
assertEq(module.add(), 18);
|
||||
assertEq(i32a[10], 18+37);
|
||||
assertEq(i32m.add_i(size*10), 18+37);
|
||||
assertEq(module.add_i(size*10), 18+37);
|
||||
assertEq(i32a[10], 18+37+37);
|
||||
|
||||
i32a[20] = 4972;
|
||||
assertEq(i32m.sub(), 4972);
|
||||
assertEq(module.sub(), 4972);
|
||||
assertEq(i32a[20], 4972 - 148);
|
||||
assertEq(i32m.sub_i(size*20), 4972 - 148);
|
||||
assertEq(module.sub_i(size*20), 4972 - 148);
|
||||
assertEq(i32a[20], 4972 - 148 - 148);
|
||||
|
||||
i32a[30] = 0x66666666;
|
||||
assertEq(i32m.and(), 0x66666666);
|
||||
assertEq(module.and(), 0x66666666);
|
||||
assertEq(i32a[30], 0x22222222);
|
||||
i32a[30] = 0x66666666;
|
||||
assertEq(i32m.and_i(size*30), 0x66666666);
|
||||
assertEq(module.and_i(size*30), 0x66666666);
|
||||
assertEq(i32a[30], 0x22222222);
|
||||
|
||||
i32a[40] = 0x22222222;
|
||||
assertEq(i32m.or(), 0x22222222);
|
||||
assertEq(module.or(), 0x22222222);
|
||||
assertEq(i32a[40], 0x33333333);
|
||||
i32a[40] = 0x22222222;
|
||||
assertEq(i32m.or_i(size*40), 0x22222222);
|
||||
assertEq(module.or_i(size*40), 0x22222222);
|
||||
assertEq(i32a[40], 0x33333333);
|
||||
|
||||
i32a[50] = 0x22222222;
|
||||
assertEq(i32m.xor(), 0x22222222);
|
||||
assertEq(module.xor(), 0x22222222);
|
||||
assertEq(i32a[50], 0x11111111);
|
||||
i32a[50] = 0x22222222;
|
||||
assertEq(i32m.xor_i(size*50), 0x22222222);
|
||||
assertEq(module.xor_i(size*50), 0x22222222);
|
||||
assertEq(i32a[50], 0x11111111);
|
||||
|
||||
i32a[100] = 0;
|
||||
assertEq(i32m.cas1(), 0);
|
||||
assertEq(i32m.cas2(), -1);
|
||||
assertEq(module.cas1(), 0);
|
||||
assertEq(module.cas2(), -1);
|
||||
assertEq(i32a[100], 0x5A5A5A5A);
|
||||
|
||||
i32a[100] = 0;
|
||||
assertEq(i32m.cas1_i(size*100), 0);
|
||||
assertEq(i32m.cas2_i(size*100), -1);
|
||||
assertEq(module.cas1_i(size*100), 0);
|
||||
assertEq(module.cas2_i(size*100), -1);
|
||||
assertEq(i32a[100], 0x5A5A5A5A);
|
||||
|
||||
// Out-of-bounds accesses.
|
||||
|
||||
assertEq(i32m.cas1_i(size*20000), 0);
|
||||
assertEq(i32m.cas2_i(size*20000), 0);
|
||||
assertEq(module.cas1_i(size*20000), 0);
|
||||
assertEq(module.cas2_i(size*20000), 0);
|
||||
|
||||
assertEq(i32m.or_i(size*20001), 0);
|
||||
assertEq(i32m.xor_i(size*20001), 0);
|
||||
assertEq(i32m.and_i(size*20001), 0);
|
||||
assertEq(i32m.add_i(size*20001), 0);
|
||||
assertEq(i32m.sub_i(size*20001), 0);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//
|
||||
// int8 tests
|
||||
|
||||
var i8a = new SharedInt8Array(heap);
|
||||
var i8m = loadModule_int8(this, {}, heap);
|
||||
|
||||
for ( var i=0 ; i < i8a.length ; i++ )
|
||||
i8a[i] = 0;
|
||||
|
||||
var size = 1;
|
||||
|
||||
i8a[0] = 123;
|
||||
assertEq(i8m.load(), 123);
|
||||
assertEq(i8m.load_i(0), 123);
|
||||
|
||||
assertEq(i8m.store(), 37);
|
||||
assertEq(i8a[0], 37);
|
||||
assertEq(i8m.store_i(0), 37);
|
||||
|
||||
i8a[10] = 18;
|
||||
assertEq(i8m.add(), 18);
|
||||
assertEq(i8a[10], 18+37);
|
||||
assertEq(i8m.add_i(10), 18+37);
|
||||
assertEq(i8a[10], 18+37+37);
|
||||
|
||||
i8a[20] = 49;
|
||||
assertEq(i8m.sub(), 49);
|
||||
assertEq(i8a[20], 49 - 108);
|
||||
assertEq(i8m.sub_i(20), 49 - 108);
|
||||
assertEq(i8a[20], ((49 - 108 - 108) << 24) >> 24); // Byte, sign extended
|
||||
|
||||
i8a[30] = 0x66;
|
||||
assertEq(i8m.and(), 0x66);
|
||||
assertEq(i8a[30], 0x22);
|
||||
i8a[30] = 0x66;
|
||||
assertEq(i8m.and_i(30), 0x66);
|
||||
assertEq(i8a[30], 0x22);
|
||||
|
||||
i8a[40] = 0x22;
|
||||
assertEq(i8m.or(), 0x22);
|
||||
assertEq(i8a[40], 0x33);
|
||||
i8a[40] = 0x22;
|
||||
assertEq(i8m.or_i(40), 0x22);
|
||||
assertEq(i8a[40], 0x33);
|
||||
|
||||
i8a[50] = 0x22;
|
||||
assertEq(i8m.xor(), 0x22);
|
||||
assertEq(i8a[50], 0x11);
|
||||
i8a[50] = 0x22;
|
||||
assertEq(i8m.xor_i(50), 0x22);
|
||||
assertEq(i8a[50], 0x11);
|
||||
|
||||
i8a[100] = 0;
|
||||
assertEq(i8m.cas1(), 0);
|
||||
assertEq(i8m.cas2(), -1);
|
||||
assertEq(i8a[100], 0x5A);
|
||||
|
||||
i8a[100] = 0;
|
||||
assertEq(i8m.cas1_i(100), 0);
|
||||
assertEq(i8m.cas2_i(100), -1);
|
||||
assertEq(i8a[100], 0x5A);
|
||||
|
||||
// Out-of-bounds accesses.
|
||||
|
||||
assertEq(i8m.cas1_i(80000), 0);
|
||||
assertEq(i8m.cas2_i(80000), 0);
|
||||
|
||||
assertEq(i8m.or_i(80001), 0);
|
||||
assertEq(i8m.xor_i(80001), 0);
|
||||
assertEq(i8m.and_i(80001), 0);
|
||||
assertEq(i8m.add_i(80001), 0);
|
||||
assertEq(i8m.sub_i(80001), 0);
|
||||
assertEq(module.or_i(size*20001), 0);
|
||||
assertEq(module.xor_i(size*20001), 0);
|
||||
assertEq(module.and_i(size*20001), 0);
|
||||
assertEq(module.add_i(size*20001), 0);
|
||||
assertEq(module.sub_i(size*20001), 0);
|
||||
|
||||
print("Done");
|
||||
|
14
js/src/jit-test/tests/profiler/bug1140643.js
Normal file
14
js/src/jit-test/tests/profiler/bug1140643.js
Normal file
@ -0,0 +1,14 @@
|
||||
// |jit-test| allow-oom
|
||||
enableSPSProfiling();
|
||||
loadFile('\
|
||||
for (var i = 0; i < 2; i++) {\
|
||||
obj = { m: function () {} };\
|
||||
obj.watch("m", function () { float32 = 0 + obj.foo; });\
|
||||
obj.m = 0;\
|
||||
}\
|
||||
');
|
||||
gcparam("maxBytes", gcparam("gcBytes") + (1)*1024);
|
||||
newGlobal("same-compartment");
|
||||
function loadFile(lfVarx) {
|
||||
evaluate(lfVarx, { noScriptRval : true, compileAndGo : true });
|
||||
}
|
@ -500,14 +500,15 @@ JitRuntime::Mark(JSTracer *trc)
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
JitRuntime::MarkJitcodeGlobalTable(JSTracer *trc)
|
||||
/* static */ bool
|
||||
JitRuntime::MarkJitcodeGlobalTableIteratively(JSTracer *trc)
|
||||
{
|
||||
if (trc->runtime()->hasJitRuntime() &&
|
||||
trc->runtime()->jitRuntime()->hasJitcodeGlobalTable())
|
||||
{
|
||||
trc->runtime()->jitRuntime()->getJitcodeGlobalTable()->mark(trc);
|
||||
return trc->runtime()->jitRuntime()->getJitcodeGlobalTable()->markIteratively(trc);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
|
@ -257,7 +257,7 @@ class JitRuntime
|
||||
void freeOsrTempData();
|
||||
|
||||
static void Mark(JSTracer *trc);
|
||||
static void MarkJitcodeGlobalTable(JSTracer *trc);
|
||||
static bool MarkJitcodeGlobalTableIteratively(JSTracer *trc);
|
||||
static void SweepJitcodeGlobalTable(JSRuntime *rt);
|
||||
|
||||
ExecutableAllocator &execAlloc() {
|
||||
|
@ -718,8 +718,8 @@ JitcodeGlobalTable::verifySkiplist()
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
JitcodeGlobalTable::mark(JSTracer *trc)
|
||||
bool
|
||||
JitcodeGlobalTable::markIteratively(JSTracer *trc)
|
||||
{
|
||||
// JitcodeGlobalTable must keep entries that are in the sampler buffer
|
||||
// alive. This conditionality is akin to holding the entries weakly.
|
||||
@ -731,19 +731,17 @@ JitcodeGlobalTable::mark(JSTracer *trc)
|
||||
// itself.
|
||||
//
|
||||
// Instead, JitcodeGlobalTable is marked at the beginning of the sweep
|
||||
// phase. The key assumption is the following. At the beginning of the
|
||||
// sweep phase, any JS frames that the sampler may put in its buffer that
|
||||
// are not already there at the beginning of the mark phase must have
|
||||
// already been marked, as either 1) the frame was on-stack at the
|
||||
// beginning of the sweep phase, or 2) the frame was pushed between
|
||||
// incremental sweep slices. Frames of case 1) are already marked. Frames
|
||||
// of case 2) must have been reachable to have been newly pushed, and thus
|
||||
// are already marked.
|
||||
// phase, along with weak references. The key assumption is the
|
||||
// following. At the beginning of the sweep phase, any JS frames that the
|
||||
// sampler may put in its buffer that are not already there at the
|
||||
// beginning of the mark phase must have already been marked, as either 1)
|
||||
// the frame was on-stack at the beginning of the sweep phase, or 2) the
|
||||
// frame was pushed between incremental sweep slices. Frames of case 1)
|
||||
// are already marked. Frames of case 2) must have been reachable to have
|
||||
// been newly pushed, and thus are already marked.
|
||||
//
|
||||
// The approach above obviates the need for read barriers. The assumption
|
||||
// above is checked in JitcodeGlobalTable::lookupForSampler.
|
||||
MOZ_ASSERT(trc->runtime()->gc.stats.currentPhase() ==
|
||||
gcstats::PHASE_SWEEP_MARK_JITCODE_GLOBAL_TABLE);
|
||||
|
||||
AutoSuppressProfilerSampling suppressSampling(trc->runtime());
|
||||
uint32_t gen = trc->runtime()->profilerSampleBufferGen();
|
||||
@ -752,7 +750,7 @@ JitcodeGlobalTable::mark(JSTracer *trc)
|
||||
if (!trc->runtime()->spsProfiler.enabled())
|
||||
gen = UINT32_MAX;
|
||||
|
||||
// Find start entry.
|
||||
bool markedAny = false;
|
||||
for (Range r(*this); !r.empty(); r.popFront()) {
|
||||
JitcodeGlobalEntry *entry = r.front();
|
||||
|
||||
@ -774,8 +772,10 @@ JitcodeGlobalTable::mark(JSTracer *trc)
|
||||
if (!entry->zone()->isCollecting() || entry->zone()->isGCFinished())
|
||||
continue;
|
||||
|
||||
entry->mark(trc);
|
||||
markedAny |= entry->markIfUnmarked(trc);
|
||||
}
|
||||
|
||||
return markedAny;
|
||||
}
|
||||
|
||||
void
|
||||
@ -795,15 +795,21 @@ JitcodeGlobalTable::sweep(JSRuntime *rt)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
JitcodeGlobalEntry::BaseEntry::markJitcode(JSTracer *trc)
|
||||
bool
|
||||
JitcodeGlobalEntry::BaseEntry::markJitcodeIfUnmarked(JSTracer *trc)
|
||||
{
|
||||
MarkJitCodeUnbarriered(trc, &jitcode_, "jitcodglobaltable-baseentry-jitcode");
|
||||
if (!isJitcodeMarkedFromAnyThread()) {
|
||||
MarkJitCodeUnbarriered(trc, &jitcode_, "jitcodglobaltable-baseentry-jitcode");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
JitcodeGlobalEntry::BaseEntry::isJitcodeMarkedFromAnyThread()
|
||||
{
|
||||
if (jitcode_->asTenured().arenaHeader()->allocatedDuringIncremental)
|
||||
return false;
|
||||
return IsJitCodeMarkedFromAnyThread(&jitcode_);
|
||||
}
|
||||
|
||||
@ -813,10 +819,14 @@ JitcodeGlobalEntry::BaseEntry::isJitcodeAboutToBeFinalized()
|
||||
return IsJitCodeAboutToBeFinalized(&jitcode_);
|
||||
}
|
||||
|
||||
void
|
||||
JitcodeGlobalEntry::BaselineEntry::mark(JSTracer *trc)
|
||||
bool
|
||||
JitcodeGlobalEntry::BaselineEntry::markIfUnmarked(JSTracer *trc)
|
||||
{
|
||||
MarkScriptUnbarriered(trc, &script_, "jitcodeglobaltable-baselineentry-script");
|
||||
if (!isMarkedFromAnyThread()) {
|
||||
MarkScriptUnbarriered(trc, &script_, "jitcodeglobaltable-baselineentry-script");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
@ -831,29 +841,41 @@ JitcodeGlobalEntry::BaselineEntry::isMarkedFromAnyThread()
|
||||
return IsScriptMarkedFromAnyThread(&script_);
|
||||
}
|
||||
|
||||
void
|
||||
JitcodeGlobalEntry::IonEntry::mark(JSTracer *trc)
|
||||
bool
|
||||
JitcodeGlobalEntry::IonEntry::markIfUnmarked(JSTracer *trc)
|
||||
{
|
||||
bool markedAny = false;
|
||||
|
||||
for (unsigned i = 0; i < numScripts(); i++) {
|
||||
MarkScriptUnbarriered(trc, &sizedScriptList()->pairs[i].script,
|
||||
"jitcodeglobaltable-ionentry-script");
|
||||
if (!IsScriptMarkedFromAnyThread(&sizedScriptList()->pairs[i].script)) {
|
||||
MarkScriptUnbarriered(trc, &sizedScriptList()->pairs[i].script,
|
||||
"jitcodeglobaltable-ionentry-script");
|
||||
markedAny = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!optsAllTypes_)
|
||||
return;
|
||||
return markedAny;
|
||||
|
||||
for (IonTrackedTypeWithAddendum *iter = optsAllTypes_->begin();
|
||||
iter != optsAllTypes_->end(); iter++)
|
||||
{
|
||||
TypeSet::MarkTypeUnbarriered(trc, &(iter->type), "jitcodeglobaltable-ionentry-type");
|
||||
if (iter->hasAllocationSite()) {
|
||||
if (!TypeSet::IsTypeMarkedFromAnyThread(&iter->type)) {
|
||||
TypeSet::MarkTypeUnbarriered(trc, &iter->type, "jitcodeglobaltable-ionentry-type");
|
||||
markedAny = true;
|
||||
}
|
||||
if (iter->hasAllocationSite() && !IsScriptMarkedFromAnyThread(&iter->script)) {
|
||||
MarkScriptUnbarriered(trc, &iter->script,
|
||||
"jitcodeglobaltable-ionentry-type-addendum-script");
|
||||
} else if (iter->hasConstructor()) {
|
||||
markedAny = true;
|
||||
} else if (iter->hasConstructor() && !IsObjectMarkedFromAnyThread(&iter->constructor)) {
|
||||
MarkObjectUnbarriered(trc, &iter->constructor,
|
||||
"jitcodeglobaltable-ionentry-type-addendum-constructor");
|
||||
markedAny = true;
|
||||
}
|
||||
}
|
||||
|
||||
return markedAny;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -207,7 +207,7 @@ class JitcodeGlobalEntry
|
||||
return startsBelowPointer(ptr) && endsAbovePointer(ptr);
|
||||
}
|
||||
|
||||
void markJitcode(JSTracer *trc);
|
||||
bool markJitcodeIfUnmarked(JSTracer *trc);
|
||||
bool isJitcodeMarkedFromAnyThread();
|
||||
bool isJitcodeAboutToBeFinalized();
|
||||
};
|
||||
@ -358,7 +358,7 @@ class JitcodeGlobalEntry
|
||||
|
||||
mozilla::Maybe<uint8_t> trackedOptimizationIndexAtAddr(void *ptr);
|
||||
|
||||
void mark(JSTracer *trc);
|
||||
bool markIfUnmarked(JSTracer *trc);
|
||||
void sweep();
|
||||
bool isMarkedFromAnyThread();
|
||||
};
|
||||
@ -414,7 +414,7 @@ class JitcodeGlobalEntry
|
||||
void youngestFrameLocationAtAddr(JSRuntime *rt, void *ptr,
|
||||
JSScript **script, jsbytecode **pc) const;
|
||||
|
||||
void mark(JSTracer *trc);
|
||||
bool markIfUnmarked(JSTracer *trc);
|
||||
void sweep();
|
||||
bool isMarkedFromAnyThread();
|
||||
};
|
||||
@ -815,14 +815,14 @@ class JitcodeGlobalEntry
|
||||
return baseEntry().jitcode()->zone();
|
||||
}
|
||||
|
||||
void mark(JSTracer *trc) {
|
||||
baseEntry().markJitcode(trc);
|
||||
bool markIfUnmarked(JSTracer *trc) {
|
||||
bool markedAny = baseEntry().markJitcodeIfUnmarked(trc);
|
||||
switch (kind()) {
|
||||
case Ion:
|
||||
ionEntry().mark(trc);
|
||||
markedAny |= ionEntry().markIfUnmarked(trc);
|
||||
break;
|
||||
case Baseline:
|
||||
baselineEntry().mark(trc);
|
||||
markedAny |= baselineEntry().markIfUnmarked(trc);
|
||||
break;
|
||||
case IonCache:
|
||||
case Dummy:
|
||||
@ -830,6 +830,7 @@ class JitcodeGlobalEntry
|
||||
default:
|
||||
MOZ_CRASH("Invalid JitcodeGlobalEntry kind.");
|
||||
}
|
||||
return markedAny;
|
||||
}
|
||||
|
||||
void sweep() {
|
||||
@ -952,7 +953,7 @@ class JitcodeGlobalTable
|
||||
void removeEntry(JitcodeGlobalEntry &entry, JitcodeGlobalEntry **prevTower, JSRuntime *rt);
|
||||
void releaseEntry(JitcodeGlobalEntry &entry, JitcodeGlobalEntry **prevTower, JSRuntime *rt);
|
||||
|
||||
void mark(JSTracer *trc);
|
||||
bool markIteratively(JSTracer *trc);
|
||||
void sweep(JSRuntime *rt);
|
||||
|
||||
private:
|
||||
|
@ -1105,6 +1105,12 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
// Note, lock_addl() is used for a memory barrier on non-SSE2 systems.
|
||||
// Do not optimize, replace by XADDL, or similar.
|
||||
void lock_addl(Imm32 imm, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
addl(imm, op);
|
||||
}
|
||||
void subl(Imm32 imm, Register dest) {
|
||||
masm.subl_ir(imm.value, dest.code());
|
||||
}
|
||||
@ -1123,21 +1129,6 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
void addl(Register src, Register dest) {
|
||||
masm.addl_rr(src.code(), dest.code());
|
||||
}
|
||||
void addl(Register src, const Operand &dest) {
|
||||
switch (dest.kind()) {
|
||||
case Operand::REG:
|
||||
masm.addl_rr(src.code(), dest.reg());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.addl_rm(src.code(), dest.disp(), dest.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.addl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void subl(Register src, Register dest) {
|
||||
masm.subl_rr(src.code(), dest.code());
|
||||
}
|
||||
@ -1161,9 +1152,6 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.subl_rm(src.code(), dest.disp(), dest.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.subl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
@ -1171,21 +1159,6 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
void orl(Register reg, Register dest) {
|
||||
masm.orl_rr(reg.code(), dest.code());
|
||||
}
|
||||
void orl(Register src, const Operand &dest) {
|
||||
switch (dest.kind()) {
|
||||
case Operand::REG:
|
||||
masm.orl_rr(src.code(), dest.reg());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.orl_rm(src.code(), dest.disp(), dest.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.orl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void orl(Imm32 imm, Register reg) {
|
||||
masm.orl_ir(imm.value, reg.code());
|
||||
}
|
||||
@ -1204,21 +1177,6 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
void xorl(Register src, Register dest) {
|
||||
masm.xorl_rr(src.code(), dest.code());
|
||||
}
|
||||
void xorl(Register src, const Operand &dest) {
|
||||
switch (dest.kind()) {
|
||||
case Operand::REG:
|
||||
masm.xorl_rr(src.code(), dest.reg());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.xorl_rm(src.code(), dest.disp(), dest.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.xorl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void xorl(Imm32 imm, Register reg) {
|
||||
masm.xorl_ir(imm.value, reg.code());
|
||||
}
|
||||
@ -1237,21 +1195,6 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
void andl(Register src, Register dest) {
|
||||
masm.andl_rr(src.code(), dest.code());
|
||||
}
|
||||
void andl(Register src, const Operand &dest) {
|
||||
switch (dest.kind()) {
|
||||
case Operand::REG:
|
||||
masm.andl_rr(src.code(), dest.reg());
|
||||
break;
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.andl_rm(src.code(), dest.disp(), dest.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.andl_rm(src.code(), dest.disp(), dest.base(), dest.index(), dest.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void andl(Imm32 imm, Register dest) {
|
||||
masm.andl_ir(imm.value, dest.code());
|
||||
}
|
||||
@ -1419,260 +1362,40 @@ class AssemblerX86Shared : public AssemblerShared
|
||||
decl(op);
|
||||
}
|
||||
|
||||
void addb(Imm32 imm, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.addb_im(imm.value, op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.addb_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
void addb(Register src, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.addb_rm(src.code(), op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.addb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void subb(Imm32 imm, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.subb_im(imm.value, op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.subb_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
void subb(Register src, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.subb_rm(src.code(), op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.subb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void andb(Imm32 imm, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.andb_im(imm.value, op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.andb_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
void andb(Register src, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.andb_rm(src.code(), op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.andb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void orb(Imm32 imm, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.orb_im(imm.value, op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.orb_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
void orb(Register src, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.orb_rm(src.code(), op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.orb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void xorb(Imm32 imm, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.xorb_im(imm.value, op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.xorb_im(imm.value, op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
void xorb(Register src, const Operand &op) {
|
||||
switch (op.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.xorb_rm(src.code(), op.disp(), op.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.xorb_rm(src.code(), op.disp(), op.base(), op.index(), op.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void lock_addb(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
addb(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_subb(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
subb(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_andb(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
andb(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_orb(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
orb(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_xorb(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
xorb(src, op);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void lock_addw(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
masm.prefix_16_for_32();
|
||||
addl(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_subw(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
masm.prefix_16_for_32();
|
||||
subl(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_andw(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
masm.prefix_16_for_32();
|
||||
andl(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_orw(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
masm.prefix_16_for_32();
|
||||
orl(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_xorw(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
masm.prefix_16_for_32();
|
||||
xorl(src, op);
|
||||
}
|
||||
|
||||
// Note, lock_addl(imm, op) is used for a memory barrier on non-SSE2 systems,
|
||||
// among other things. Do not optimize, replace by XADDL, or similar.
|
||||
template<typename T>
|
||||
void lock_addl(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
addl(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_subl(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
subl(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_andl(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
andl(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_orl(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
orl(src, op);
|
||||
}
|
||||
template<typename T>
|
||||
void lock_xorl(T src, const Operand &op) {
|
||||
masm.prefix_lock();
|
||||
xorl(src, op);
|
||||
}
|
||||
|
||||
void lock_cmpxchgb(Register src, const Operand &mem) {
|
||||
void lock_cmpxchg8(Register src, const Operand &mem) {
|
||||
masm.prefix_lock();
|
||||
switch (mem.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.cmpxchgb(src.code(), mem.disp(), mem.base());
|
||||
masm.cmpxchg8(src.code(), mem.disp(), mem.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.cmpxchgb(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale());
|
||||
masm.cmpxchg8(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void lock_cmpxchgw(Register src, const Operand &mem) {
|
||||
void lock_cmpxchg16(Register src, const Operand &mem) {
|
||||
masm.prefix_lock();
|
||||
switch (mem.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.cmpxchgw(src.code(), mem.disp(), mem.base());
|
||||
masm.cmpxchg16(src.code(), mem.disp(), mem.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.cmpxchgw(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale());
|
||||
masm.cmpxchg16(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
}
|
||||
}
|
||||
void lock_cmpxchgl(Register src, const Operand &mem) {
|
||||
void lock_cmpxchg32(Register src, const Operand &mem) {
|
||||
masm.prefix_lock();
|
||||
switch (mem.kind()) {
|
||||
case Operand::MEM_REG_DISP:
|
||||
masm.cmpxchgl(src.code(), mem.disp(), mem.base());
|
||||
masm.cmpxchg32(src.code(), mem.disp(), mem.base());
|
||||
break;
|
||||
case Operand::MEM_SCALE:
|
||||
masm.cmpxchgl(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale());
|
||||
masm.cmpxchg32(src.code(), mem.disp(), mem.base(), mem.index(), mem.scale());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected operand kind");
|
||||
|
@ -288,12 +288,6 @@ public:
|
||||
m_formatter.oneByteOp(OP_ADD_EvGv, offset, base, src);
|
||||
}
|
||||
|
||||
void addl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("addl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_ADD_EvGv, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void addl_ir(int32_t imm, RegisterID dst)
|
||||
{
|
||||
spew("addl $%d, %s", imm, GPReg32Name(dst));
|
||||
@ -401,138 +395,18 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void addb_im(int32_t imm, int32_t offset, RegisterID base) {
|
||||
spew("addb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_ADD);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void addb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("addb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_ADD);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void addb_rm(RegisterID src, int32_t offset, RegisterID base) {
|
||||
spew("addb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp8(OP_ADD_EbGb, offset, base, src);
|
||||
}
|
||||
|
||||
void addb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("addb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp8(OP_ADD_EbGb, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void subb_im(int32_t imm, int32_t offset, RegisterID base) {
|
||||
spew("subb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_SUB);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void subb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("subb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_SUB);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void subb_rm(RegisterID src, int32_t offset, RegisterID base) {
|
||||
spew("subb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp8(OP_SUB_EbGb, offset, base, src);
|
||||
}
|
||||
|
||||
void subb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("subb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp8(OP_SUB_EbGb, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void andb_im(int32_t imm, int32_t offset, RegisterID base) {
|
||||
spew("andb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_AND);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void andb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("andb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_AND);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void andb_rm(RegisterID src, int32_t offset, RegisterID base) {
|
||||
spew("andb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp8(OP_AND_EbGb, offset, base, src);
|
||||
}
|
||||
|
||||
void andb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("andb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp8(OP_AND_EbGb, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void orb_im(int32_t imm, int32_t offset, RegisterID base) {
|
||||
spew("orb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_OR);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void orb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("orb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_OR);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void orb_rm(RegisterID src, int32_t offset, RegisterID base) {
|
||||
spew("orb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp8(OP_OR_EbGb, offset, base, src);
|
||||
}
|
||||
|
||||
void orb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("orb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp8(OP_OR_EbGb, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void xorb_im(int32_t imm, int32_t offset, RegisterID base) {
|
||||
spew("xorb $%d, " MEM_ob, int8_t(imm), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, GROUP1_OP_XOR);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void xorb_im(int32_t imm, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("xorb $%d, " MEM_obs, int8_t(imm), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_GROUP1_EbIb, offset, base, index, scale, GROUP1_OP_XOR);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
void xorb_rm(RegisterID src, int32_t offset, RegisterID base) {
|
||||
spew("xorb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp8(OP_XOR_EbGb, offset, base, src);
|
||||
}
|
||||
|
||||
void xorb_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("xorb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp8(OP_XOR_EbGb, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void lock_xaddb_rm(RegisterID srcdest, int32_t offset, RegisterID base)
|
||||
{
|
||||
spew("lock xaddb %s, " MEM_ob, GPReg8Name(srcdest), ADDR_ob(offset, base));
|
||||
spew("lock xaddl %s, " MEM_ob, GPReg8Name(srcdest), ADDR_ob(offset, base));
|
||||
m_formatter.oneByteOp(PRE_LOCK);
|
||||
m_formatter.twoByteOp8(OP2_XADD_EbGb, offset, base, srcdest);
|
||||
m_formatter.twoByteOp(OP2_XADD_EbGb, offset, base, srcdest);
|
||||
}
|
||||
|
||||
void lock_xaddb_rm(RegisterID srcdest, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("lock xaddb %s, " MEM_obs, GPReg8Name(srcdest), ADDR_obs(offset, base, index, scale));
|
||||
spew("lock xaddl %s, " MEM_obs, GPReg8Name(srcdest), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(PRE_LOCK);
|
||||
m_formatter.twoByteOp8(OP2_XADD_EbGb, offset, base, index, scale, srcdest);
|
||||
m_formatter.twoByteOp(OP2_XADD_EbGb, offset, base, index, scale, srcdest);
|
||||
}
|
||||
|
||||
void lock_xaddl_rm(RegisterID srcdest, int32_t offset, RegisterID base)
|
||||
@ -693,12 +567,6 @@ public:
|
||||
m_formatter.oneByteOp(OP_AND_EvGv, offset, base, src);
|
||||
}
|
||||
|
||||
void andl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("andl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_AND_EvGv, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void andl_ir(int32_t imm, RegisterID dst)
|
||||
{
|
||||
spew("andl $0x%x, %s", imm, GPReg32Name(dst));
|
||||
@ -859,12 +727,6 @@ public:
|
||||
m_formatter.oneByteOp(OP_OR_EvGv, offset, base, src);
|
||||
}
|
||||
|
||||
void orl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("orl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_OR_EvGv, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void orl_ir(int32_t imm, RegisterID dst)
|
||||
{
|
||||
spew("orl $0x%x, %s", imm, GPReg32Name(dst));
|
||||
@ -957,12 +819,6 @@ public:
|
||||
m_formatter.oneByteOp(OP_SUB_EvGv, offset, base, src);
|
||||
}
|
||||
|
||||
void subl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("subl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_SUB_EvGv, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void subl_ir(int32_t imm, RegisterID dst)
|
||||
{
|
||||
spew("subl $%d, %s", imm, GPReg32Name(dst));
|
||||
@ -1061,12 +917,6 @@ public:
|
||||
m_formatter.oneByteOp(OP_XOR_EvGv, offset, base, src);
|
||||
}
|
||||
|
||||
void xorl_rm(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("xorl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.oneByteOp(OP_XOR_EvGv, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
void xorl_im(int32_t imm, int32_t offset, RegisterID base)
|
||||
{
|
||||
spew("xorl $0x%x, " MEM_ob, imm, ADDR_ob(offset, base));
|
||||
@ -1286,41 +1136,41 @@ public:
|
||||
m_formatter.oneByteOp(OP_GROUP5_Ev, offset, base, GROUP5_OP_DEC);
|
||||
}
|
||||
|
||||
// Note that CMPXCHG performs comparison against REG = %al/%ax/%eax/%rax.
|
||||
// Note that CMPXCHG performs comparison against REG = %al/%ax/%eax.
|
||||
// If %REG == [%base+offset], then %src -> [%base+offset].
|
||||
// Otherwise, [%base+offset] -> %REG.
|
||||
// For the 8-bit operations src must also be an 8-bit register.
|
||||
|
||||
void cmpxchgb(RegisterID src, int32_t offset, RegisterID base)
|
||||
void cmpxchg8(RegisterID src, int32_t offset, RegisterID base)
|
||||
{
|
||||
spew("cmpxchgb %s, " MEM_ob, GPReg8Name(src), ADDR_ob(offset, base));
|
||||
m_formatter.twoByteOp8(OP2_CMPXCHG_GvEb, offset, base, src);
|
||||
spew("cmpxchg8 %s, " MEM_ob, GPRegName(src), ADDR_ob(offset, base));
|
||||
m_formatter.twoByteOp(OP2_CMPXCHG_GvEb, offset, base, src);
|
||||
}
|
||||
void cmpxchgb(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
void cmpxchg8(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("cmpxchgb %s, " MEM_obs, GPReg8Name(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.twoByteOp8(OP2_CMPXCHG_GvEb, offset, base, index, scale, src);
|
||||
spew("cmpxchg8 %s, " MEM_obs, GPRegName(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.twoByteOp(OP2_CMPXCHG_GvEb, offset, base, index, scale, src);
|
||||
}
|
||||
void cmpxchgw(RegisterID src, int32_t offset, RegisterID base)
|
||||
void cmpxchg16(RegisterID src, int32_t offset, RegisterID base)
|
||||
{
|
||||
spew("cmpxchgw %s, " MEM_ob, GPReg16Name(src), ADDR_ob(offset, base));
|
||||
spew("cmpxchg16 %s, " MEM_ob, GPRegName(src), ADDR_ob(offset, base));
|
||||
m_formatter.prefix(PRE_OPERAND_SIZE);
|
||||
m_formatter.twoByteOp(OP2_CMPXCHG_GvEw, offset, base, src);
|
||||
}
|
||||
void cmpxchgw(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
void cmpxchg16(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("cmpxchgw %s, " MEM_obs, GPReg16Name(src), ADDR_obs(offset, base, index, scale));
|
||||
spew("cmpxchg16 %s, " MEM_obs, GPRegName(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.prefix(PRE_OPERAND_SIZE);
|
||||
m_formatter.twoByteOp(OP2_CMPXCHG_GvEw, offset, base, index, scale, src);
|
||||
}
|
||||
void cmpxchgl(RegisterID src, int32_t offset, RegisterID base)
|
||||
void cmpxchg32(RegisterID src, int32_t offset, RegisterID base)
|
||||
{
|
||||
spew("cmpxchgl %s, " MEM_ob, GPReg32Name(src), ADDR_ob(offset, base));
|
||||
spew("cmpxchg32 %s, " MEM_ob, GPRegName(src), ADDR_ob(offset, base));
|
||||
m_formatter.twoByteOp(OP2_CMPXCHG_GvEw, offset, base, src);
|
||||
}
|
||||
void cmpxchgl(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
void cmpxchg32(RegisterID src, int32_t offset, RegisterID base, RegisterID index, int scale)
|
||||
{
|
||||
spew("cmpxchgl %s, " MEM_obs, GPReg32Name(src), ADDR_obs(offset, base, index, scale));
|
||||
spew("cmpxchg32 %s, " MEM_obs, GPRegName(src), ADDR_obs(offset, base, index, scale));
|
||||
m_formatter.twoByteOp(OP2_CMPXCHG_GvEw, offset, base, index, scale, src);
|
||||
}
|
||||
|
||||
@ -1905,7 +1755,7 @@ public:
|
||||
void movb_ir(int32_t imm, RegisterID reg)
|
||||
{
|
||||
spew("movb $0x%x, %s", imm, GPReg8Name(reg));
|
||||
m_formatter.oneByteOp8(OP_MOV_EbIb, reg);
|
||||
m_formatter.oneByteOp(OP_MOV_EbGv, reg);
|
||||
m_formatter.immediate8(imm);
|
||||
}
|
||||
|
||||
@ -4850,13 +4700,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
}
|
||||
|
||||
void oneByteOp8(OneByteOpcodeID opcode, RegisterID r)
|
||||
{
|
||||
m_buffer.ensureSpace(MaxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(r), 0, 0, r);
|
||||
m_buffer.putByteUnchecked(opcode + (r & 7));
|
||||
}
|
||||
|
||||
void oneByteOp8(OneByteOpcodeID opcode, RegisterID rm, GroupOpcodeID groupOp)
|
||||
{
|
||||
m_buffer.ensureSpace(MaxInstructionSize);
|
||||
@ -4917,26 +4760,6 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
|
||||
registerModRM(rm, reg);
|
||||
}
|
||||
|
||||
void twoByteOp8(TwoByteOpcodeID opcode, int32_t offset, RegisterID base, RegisterID reg)
|
||||
{
|
||||
m_buffer.ensureSpace(MaxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(reg)|regRequiresRex(base), reg, 0, base);
|
||||
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
memoryModRM(offset, base, reg);
|
||||
}
|
||||
|
||||
void twoByteOp8(TwoByteOpcodeID opcode, int32_t offset, RegisterID base, RegisterID index,
|
||||
int scale, RegisterID reg)
|
||||
{
|
||||
m_buffer.ensureSpace(MaxInstructionSize);
|
||||
emitRexIf(byteRegRequiresRex(reg)|regRequiresRex(base)|regRequiresRex(index),
|
||||
reg, index, base);
|
||||
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
|
||||
m_buffer.putByteUnchecked(opcode);
|
||||
memoryModRM(offset, base, index, scale, reg);
|
||||
}
|
||||
|
||||
// Like twoByteOp8 but doesn't add a REX prefix if the destination reg
|
||||
// is in esp..edi. This may be used when the destination is not an 8-bit
|
||||
// register (as in a movzbl instruction), so it doesn't need a REX
|
||||
@ -5124,8 +4947,7 @@ threeByteOpImmSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_3A, imm, off
|
||||
//
|
||||
// NB: WebKit's use of emitRexIf() is limited such that the
|
||||
// reqRequiresRex() checks are not needed. SpiderMonkey extends
|
||||
// oneByteOp8 and twoByteOp8 functionality such that r, x, and b
|
||||
// can all be used.
|
||||
// oneByteOp8 functionality such that r, x, and b can all be used.
|
||||
void emitRexIf(bool condition, int r, int x, int b)
|
||||
{
|
||||
if (condition ||
|
||||
|
@ -89,7 +89,6 @@ enum OneByteOpcodeID {
|
||||
OP_MOV_OvEAX = 0xA3,
|
||||
OP_TEST_EAXIb = 0xA8,
|
||||
OP_TEST_EAXIv = 0xA9,
|
||||
OP_MOV_EbIb = 0xB0,
|
||||
OP_MOV_EAXIv = 0xB8,
|
||||
OP_GROUP2_EvIb = 0xC1,
|
||||
OP_RET_Iz = 0xC2,
|
||||
|
@ -364,8 +364,7 @@ LIRGeneratorX86Shared::lowerTruncateFToInt32(MTruncateToInt32 *ins)
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86Shared::lowerCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins,
|
||||
bool useI386ByteRegisters)
|
||||
LIRGeneratorX86Shared::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->arrayType() != Scalar::Float32);
|
||||
MOZ_ASSERT(ins->arrayType() != Scalar::Float64);
|
||||
@ -386,11 +385,12 @@ LIRGeneratorX86Shared::lowerCompareExchangeTypedArrayElement(MCompareExchangeTyp
|
||||
//
|
||||
// oldval must be in a register.
|
||||
//
|
||||
// newval must be in a register. If the source is a byte array
|
||||
// then newval must be a register that has a byte size: on x86
|
||||
// this must be ebx, ecx, or edx (eax is taken for the output).
|
||||
// newval will need to be in a register. If the source is a byte
|
||||
// array then the newval must be a register that has a byte size:
|
||||
// ebx, ecx, or edx, since eax is taken for the output in this
|
||||
// case.
|
||||
//
|
||||
// Bug #1077036 describes some further optimization opportunities.
|
||||
// Bug #1077036 describes some optimization opportunities.
|
||||
|
||||
bool fixedOutput = false;
|
||||
LDefinition tempDef = LDefinition::BogusTemp();
|
||||
@ -400,12 +400,13 @@ LIRGeneratorX86Shared::lowerCompareExchangeTypedArrayElement(MCompareExchangeTyp
|
||||
newval = useRegister(ins->newval());
|
||||
} else {
|
||||
fixedOutput = true;
|
||||
if (useI386ByteRegisters && ins->isByteArray())
|
||||
if (ins->isByteArray())
|
||||
newval = useFixed(ins->newval(), ebx);
|
||||
else
|
||||
newval = useRegister(ins->newval());
|
||||
}
|
||||
|
||||
// A register allocator limitation precludes 'useRegisterAtStart()' here.
|
||||
const LAllocation oldval = useRegister(ins->oldval());
|
||||
|
||||
LCompareExchangeTypedArrayElement *lir =
|
||||
@ -418,8 +419,7 @@ LIRGeneratorX86Shared::lowerCompareExchangeTypedArrayElement(MCompareExchangeTyp
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86Shared::lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins,
|
||||
bool useI386ByteRegisters)
|
||||
LIRGeneratorX86Shared::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->arrayType() != Scalar::Uint8Clamped);
|
||||
MOZ_ASSERT(ins->arrayType() != Scalar::Float32);
|
||||
@ -452,7 +452,7 @@ LIRGeneratorX86Shared::lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElemen
|
||||
//
|
||||
// Note the placement of L, cmpxchg will update eax with *mem if
|
||||
// *mem does not have the expected value, so reloading it at the
|
||||
// top of the loop would be redundant.
|
||||
// top of the loop is redundant.
|
||||
//
|
||||
// If the array is not a uint32 array then:
|
||||
// - eax should be the output (one result of the cmpxchg)
|
||||
@ -488,11 +488,12 @@ LIRGeneratorX86Shared::lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElemen
|
||||
} else {
|
||||
tempDef1 = temp();
|
||||
}
|
||||
} else if (useI386ByteRegisters && ins->isByteArray()) {
|
||||
} else if (ins->isByteArray()) {
|
||||
value = useFixed(ins->value(), ebx);
|
||||
if (bitOp)
|
||||
tempDef1 = tempFixed(ecx);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
value = useRegister(ins->value());
|
||||
if (bitOp)
|
||||
tempDef1 = temp();
|
||||
@ -507,6 +508,133 @@ LIRGeneratorX86Shared::lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElemen
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86Shared::lowerAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins,
|
||||
const LDefinition& addrTemp)
|
||||
{
|
||||
MDefinition *ptr = ins->ptr();
|
||||
MOZ_ASSERT(ptr->type() == MIRType_Int32);
|
||||
|
||||
bool byteArray = false;
|
||||
switch (ins->accessType()) {
|
||||
case Scalar::Int8:
|
||||
case Scalar::Uint8:
|
||||
byteArray = true;
|
||||
break;
|
||||
case Scalar::Int16:
|
||||
case Scalar::Uint16:
|
||||
case Scalar::Int32:
|
||||
case Scalar::Uint32:
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected array type");
|
||||
}
|
||||
|
||||
// Register allocation:
|
||||
//
|
||||
// The output must be eax.
|
||||
//
|
||||
// oldval must be in a register (it'll eventually end up in eax so
|
||||
// ideally it's there to begin with).
|
||||
//
|
||||
// newval will need to be in a register. If the source is a byte
|
||||
// array then the newval must be a register that has a byte size:
|
||||
// ebx, ecx, or edx, since eax is taken for the output in this
|
||||
// case. We pick ebx but it would be more flexible to pick any of
|
||||
// the three that wasn't being used.
|
||||
//
|
||||
// Bug #1077036 describes some optimization opportunities.
|
||||
|
||||
const LAllocation newval = byteArray ? useFixed(ins->newValue(), ebx) : useRegister(ins->newValue());
|
||||
const LAllocation oldval = useRegister(ins->oldValue());
|
||||
|
||||
LAsmJSCompareExchangeHeap *lir =
|
||||
new(alloc()) LAsmJSCompareExchangeHeap(useRegister(ptr), oldval, newval);
|
||||
|
||||
lir->setAddrTemp(addrTemp);
|
||||
defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86Shared::lowerAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins,
|
||||
const LDefinition& addrTemp)
|
||||
{
|
||||
MDefinition *ptr = ins->ptr();
|
||||
MOZ_ASSERT(ptr->type() == MIRType_Int32);
|
||||
|
||||
bool byteArray = false;
|
||||
switch (ins->accessType()) {
|
||||
case Scalar::Int8:
|
||||
case Scalar::Uint8:
|
||||
byteArray = true;
|
||||
break;
|
||||
case Scalar::Int16:
|
||||
case Scalar::Uint16:
|
||||
case Scalar::Int32:
|
||||
case Scalar::Uint32:
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected array type");
|
||||
}
|
||||
|
||||
// Register allocation:
|
||||
//
|
||||
// For ADD and SUB we'll use XADD:
|
||||
//
|
||||
// movl value, output
|
||||
// lock xaddl output, mem
|
||||
//
|
||||
// For the 8-bit variants XADD needs a byte register for the
|
||||
// output only, we can still set up with movl; just pin the output
|
||||
// to eax (or ebx / ecx / edx).
|
||||
//
|
||||
// For AND/OR/XOR we need to use a CMPXCHG loop:
|
||||
//
|
||||
// movl *mem, eax
|
||||
// L: mov eax, temp
|
||||
// andl value, temp
|
||||
// lock cmpxchg temp, mem ; reads eax also
|
||||
// jnz L
|
||||
// ; result in eax
|
||||
//
|
||||
// Note the placement of L, cmpxchg will update eax with *mem if
|
||||
// *mem does not have the expected value, so reloading it at the
|
||||
// top of the loop is redundant.
|
||||
//
|
||||
// We want to fix eax as the output. We also need a temp for
|
||||
// the intermediate value.
|
||||
//
|
||||
// For the 8-bit variants the temp must have a byte register.
|
||||
//
|
||||
// There are optimization opportunities:
|
||||
// - when the result is unused, Bug #1077014.
|
||||
// - better register allocation and instruction selection, Bug #1077036.
|
||||
|
||||
bool bitOp = !(ins->operation() == AtomicFetchAddOp || ins->operation() == AtomicFetchSubOp);
|
||||
LDefinition tempDef = LDefinition::BogusTemp();
|
||||
LAllocation value;
|
||||
|
||||
// Optimization opportunity: "value" need not be pinned to something that
|
||||
// has a byte register unless the back-end insists on using a byte move
|
||||
// for the setup or the payload computation, which really it need not do.
|
||||
|
||||
if (byteArray) {
|
||||
value = useFixed(ins->value(), ebx);
|
||||
if (bitOp)
|
||||
tempDef = tempFixed(ecx);
|
||||
} else {
|
||||
value = useRegister(ins->value());
|
||||
if (bitOp)
|
||||
tempDef = temp();
|
||||
}
|
||||
|
||||
LAsmJSAtomicBinopHeap *lir =
|
||||
new(alloc()) LAsmJSAtomicBinopHeap(useRegister(ptr), value, tempDef);
|
||||
|
||||
lir->setAddrTemp(addrTemp);
|
||||
defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86Shared::visitSimdBinaryArith(MSimdBinaryArith *ins)
|
||||
{
|
||||
|
@ -56,10 +56,10 @@ class LIRGeneratorX86Shared : public LIRGeneratorShared
|
||||
void visitSimdSelect(MSimdSelect *ins);
|
||||
void visitSimdSplatX4(MSimdSplatX4 *ins);
|
||||
void visitSimdValueX4(MSimdValueX4 *ins);
|
||||
void lowerCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins,
|
||||
bool useI386ByteRegisters);
|
||||
void lowerAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins,
|
||||
bool useI386ByteRegisters);
|
||||
void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins);
|
||||
void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins);
|
||||
void lowerAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins, const LDefinition& addrTemp);
|
||||
void lowerAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins, const LDefinition& addrTemp);
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
@ -16,19 +16,6 @@
|
||||
# include "jit/x64/Assembler-x64.h"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define CHECK_BYTEREG(reg) \
|
||||
GeneralRegisterSet byteRegs(Registers::SingleByteRegs); \
|
||||
MOZ_ASSERT(byteRegs.has(reg))
|
||||
#define CHECK_BYTEREGS(r1, r2) \
|
||||
GeneralRegisterSet byteRegs(Registers::SingleByteRegs); \
|
||||
MOZ_ASSERT(byteRegs.has(r1)); \
|
||||
MOZ_ASSERT(byteRegs.has(r2));
|
||||
#else
|
||||
#define CHECK_BYTEREG(reg) (void)0
|
||||
#define CHECK_BYTEREGS(r1, r2) (void)0
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
@ -224,10 +211,25 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
void atomic_dec32(const Operand &addr) {
|
||||
lock_decl(addr);
|
||||
}
|
||||
void atomic_cmpxchg8(Register newval, const Operand &addr, Register oldval_and_result) {
|
||||
// %eax must be explicitly provided for calling clarity.
|
||||
MOZ_ASSERT(oldval_and_result.code() == X86Encoding::rax);
|
||||
lock_cmpxchg8(newval, addr);
|
||||
}
|
||||
void atomic_cmpxchg16(Register newval, const Operand &addr, Register oldval_and_result) {
|
||||
// %eax must be explicitly provided for calling clarity.
|
||||
MOZ_ASSERT(oldval_and_result.code() == X86Encoding::rax);
|
||||
lock_cmpxchg16(newval, addr);
|
||||
}
|
||||
void atomic_cmpxchg32(Register newval, const Operand &addr, Register oldval_and_result) {
|
||||
// %eax must be explicitly provided for calling clarity.
|
||||
MOZ_ASSERT(oldval_and_result.code() == X86Encoding::rax);
|
||||
lock_cmpxchg32(newval, addr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void atomicFetchAdd8SignExtend(Register src, const T &mem, Register temp, Register output) {
|
||||
CHECK_BYTEREGS(src, output);
|
||||
MOZ_ASSERT(output == eax);
|
||||
if (src != output)
|
||||
movl(src, output);
|
||||
lock_xaddb(output, Operand(mem));
|
||||
@ -236,7 +238,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
|
||||
template <typename T>
|
||||
void atomicFetchAdd8ZeroExtend(Register src, const T &mem, Register temp, Register output) {
|
||||
CHECK_BYTEREGS(src, output);
|
||||
MOZ_ASSERT(output == eax);
|
||||
MOZ_ASSERT(temp == InvalidReg);
|
||||
if (src != output)
|
||||
movl(src, output);
|
||||
@ -246,7 +248,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
|
||||
template <typename T>
|
||||
void atomicFetchAdd8SignExtend(Imm32 src, const T &mem, Register temp, Register output) {
|
||||
CHECK_BYTEREG(output);
|
||||
MOZ_ASSERT(output == eax);
|
||||
MOZ_ASSERT(temp == InvalidReg);
|
||||
movb(src, output);
|
||||
lock_xaddb(output, Operand(mem));
|
||||
@ -255,7 +257,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
|
||||
template <typename T>
|
||||
void atomicFetchAdd8ZeroExtend(Imm32 src, const T &mem, Register temp, Register output) {
|
||||
CHECK_BYTEREG(output);
|
||||
MOZ_ASSERT(output == eax);
|
||||
MOZ_ASSERT(temp == InvalidReg);
|
||||
movb(src, output);
|
||||
lock_xaddb(output, Operand(mem));
|
||||
@ -313,7 +315,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
|
||||
template <typename T>
|
||||
void atomicFetchSub8SignExtend(Register src, const T &mem, Register temp, Register output) {
|
||||
CHECK_BYTEREGS(src, output);
|
||||
MOZ_ASSERT(output == eax);
|
||||
MOZ_ASSERT(temp == InvalidReg);
|
||||
if (src != output)
|
||||
movl(src, output);
|
||||
@ -324,7 +326,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
|
||||
template <typename T>
|
||||
void atomicFetchSub8ZeroExtend(Register src, const T &mem, Register temp, Register output) {
|
||||
CHECK_BYTEREGS(src, output);
|
||||
MOZ_ASSERT(output == eax);
|
||||
MOZ_ASSERT(temp == InvalidReg);
|
||||
if (src != output)
|
||||
movl(src, output);
|
||||
@ -335,7 +337,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
|
||||
template <typename T>
|
||||
void atomicFetchSub8SignExtend(Imm32 src, const T &mem, Register temp, Register output) {
|
||||
CHECK_BYTEREG(output);
|
||||
MOZ_ASSERT(output == eax);
|
||||
MOZ_ASSERT(temp == InvalidReg);
|
||||
movb(Imm32(-src.value), output);
|
||||
lock_xaddb(output, Operand(mem));
|
||||
@ -344,7 +346,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
|
||||
template <typename T>
|
||||
void atomicFetchSub8ZeroExtend(Imm32 src, const T &mem, Register temp, Register output) {
|
||||
CHECK_BYTEREG(output);
|
||||
MOZ_ASSERT(output == eax);
|
||||
MOZ_ASSERT(temp == InvalidReg);
|
||||
movb(Imm32(-src.value), output);
|
||||
lock_xaddb(output, Operand(mem));
|
||||
@ -403,95 +405,89 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
}
|
||||
|
||||
// requires output == eax
|
||||
#define ATOMIC_BITOP_BODY(LOAD, OP, LOCK_CMPXCHG) \
|
||||
MOZ_ASSERT(output == eax); \
|
||||
LOAD(Operand(mem), eax); \
|
||||
Label again; \
|
||||
bind(&again); \
|
||||
movl(eax, temp); \
|
||||
OP(src, temp); \
|
||||
LOCK_CMPXCHG(temp, Operand(mem)); \
|
||||
#define ATOMIC_BITOP_BODY(LOAD, OP, LOCK_CMPXCHG) \
|
||||
MOZ_ASSERT(output == eax); \
|
||||
LOAD(Operand(mem), eax); \
|
||||
Label again; \
|
||||
bind(&again); \
|
||||
movl(eax, temp); \
|
||||
OP(src, temp); \
|
||||
LOCK_CMPXCHG(temp, Operand(mem)); \
|
||||
j(NonZero, &again);
|
||||
|
||||
template <typename S, typename T>
|
||||
void atomicFetchAnd8SignExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movb, andl, lock_cmpxchgb)
|
||||
CHECK_BYTEREG(temp);
|
||||
ATOMIC_BITOP_BODY(movb, andl, lock_cmpxchg8)
|
||||
movsbl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchAnd8ZeroExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movb, andl, lock_cmpxchgb)
|
||||
CHECK_BYTEREG(temp);
|
||||
ATOMIC_BITOP_BODY(movb, andl, lock_cmpxchg8)
|
||||
movzbl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchAnd16SignExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movw, andl, lock_cmpxchgw)
|
||||
ATOMIC_BITOP_BODY(movw, andl, lock_cmpxchg16)
|
||||
movswl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchAnd16ZeroExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movw, andl, lock_cmpxchgw)
|
||||
ATOMIC_BITOP_BODY(movw, andl, lock_cmpxchg16)
|
||||
movzwl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchAnd32(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movl, andl, lock_cmpxchgl)
|
||||
ATOMIC_BITOP_BODY(movl, andl, lock_cmpxchg32)
|
||||
}
|
||||
|
||||
template <typename S, typename T>
|
||||
void atomicFetchOr8SignExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movb, orl, lock_cmpxchgb)
|
||||
CHECK_BYTEREG(temp);
|
||||
ATOMIC_BITOP_BODY(movb, orl, lock_cmpxchg8)
|
||||
movsbl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchOr8ZeroExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movb, orl, lock_cmpxchgb)
|
||||
CHECK_BYTEREG(temp);
|
||||
ATOMIC_BITOP_BODY(movb, orl, lock_cmpxchg8)
|
||||
movzbl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchOr16SignExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movw, orl, lock_cmpxchgw)
|
||||
ATOMIC_BITOP_BODY(movw, orl, lock_cmpxchg16)
|
||||
movswl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchOr16ZeroExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movw, orl, lock_cmpxchgw)
|
||||
ATOMIC_BITOP_BODY(movw, orl, lock_cmpxchg16)
|
||||
movzwl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchOr32(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movl, orl, lock_cmpxchgl)
|
||||
ATOMIC_BITOP_BODY(movl, orl, lock_cmpxchg32)
|
||||
}
|
||||
|
||||
template <typename S, typename T>
|
||||
void atomicFetchXor8SignExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movb, xorl, lock_cmpxchgb)
|
||||
CHECK_BYTEREG(temp);
|
||||
ATOMIC_BITOP_BODY(movb, xorl, lock_cmpxchg8)
|
||||
movsbl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchXor8ZeroExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movb, xorl, lock_cmpxchgb)
|
||||
CHECK_BYTEREG(temp);
|
||||
ATOMIC_BITOP_BODY(movb, xorl, lock_cmpxchg8)
|
||||
movzbl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchXor16SignExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movw, xorl, lock_cmpxchgw)
|
||||
ATOMIC_BITOP_BODY(movw, xorl, lock_cmpxchg16)
|
||||
movswl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchXor16ZeroExtend(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movw, xorl, lock_cmpxchgw)
|
||||
ATOMIC_BITOP_BODY(movw, xorl, lock_cmpxchg16)
|
||||
movzwl(eax, eax);
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void atomicFetchXor32(const S &src, const T &mem, Register temp, Register output) {
|
||||
ATOMIC_BITOP_BODY(movl, xorl, lock_cmpxchgl)
|
||||
ATOMIC_BITOP_BODY(movl, xorl, lock_cmpxchg32)
|
||||
}
|
||||
|
||||
#undef ATOMIC_BITOP_BODY
|
||||
@ -720,19 +716,19 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
template <typename T>
|
||||
void compareExchange8ZeroExtend(const T &mem, Register oldval, Register newval, Register output) {
|
||||
MOZ_ASSERT(output == eax);
|
||||
CHECK_BYTEREGS(oldval, newval);
|
||||
MOZ_ASSERT(newval == ebx || newval == ecx || newval == edx);
|
||||
if (oldval != output)
|
||||
movl(oldval, output);
|
||||
lock_cmpxchgb(newval, Operand(mem));
|
||||
lock_cmpxchg8(newval, Operand(mem));
|
||||
movzbl(output, output);
|
||||
}
|
||||
template <typename T>
|
||||
void compareExchange8SignExtend(const T &mem, Register oldval, Register newval, Register output) {
|
||||
MOZ_ASSERT(output == eax);
|
||||
CHECK_BYTEREGS(oldval, newval);
|
||||
MOZ_ASSERT(newval == ebx || newval == ecx || newval == edx);
|
||||
if (oldval != output)
|
||||
movl(oldval, output);
|
||||
lock_cmpxchgb(newval, Operand(mem));
|
||||
lock_cmpxchg8(newval, Operand(mem));
|
||||
movsbl(output, output);
|
||||
}
|
||||
void load16ZeroExtend(const Address &src, Register dest) {
|
||||
@ -750,7 +746,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
MOZ_ASSERT(output == eax);
|
||||
if (oldval != output)
|
||||
movl(oldval, output);
|
||||
lock_cmpxchgw(newval, Operand(mem));
|
||||
lock_cmpxchg16(newval, Operand(mem));
|
||||
movzwl(output, output);
|
||||
}
|
||||
template <typename T>
|
||||
@ -758,7 +754,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
MOZ_ASSERT(output == eax);
|
||||
if (oldval != output)
|
||||
movl(oldval, output);
|
||||
lock_cmpxchgw(newval, Operand(mem));
|
||||
lock_cmpxchg16(newval, Operand(mem));
|
||||
movswl(output, output);
|
||||
}
|
||||
void load16SignExtend(const Address &src, Register dest) {
|
||||
@ -785,7 +781,7 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
MOZ_ASSERT(output == eax);
|
||||
if (oldval != output)
|
||||
movl(oldval, output);
|
||||
lock_cmpxchgl(newval, Operand(mem));
|
||||
lock_cmpxchg32(newval, Operand(mem));
|
||||
}
|
||||
template <typename S, typename T>
|
||||
void store32_NoSecondScratch(const S &src, const T &dest) {
|
||||
@ -1348,7 +1344,4 @@ class MacroAssemblerX86Shared : public Assembler
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
#undef CHECK_BYTEREG
|
||||
#undef CHECK_BYTEREGS
|
||||
|
||||
#endif /* jit_shared_MacroAssembler_x86_shared_h */
|
||||
|
@ -131,18 +131,6 @@ LIRGeneratorX64::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock
|
||||
lowerTypedPhiInput(phi, inputPosition, block, lirIndex);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX64::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins)
|
||||
{
|
||||
lowerCompareExchangeTypedArrayElement(ins, /* useI386ByteRegisters = */ false);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX64::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins)
|
||||
{
|
||||
lowerAtomicTypedArrayElementBinop(ins, /* useI386ByteRegisters = */ false);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX64::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins)
|
||||
{
|
||||
@ -212,58 +200,13 @@ LIRGeneratorX64::visitAsmJSStoreHeap(MAsmJSStoreHeap *ins)
|
||||
void
|
||||
LIRGeneratorX64::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins)
|
||||
{
|
||||
MDefinition *ptr = ins->ptr();
|
||||
MOZ_ASSERT(ptr->type() == MIRType_Int32);
|
||||
|
||||
const LAllocation oldval = useRegister(ins->oldValue());
|
||||
const LAllocation newval = useRegister(ins->newValue());
|
||||
|
||||
LAsmJSCompareExchangeHeap *lir =
|
||||
new(alloc()) LAsmJSCompareExchangeHeap(useRegister(ptr), oldval, newval);
|
||||
|
||||
defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
|
||||
lowerAsmJSCompareExchangeHeap(ins, LDefinition::BogusTemp());
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX64::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins)
|
||||
{
|
||||
MDefinition *ptr = ins->ptr();
|
||||
MOZ_ASSERT(ptr->type() == MIRType_Int32);
|
||||
|
||||
// Register allocation:
|
||||
//
|
||||
// For ADD and SUB we'll use XADD (with word and byte ops as appropriate):
|
||||
//
|
||||
// movl value, output
|
||||
// lock xaddl output, mem
|
||||
//
|
||||
// For AND/OR/XOR we need to use a CMPXCHG loop:
|
||||
//
|
||||
// movl *mem, eax
|
||||
// L: mov eax, temp
|
||||
// andl value, temp
|
||||
// lock cmpxchg temp, mem ; reads eax also
|
||||
// jnz L
|
||||
// ; result in eax
|
||||
//
|
||||
// Note the placement of L, cmpxchg will update eax with *mem if
|
||||
// *mem does not have the expected value, so reloading it at the
|
||||
// top of the loop would be redundant.
|
||||
//
|
||||
// We want to fix eax as the output. We also need a temp for
|
||||
// the intermediate value.
|
||||
//
|
||||
// There are optimization opportunities:
|
||||
// - when the result is unused, Bug #1077014.
|
||||
|
||||
bool bitOp = !(ins->operation() == AtomicFetchAddOp || ins->operation() == AtomicFetchSubOp);
|
||||
LAllocation value = useRegister(ins->value());
|
||||
LDefinition tempDef = bitOp ? temp() : LDefinition::BogusTemp();
|
||||
|
||||
LAsmJSAtomicBinopHeap *lir =
|
||||
new(alloc()) LAsmJSAtomicBinopHeap(useRegister(ptr), value, tempDef);
|
||||
|
||||
defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
|
||||
lowerAsmJSAtomicBinopHeap(ins, LDefinition::BogusTemp());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -42,8 +42,6 @@ class LIRGeneratorX64 : public LIRGeneratorX86Shared
|
||||
void visitBox(MBox *box);
|
||||
void visitUnbox(MUnbox *unbox);
|
||||
void visitReturn(MReturn *ret);
|
||||
void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins);
|
||||
void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins);
|
||||
void visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
|
||||
void visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins);
|
||||
void visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
|
||||
|
@ -182,18 +182,6 @@ LIRGeneratorX86::lowerUntypedPhiInput(MPhi *phi, uint32_t inputPosition, LBlock
|
||||
payload->setOperand(inputPosition, LUse(VirtualRegisterOfPayload(operand), LUse::ANY));
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86::visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins)
|
||||
{
|
||||
lowerCompareExchangeTypedArrayElement(ins, /* useI386ByteRegisters = */ true);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86::visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins)
|
||||
{
|
||||
lowerAtomicTypedArrayElementBinop(ins, /* useI386ByteRegisters = */ true);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86::visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins)
|
||||
{
|
||||
@ -285,101 +273,13 @@ LIRGeneratorX86::visitStoreTypedArrayElementStatic(MStoreTypedArrayElementStatic
|
||||
void
|
||||
LIRGeneratorX86::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap *ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->accessType() < Scalar::Float32);
|
||||
|
||||
MDefinition *ptr = ins->ptr();
|
||||
MOZ_ASSERT(ptr->type() == MIRType_Int32);
|
||||
|
||||
bool byteArray = byteSize(ins->accessType()) == 1;
|
||||
|
||||
// Register allocation:
|
||||
//
|
||||
// The output must be eax.
|
||||
//
|
||||
// oldval must be in a register.
|
||||
//
|
||||
// newval must be in a register. If the source is a byte array
|
||||
// then newval must be a register that has a byte size: on x86
|
||||
// this must be ebx, ecx, or edx (eax is taken for the output).
|
||||
//
|
||||
// Bug #1077036 describes some optimization opportunities.
|
||||
|
||||
const LAllocation oldval = useRegister(ins->oldValue());
|
||||
const LAllocation newval = byteArray ? useFixed(ins->newValue(), ebx) : useRegister(ins->newValue());
|
||||
|
||||
LAsmJSCompareExchangeHeap *lir =
|
||||
new(alloc()) LAsmJSCompareExchangeHeap(useRegister(ptr), oldval, newval);
|
||||
|
||||
lir->setAddrTemp(temp());
|
||||
defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
|
||||
lowerAsmJSCompareExchangeHeap(ins, temp());
|
||||
}
|
||||
|
||||
void
|
||||
LIRGeneratorX86::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap *ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->accessType() < Scalar::Float32);
|
||||
|
||||
MDefinition *ptr = ins->ptr();
|
||||
MOZ_ASSERT(ptr->type() == MIRType_Int32);
|
||||
|
||||
bool byteArray = byteSize(ins->accessType()) == 1;
|
||||
|
||||
// Register allocation:
|
||||
//
|
||||
// For ADD and SUB we'll use XADD:
|
||||
//
|
||||
// movl value, output
|
||||
// lock xaddl output, mem
|
||||
//
|
||||
// For the 8-bit variants XADD needs a byte register for the
|
||||
// output only, we can still set up with movl; just pin the output
|
||||
// to eax (or ebx / ecx / edx).
|
||||
//
|
||||
// For AND/OR/XOR we need to use a CMPXCHG loop:
|
||||
//
|
||||
// movl *mem, eax
|
||||
// L: mov eax, temp
|
||||
// andl value, temp
|
||||
// lock cmpxchg temp, mem ; reads eax also
|
||||
// jnz L
|
||||
// ; result in eax
|
||||
//
|
||||
// Note the placement of L, cmpxchg will update eax with *mem if
|
||||
// *mem does not have the expected value, so reloading it at the
|
||||
// top of the loop would be redundant.
|
||||
//
|
||||
// We want to fix eax as the output. We also need a temp for
|
||||
// the intermediate value.
|
||||
//
|
||||
// For the 8-bit variants the temp must have a byte register.
|
||||
//
|
||||
// There are optimization opportunities:
|
||||
// - when the result is unused, Bug #1077014.
|
||||
// - better register allocation and instruction selection, Bug #1077036.
|
||||
|
||||
bool bitOp = !(ins->operation() == AtomicFetchAddOp || ins->operation() == AtomicFetchSubOp);
|
||||
LDefinition tempDef = LDefinition::BogusTemp();
|
||||
LAllocation value;
|
||||
|
||||
// Optimization opportunity: "value" need not be pinned to something that
|
||||
// has a byte register unless the back-end insists on using a byte move
|
||||
// for the setup or the payload computation, which really it need not do.
|
||||
|
||||
if (byteArray) {
|
||||
value = useFixed(ins->value(), ebx);
|
||||
if (bitOp)
|
||||
tempDef = tempFixed(ecx);
|
||||
} else {
|
||||
value = useRegister(ins->value());
|
||||
if (bitOp)
|
||||
tempDef = temp();
|
||||
}
|
||||
|
||||
LAsmJSAtomicBinopHeap *lir =
|
||||
new(alloc()) LAsmJSAtomicBinopHeap(useRegister(ptr), value, tempDef);
|
||||
|
||||
lir->setAddrTemp(temp());
|
||||
defineFixed(lir, ins, LAllocation(AnyRegister(eax)));
|
||||
lowerAsmJSAtomicBinopHeap(ins, temp());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -48,8 +48,6 @@ class LIRGeneratorX86 : public LIRGeneratorX86Shared
|
||||
void visitBox(MBox *box);
|
||||
void visitUnbox(MUnbox *unbox);
|
||||
void visitReturn(MReturn *ret);
|
||||
void visitCompareExchangeTypedArrayElement(MCompareExchangeTypedArrayElement *ins);
|
||||
void visitAtomicTypedArrayElementBinop(MAtomicTypedArrayElementBinop *ins);
|
||||
void visitAsmJSUnsignedToDouble(MAsmJSUnsignedToDouble *ins);
|
||||
void visitAsmJSUnsignedToFloat32(MAsmJSUnsignedToFloat32 *ins);
|
||||
void visitAsmJSLoadHeap(MAsmJSLoadHeap *ins);
|
||||
|
@ -4102,6 +4102,7 @@ GCRuntime::markWeakReferences(gcstats::Phase phase)
|
||||
markedAny |= WeakMapBase::markCompartmentIteratively(c, &marker);
|
||||
}
|
||||
markedAny |= Debugger::markAllIteratively(&marker);
|
||||
markedAny |= jit::JitRuntime::MarkJitcodeGlobalTableIteratively(&marker);
|
||||
|
||||
if (!markedAny)
|
||||
break;
|
||||
@ -4153,15 +4154,6 @@ GCRuntime::markAllGrayReferences(gcstats::Phase phase)
|
||||
markGrayReferences<GCZonesIter, GCCompartmentsIter>(phase);
|
||||
}
|
||||
|
||||
void
|
||||
GCRuntime::markJitcodeGlobalTable()
|
||||
{
|
||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_MARK_JITCODE_GLOBAL_TABLE);
|
||||
jit::JitRuntime::MarkJitcodeGlobalTable(&marker);
|
||||
SliceBudget budget;
|
||||
marker.drainMarkStack(budget);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
class js::gc::MarkingValidator
|
||||
@ -4279,7 +4271,6 @@ js::gc::MarkingValidator::nonIncrementalMark()
|
||||
{
|
||||
gcstats::AutoPhase ap1(gc->stats, gcstats::PHASE_SWEEP);
|
||||
gcstats::AutoPhase ap2(gc->stats, gcstats::PHASE_SWEEP_MARK);
|
||||
gc->markJitcodeGlobalTable();
|
||||
|
||||
gc->markAllWeakReferences(gcstats::PHASE_SWEEP_MARK_WEAK);
|
||||
|
||||
@ -4823,8 +4814,6 @@ GCRuntime::endMarkingZoneGroup()
|
||||
{
|
||||
gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_MARK);
|
||||
|
||||
markJitcodeGlobalTable();
|
||||
|
||||
/*
|
||||
* Mark any incoming black pointers from previously swept compartments
|
||||
* whose referents are not marked. This can occur when gray cells become
|
||||
|
@ -3023,9 +3023,9 @@ ElementRestyler::ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
||||
return eRestyleResult_Continue;
|
||||
}
|
||||
|
||||
if (oldContext->IsInlineDescendantOfRuby() !=
|
||||
aNewContext->IsInlineDescendantOfRuby()) {
|
||||
LOG_RESTYLE_CONTINUE("NS_STYLE_IS_INLINE_DESCENDANT_OF_RUBY differes"
|
||||
if (oldContext->ShouldSuppressLineBreak() !=
|
||||
aNewContext->ShouldSuppressLineBreak()) {
|
||||
LOG_RESTYLE_CONTINUE("NS_STYLE_SUPPRESS_LINEBREAK differes"
|
||||
"between old and new style contexts");
|
||||
return eRestyleResult_Continue;
|
||||
}
|
||||
|
@ -97,7 +97,7 @@ BRFrame::Reflow(nsPresContext* aPresContext,
|
||||
// Only when the BR is operating in a line-layout situation will it
|
||||
// behave like a BR. BR is suppressed when it is inside ruby frames.
|
||||
nsLineLayout* ll = aReflowState.mLineLayout;
|
||||
if (ll && !StyleContext()->IsInlineDescendantOfRuby()) {
|
||||
if (ll && !StyleContext()->ShouldSuppressLineBreak()) {
|
||||
// Note that the compatibility mode check excludes AlmostStandards
|
||||
// mode, since this is the inline box model. See bug 161691.
|
||||
if ( ll->LineIsEmpty() ||
|
||||
@ -164,7 +164,7 @@ BRFrame::Reflow(nsPresContext* aPresContext,
|
||||
BRFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
|
||||
nsIFrame::InlineMinISizeData *aData)
|
||||
{
|
||||
if (!StyleContext()->IsInlineDescendantOfRuby()) {
|
||||
if (!StyleContext()->ShouldSuppressLineBreak()) {
|
||||
aData->ForceBreak(aRenderingContext);
|
||||
}
|
||||
}
|
||||
@ -173,7 +173,7 @@ BRFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
|
||||
BRFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
|
||||
nsIFrame::InlinePrefISizeData *aData)
|
||||
{
|
||||
if (!StyleContext()->IsInlineDescendantOfRuby()) {
|
||||
if (!StyleContext()->ShouldSuppressLineBreak()) {
|
||||
aData->ForceBreak(aRenderingContext);
|
||||
}
|
||||
}
|
||||
|
@ -3825,14 +3825,10 @@ nsBlockFrame::DoReflowInlineFrames(nsBlockReflowState& aState,
|
||||
}
|
||||
if (needsBackup) {
|
||||
// We need to try backing up to before a text run
|
||||
int32_t offset;
|
||||
gfxBreakPriority breakPriority;
|
||||
nsIFrame* breakFrame =
|
||||
aLineLayout.GetLastOptionalBreakPosition(&offset, &breakPriority);
|
||||
// XXX It's possible, in fact not unusual, for the break opportunity to already
|
||||
// be the end of the line. We should detect that and optimize to not
|
||||
// re-do the line.
|
||||
if (breakFrame) {
|
||||
if (aLineLayout.HasOptionalBreakPosition()) {
|
||||
// We can back up!
|
||||
lineReflowStatus = LINE_REFLOW_REDO_NO_PULL;
|
||||
}
|
||||
|
@ -3929,7 +3929,7 @@ nsFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
|
||||
NS_ASSERTION(GetParent(), "Must have a parent if we get here!");
|
||||
nsIFrame* parent = GetParent();
|
||||
bool canBreak = !CanContinueTextRun() &&
|
||||
!parent->StyleContext()->IsInlineDescendantOfRuby() &&
|
||||
!parent->StyleContext()->ShouldSuppressLineBreak() &&
|
||||
parent->StyleText()->WhiteSpaceCanWrap(parent);
|
||||
|
||||
if (canBreak)
|
||||
|
@ -457,7 +457,7 @@ nsLineLayout::BeginSpan(nsIFrame* aFrame,
|
||||
nsIFrame* frame = aSpanReflowState->frame;
|
||||
psd->mNoWrap = !frame->StyleText()->WhiteSpaceCanWrap(frame) ||
|
||||
mSuppressLineWrap ||
|
||||
frame->StyleContext()->IsInlineDescendantOfRuby();
|
||||
frame->StyleContext()->ShouldSuppressLineBreak();
|
||||
psd->mWritingMode = aSpanReflowState->GetWritingMode();
|
||||
|
||||
// Switch to new span
|
||||
@ -2790,8 +2790,13 @@ nsLineLayout::AdvanceAnnotationInlineBounds(PerFrameData* aPFD,
|
||||
// This ruby text container is a span.
|
||||
(psd->mFirstFrame == psd->mLastFrame && psd->mFirstFrame &&
|
||||
!psd->mFirstFrame->mIsLinkedToBase)) {
|
||||
nscoord reservedISize = RubyUtils::GetReservedISize(frame);
|
||||
RubyUtils::SetReservedISize(frame, reservedISize + aDeltaISize);
|
||||
// For ruby text frames, only increase frames
|
||||
// which are not auto-hidden.
|
||||
if (frameType != nsGkAtoms::rubyTextFrame ||
|
||||
!static_cast<nsRubyTextFrame*>(frame)->IsAutoHidden()) {
|
||||
nscoord reservedISize = RubyUtils::GetReservedISize(frame);
|
||||
RubyUtils::SetReservedISize(frame, reservedISize + aDeltaISize);
|
||||
}
|
||||
} else {
|
||||
// It is a normal ruby text container. Its children will expand
|
||||
// themselves properly. We only need to expand its own size here.
|
||||
@ -2891,7 +2896,7 @@ nsLineLayout::ApplyFrameJustification(PerSpanData* aPSD,
|
||||
static nsIFrame*
|
||||
FindNearestRubyBaseAncestor(nsIFrame* aFrame)
|
||||
{
|
||||
MOZ_ASSERT(aFrame->StyleContext()->IsInlineDescendantOfRuby());
|
||||
MOZ_ASSERT(aFrame->StyleContext()->ShouldSuppressLineBreak());
|
||||
while (aFrame && aFrame->GetType() != nsGkAtoms::rubyBaseFrame) {
|
||||
aFrame = aFrame->GetParent();
|
||||
}
|
||||
@ -3066,7 +3071,7 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine,
|
||||
ComputeFrameJustification(psd, computeState);
|
||||
if (mHasRuby && computeState.mFirstParticipant) {
|
||||
PerFrameData* firstFrame = computeState.mFirstParticipant;
|
||||
if (firstFrame->mFrame->StyleContext()->IsInlineDescendantOfRuby()) {
|
||||
if (firstFrame->mFrame->StyleContext()->ShouldSuppressLineBreak()) {
|
||||
MOZ_ASSERT(!firstFrame->mJustificationAssignment.mGapsAtStart);
|
||||
nsIFrame* rubyBase = FindNearestRubyBaseAncestor(firstFrame->mFrame);
|
||||
if (rubyBase && IsRubyAlignSpaceAround(rubyBase)) {
|
||||
@ -3075,7 +3080,7 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine,
|
||||
}
|
||||
}
|
||||
PerFrameData* lastFrame = computeState.mLastParticipant;
|
||||
if (lastFrame->mFrame->StyleContext()->IsInlineDescendantOfRuby()) {
|
||||
if (lastFrame->mFrame->StyleContext()->ShouldSuppressLineBreak()) {
|
||||
MOZ_ASSERT(!lastFrame->mJustificationAssignment.mGapsAtEnd);
|
||||
nsIFrame* rubyBase = FindNearestRubyBaseAncestor(lastFrame->mFrame);
|
||||
if (rubyBase && IsRubyAlignSpaceAround(rubyBase)) {
|
||||
|
@ -303,6 +303,11 @@ public:
|
||||
{
|
||||
return mLastOptionalBreakFrame != nullptr;
|
||||
}
|
||||
// Get the priority of the last optional break position recorded.
|
||||
gfxBreakPriority LastOptionalBreakPriority() const
|
||||
{
|
||||
return mLastOptionalBreakPriority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether frames overflowed the available width and CanPlaceFrame
|
||||
|
@ -250,14 +250,14 @@ GetIsLineBreakAllowed(nsIFrame* aFrame, bool aIsLineBreakable,
|
||||
bool* aAllowInitialLineBreak, bool* aAllowLineBreak)
|
||||
{
|
||||
nsIFrame* parent = aFrame->GetParent();
|
||||
bool inNestedRuby = parent->StyleContext()->IsInlineDescendantOfRuby();
|
||||
bool lineBreakSuppressed = parent->StyleContext()->ShouldSuppressLineBreak();
|
||||
// Allow line break between ruby bases when white-space allows,
|
||||
// we are not inside a nested ruby, and there is no span.
|
||||
bool allowLineBreak = !inNestedRuby &&
|
||||
bool allowLineBreak = !lineBreakSuppressed &&
|
||||
aFrame->StyleText()->WhiteSpaceCanWrap(aFrame);
|
||||
bool allowInitialLineBreak = allowLineBreak;
|
||||
if (!aFrame->GetPrevInFlow()) {
|
||||
allowInitialLineBreak = !inNestedRuby &&
|
||||
allowInitialLineBreak = !lineBreakSuppressed &&
|
||||
parent->StyleText()->WhiteSpaceCanWrap(parent);
|
||||
}
|
||||
if (!aIsLineBreakable) {
|
||||
@ -700,22 +700,36 @@ nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
|
||||
{
|
||||
const nsHTMLReflowState& baseReflowState = aReflowState.mBaseReflowState;
|
||||
const auto& textReflowStates = aReflowState.mTextReflowStates;
|
||||
nscoord istart = baseReflowState.mLineLayout->GetCurrentICoord();
|
||||
|
||||
if (aColumn.mBaseFrame) {
|
||||
int32_t pos = baseReflowState.mLineLayout->
|
||||
GetForcedBreakPosition(aColumn.mBaseFrame);
|
||||
MOZ_ASSERT(pos == -1 || pos == 0,
|
||||
"It should either break before, or not break at all.");
|
||||
if (pos >= 0) {
|
||||
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
||||
return 0;
|
||||
bool allowBreakBefore = aColumnIndex ?
|
||||
aReflowState.mAllowLineBreak : aReflowState.mAllowInitialLineBreak;
|
||||
if (allowBreakBefore) {
|
||||
gfxBreakPriority breakPriority = LineBreakBefore(
|
||||
aColumn.mBaseFrame, baseReflowState.rendContext,
|
||||
baseReflowState.mLineLayout->LineContainerFrame(),
|
||||
baseReflowState.mLineLayout->GetLine());
|
||||
if (breakPriority != gfxBreakPriority::eNoBreak) {
|
||||
gfxBreakPriority lastBreakPriority =
|
||||
baseReflowState.mLineLayout->LastOptionalBreakPriority();
|
||||
if (breakPriority >= lastBreakPriority) {
|
||||
// Either we have been overflow, or we are forced
|
||||
// to break here, do break before.
|
||||
if (istart > baseReflowState.AvailableISize() ||
|
||||
baseReflowState.mLineLayout->NotifyOptionalBreakPosition(
|
||||
aColumn.mBaseFrame, 0, true, breakPriority)) {
|
||||
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uint32_t rtcCount = aReflowState.mTextContainers.Length();
|
||||
MOZ_ASSERT(aColumn.mTextFrames.Length() == rtcCount);
|
||||
MOZ_ASSERT(textReflowStates.Length() == rtcCount);
|
||||
nscoord istart = baseReflowState.mLineLayout->GetCurrentICoord();
|
||||
nscoord columnISize = 0;
|
||||
|
||||
nsAutoString baseText;
|
||||
@ -773,42 +787,10 @@ nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
|
||||
"Any line break inside ruby box should has been suppressed");
|
||||
nscoord baseISize = lineLayout->GetCurrentICoord() - baseIStart;
|
||||
columnISize = std::max(columnISize, baseISize);
|
||||
|
||||
bool allowBreakBefore = aColumnIndex ?
|
||||
aReflowState.mAllowLineBreak : aReflowState.mAllowInitialLineBreak;
|
||||
if (allowBreakBefore) {
|
||||
bool shouldBreakBefore = false;
|
||||
gfxBreakPriority breakPriority = LineBreakBefore(
|
||||
aColumn.mBaseFrame, baseReflowState.rendContext,
|
||||
baseReflowState.mLineLayout->LineContainerFrame(),
|
||||
baseReflowState.mLineLayout->GetLine());
|
||||
if (breakPriority != gfxBreakPriority::eNoBreak) {
|
||||
int32_t offset;
|
||||
gfxBreakPriority lastBreakPriority;
|
||||
baseReflowState.mLineLayout->
|
||||
GetLastOptionalBreakPosition(&offset, &lastBreakPriority);
|
||||
shouldBreakBefore = breakPriority >= lastBreakPriority;
|
||||
}
|
||||
if (shouldBreakBefore) {
|
||||
bool fits = istart <= baseReflowState.AvailableISize();
|
||||
DebugOnly<bool> breakBefore =
|
||||
baseReflowState.mLineLayout->NotifyOptionalBreakPosition(
|
||||
aColumn.mBaseFrame, 0, fits, breakPriority);
|
||||
MOZ_ASSERT(!breakBefore, "The break notified here should have "
|
||||
"triggered at the start of this method.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nscoord icoord = istart + columnISize;
|
||||
// If we can break here, do it now.
|
||||
if (icoord > baseReflowState.AvailableISize() &&
|
||||
baseReflowState.mLineLayout->HasOptionalBreakPosition()) {
|
||||
aStatus = NS_INLINE_LINE_BREAK_BEFORE();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Align all the line layout to the new coordinate.
|
||||
nscoord icoord = istart + columnISize;
|
||||
nscoord deltaISize = icoord - baseReflowState.mLineLayout->GetCurrentICoord();
|
||||
if (deltaISize > 0) {
|
||||
baseReflowState.mLineLayout->AdvanceICoord(deltaISize);
|
||||
@ -825,7 +807,7 @@ nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
|
||||
nscoord deltaISize = icoord - lineLayout->GetCurrentICoord();
|
||||
if (deltaISize > 0) {
|
||||
lineLayout->AdvanceICoord(deltaISize);
|
||||
if (textFrame) {
|
||||
if (textFrame && !textFrame->IsAutoHidden()) {
|
||||
RubyUtils::SetReservedISize(textFrame, deltaISize);
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ nsRubyTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsDisplayListSet& aLists)
|
||||
{
|
||||
if (GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE) {
|
||||
if (IsAutoHidden()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ nsRubyTextFrame::Reflow(nsPresContext* aPresContext,
|
||||
nsRubyTextFrameSuper::Reflow(aPresContext, aDesiredSize,
|
||||
aReflowState, aStatus);
|
||||
|
||||
if (GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE) {
|
||||
if (IsAutoHidden()) {
|
||||
// Reset the ISize. The BSize is not changed so that it won't
|
||||
// affect vertical positioning in unexpected way.
|
||||
WritingMode lineWM = aReflowState.mLineLayout->GetWritingMode();
|
||||
|
@ -44,6 +44,11 @@ public:
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus) MOZ_OVERRIDE;
|
||||
|
||||
bool IsAutoHidden() const
|
||||
{
|
||||
return GetStateBits() & NS_RUBY_TEXT_FRAME_AUTOHIDE;
|
||||
}
|
||||
|
||||
protected:
|
||||
friend nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell,
|
||||
nsStyleContext* aContext);
|
||||
|
@ -1927,7 +1927,7 @@ BuildTextRunsScanner::BuildTextRunForFrames(void* aTextBuffer)
|
||||
textFlags |= GetSpacingFlags(WordSpacing(f));
|
||||
nsTextFrameUtils::CompressionMode compression =
|
||||
CSSWhitespaceToCompressionMode[textStyle->mWhiteSpace];
|
||||
if ((enabledJustification || f->StyleContext()->IsInlineDescendantOfRuby()) &&
|
||||
if ((enabledJustification || f->StyleContext()->ShouldSuppressLineBreak()) &&
|
||||
!textStyle->WhiteSpaceIsSignificant() && !isSVG) {
|
||||
textFlags |= gfxTextRunFactory::TEXT_ENABLE_SPACING;
|
||||
}
|
||||
@ -2803,7 +2803,7 @@ static int32_t FindChar(const nsTextFragment* frag,
|
||||
|
||||
static bool IsChineseOrJapanese(nsIFrame* aFrame)
|
||||
{
|
||||
if (aFrame->StyleContext()->IsInlineDescendantOfRuby()) {
|
||||
if (aFrame->StyleContext()->ShouldSuppressLineBreak()) {
|
||||
// Always treat ruby as CJ language so that those characters can
|
||||
// be expanded properly even when surrounded by other language.
|
||||
return true;
|
||||
@ -8291,11 +8291,9 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
||||
gfxFloat availWidth = aAvailableWidth;
|
||||
bool canTrimTrailingWhitespace = !textStyle->WhiteSpaceIsSignificant() ||
|
||||
(GetStateBits() & TEXT_IS_IN_TOKEN_MATHML);
|
||||
int32_t unusedOffset;
|
||||
gfxBreakPriority breakPriority;
|
||||
aLineLayout.GetLastOptionalBreakPosition(&unusedOffset, &breakPriority);
|
||||
gfxBreakPriority breakPriority = aLineLayout.LastOptionalBreakPriority();
|
||||
gfxTextRun::SuppressBreak suppressBreak = gfxTextRun::eNoSuppressBreak;
|
||||
if (StyleContext()->IsInlineDescendantOfRuby()) {
|
||||
if (StyleContext()->ShouldSuppressLineBreak()) {
|
||||
suppressBreak = gfxTextRun::eSuppressAllBreaks;
|
||||
} else if (!aLineLayout.LineIsBreakable()) {
|
||||
suppressBreak = gfxTextRun::eSuppressInitialBreak;
|
||||
@ -8506,7 +8504,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
||||
bool emptyTextAtStartOfLine = atStartOfLine && length == 0;
|
||||
if (!breakAfter && charsFit == length && !emptyTextAtStartOfLine &&
|
||||
transformedOffset + transformedLength == mTextRun->GetLength() &&
|
||||
!StyleContext()->IsInlineDescendantOfRuby() &&
|
||||
!StyleContext()->ShouldSuppressLineBreak() &&
|
||||
(mTextRun->GetFlags() & nsTextFrameUtils::TEXT_HAS_TRAILING_BREAK)) {
|
||||
// We placed all the text in the textrun and we have a break opportunity at
|
||||
// the end of the textrun. We need to record it because the following
|
||||
@ -8568,7 +8566,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
||||
if (!textStyle->WhiteSpaceIsSignificant() &&
|
||||
(lineContainer->StyleText()->mTextAlign == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
|
||||
lineContainer->StyleText()->mTextAlignLast == NS_STYLE_TEXT_ALIGN_JUSTIFY ||
|
||||
StyleContext()->IsInlineDescendantOfRuby()) &&
|
||||
StyleContext()->ShouldSuppressLineBreak()) &&
|
||||
!lineContainer->IsSVGText()) {
|
||||
AddStateBits(TEXT_JUSTIFICATION_ENABLED);
|
||||
provider.ComputeJustification(offset, charsFit);
|
||||
|
@ -39,7 +39,7 @@
|
||||
><rtc pseudo><rt>o</rt><rt pseudo><span> </span></rt><rt>p</rt></rtc><rbc><rb><span>
|
||||
</span></rb></rbc><rbc><rb>q</rb></rbc></ruby><span> <span>r</span>
|
||||
</span><ruby><rbc></rbc><rtc pseudo><rt>s</rt></rtc></ruby><span> <span>t</span>
|
||||
</span><ruby><rbc><rb>u</rb></rbc><rbc><rbc><rb><span> </span></rb></rbc
|
||||
</span><ruby><rbc><rb>u</rb></rbc><rbc><rb><span> </span></rb></rbc
|
||||
><rbc><rb>v</rb></rbc><rbc><rb><span>
|
||||
</span></rb></rbc><rbc><rb>w</rb></rbc><rtc pseudo><rt>x</rt></rtc><rbc><rb><span>
|
||||
</span></rb></rbc><rbc><rb>y</rb></rbc><rtc><rt>z</rt></rtc></ruby
|
||||
|
13
layout/reftests/css-ruby/line-breaking-2-ref.html
Normal file
13
layout/reftests/css-ruby/line-breaking-2-ref.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1140264</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 5em; border: 1px solid silver;">
|
||||
の「<span style="font-family: Ahem; padding: 0 10rem;">X</span>」
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
13
layout/reftests/css-ruby/line-breaking-2.html
Normal file
13
layout/reftests/css-ruby/line-breaking-2.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1140264</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: 5em; border: 1px solid silver;">
|
||||
の「<ruby style="font-family: Ahem;">X<rt style="font-size: 0;"><div style="width: 21rem"></div></ruby>」
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user