Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2015-03-11 13:07:07 +01:00
commit f7a74303f9
176 changed files with 3692 additions and 4825 deletions

View File

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

View File

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

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="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"/>

View File

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

View File

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

View File

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

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="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"/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -43,6 +43,7 @@ public:
void LinkRemoved();
void UpdateImport();
void UpdatePreconnect();
// nsIDOMEventTarget
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -37,6 +37,7 @@ struct RemoteObject
uint64_t serializedId;
bool isCallable;
bool isConstructor;
bool isDOMObject;
nsCString objectTag;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View 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