This commit is contained in:
Phil Ringnalda 2014-03-09 20:42:27 -07:00
Родитель e1b8d5b915 3f542fd993
Коммит f455494d76
60 изменённых файлов: 631 добавлений и 668 удалений

Просмотреть файл

@ -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="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="707630df1b4270eae3dd49b7344c645f32c1b5f4"/>

Просмотреть файл

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="a9e08b91e9cd1f0930f16cfc49ec72f63575d5fe">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>

Просмотреть файл

@ -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="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>

Просмотреть файл

@ -4,6 +4,6 @@
"branch": "",
"revision": ""
},
"revision": "2d53c8213843d04a5fa3421ff8263fbe67fd5e49",
"revision": "d4f876f6f000a8b56c160c9dad8e62547a4a6959",
"repo_path": "/integration/gaia-central"
}

Просмотреть файл

@ -17,7 +17,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="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -15,7 +15,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="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -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="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -17,7 +17,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="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="707630df1b4270eae3dd49b7344c645f32c1b5f4"/>

Просмотреть файл

@ -17,7 +17,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="6c109df47006b08c082761c0ddd6ba53a864983a"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="af37a57729c6911f1d2ba83fafa32f7c1a18508f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>

Просмотреть файл

@ -108,8 +108,9 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
return;
#else
webrtc::ViEBase* ptrViEBase;
webrtc::ViECapture* ptrViECapture;
ScopedCustomReleasePtr<webrtc::ViEBase> ptrViEBase;
ScopedCustomReleasePtr<webrtc::ViECapture> ptrViECapture;
// We spawn threads to handle gUM runnables, so we must protect the member vars
MutexAutoLock lock(mMutex);
@ -232,9 +233,6 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
}
}
ptrViEBase->Release();
ptrViECapture->Release();
return;
#endif
}
@ -242,8 +240,8 @@ MediaEngineWebRTC::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSourc
void
MediaEngineWebRTC::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSource> >* aASources)
{
webrtc::VoEBase* ptrVoEBase = nullptr;
webrtc::VoEHardware* ptrVoEHw = nullptr;
ScopedCustomReleasePtr<webrtc::VoEBase> ptrVoEBase;
ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw;
// We spawn threads to handle gUM runnables, so we must protect the member vars
MutexAutoLock lock(mMutex);
@ -336,9 +334,6 @@ MediaEngineWebRTC::EnumerateAudioDevices(nsTArray<nsRefPtr<MediaEngineAudioSourc
aASources->AppendElement(aSource);
}
}
ptrVoEHw->Release();
ptrVoEBase->Release();
}
void

Просмотреть файл

@ -28,6 +28,8 @@
#include "MediaStreamGraph.h"
#include "LoadMonitor.h"
#include "MediaEngineWrapper.h"
// WebRTC library includes follow
// Audio Engine
@ -308,10 +310,10 @@ private:
void Shutdown();
webrtc::VoiceEngine* mVoiceEngine;
webrtc::VoEBase* mVoEBase;
webrtc::VoEExternalMedia* mVoERender;
webrtc::VoENetwork* mVoENetwork;
webrtc::VoEAudioProcessing *mVoEProcessing;
ScopedCustomReleasePtr<webrtc::VoEBase> mVoEBase;
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mVoERender;
ScopedCustomReleasePtr<webrtc::VoENetwork> mVoENetwork;
ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mVoEProcessing;
// mMonitor protects mSources[] access/changes, and transitions of mState
// from kStarted to kStopped (which are combined with EndTrack()).

Просмотреть файл

@ -109,10 +109,8 @@ MediaEngineWebRTCAudioSource::Allocate(const MediaEnginePrefs &aPrefs)
{
if (mState == kReleased) {
if (mInitDone) {
webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
int res = ptrVoEHw->SetRecordingDevice(mCapIndex);
ptrVoEHw->Release();
if (res) {
ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw(webrtc::VoEHardware::GetInterface(mVoiceEngine));
if (!ptrVoEHw || ptrVoEHw->SetRecordingDevice(mCapIndex)) {
return NS_ERROR_FAILURE;
}
mState = kAllocated;
@ -278,9 +276,8 @@ MediaEngineWebRTCAudioSource::Init()
}
// Check for availability.
webrtc::VoEHardware* ptrVoEHw = webrtc::VoEHardware::GetInterface(mVoiceEngine);
if (ptrVoEHw->SetRecordingDevice(mCapIndex)) {
ptrVoEHw->Release();
ScopedCustomReleasePtr<webrtc::VoEHardware> ptrVoEHw(webrtc::VoEHardware::GetInterface(mVoiceEngine));
if (!ptrVoEHw || ptrVoEHw->SetRecordingDevice(mCapIndex)) {
return;
}
@ -289,19 +286,18 @@ MediaEngineWebRTCAudioSource::Init()
// check here.
bool avail = false;
ptrVoEHw->GetRecordingDeviceStatus(avail);
ptrVoEHw->Release();
if (!avail) {
return;
}
#endif // MOZ_B2G
// Set "codec" to PCM, 32kHz on 1 channel
webrtc::VoECodec* ptrVoECodec;
webrtc::CodecInst codec;
ptrVoECodec = webrtc::VoECodec::GetInterface(mVoiceEngine);
ScopedCustomReleasePtr<webrtc::VoECodec> ptrVoECodec(webrtc::VoECodec::GetInterface(mVoiceEngine));
if (!ptrVoECodec) {
return;
}
webrtc::CodecInst codec;
strcpy(codec.plname, ENCODING);
codec.channels = CHANNELS;
codec.rate = SAMPLE_RATE;
@ -309,11 +305,9 @@ MediaEngineWebRTCAudioSource::Init()
codec.pacsize = SAMPLE_LENGTH;
codec.pltype = 0; // Default payload type
if (ptrVoECodec->SetSendCodec(mChannel, codec)) {
return;
if (!ptrVoECodec->SetSendCodec(mChannel, codec)) {
mInitDone = true;
}
mInitDone = true;
}
void
@ -352,8 +346,10 @@ MediaEngineWebRTCAudioSource::Shutdown()
delete mNullTransport;
}
mVoERender->Release();
mVoEBase->Release();
mVoEProcessing = nullptr;
mVoENetwork = nullptr;
mVoERender = nullptr;
mVoEBase = nullptr;
mState = kReleased;
mInitDone = false;

Просмотреть файл

@ -10,13 +10,18 @@ Components.utils.import("resource://gre/modules/Services.jsm");
const Ci = Components.interfaces;
const Cc = Components.classes;
const POSITION_UNAVAILABLE = Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE;
let gLoggingEnabled = false;
let gTestingEnabled = false;
let gUseScanning = true;
// if we don't see any wifi responses in 5 seconds, send the request.
let gTimeToWaitBeforeSending = 5000; //ms
let gWifiScanningEnabled = true;
let gWifiResults;
function LOG(aMsg) {
if (gLoggingEnabled)
{
if (gLoggingEnabled) {
aMsg = "*** WIFI GEO: " + aMsg + "\n";
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(aMsg);
dump(aMsg);
@ -62,20 +67,16 @@ function WifiGeoPositionProvider() {
} catch (e) {}
try {
gTestingEnabled = Services.prefs.getBoolPref("geo.wifi.testing");
gTimeToWaitBeforeSending = Services.prefs.getIntPref("geo.wifi.timeToWaitBeforeSending");
} catch (e) {}
try {
gUseScanning = Services.prefs.getBoolPref("geo.wifi.scan");
gWifiScanningEnabled = Services.prefs.getBoolPref("geo.wifi.scan");
} catch (e) {}
this.wifiService = null;
this.timer = null;
this.hasSeenWiFi = false;
this.timeoutTimer = null;
this.started = false;
// this is only used when logging is enabled, to debug interactions with the
// geolocation service
this.highAccuracy = false;
}
WifiGeoPositionProvider.prototype = {
@ -87,74 +88,51 @@ WifiGeoPositionProvider.prototype = {
if (this.started)
return;
this.started = true;
this.hasSeenWiFi = false;
LOG("startup called. testing mode is" + gTestingEnabled);
// if we don't see anything in 5 seconds, kick of one IP geo lookup.
// if we are testing, just hammer this callback so that we are more or less
// always sending data. It doesn't matter if we have an access point or not.
this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
if (!gTestingEnabled)
this.timer.initWithCallback(this, 5000, this.timer.TYPE_ONE_SHOT);
else
this.timer.initWithCallback(this, 200, this.timer.TYPE_REPEATING_SLACK);
},
watch: function(c) {
LOG("watch called");
if (!this.wifiService && gUseScanning) {
if (gWifiScanningEnabled) {
this.wifiService = Cc["@mozilla.org/wifi/monitor;1"].getService(Components.interfaces.nsIWifiMonitor);
this.wifiService.startWatching(this);
}
if (this.hasSeenWiFi) {
this.hasSeenWiFi = false;
if (gUseScanning) {
this.wifiService.stopWatching(this);
this.wifiService.startWatching(this);
} else {
// For testing situations, ensure that we always trigger an update.
this.timer.initWithCallback(this, 5000, this.timer.TYPE_ONE_SHOT);
}
}
this.timeoutTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
this.timeoutTimer.initWithCallback(this,
gTimeToWaitBeforeSending,
this.timeoutTimer.TYPE_REPEATING_SLACK);
LOG("startup called.");
},
shutdown: function() {
watch: function(c) {
},
shutdown: function() {
LOG("shutdown called");
if (this.started == false) {
return;
}
if (this.timeoutTimer) {
this.timeoutTimer.cancel();
this.timeoutTimer = null;
}
if(this.wifiService) {
this.wifiService.stopWatching(this);
this.wifiService = null;
}
if (this.timer != null) {
this.timer.cancel();
this.timer = null;
}
this.started = false;
},
setHighAccuracy: function(enable) {
this.highAccuracy = enable;
LOG("setting highAccuracy to " + (this.highAccuracy?"TRUE":"FALSE"));
},
onChange: function(accessPoints) {
LOG("onChange called, highAccuracy = " + (this.highAccuracy?"TRUE":"FALSE"));
this.hasSeenWiFi = true;
Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate)
.locationUpdatePending();
let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");
function isPublic(ap) {
let mask = "_nomap"
let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length);
if (result != -1) {
LOG("Filtering out " + ap.ssid + " " + result);
}
return result;
let mask = "_nomap"
let result = ap.ssid.indexOf(mask, ap.ssid.length - mask.length);
if (result != -1) {
LOG("Filtering out " + ap.ssid + " " + result);
}
return result;
};
function sort(a, b) {
@ -162,80 +140,65 @@ WifiGeoPositionProvider.prototype = {
};
function encode(ap) {
return { 'macAddress': ap.mac, 'signalStrength': ap.signal };
return { 'macAddress': ap.mac, 'signalStrength': ap.signal };
};
var data;
if (accessPoints) {
data = JSON.stringify({wifiAccessPoints: accessPoints.filter(isPublic).sort(sort).map(encode)})
data = JSON.stringify({wifiAccessPoints: accessPoints.filter(isPublic).sort(sort).map(encode)})
}
LOG("************************************* Sending request:\n" + url + "\n");
// send our request to a wifi geolocation network provider:
let xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
// This is a background load
try {
xhr.open("POST", url, true);
} catch (e) {
triggerError();
return;
}
xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
xhr.responseType = "json";
xhr.mozBackgroundRequest = true;
xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS;
xhr.onerror = function() {
LOG("onerror: " + xhr);
triggerError();
};
xhr.onload = function() {
LOG("gls returned status: " + xhr.status + " --> " + JSON.stringify(xhr.response));
if (xhr.channel instanceof Ci.nsIHttpChannel && xhr.status != 200) {
triggerError();
return;
}
if (!xhr.response || !xhr.response.location) {
triggerError();
return;
}
let newLocation = new WifiGeoPositionObject(xhr.response.location.lat,
xhr.response.location.lng,
xhr.response.accuracy);
Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate)
.update(newLocation);
};
LOG("************************************* ------>>>> sending " + data);
xhr.send(data);
gWifiResults = data;
},
onError: function (code) {
LOG("wifi error: " + code);
},
notify: function (timer) {
if (gTestingEnabled || !gUseScanning) {
// if we are testing, timer is repeating
this.onChange(null);
}
else {
if (!this.hasSeenWiFi)
this.onChange(null);
this.timer = null;
notify: function (timeoutTimer) {
let url = Services.urlFormatter.formatURLPref("geo.wifi.uri");
LOG("Sending request: " + url + "\n");
let xhr = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Ci.nsIXMLHttpRequest);
getGeoService().locationUpdatePending();
try {
xhr.open("POST", url, true);
} catch (e) {
getGeoService().notifyError(POSITION_UNAVAILABLE);
return;
}
xhr.setRequestHeader("Content-Type", "application/json; charset=UTF-8");
xhr.responseType = "json";
xhr.mozBackgroundRequest = true;
xhr.channel.loadFlags = Ci.nsIChannel.LOAD_ANONYMOUS;
xhr.onerror = function() {
getGeoService().notifyError(POSITION_UNAVAILABLE);
};
xhr.onload = function() {
LOG("gls returned status: " + xhr.status + " --> " + JSON.stringify(xhr.response));
if ((xhr.channel instanceof Ci.nsIHttpChannel && xhr.status != 200) ||
!xhr.response || !xhr.response.location) {
getGeoService().notifyError(POSITION_UNAVAILABLE);
return;
}
let newLocation = new WifiGeoPositionObject(xhr.response.location.lat,
xhr.response.location.lng,
xhr.response.accuracy);
getGeoService().update(newLocation);
};
let data = gWifiResults;
LOG("sending " + data);
xhr.send(data);
},
};
function triggerError() {
Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate)
.notifyError(Ci.nsIDOMGeoPositionError.POSITION_UNAVAILABLE);
function getGeoService() {
return Cc["@mozilla.org/geolocation/service;1"].getService(Ci.nsIGeolocationUpdate);
}
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WifiGeoPositionProvider]);

Просмотреть файл

@ -37,6 +37,11 @@ class GenericRefCountedBase
// mechanism, it is welcome to do so by overriding AddRef() and Release().
void ref() { AddRef(); }
void deref() { Release(); }
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
virtual const char* typeName() const = 0;
virtual size_t typeSize() const = 0;
#endif
};
namespace detail {
@ -55,11 +60,18 @@ class GenericRefCounted : public GenericRefCountedBase
virtual void AddRef() {
MOZ_ASSERT(int32_t(refCnt) >= 0);
++refCnt;
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
detail::RefCountLogger::logAddRef(this, refCnt, typeName(), typeSize());
#endif
}
virtual void Release() {
MOZ_ASSERT(int32_t(refCnt) > 0);
if (0 == --refCnt) {
--refCnt;
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
detail::RefCountLogger::logRelease(this, refCnt, typeName());
#endif
if (0 == refCnt) {
#ifdef DEBUG
refCnt = detail::DEAD;
#endif

Просмотреть файл

@ -27,6 +27,7 @@ class GLContextCGL : public GLContext
NSOpenGLContext *mContext;
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextCGL)
GLContextCGL(const SurfaceCaps& caps,
GLContext *shareContext,
NSOpenGLContext *context,

Просмотреть файл

@ -29,6 +29,7 @@ class GLContextEGL : public GLContext
EGLSurface surface);
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextEGL)
GLContextEGL(const SurfaceCaps& caps,
GLContext* shareContext,
bool isOffscreen,

Просмотреть файл

@ -16,6 +16,7 @@ namespace gl {
class GLContextGLX : public GLContext
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextGLX)
static already_AddRefed<GLContextGLX>
CreateGLContext(const SurfaceCaps& caps,
GLContextGLX* shareContext,

Просмотреть файл

@ -16,6 +16,7 @@ namespace gl {
class GLContextWGL : public GLContext
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(GLContextWGL)
// From Window: (possibly for offscreen!)
GLContextWGL(const SurfaceCaps& caps,
GLContext* sharedContext,

Просмотреть файл

@ -17,6 +17,7 @@ namespace gl {
class SkiaGLGlue : public GenericAtomicRefCounted
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SkiaGLGlue)
SkiaGLGlue(GLContext* context);
GLContext* GetGLContext() const { return mGLContext.get(); }
GrContext* GetGrContext() const { return mGrContext.get(); }

Просмотреть файл

@ -28,6 +28,7 @@ class SurfaceFactory;
class SurfaceStream : public GenericAtomicRefCounted
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SurfaceStream)
typedef enum {
MainThread,
OffMainThread
@ -145,6 +146,7 @@ protected:
SharedSurface* mConsumer; // Only present after resize-swap.
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SurfaceStream_SingleBuffer)
SurfaceStream_SingleBuffer(SurfaceStream* prevStream);
virtual ~SurfaceStream_SingleBuffer();
@ -169,6 +171,7 @@ protected:
SharedSurface* mConsumer;
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SurfaceStream_TripleBuffer_Copy)
SurfaceStream_TripleBuffer_Copy(SurfaceStream* prevStream);
virtual ~SurfaceStream_TripleBuffer_Copy();
@ -192,6 +195,7 @@ protected:
SurfaceStream_TripleBuffer(SurfaceStreamType type, SurfaceStream* prevStream);
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(SurfaceStream_TripleBuffer)
SurfaceStream_TripleBuffer(SurfaceStream* prevStream);
virtual ~SurfaceStream_TripleBuffer();
virtual bool CopySurfaceToProducer(SharedSurface* src, SurfaceFactory* factory);

Просмотреть файл

@ -390,34 +390,12 @@ void MessageLoop::ReloadWorkQueue() {
}
bool MessageLoop::DeletePendingTasks() {
bool did_work = !work_queue_.empty();
while (!work_queue_.empty()) {
PendingTask pending_task = work_queue_.front();
work_queue_.pop();
if (!pending_task.delayed_run_time.is_null()) {
// We want to delete delayed tasks in the same order in which they would
// normally be deleted in case of any funny dependencies between delayed
// tasks.
AddToDelayedWorkQueue(pending_task);
} else {
// TODO(darin): Delete all tasks once it is safe to do so.
// Until it is totally safe, just do it when running purify.
#ifdef PURIFY
delete pending_task.task;
#endif // PURIFY
}
}
did_work |= !deferred_non_nestable_work_queue_.empty();
MOZ_ASSERT(work_queue_.empty());
bool did_work = !deferred_non_nestable_work_queue_.empty();
while (!deferred_non_nestable_work_queue_.empty()) {
// TODO(darin): Delete all tasks once it is safe to do so.
// Until it is totaly safe, just delete them to keep purify happy.
#ifdef PURIFY
Task* task = deferred_non_nestable_work_queue_.front().task;
#endif
deferred_non_nestable_work_queue_.pop();
#ifdef PURIFY
delete task;
#endif
}
did_work |= !delayed_work_queue_.empty();
while (!delayed_work_queue_.empty()) {

Просмотреть файл

@ -152,9 +152,6 @@ struct AutoStopVerifyingBarriers
};
#endif /* JS_GC_ZEAL */
void
CrashAtUnhandlableOOM(const char *reason);
} /* namespace gc */
} /* namespace js */

Просмотреть файл

@ -24,10 +24,11 @@
#include "js/Tracer.h"
namespace js {
namespace gc {
extern void
CrashAtUnhandlableOOM(const char *);
void
CrashAtUnhandlableOOM(const char *reason);
namespace gc {
/*
* BufferableRef represents an abstract reference for use in the generational

Просмотреть файл

@ -882,12 +882,3 @@ js::gc::FinishVerifier(JSRuntime *rt)
}
#endif /* JS_GC_ZEAL */
void
js::gc::CrashAtUnhandlableOOM(const char *reason)
{
char msgbuf[1024];
JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
MOZ_CRASH();
}

Просмотреть файл

@ -1,6 +0,0 @@
// |jit-test| allow-oom
if (typeof oomAfterAllocations == 'function') {
gczeal(4);
oomAfterAllocations(1);
var s = new Set;
}

Просмотреть файл

@ -2065,7 +2065,8 @@ AnalyzePoppedThis(JSContext *cx, types::TypeObject *type,
block = rp->block(), rp = block->callerResumePoint())
{
JSScript *script = rp->block()->info().script();
types::AddClearDefiniteFunctionUsesInScript(cx, type, script, block->info().script());
if (!types::AddClearDefiniteFunctionUsesInScript(cx, type, script, block->info().script()))
return true;
if (!callerResumePoints.append(rp))
return false;
}

Просмотреть файл

@ -617,8 +617,7 @@ IonBuilder::build()
}
#endif
if (!initParameters())
return false;
initParameters();
// Initialize local variables.
for (uint32_t i = 0; i < info().nlocals(); i++) {
@ -910,20 +909,18 @@ IonBuilder::rewriteParameters()
}
}
bool
void
IonBuilder::initParameters()
{
if (!info().funMaybeLazy())
return true;
return;
// If we are doing OSR on a frame which initially executed in the
// interpreter and didn't accumulate type information, try to use that OSR
// frame to determine possible initial types for 'this' and parameters.
if (thisTypes->empty() && baselineFrame_) {
if (!thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc()))
return false;
}
if (thisTypes->empty() && baselineFrame_)
thisTypes->addType(baselineFrame_->thisType, alloc_->lifoAlloc());
MParameter *param = MParameter::New(alloc(), MParameter::THIS_SLOT, thisTypes);
current->add(param);
@ -934,16 +931,13 @@ IonBuilder::initParameters()
if (types->empty() && baselineFrame_ &&
!script_->baselineScript()->modifiesArguments())
{
if (!types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc()))
return false;
types->addType(baselineFrame_->argTypes[i], alloc_->lifoAlloc());
}
param = MParameter::New(alloc(), i, types);
current->add(param);
current->initSlot(info().argSlotUnchecked(i), param);
}
return true;
}
bool
@ -4971,14 +4965,12 @@ IonBuilder::jsop_call(uint32_t argc, bool constructing)
types::TemporaryTypeSet *observed = bytecodeTypes(pc);
if (observed->empty()) {
if (BytecodeFlowsToBitop(pc)) {
if (!observed->addType(types::Type::Int32Type(), alloc_->lifoAlloc()))
return false;
observed->addType(types::Type::Int32Type(), alloc_->lifoAlloc());
} else if (*GetNextPc(pc) == JSOP_POS) {
// Note: this is lame, overspecialized on the code patterns used
// by asm.js and should be replaced by a more general mechanism.
// See bug 870847.
if (!observed->addType(types::Type::DoubleType(), alloc_->lifoAlloc()))
return false;
observed->addType(types::Type::DoubleType(), alloc_->lifoAlloc());
}
}
@ -7091,8 +7083,7 @@ IonBuilder::jsop_getelem_dense(MDefinition *obj, MDefinition *index)
// Indexed call on an element of an array. Populate the observed types
// with any objects that could be in the array, to avoid extraneous
// type barriers.
if (!AddObjectsForPropertyRead(obj, nullptr, types))
return false;
AddObjectsForPropertyRead(obj, nullptr, types);
}
bool barrier = PropertyReadNeedsTypeBarrier(analysisContext, constraints(), obj, nullptr, types);
@ -9288,8 +9279,7 @@ IonBuilder::jsop_setarg(uint32_t arg)
}
if (!otherUses) {
JS_ASSERT(op->resultTypeSet() == &argTypes[arg]);
if (!argTypes[arg].addType(types::Type::UnknownType(), alloc_->lifoAlloc()))
return false;
argTypes[arg].addType(types::Type::UnknownType(), alloc_->lifoAlloc());
if (val->isMul()) {
val->setResultType(MIRType_Double);
val->toMul()->setSpecialization(MIRType_Double);

Просмотреть файл

@ -327,7 +327,7 @@ class IonBuilder : public MIRGenerator
void insertRecompileCheck();
bool initParameters();
void initParameters();
void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex);
void rewriteParameters();
bool initScopeChain(MDefinition *callee = nullptr);

Просмотреть файл

@ -940,8 +940,7 @@ IonBuilder::inlineMathFRound(CallInfo &callInfo)
if (returned->empty()) {
// As there's only one possible returned type, just add it to the observed
// returned typeset
if (!returned->addType(types::Type::DoubleType(), alloc_->lifoAlloc()))
return InliningStatus_Error;
returned->addType(types::Type::DoubleType(), alloc_->lifoAlloc());
} else {
MIRType returnType = getInlineReturnType();
if (!IsNumberType(returnType))

Просмотреть файл

@ -2765,10 +2765,8 @@ InlinePropertyTable::buildTypeSetForFunction(JSFunction *func) const
if (!types)
return nullptr;
for (size_t i = 0; i < numEntries(); i++) {
if (entries_[i]->func == func) {
if (!types->addType(types::Type::ObjectType(entries_[i]->typeObj), alloc))
return nullptr;
}
if (entries_[i]->func == func)
types->addType(types::Type::ObjectType(entries_[i]->typeObj), alloc);
}
return types;
}
@ -3172,7 +3170,7 @@ jit::PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
return true;
}
bool
void
jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *observed)
{
@ -3182,16 +3180,20 @@ jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
LifoAlloc *alloc = GetIonContext()->temp->lifoAlloc();
types::TemporaryTypeSet *types = obj->resultTypeSet();
if (!types || types->unknownObject())
return observed->addType(types::Type::AnyObjectType(), alloc);
if (!types || types->unknownObject()) {
observed->addType(types::Type::AnyObjectType(), alloc);
return;
}
for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObjectKey *object = types->getObject(i);
if (!object)
continue;
if (object->unknownProperties())
return observed->addType(types::Type::AnyObjectType(), alloc);
if (object->unknownProperties()) {
observed->addType(types::Type::AnyObjectType(), alloc);
return;
}
jsid id = name ? NameToId(name) : JSID_VOID;
types::HeapTypeSetKey property = object->property(id);
@ -3199,17 +3201,17 @@ jit::AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
if (!types)
continue;
if (types->unknownObject())
return observed->addType(types::Type::AnyObjectType(), alloc);
if (types->unknownObject()) {
observed->addType(types::Type::AnyObjectType(), alloc);
return;
}
for (size_t i = 0; i < types->getObjectCount(); i++) {
types::TypeObjectKey *object = types->getObject(i);
if (object && !observed->addType(types::Type::ObjectType(object), alloc))
return false;
if (object)
observed->addType(types::Type::ObjectType(object), alloc);
}
}
return true;
}
static bool

Просмотреть файл

@ -9866,7 +9866,7 @@ bool PropertyReadOnPrototypeNeedsTypeBarrier(types::CompilerConstraintList *cons
types::TemporaryTypeSet *observed);
bool PropertyReadIsIdempotent(types::CompilerConstraintList *constraints,
MDefinition *obj, PropertyName *name);
bool AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
void AddObjectsForPropertyRead(MDefinition *obj, PropertyName *name,
types::TemporaryTypeSet *observed);
bool PropertyWriteNeedsTypeBarrier(TempAllocator &alloc, types::CompilerConstraintList *constraints,
MBasicBlock *current, MDefinition **pobj,

Просмотреть файл

@ -2206,10 +2206,8 @@ ScriptAnalysis::needsArgsObj(JSContext *cx, SeenVector &seen, const SSAValue &v)
if (v == seen[i])
return false;
}
if (!seen.append(v)) {
cx->compartment()->types.setPendingNukeTypes(cx);
if (!seen.append(v))
return true;
}
SSAUseChain *use = useChain(v);
while (use) {

Просмотреть файл

@ -1365,3 +1365,11 @@ void CompartmentChecker::check(AbstractFramePtr frame)
}
#endif
void
js::CrashAtUnhandlableOOM(const char *reason)
{
char msgbuf[1024];
JS_snprintf(msgbuf, sizeof(msgbuf), "[unhandlable oom] %s", reason);
MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
MOZ_CRASH();
}

Просмотреть файл

@ -1093,6 +1093,9 @@ class AutoLockForExclusiveAccess
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
};
void
CrashAtUnhandlableOOM(const char *reason);
} /* namespace js */
#ifdef _MSC_VER

Просмотреть файл

@ -374,7 +374,7 @@ TypeSet::enumerateTypes(TypeList *list)
return true;
}
inline void
inline bool
TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
{
/*
@ -383,19 +383,20 @@ TypeSet::addTypesToConstraint(JSContext *cx, TypeConstraint *constraint)
*/
TypeList types;
if (!enumerateTypes(&types))
cx->compartment()->types.setPendingNukeTypes(cx);
return false;
for (unsigned i = 0; i < types.length(); i++)
constraint->newType(cx, this, types[i]);
return true;
}
void
ConstraintTypeSet::add(JSContext *cx, TypeConstraint *constraint, bool callExisting)
bool
ConstraintTypeSet::addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting)
{
if (!constraint) {
/* OOM failure while constructing the constraint. */
cx->compartment()->types.setPendingNukeTypes(cx);
return;
return false;
}
JS_ASSERT(cx->compartment()->activeAnalysis);
@ -410,7 +411,8 @@ ConstraintTypeSet::add(JSContext *cx, TypeConstraint *constraint, bool callExist
constraintList = constraint;
if (callExisting)
addTypesToConstraint(cx, constraint);
return addTypesToConstraint(cx, constraint);
return true;
}
void
@ -502,14 +504,12 @@ TypeSet::unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc)
if (!res->unknownObject()) {
for (size_t i = 0; i < a->getObjectCount() && !res->unknownObject(); i++) {
TypeObjectKey *key = a->getObject(i);
if (key && !res->addType(Type::ObjectType(key), alloc))
return nullptr;
if (TypeObjectKey *key = a->getObject(i))
res->addType(Type::ObjectType(key), alloc);
}
for (size_t i = 0; i < b->getObjectCount() && !res->unknownObject(); i++) {
TypeObjectKey *key = b->getObject(i);
if (key && !res->addType(Type::ObjectType(key), alloc))
return nullptr;
if (TypeObjectKey *key = b->getObject(i))
res->addType(Type::ObjectType(key), alloc);
}
}
@ -761,13 +761,11 @@ class TypeCompilerConstraint : public TypeConstraint
cx->zone()->types.addPendingRecompile(cx, compilation);
}
TypeConstraint *sweep(TypeZone &zone) {
bool sweep(TypeZone &zone, TypeConstraint **res) {
if (data.shouldSweep() || compilation.shouldSweep(zone))
return nullptr;
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeCompilerConstraint<T> >(compilation, data);
if (!res)
zone.setPendingNukeTypes();
return res;
return false;
*res = zone.typeLifoAlloc.new_<TypeCompilerConstraint<T> >(compilation, data);
return true;
}
};
@ -784,9 +782,8 @@ CompilerConstraintInstance<T>::generateTypeConstraint(JSContext *cx, RecompileIn
if (!data.constraintHolds(cx, property, expected))
return false;
property.maybeTypes()->add(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
/* callExisting = */ false);
return true;
return property.maybeTypes()->addConstraint(cx, cx->typeLifoAlloc().new_<TypeCompilerConstraint<T> >(recompileInfo, data),
/* callExisting = */ false);
}
} /* anonymous namespace */
@ -941,13 +938,11 @@ class TypeConstraintFreezeStack : public TypeConstraint
cx->zone()->types.addPendingRecompile(cx, script_);
}
TypeConstraint *sweep(TypeZone &zone) {
bool sweep(TypeZone &zone, TypeConstraint **res) {
if (IsScriptAboutToBeFinalized(&script_))
return nullptr;
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintFreezeStack>(script_);
if (!res)
zone.setPendingNukeTypes();
return res;
return false;
*res = zone.typeLifoAlloc.new_<TypeConstraintFreezeStack>(script_);
return true;
}
};
@ -1017,8 +1012,10 @@ types::FinishCompilation(JSContext *cx, HandleScript script, ExecutionMode execu
size_t count = TypeScript::NumTypeSets(entry.script);
StackTypeSet *array = entry.script->types->typeArray();
for (size_t i = 0; i < count; i++)
array[i].add(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false);
for (size_t i = 0; i < count; i++) {
if (!array[i].addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintFreezeStack>(entry.script), false))
succeeded = false;
}
}
if (!succeeded || types.compilerOutputs->back().pendingInvalidation()) {
@ -1976,7 +1973,7 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
if (!allocationSiteTable) {
allocationSiteTable = cx->new_<AllocationSiteTable>();
if (!allocationSiteTable || !allocationSiteTable->init()) {
cx->compartment()->types.setPendingNukeTypes(cx);
js_delete(allocationSiteTable);
return nullptr;
}
}
@ -2012,10 +2009,8 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
Rooted<TaggedProto> tagged(cx, TaggedProto(proto));
res = newTypeObject(cx, GetClassForProtoKey(key.kind), tagged, OBJECT_FLAG_FROM_ALLOCATION_SITE);
if (!res) {
cx->compartment()->types.setPendingNukeTypes(cx);
if (!res)
return nullptr;
}
key.script = keyScript;
}
@ -2031,10 +2026,8 @@ TypeCompartment::addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey ke
return nullptr;
}
if (!allocationSiteTable->add(p, key, res)) {
cx->compartment()->types.setPendingNukeTypes(cx);
if (!allocationSiteTable->add(p, key, res))
return nullptr;
}
return res;
}
@ -2209,60 +2202,6 @@ TypeZone::processPendingRecompiles(FreeOp *fop)
fop->delete_(pending);
}
void
TypeCompartment::setPendingNukeTypes(ExclusiveContext *cx)
{
TypeZone *zone = &compartment()->zone()->types;
if (!zone->pendingNukeTypes) {
if (cx->compartment())
js_ReportOutOfMemory(cx);
zone->pendingNukeTypes = true;
}
}
void
TypeZone::setPendingNukeTypes()
{
pendingNukeTypes = true;
}
void
TypeZone::nukeTypes(FreeOp *fop)
{
/*
* This is the usual response if we encounter an OOM while adding a type
* or resolving type constraints. Reset the compartment to not use type
* inference, and recompile all scripts.
*
* Because of the nature of constraint-based analysis (add constraints, and
* iterate them until reaching a fixpoint), we can't undo an add of a type set,
* and merely aborting the operation which triggered the add will not be
* sufficient for correct behavior as we will be leaving the types in an
* inconsistent state.
*/
JS_ASSERT(pendingNukeTypes);
if (pendingRecompiles) {
fop->free_(pendingRecompiles);
pendingRecompiles = nullptr;
}
inferenceEnabled = false;
#ifdef JS_ION
jit::InvalidateAll(fop, zone());
/* Throw away all JIT code in the compartment, but leave everything else alone. */
for (gc::CellIter i(zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
JSScript *script = i.get<JSScript>();
jit::FinishInvalidation(fop, script);
}
#endif /* JS_ION */
pendingNukeTypes = false;
}
void
TypeZone::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
{
@ -2270,23 +2209,19 @@ TypeZone::addPendingRecompile(JSContext *cx, const RecompileInfo &info)
if (!co || !co->isValid() || co->pendingInvalidation())
return;
if (!pendingRecompiles) {
pendingRecompiles = cx->new_< Vector<RecompileInfo> >(cx);
if (!pendingRecompiles) {
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
}
if (!pendingRecompiles->append(info)) {
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
InferSpew(ISpewOps, "addPendingRecompile: %p:%s:%d",
co->script(), co->script()->filename(), co->script()->lineno());
co->setPendingInvalidation();
if (!pendingRecompiles) {
pendingRecompiles = cx->new_< Vector<RecompileInfo> >(cx);
if (!pendingRecompiles)
CrashAtUnhandlableOOM("Could not update pendingRecompiles");
}
if (!pendingRecompiles->append(info))
CrashAtUnhandlableOOM("Could not update pendingRecompiles");
}
void
@ -2325,32 +2260,18 @@ TypeCompartment::markSetsUnknown(JSContext *cx, TypeObject *target)
AutoEnterAnalysis enter(cx);
/*
* Mark both persistent and transient type sets which contain obj as having
* a generic object type. It is not sufficient to mark just the persistent
* sets, as analysis of individual opcodes can pull type objects from
* static information (like initializer objects at various offsets).
*
* We make a list of properties to update and fix them afterwards, as adding
* types can't be done while iterating over cells as it can potentially make
* new type objects as well or trigger GC.
*/
Vector<ConstraintTypeSet *> pending(cx);
/* Mark type sets which contain obj as having a generic object types. */
for (gc::CellIter i(cx->zone(), gc::FINALIZE_TYPE_OBJECT); !i.done(); i.next()) {
TypeObject *object = i.get<TypeObject>();
unsigned count = object->getPropertyCount();
for (unsigned i = 0; i < count; i++) {
Property *prop = object->getProperty(i);
if (prop && prop->types.hasType(Type::ObjectType(target))) {
if (!pending.append(&prop->types))
cx->compartment()->types.setPendingNukeTypes(cx);
}
if (prop && prop->types.hasType(Type::ObjectType(target)))
prop->types.addType(cx, Type::AnyObjectType());
}
}
for (unsigned i = 0; i < pending.length(); i++)
pending[i]->addType(cx, Type::AnyObjectType());
for (gc::CellIter i(cx->zone(), gc::FINALIZE_SCRIPT); !i.done(); i.next()) {
RootedScript script(cx, i.get<JSScript>());
if (script->types) {
@ -2461,7 +2382,6 @@ TypeCompartment::setTypeToHomogenousArray(ExclusiveContext *cx,
arrayTypeTable = cx->new_<ArrayTypeTable>();
if (!arrayTypeTable || !arrayTypeTable->init()) {
arrayTypeTable = nullptr;
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
}
@ -2474,20 +2394,15 @@ TypeCompartment::setTypeToHomogenousArray(ExclusiveContext *cx,
/* Make a new type to use for future arrays with the same elements. */
RootedObject objProto(cx, obj->getProto());
TypeObject *objType = newTypeObject(cx, &ArrayObject::class_, objProto);
if (!objType) {
cx->compartment()->types.setPendingNukeTypes(cx);
if (!objType)
return;
}
obj->setType(objType);
if (!objType->unknownProperties())
objType->addPropertyType(cx, JSID_VOID, elementType);
key.proto = objProto;
if (!p.add(cx, *arrayTypeTable, key, objType)) {
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
(void) p.add(cx, *arrayTypeTable, key, objType);
}
}
@ -2625,8 +2540,8 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
if (!objectTypeTable) {
objectTypeTable = cx->new_<ObjectTypeTable>();
if (!objectTypeTable || !objectTypeTable->init()) {
js_delete(objectTypeTable);
objectTypeTable = nullptr;
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
}
@ -2646,10 +2561,8 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
return;
Vector<IdValuePair> properties(cx);
if (!properties.resize(obj->slotSpan())) {
cx->compartment()->types.setPendingNukeTypes(cx);
if (!properties.resize(obj->slotSpan()))
return;
}
Shape *shape = obj->lastProperty();
while (!shape->isEmptyShape()) {
@ -2674,25 +2587,19 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
/* Make a new type to use for the object and similar future ones. */
Rooted<TaggedProto> objProto(cx, obj->getTaggedProto());
TypeObject *objType = newTypeObject(cx, &JSObject::class_, objProto);
if (!objType || !objType->addDefiniteProperties(cx, obj)) {
cx->compartment()->types.setPendingNukeTypes(cx);
if (!objType || !objType->addDefiniteProperties(cx, obj))
return;
}
if (obj->isIndexed())
objType->setFlags(cx, OBJECT_FLAG_SPARSE_INDEXES);
jsid *ids = cx->pod_calloc<jsid>(properties.length());
if (!ids) {
cx->compartment()->types.setPendingNukeTypes(cx);
ScopedJSFreePtr<jsid> ids(cx->pod_calloc<jsid>(properties.length()));
if (!ids)
return;
}
Type *types = cx->pod_calloc<Type>(properties.length());
if (!types) {
cx->compartment()->types.setPendingNukeTypes(cx);
ScopedJSFreePtr<Type> types(cx->pod_calloc<Type>(properties.length()));
if (!types)
return;
}
for (size_t i = 0; i < properties.length(); i++) {
ids[i] = properties[i].id;
@ -2712,13 +2619,13 @@ TypeCompartment::fixObjectType(ExclusiveContext *cx, JSObject *obj)
entry.shape = obj->lastProperty();
entry.types = types;
p = objectTypeTable->lookupForAdd(lookup);
if (!objectTypeTable->add(p, key, entry)) {
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
obj->setType(objType);
p = objectTypeTable->lookupForAdd(lookup);
if (objectTypeTable->add(p, key, entry)) {
ids.forget();
types.forget();
}
}
JSObject *
@ -2729,8 +2636,8 @@ TypeCompartment::newTypedObject(JSContext *cx, IdValuePair *properties, size_t n
if (!objectTypeTable) {
objectTypeTable = cx->new_<ObjectTypeTable>();
if (!objectTypeTable || !objectTypeTable->init()) {
js_delete(objectTypeTable);
objectTypeTable = nullptr;
cx->compartment()->types.setPendingNukeTypes(cx);
return nullptr;
}
}
@ -2807,8 +2714,7 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap
if (shape->hasGetterValue() || shape->hasSetterValue()) {
types->setNonDataProperty(cx);
if (!types->TypeSet::addType(Type::UnknownType(), &cx->typeLifoAlloc()))
cx->compartment()->types.setPendingNukeTypes(cx);
types->TypeSet::addType(Type::UnknownType(), &cx->typeLifoAlloc());
} else if (shape->hasDefaultGetter() && shape->hasSlot()) {
if (!indexed && types->canSetDefinite(shape->slot()))
types->setDefinite(shape->slot());
@ -2822,8 +2728,7 @@ UpdatePropertyType(ExclusiveContext *cx, HeapTypeSet *types, JSObject *obj, Shap
*/
if (indexed || !value.isUndefined() || !CanHaveEmptyPropertyTypesForOwnProperty(obj)) {
Type type = GetValueType(value);
if (!types->TypeSet::addType(type, &cx->typeLifoAlloc()))
cx->compartment()->types.setPendingNukeTypes(cx);
types->TypeSet::addType(type, &cx->typeLifoAlloc());
}
}
}
@ -2833,10 +2738,8 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
{
JS_ASSERT(!*pprop);
Property *base = cx->typeLifoAlloc().new_<Property>(id);
if (!base) {
cx->compartment()->types.setPendingNukeTypes(cx);
if (!base)
return false;
}
if (singleton() && singleton()->isNative()) {
/*
@ -2860,8 +2763,7 @@ TypeObject::addProperty(ExclusiveContext *cx, jsid id, Property **pprop)
const Value &value = singleton()->getDenseElement(i);
if (!value.isMagic(JS_ELEMENTS_HOLE)) {
Type type = GetValueType(value);
if (!base->types.TypeSet::addType(type, &cx->typeLifoAlloc()))
cx->compartment()->types.setPendingNukeTypes(cx);
base->types.TypeSet::addType(type, &cx->typeLifoAlloc());
}
}
} else if (!JSID_IS_EMPTY(id)) {
@ -2969,28 +2871,6 @@ TypeObject::addPropertyType(ExclusiveContext *cx, jsid id, const Value &value)
InlineAddTypeProperty(cx, this, id, GetValueType(value));
}
void
TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, Type type)
{
jsid id = JSID_VOID;
if (name) {
JSAtom *atom = Atomize(cx, name, strlen(name));
if (!atom) {
AutoEnterAnalysis enter(cx);
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
id = AtomToId(atom);
}
InlineAddTypeProperty(cx, this, id, type);
}
void
TypeObject::addPropertyType(ExclusiveContext *cx, const char *name, const Value &value)
{
addPropertyType(cx, name, GetValueType(value));
}
void
TypeObject::markPropertyNonData(ExclusiveContext *cx, jsid id)
{
@ -3242,10 +3122,8 @@ TypeObject::clearNewScriptAddendum(ExclusiveContext *cx)
}
}
if (!finished) {
if (!JSObject::rollbackProperties(cx, obj, numProperties))
cx->compartment()->types.setPendingNukeTypes(cx);
}
if (!finished)
(void) JSObject::rollbackProperties(cx, obj, numProperties);
}
} else {
// Threads with an ExclusiveContext are not allowed to run scripts.
@ -3339,13 +3217,11 @@ class TypeConstraintClearDefiniteGetterSetter : public TypeConstraint
void newType(JSContext *cx, TypeSet *source, Type type) {}
TypeConstraint *sweep(TypeZone &zone) {
bool sweep(TypeZone &zone, TypeConstraint **res) {
if (IsTypeObjectAboutToBeFinalized(&object))
return nullptr;
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteGetterSetter>(object);
if (!res)
zone.setPendingNukeTypes();
return res;
return false;
*res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteGetterSetter>(object);
return true;
}
};
@ -3365,7 +3241,8 @@ types::AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *
HeapTypeSet *parentTypes = parentObject->getProperty(cx, id);
if (!parentTypes || parentTypes->nonDataProperty() || parentTypes->nonWritableProperty())
return false;
parentTypes->add(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(type));
if (!parentTypes->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteGetterSetter>(type)))
return false;
parent = parent->getProto();
}
return true;
@ -3394,17 +3271,15 @@ class TypeConstraintClearDefiniteSingle : public TypeConstraint
object->clearAddendum(cx);
}
TypeConstraint *sweep(TypeZone &zone) {
bool sweep(TypeZone &zone, TypeConstraint **res) {
if (IsTypeObjectAboutToBeFinalized(&object))
return nullptr;
TypeConstraint *res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteSingle>(object);
if (!res)
zone.setPendingNukeTypes();
return res;
return false;
*res = zone.typeLifoAlloc.new_<TypeConstraintClearDefiniteSingle>(object);
return true;
}
};
void
bool
types::AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
JSScript *script, JSScript *calleeScript)
{
@ -3437,10 +3312,12 @@ types::AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
}
// This is a type set that might have been used when inlining
// |calleeScript| into |script|.
types->add(cx,
cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type));
if (!types->addConstraint(cx, cx->typeLifoAlloc().new_<TypeConstraintClearDefiniteSingle>(type)))
return false;
}
}
return true;
}
/*
@ -3464,12 +3341,8 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
Vector<TypeNewScript::Initializer> initializerList(cx);
if (!jit::AnalyzeNewScriptProperties(cx, fun, type, baseobj, &initializerList)) {
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
if (baseobj->slotSpan() == 0 ||
if (!jit::AnalyzeNewScriptProperties(cx, fun, type, baseobj, &initializerList) ||
baseobj->slotSpan() == 0 ||
!!(type->flags() & OBJECT_FLAG_ADDENDUM_CLEARED))
{
if (type->hasNewScript())
@ -3509,7 +3382,6 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
!type->addDefiniteProperties(cx, baseobj) ||
!initializerList.append(done))
{
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
@ -3526,15 +3398,13 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
#else
newScript = (TypeNewScript *) cx->calloc_(numBytes);
#endif
if (!newScript)
return;
new (newScript) TypeNewScript();
type->setAddendum(newScript);
if (!newScript) {
cx->compartment()->types.setPendingNukeTypes(cx);
return;
}
newScript->fun = fun;
newScript->templateObject = baseobj;
@ -3684,10 +3554,8 @@ JSScript::makeTypes(JSContext *cx)
unsigned count = TypeScript::NumTypeSets(this);
TypeScript *typeScript = (TypeScript *) cx->calloc_(sizeof(TypeScript) + (sizeof(StackTypeSet) * count));
if (!typeScript) {
cx->compartment()->types.setPendingNukeTypes(cx);
if (!typeScript)
return false;
}
new(typeScript) TypeScript();
@ -3836,6 +3704,7 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
{
JS_ASSERT(obj->hasLazyType());
JS_ASSERT(cx->compartment() == obj->compartment());
JS_ASSERT(cx->typeInferenceEnabled());
/* De-lazification of functions can GC, so we need to do it up here. */
if (obj->is<JSFunction>() && obj->as<JSFunction>().isInterpretedLazy()) {
@ -3859,17 +3728,8 @@ JSObject::makeLazyType(JSContext *cx, HandleObject obj)
Rooted<TaggedProto> proto(cx, obj->getTaggedProto());
TypeObject *type = cx->compartment()->types.newTypeObject(cx, obj->getClass(), proto, initialFlags);
if (!type) {
if (cx->typeInferenceEnabled())
cx->compartment()->types.setPendingNukeTypes(cx);
if (!type)
return nullptr;
}
if (!cx->typeInferenceEnabled()) {
/* This can only happen if types were previously nuked. */
obj->type_ = type;
return type;
}
AutoEnterAnalysis enter(cx);
@ -4048,22 +3908,22 @@ ExclusiveContext::getNewType(const Class *clasp, TaggedProto proto, JSFunction *
*/
if (obj->is<RegExpObject>()) {
AddTypeProperty(this, type, "source", types::Type::StringType());
AddTypeProperty(this, type, "global", types::Type::BooleanType());
AddTypeProperty(this, type, "ignoreCase", types::Type::BooleanType());
AddTypeProperty(this, type, "multiline", types::Type::BooleanType());
AddTypeProperty(this, type, "sticky", types::Type::BooleanType());
AddTypeProperty(this, type, "lastIndex", types::Type::Int32Type());
AddTypePropertyId(this, type, NameToId(names().source), Type::StringType());
AddTypePropertyId(this, type, NameToId(names().global), Type::BooleanType());
AddTypePropertyId(this, type, NameToId(names().ignoreCase), Type::BooleanType());
AddTypePropertyId(this, type, NameToId(names().multiline), Type::BooleanType());
AddTypePropertyId(this, type, NameToId(names().sticky), Type::BooleanType());
AddTypePropertyId(this, type, NameToId(names().lastIndex), Type::Int32Type());
}
if (obj->is<StringObject>())
AddTypeProperty(this, type, "length", Type::Int32Type());
AddTypePropertyId(this, type, NameToId(names().length), Type::Int32Type());
if (obj->is<ErrorObject>()) {
AddTypeProperty(this, type, "fileName", types::Type::StringType());
AddTypeProperty(this, type, "lineNumber", types::Type::Int32Type());
AddTypeProperty(this, type, "columnNumber", types::Type::Int32Type());
AddTypeProperty(this, type, "stack", types::Type::StringType());
AddTypePropertyId(this, type, NameToId(names().fileName), Type::StringType());
AddTypePropertyId(this, type, NameToId(names().lineNumber), Type::Int32Type());
AddTypePropertyId(this, type, NameToId(names().columnNumber), Type::Int32Type());
AddTypePropertyId(this, type, NameToId(names().stack), Type::StringType());
}
}
@ -4152,10 +4012,9 @@ ConstraintTypeSet::sweep(Zone *zone)
TypeObjectKey **pentry =
HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
(zone->types.typeLifoAlloc, objectSet, objectCount, object);
if (pentry)
*pentry = object;
else
zone->types.setPendingNukeTypes();
if (!pentry)
CrashAtUnhandlableOOM("OOM in ConstraintTypeSet::sweep");
*pentry = object;
}
}
setBaseObjectCount(objectCount);
@ -4174,7 +4033,10 @@ ConstraintTypeSet::sweep(Zone *zone)
TypeConstraint *constraint = constraintList;
constraintList = nullptr;
while (constraint) {
if (TypeConstraint *copy = constraint->sweep(zone->types)) {
TypeConstraint *copy;
if (constraint->sweep(zone->types, &copy)) {
if (!copy)
CrashAtUnhandlableOOM("OOM in ConstraintTypeSet::sweep");
copy->next = constraintList;
constraintList = copy;
}
@ -4230,20 +4092,19 @@ TypeObject::sweep(FreeOp *fop)
*/
continue;
}
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
if (newProp) {
Property **pentry =
HashSetInsert<jsid,Property,Property>
(typeLifoAlloc, propertySet, propertyCount, prop->id);
if (pentry) {
*pentry = newProp;
newProp->types.sweep(zone());
} else {
zone()->types.setPendingNukeTypes();
}
} else {
zone()->types.setPendingNukeTypes();
}
if (!newProp)
CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
Property **pentry =
HashSetInsert<jsid,Property,Property>
(typeLifoAlloc, propertySet, propertyCount, prop->id);
if (!pentry)
CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
*pentry = newProp;
newProp->types.sweep(zone());
}
}
setBasePropertyCount(propertyCount);
@ -4254,12 +4115,11 @@ TypeObject::sweep(FreeOp *fop)
clearProperties();
} else {
Property *newProp = typeLifoAlloc.new_<Property>(*prop);
if (newProp) {
propertySet = (Property **) newProp;
newProp->types.sweep(zone());
} else {
zone()->types.setPendingNukeTypes();
}
if (!newProp)
CrashAtUnhandlableOOM("OOM in TypeObject::sweep");
propertySet = (Property **) newProp;
newProp->types.sweep(zone());
}
}
@ -4449,7 +4309,6 @@ TypeZone::TypeZone(Zone *zone)
typeLifoAlloc(TYPE_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
compilerOutputs(nullptr),
pendingRecompiles(nullptr),
pendingNukeTypes(false),
inferenceEnabled(false)
{
}

Просмотреть файл

@ -242,6 +242,10 @@ class Type
return data > JSVAL_TYPE_UNKNOWN;
}
bool isObjectUnchecked() const {
return data > JSVAL_TYPE_UNKNOWN;
}
inline TypeObjectKey *objectKey() const;
/* Accessors for JSObject types */
@ -335,7 +339,7 @@ public:
* If the data this constraint refers to is still live, copy it into the
* zone's new allocator. Type constraints only hold weak references.
*/
virtual TypeConstraint *sweep(TypeZone &zone) = 0;
virtual bool sweep(TypeZone &zone, TypeConstraint **res) = 0;
};
/* Flags and other state stored in TypeSet::flags */
@ -528,7 +532,7 @@ class TypeSet
static TemporaryTypeSet *unionSets(TypeSet *a, TypeSet *b, LifoAlloc *alloc);
/* Add a type to this set using the specified allocator. */
inline bool addType(Type type, LifoAlloc *alloc);
inline void addType(Type type, LifoAlloc *alloc);
/* Get a list of all types in this set. */
typedef Vector<Type, 1, SystemAllocPolicy> TypeList;
@ -543,7 +547,6 @@ class TypeSet
inline TypeObjectKey *getObject(unsigned i) const;
inline JSObject *getSingleObject(unsigned i) const;
inline TypeObject *getTypeObject(unsigned i) const;
inline bool getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **obj) const;
/* The Class of an object in this set. */
inline const Class *getObjectClass(unsigned i) const;
@ -568,7 +571,7 @@ class TypeSet
bool isSubset(TypeSet *other);
/* Forward all types in this set to the specified constraint. */
void addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
bool addTypesToConstraint(JSContext *cx, TypeConstraint *constraint);
// Clone a type set into an arbitrary allocator.
TemporaryTypeSet *clone(LifoAlloc *alloc) const;
@ -599,7 +602,7 @@ class ConstraintTypeSet : public TypeSet
inline void addType(ExclusiveContext *cx, Type type);
/* Add a new constraint to this set. */
void add(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
bool addConstraint(JSContext *cx, TypeConstraint *constraint, bool callExisting = true);
inline void sweep(JS::Zone *zone);
};
@ -739,7 +742,7 @@ class TemporaryTypeSet : public TypeSet
bool
AddClearDefiniteGetterSetterForPrototypeChain(JSContext *cx, TypeObject *type, HandleId id);
void
bool
AddClearDefiniteFunctionUsesInScript(JSContext *cx, TypeObject *type,
JSScript *script, JSScript *calleeScript);
@ -1108,8 +1111,6 @@ struct TypeObject : gc::BarrieredCell<TypeObject>
void addPrototype(JSContext *cx, TypeObject *proto);
void addPropertyType(ExclusiveContext *cx, jsid id, Type type);
void addPropertyType(ExclusiveContext *cx, jsid id, const Value &value);
void addPropertyType(ExclusiveContext *cx, const char *name, Type type);
void addPropertyType(ExclusiveContext *cx, const char *name, const Value &value);
void markPropertyNonData(ExclusiveContext *cx, jsid id);
void markPropertyNonWritable(ExclusiveContext *cx, jsid id);
void markStateChange(ExclusiveContext *cx);
@ -1527,9 +1528,6 @@ struct TypeCompartment
/* Get or make an object for an allocation site, and add to the allocation site table. */
TypeObject *addAllocationSiteTypeObject(JSContext *cx, AllocationSiteKey key);
/* Mark all types as needing destruction once inference has 'finished'. */
void setPendingNukeTypes(ExclusiveContext *cx);
/* Mark any type set containing obj as having a generic object type. */
void markSetsUnknown(JSContext *cx, TypeObject *obj);
@ -1562,12 +1560,6 @@ struct TypeZone
/* Pending recompilations to perform before execution of JIT code can resume. */
Vector<RecompileInfo> *pendingRecompiles;
/*
* Bit set if all current types must be marked as unknown, and all scripts
* recompiled. Caused by OOM failure within inference operations.
*/
bool pendingNukeTypes;
/* Whether type inference is enabled in this compartment. */
bool inferenceEnabled;
@ -1579,16 +1571,11 @@ struct TypeZone
void sweep(FreeOp *fop, bool releaseTypes);
/* Mark all types as needing destruction once inference has 'finished'. */
void setPendingNukeTypes();
/* Mark a script as needing recompilation once inference has finished. */
void addPendingRecompile(JSContext *cx, const RecompileInfo &info);
void addPendingRecompile(JSContext *cx, JSScript *script);
void processPendingRecompiles(FreeOp *fop);
void nukeTypes(FreeOp *fop);
};
enum SpewChannel {

Просмотреть файл

@ -247,9 +247,7 @@ struct AutoEnterAnalysis
*/
if (!compartment->activeAnalysis) {
TypeZone &types = compartment->zone()->types;
if (types.pendingNukeTypes)
types.nukeTypes(freeOp);
else if (types.pendingRecompiles)
if (types.pendingRecompiles)
types.processPendingRecompiles(freeOp);
}
}
@ -385,12 +383,11 @@ EnsureTrackPropertyTypes(JSContext *cx, JSObject *obj, jsid id)
if (obj->hasSingletonType()) {
AutoEnterAnalysis enter(cx);
if (obj->hasLazyType() && !obj->getType(cx)) {
cx->compartment()->types.setPendingNukeTypes(cx);
cx->clearPendingException();
CrashAtUnhandlableOOM("Could not allocate TypeObject in EnsureTrackPropertyTypes");
return;
}
if (!obj->type()->unknownProperties() && !obj->type()->getProperty(cx, id)) {
cx->compartment()->types.setPendingNukeTypes(cx);
obj->type()->markUnknown(cx);
return;
}
}
@ -450,17 +447,17 @@ AddTypePropertyId(ExclusiveContext *cx, JSObject *obj, jsid id, const Value &val
}
inline void
AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, Type type)
AddTypePropertyId(ExclusiveContext *cx, TypeObject *obj, jsid id, Type type)
{
if (cx->typeInferenceEnabled() && !obj->unknownProperties())
obj->addPropertyType(cx, name, type);
obj->addPropertyType(cx, id, type);
}
inline void
AddTypeProperty(ExclusiveContext *cx, TypeObject *obj, const char *name, const Value &value)
AddTypePropertyId(ExclusiveContext *cx, TypeObject *obj, jsid id, const Value &value)
{
if (cx->typeInferenceEnabled() && !obj->unknownProperties())
obj->addPropertyType(cx, name, value);
obj->addPropertyType(cx, id, value);
}
/* Set one or more dynamic flags on a type object. */
@ -1055,34 +1052,34 @@ TypeSet::clearObjects()
objectSet = nullptr;
}
bool
void
TypeSet::addType(Type type, LifoAlloc *alloc)
{
if (unknown())
return true;
return;
if (type.isUnknown()) {
flags |= TYPE_FLAG_BASE_MASK;
clearObjects();
JS_ASSERT(unknown());
return true;
return;
}
if (type.isPrimitive()) {
TypeFlags flag = PrimitiveTypeFlag(type.primitive());
if (flags & flag)
return true;
return;
/* If we add float to a type set it is also considered to contain int. */
if (flag == TYPE_FLAG_DOUBLE)
flag |= TYPE_FLAG_INT32;
flags |= flag;
return true;
return;
}
if (flags & TYPE_FLAG_ANYOBJECT)
return true;
return;
if (type.isAnyObject())
goto unknownObject;
@ -1092,9 +1089,9 @@ TypeSet::addType(Type type, LifoAlloc *alloc)
TypeObjectKey **pentry = HashSetInsert<TypeObjectKey *,TypeObjectKey,TypeObjectKey>
(*alloc, objectSet, objectCount, object);
if (!pentry)
return false;
goto unknownObject;
if (*pentry)
return true;
return;
*pentry = object;
setBaseObjectCount(objectCount);
@ -1116,8 +1113,6 @@ TypeSet::addType(Type type, LifoAlloc *alloc)
flags |= TYPE_FLAG_ANYOBJECT;
clearObjects();
}
return true;
}
inline void
@ -1128,10 +1123,10 @@ ConstraintTypeSet::addType(ExclusiveContext *cxArg, Type type)
if (hasType(type))
return;
if (!TypeSet::addType(type, &cxArg->typeLifoAlloc())) {
cxArg->compartment()->types.setPendingNukeTypes(cxArg);
return;
}
TypeSet::addType(type, &cxArg->typeLifoAlloc());
if (type.isObjectUnchecked() && unknownObject())
type = Type::AnyObjectType();
InferSpew(ISpewOps, "addType: %sT%p%s %s",
InferSpewColor(this), this, InferSpewColorReset(),
@ -1219,30 +1214,6 @@ TypeSet::getTypeObject(unsigned i) const
return (key && key->isTypeObject()) ? key->asTypeObject() : nullptr;
}
inline bool
TypeSet::getTypeOrSingleObject(JSContext *cx, unsigned i, TypeObject **result) const
{
JS_ASSERT(result);
JS_ASSERT(cx->compartment()->activeAnalysis);
*result = nullptr;
TypeObject *type = getTypeObject(i);
if (!type) {
JSObject *singleton = getSingleObject(i);
if (!singleton)
return true;
type = singleton->uninlinedGetType(cx);
if (!type) {
cx->compartment()->types.setPendingNukeTypes(cx);
return false;
}
}
*result = type;
return true;
}
inline const Class *
TypeSet::getObjectClass(unsigned i) const
{
@ -1302,7 +1273,7 @@ TypeObject::getProperty(ExclusiveContext *cx, jsid id)
Property **pprop = HashSetInsert<jsid,Property,Property>
(cx->typeLifoAlloc(), propertySet, propertyCount, id);
if (!pprop) {
cx->compartment()->types.setPendingNukeTypes(cx);
markUnknown(cx);
return nullptr;
}
@ -1310,8 +1281,7 @@ TypeObject::getProperty(ExclusiveContext *cx, jsid id)
setBasePropertyCount(propertyCount);
if (!addProperty(cx, id, pprop)) {
setBasePropertyCount(0);
propertySet = nullptr;
markUnknown(cx);
return nullptr;
}

Просмотреть файл

@ -3209,7 +3209,7 @@ SplitHelper(JSContext *cx, Handle<JSLinearString*> str, uint32_t limit, const Ma
return nullptr;
} else {
/* Only string entries have been accounted for so far. */
AddTypeProperty(cx, type, nullptr, UndefinedValue());
AddTypePropertyId(cx, type, JSID_VOID, UndefinedValue());
if (!splits.append(UndefinedValue()))
return nullptr;
}
@ -3344,7 +3344,7 @@ js::str_split(JSContext *cx, unsigned argc, Value *vp)
RootedTypeObject type(cx, GetTypeCallerInitObject(cx, JSProto_Array));
if (!type)
return false;
AddTypeProperty(cx, type, nullptr, Type::StringType());
AddTypePropertyId(cx, type, JSID_VOID, Type::StringType());
/* Step 5: Use the second argument as the split limit, if given. */
uint32_t limit;

Просмотреть файл

@ -176,9 +176,6 @@ XPCJSContextStack::InitSafeJSContext()
MOZ_CRASH();
JSAutoRequest req(mSafeJSContext);
ContextOptionsRef(mSafeJSContext).setNoDefaultCompartmentObject(true);
#ifdef DEBUG
ContextOptionsRef(mSafeJSContext).setExtraWarnings(true);
#endif
JS_SetErrorReporter(mSafeJSContext, xpc::SystemErrorReporter);

Просмотреть файл

@ -36,9 +36,7 @@
*/
#include <map>
#include "SharedPtr.h"
#include "prlock.h"
#include "base/lock.h"
#include "mozilla/Assertions.h"
/*

Просмотреть файл

@ -74,9 +74,6 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
delete mRecvCodecList[i];
}
delete mCurSendCodecConfig;
if (mPtrVoERTP_RTCP) {
mPtrVoERTP_RTCP->Release();
}
// The first one of a pair to be deleted shuts down media for both
if(mPtrVoEXmedia)
@ -85,12 +82,6 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
mPtrVoEXmedia->SetExternalRecordingStatus(false);
mPtrVoEXmedia->SetExternalPlayoutStatus(false);
}
mPtrVoEXmedia->Release();
}
if(mPtrVoEProcessing)
{
mPtrVoEProcessing->Release();
}
//Deal with the transport
@ -99,12 +90,6 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
if (!mShutDown) {
mPtrVoENetwork->DeRegisterExternalTransport(mChannel);
}
mPtrVoENetwork->Release();
}
if(mPtrVoECodec)
{
mPtrVoECodec->Release();
}
if(mPtrVoEBase)
@ -116,12 +101,6 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
mPtrVoEBase->DeleteChannel(mChannel);
mPtrVoEBase->Terminate();
}
mPtrVoEBase->Release();
}
if (mPtrRTP)
{
mPtrRTP->Release();
}
if (mOtherDirection)

Просмотреть файл

@ -11,6 +11,7 @@
#include "nsTArray.h"
#include "MediaConduitInterface.h"
#include "MediaEngineWrapper.h"
// Audio Engine Includes
#include "webrtc/common_types.h"
@ -156,7 +157,6 @@ public:
mShutDown(false),
mVoiceEngine(nullptr),
mTransport(nullptr),
mPtrRTP(nullptr),
mEngineTransmitting(false),
mEngineReceiving(false),
mChannel(-1),
@ -230,14 +230,14 @@ private:
// conduit to die
webrtc::VoiceEngine* mVoiceEngine;
mozilla::RefPtr<TransportInterface> mTransport;
webrtc::VoENetwork* mPtrVoENetwork;
webrtc::VoEBase* mPtrVoEBase;
webrtc::VoECodec* mPtrVoECodec;
webrtc::VoEExternalMedia* mPtrVoEXmedia;
webrtc::VoEAudioProcessing* mPtrVoEProcessing;
webrtc::VoEVideoSync* mPtrVoEVideoSync;
webrtc::VoERTP_RTCP* mPtrVoERTP_RTCP;
webrtc::VoERTP_RTCP* mPtrRTP;
ScopedCustomReleasePtr<webrtc::VoENetwork> mPtrVoENetwork;
ScopedCustomReleasePtr<webrtc::VoEBase> mPtrVoEBase;
ScopedCustomReleasePtr<webrtc::VoECodec> mPtrVoECodec;
ScopedCustomReleasePtr<webrtc::VoEExternalMedia> mPtrVoEXmedia;
ScopedCustomReleasePtr<webrtc::VoEAudioProcessing> mPtrVoEProcessing;
ScopedCustomReleasePtr<webrtc::VoEVideoSync> mPtrVoEVideoSync;
ScopedCustomReleasePtr<webrtc::VoERTP_RTCP> mPtrVoERTP_RTCP;
ScopedCustomReleasePtr<webrtc::VoERTP_RTCP> mPtrRTP;
//engine states of our interets
bool mEngineTransmitting; // If true => VoiceEngine Send-subsystem is up
bool mEngineReceiving; // If true => VoiceEngine Receive-subsystem is up

Просмотреть файл

@ -76,7 +76,6 @@ WebrtcVideoConduit::~WebrtcVideoConduit()
if (mOtherDirection)
mOtherDirection->mPtrExtCapture = nullptr;
}
mPtrViECapture->Release();
}
//Deal with External Renderer
@ -88,7 +87,6 @@ WebrtcVideoConduit::~WebrtcVideoConduit()
}
mPtrViERender->RemoveRenderer(mChannel);
}
mPtrViERender->Release();
}
//Deal with the transport
@ -97,12 +95,6 @@ WebrtcVideoConduit::~WebrtcVideoConduit()
if (!mShutDown) {
mPtrViENetwork->DeregisterSendTransport(mChannel);
}
mPtrViENetwork->Release();
}
if(mPtrViECodec)
{
mPtrViECodec->Release();
}
if(mPtrViEBase)
@ -113,12 +105,6 @@ WebrtcVideoConduit::~WebrtcVideoConduit()
SyncTo(nullptr);
mPtrViEBase->DeleteChannel(mChannel);
}
mPtrViEBase->Release();
}
if (mPtrRTP)
{
mPtrRTP->Release();
}
if (mOtherDirection)

Просмотреть файл

@ -8,6 +8,7 @@
#include "mozilla/Attributes.h"
#include "MediaConduitInterface.h"
#include "MediaEngineWrapper.h"
// Video Engine Includes
#include "webrtc/common_types.h"
@ -185,13 +186,7 @@ public:
mVideoEngine(nullptr),
mTransport(nullptr),
mRenderer(nullptr),
mPtrViEBase(nullptr),
mPtrViECapture(nullptr),
mPtrViECodec(nullptr),
mPtrViENetwork(nullptr),
mPtrViERender(nullptr),
mPtrExtCapture(nullptr),
mPtrRTP(nullptr),
mEngineTransmitting(false),
mEngineReceiving(false),
mChannel(-1),
@ -260,13 +255,14 @@ private:
mozilla::RefPtr<TransportInterface> mTransport;
mozilla::RefPtr<VideoRenderer> mRenderer;
webrtc::ViEBase* mPtrViEBase;
webrtc::ViECapture* mPtrViECapture;
webrtc::ViECodec* mPtrViECodec;
webrtc::ViENetwork* mPtrViENetwork;
webrtc::ViERender* mPtrViERender;
webrtc::ViEExternalCapture* mPtrExtCapture; // shared
webrtc::ViERTP_RTCP* mPtrRTP;
ScopedCustomReleasePtr<webrtc::ViEBase> mPtrViEBase;
ScopedCustomReleasePtr<webrtc::ViECapture> mPtrViECapture;
ScopedCustomReleasePtr<webrtc::ViECodec> mPtrViECodec;
ScopedCustomReleasePtr<webrtc::ViENetwork> mPtrViENetwork;
ScopedCustomReleasePtr<webrtc::ViERender> mPtrViERender;
ScopedCustomReleasePtr<webrtc::ViERTP_RTCP> mPtrRTP;
webrtc::ViEExternalCapture* mPtrExtCapture; // shared
// Engine state we are concerned with.
bool mEngineTransmitting; //If true ==> Transmit Sub-system is up and running

41
mfbt/ChaosMode.h Normal file
Просмотреть файл

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_ChaosMode_h
#define mozilla_ChaosMode_h
#include <stdint.h>
#include <stdlib.h>
namespace mozilla {
/**
* When "chaos mode" is activated, code that makes implicitly nondeterministic
* choices is encouraged to make random and extreme choices, to test more
* code paths and uncover bugs.
*/
class ChaosMode
{
public:
static bool isActive()
{
// Flip this to true to activate chaos mode
return false;
}
/**
* Returns a somewhat (but not uniformly) random uint32_t < aBound.
* Not to be used for anything except ChaosMode, since it's not very random.
*/
static uint32_t randomUint32LessThan(uint32_t aBound)
{
return uint32_t(rand()) % aBound;
}
};
} /* namespace mozilla */
#endif /* mozilla_ChaosMode_h */

Просмотреть файл

@ -14,6 +14,13 @@
#include "mozilla/Attributes.h"
#include "mozilla/RefCountType.h"
#include "mozilla/TypeTraits.h"
#if defined(MOZILLA_INTERNAL_API)
#include "nsXPCOM.h"
#endif
#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
#define MOZ_REFCOUNTED_LEAK_CHECKING
#endif
namespace mozilla {
@ -53,6 +60,28 @@ namespace detail {
const MozRefCountType DEAD = 0xffffdead;
#endif
// When building code that gets compiled into Gecko, try to use the
// trace-refcount leak logging facilities.
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
class RefCountLogger
{
public:
static void logAddRef(const void* aPointer, MozRefCountType aRefCount,
const char* aTypeName, uint32_t aInstanceSize)
{
MOZ_ASSERT(aRefCount != DEAD);
NS_LogAddRef(const_cast<void*>(aPointer), aRefCount, aTypeName, aInstanceSize);
}
static void logRelease(const void* aPointer, MozRefCountType aRefCount,
const char* aTypeName)
{
MOZ_ASSERT(aRefCount != DEAD);
NS_LogRelease(const_cast<void*>(aPointer), aRefCount, aTypeName);
}
};
#endif
// This is used WeakPtr.h as well as this file.
enum RefCountAtomicity
{
@ -76,11 +105,21 @@ class RefCounted
void AddRef() const {
MOZ_ASSERT(int32_t(refCnt) >= 0);
++refCnt;
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
detail::RefCountLogger::logAddRef(static_cast<const T*>(this), refCnt,
static_cast<const T*>(this)->typeName(),
static_cast<const T*>(this)->typeSize());
#endif
}
void Release() const {
MOZ_ASSERT(int32_t(refCnt) > 0);
if (0 == --refCnt) {
--refCnt;
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
detail::RefCountLogger::logRelease(static_cast<const T*>(this), refCnt,
static_cast<const T*>(this)->typeName());
#endif
if (0 == refCnt) {
#ifdef DEBUG
refCnt = detail::DEAD;
#endif
@ -101,7 +140,7 @@ class RefCounted
mutable typename Conditional<Atomicity == AtomicRefCount, Atomic<MozRefCountType>, MozRefCountType>::Type refCnt;
};
#if defined(MOZILLA_INTERNAL_API) && (defined(DEBUG) || defined(FORCE_BUILD_REFCNT_LOGGING))
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
#define MOZ_DECLARE_REFCOUNTED_TYPENAME(T) \
const char* typeName() const { return #T; } \
size_t typeSize() const { return sizeof(*this); }

Просмотреть файл

@ -64,11 +64,14 @@
#ifndef mozilla_WeakPtr_h
#define mozilla_WeakPtr_h
#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "mozilla/NullPtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/TypeTraits.h"
#include <string.h>
namespace mozilla {
template <typename T, class WeakReference> class WeakPtrBase;
@ -86,6 +89,29 @@ class WeakReference : public ::mozilla::RefCounted<WeakReference<T> >
return ptr;
}
#ifdef MOZ_REFCOUNTED_LEAK_CHECKING
#ifdef XP_WIN
#define snprintf _snprintf
#endif
const char* typeName() const {
static char nameBuffer[1024];
const char* innerType = ptr->typeName();
// We could do fancier length checks at runtime, but innerType is
// controlled by us so we can ensure that this never causes a buffer
// overflow by this assertion.
MOZ_ASSERT(strlen(innerType) + sizeof("WeakReference<>") < ArrayLength(nameBuffer),
"Exceedingly large type name");
snprintf(nameBuffer, ArrayLength(nameBuffer), "WeakReference<%s>", innerType);
// This is usually not OK, but here we are returning a pointer to a static
// buffer which will immediately be used by the caller.
return nameBuffer;
}
size_t typeSize() const {
return sizeof(*this);
}
#undef snprintf
#endif
private:
friend class WeakPtrBase<T, WeakReference<T> >;
friend class SupportsWeakPtrBase<T, WeakReference<T> >;

Просмотреть файл

@ -18,6 +18,7 @@ EXPORTS.mozilla = [
'Attributes.h',
'BloomFilter.h',
'Casting.h',
'ChaosMode.h',
'Char16.h',
'CheckedInt.h',
'Compiler.h',

Просмотреть файл

@ -21,6 +21,8 @@
#include "mozilla/Preferences.h"
#include "mozilla/Likely.h"
#include "mozilla/PublicSSL.h"
#include "mozilla/ChaosMode.h"
#include "mozilla/PodOperations.h"
#include "nsThreadUtils.h"
#include "nsIFile.h"
@ -227,12 +229,20 @@ nsSocketTransportService::AddToPollList(SocketContext *sock)
}
}
mActiveList[mActiveCount] = *sock;
uint32_t newSocketIndex = mActiveCount;
if (ChaosMode::isActive()) {
newSocketIndex = ChaosMode::randomUint32LessThan(mActiveCount + 1);
PodMove(mActiveList + newSocketIndex + 1, mActiveList + newSocketIndex,
mActiveCount - newSocketIndex);
PodMove(mPollList + newSocketIndex + 2, mPollList + newSocketIndex + 1,
mActiveCount - newSocketIndex);
}
mActiveList[newSocketIndex] = *sock;
mActiveCount++;
mPollList[mActiveCount].fd = sock->mFD;
mPollList[mActiveCount].in_flags = sock->mHandler->mPollFlags;
mPollList[mActiveCount].out_flags = 0;
mPollList[newSocketIndex + 1].fd = sock->mFD;
mPollList[newSocketIndex + 1].in_flags = sock->mHandler->mPollFlags;
mPollList[newSocketIndex + 1].out_flags = 0;
SOCKET_LOG((" active=%u idle=%u\n", mActiveCount, mIdleCount));
return NS_OK;

Просмотреть файл

@ -30,6 +30,7 @@
#include "nsISupportsPriority.h"
#include "nsHttpPipeline.h"
#include <algorithm>
#include "mozilla/ChaosMode.h"
#ifdef DEBUG
// defined by the socket transport service while active
@ -1432,6 +1433,11 @@ nsHttpConnection::OnWriteSegment(char *buf,
return NS_ERROR_FAILURE; // stop iterating
}
if (ChaosMode::isActive() && ChaosMode::randomUint32LessThan(2)) {
// read 1...count bytes
count = ChaosMode::randomUint32LessThan(count) + 1;
}
nsresult rv = mSocketIn->Read(buf, count, countWritten);
if (NS_FAILED(rv))
mSocketInCondition = rv;

Просмотреть файл

@ -30,6 +30,7 @@
#include "nsISocketTransportService.h"
#include <algorithm>
#include "Http2Compression.h"
#include "mozilla/ChaosMode.h"
// defined by the socket transport service while active
extern PRThread *gSocketThread;
@ -51,6 +52,16 @@ InsertTransactionSorted(nsTArray<nsHttpTransaction*> &pendingQ, nsHttpTransactio
for (int32_t i=pendingQ.Length()-1; i>=0; --i) {
nsHttpTransaction *t = pendingQ[i];
if (trans->Priority() >= t->Priority()) {
if (ChaosMode::isActive()) {
int32_t samePriorityCount;
for (samePriorityCount = 0; i - samePriorityCount >= 0; ++samePriorityCount) {
if (pendingQ[i - samePriorityCount]->Priority() != trans->Priority()) {
break;
}
}
// skip over 0...all of the elements with the same priority.
i -= ChaosMode::randomUint32LessThan(samePriorityCount + 1);
}
pendingQ.InsertElementAt(i+1, trans);
return;
}

Просмотреть файл

@ -61,7 +61,8 @@ user_pref("extensions.installDistroAddons", false);
user_pref("extensions.defaultProviders.enabled", true);
user_pref("geo.wifi.uri", "http://%(server)s/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs");
user_pref("geo.wifi.testing", true);
user_pref("geo.wifi.timeToWaitBeforeSending", 200);
user_pref("geo.wifi.scan", false);
user_pref("geo.wifi.logging.enabled", true);
user_pref("camino.warn_when_closing", false); // Camino-only, harmless to others

Просмотреть файл

@ -16,6 +16,7 @@
#include "nsAlgorithm.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/ChaosMode.h"
#ifdef PL_DHASHMETER
# define METER(x) x
@ -640,10 +641,22 @@ PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg)
char *entryAddr = table->entryStore;
uint32_t entrySize = table->entrySize;
uint32_t capacity = PL_DHASH_TABLE_SIZE(table);
char *entryLimit = entryAddr + capacity * entrySize;
uint32_t tableSize = capacity * entrySize;
char *entryLimit = entryAddr + tableSize;
uint32_t i = 0;
bool didRemove = false;
while (entryAddr < entryLimit) {
if (ChaosMode::isActive()) {
// Start iterating at a random point in the hashtable. It would be
// even more chaotic to iterate in fully random order, but that's a lot
// more work.
entryAddr += ChaosMode::randomUint32LessThan(capacity) * entrySize;
if (entryAddr >= entryLimit) {
entryAddr -= tableSize;
}
}
for (uint32_t e = 0; e < capacity; ++e) {
PLDHashEntryHdr *entry = (PLDHashEntryHdr *)entryAddr;
if (ENTRY_IS_LIVE(entry)) {
PLDHashOperator op = etor(table, entry, i++, arg);
@ -656,6 +669,9 @@ PL_DHashTableEnumerate(PLDHashTable *table, PLDHashEnumerator etor, void *arg)
break;
}
entryAddr += entrySize;
if (entryAddr >= entryLimit) {
entryAddr -= tableSize;
}
}
MOZ_ASSERT(!didRemove || table->recursionLevel == 1);

Просмотреть файл

@ -12,6 +12,8 @@
#include "nsIObserverService.h"
#include "nsIServiceManager.h"
#include "mozilla/Services.h"
#include "mozilla/ChaosMode.h"
#include "mozilla/ArrayUtils.h"
#include <math.h>
@ -25,6 +27,7 @@ TimerThread::TimerThread() :
mMonitor("TimerThread.mMonitor"),
mShutdown(false),
mWaiting(false),
mNotified(false),
mSleeping(false)
{
}
@ -133,8 +136,10 @@ nsresult TimerThread::Shutdown()
mShutdown = true;
// notify the cond var so that Run() can return
if (mWaiting)
if (mWaiting) {
mNotified = true;
mMonitor.Notify();
}
// Need to copy content of mTimers array to a local array
// because call to timers' ReleaseCallback() (and release its self)
@ -199,14 +204,21 @@ NS_IMETHODIMP TimerThread::Run()
// Half of the amount of microseconds needed to get positive PRIntervalTime.
// We use this to decide how to round our wait times later
int32_t halfMicrosecondsIntervalResolution = high >> 1;
bool forceRunNextTimer = false;
while (!mShutdown) {
// Have to use PRIntervalTime here, since PR_WaitCondVar takes it
PRIntervalTime waitFor;
bool forceRunThisTimer = forceRunNextTimer;
forceRunNextTimer = false;
if (mSleeping) {
// Sleep for 0.1 seconds while not firing timers.
waitFor = PR_MillisecondsToInterval(100);
uint32_t milliseconds = 100;
if (ChaosMode::isActive()) {
milliseconds = ChaosMode::randomUint32LessThan(200);
}
waitFor = PR_MillisecondsToInterval(milliseconds);
} else {
waitFor = PR_INTERVAL_NO_TIMEOUT;
TimeStamp now = TimeStamp::Now();
@ -215,7 +227,7 @@ NS_IMETHODIMP TimerThread::Run()
if (!mTimers.IsEmpty()) {
timer = mTimers[0];
if (now >= timer->mTimeout) {
if (now >= timer->mTimeout || forceRunThisTimer) {
next:
// NB: AddRef before the Release under RemoveTimerInternal to avoid
// mRefCnt passing through zero, in case all other refs than the one
@ -283,8 +295,22 @@ NS_IMETHODIMP TimerThread::Run()
// before, to do the optimal rounding (i.e., of how to decide what
// interval is so small we should not wait at all).
double microseconds = (timeout - now).ToMilliseconds()*1000;
if (microseconds < halfMicrosecondsIntervalResolution)
if (ChaosMode::isActive()) {
// The mean value of sFractions must be 1 to ensure that
// the average of a long sequence of timeouts converges to the
// actual sum of their times.
static const float sFractions[] = {
0.0f, 0.25f, 0.5f, 0.75f, 1.0f, 1.75f, 2.75f
};
microseconds *= sFractions[ChaosMode::randomUint32LessThan(ArrayLength(sFractions))];
forceRunNextTimer = true;
}
if (microseconds < halfMicrosecondsIntervalResolution) {
forceRunNextTimer = false;
goto next; // round down; execute event now
}
waitFor = PR_MicrosecondsToInterval(static_cast<uint32_t>(microseconds)); // Floor is accurate enough.
if (waitFor == 0)
waitFor = 1; // round up, wait the minimum time we can wait
@ -303,7 +329,11 @@ NS_IMETHODIMP TimerThread::Run()
}
mWaiting = true;
mNotified = false;
mMonitor.Wait(waitFor);
if (mNotified) {
forceRunNextTimer = false;
}
mWaiting = false;
}
@ -320,8 +350,10 @@ nsresult TimerThread::AddTimer(nsTimerImpl *aTimer)
return NS_ERROR_OUT_OF_MEMORY;
// Awaken the timer thread.
if (mWaiting && i == 0)
if (mWaiting && i == 0) {
mNotified = true;
mMonitor.Notify();
}
return NS_OK;
}
@ -339,8 +371,10 @@ nsresult TimerThread::TimerDelayChanged(nsTimerImpl *aTimer)
return NS_ERROR_OUT_OF_MEMORY;
// Awaken the timer thread.
if (mWaiting && i == 0)
if (mWaiting && i == 0) {
mNotified = true;
mMonitor.Notify();
}
return NS_OK;
}
@ -360,8 +394,10 @@ nsresult TimerThread::RemoveTimer(nsTimerImpl *aTimer)
return NS_ERROR_NOT_AVAILABLE;
// Awaken the timer thread.
if (mWaiting)
if (mWaiting) {
mNotified = true;
mMonitor.Notify();
}
return NS_OK;
}

Просмотреть файл

@ -71,6 +71,7 @@ private:
bool mShutdown;
bool mWaiting;
bool mNotified;
bool mSleeping;
nsTArray<nsTimerImpl*> mTimers;

Просмотреть файл

@ -8,6 +8,8 @@
#include "nsAutoPtr.h"
#include "prlog.h"
#include "nsThreadUtils.h"
#include "prthread.h"
#include "mozilla/ChaosMode.h"
using namespace mozilla;
@ -85,6 +87,14 @@ nsEventQueue::PutEvent(nsIRunnable *runnable)
nsRefPtr<nsIRunnable> event(runnable);
bool rv = true;
{
if (ChaosMode::isActive()) {
// With probability 0.5, yield so other threads have a chance to
// dispatch events to this queue first.
if (ChaosMode::randomUint32LessThan(2)) {
PR_Sleep(PR_INTERVAL_NO_WAIT);
}
}
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
if (!mHead) {

Просмотреть файл

@ -26,11 +26,22 @@
#include "mozilla/HangMonitor.h"
#include "mozilla/Services.h"
#include "nsXPCOMPrivate.h"
#include "mozilla/ChaosMode.h"
#ifdef XP_LINUX
#include <sys/time.h>
#include <sys/resource.h>
#include <sched.h>
#endif
#define HAVE_UALARM _BSD_SOURCE || (_XOPEN_SOURCE >= 500 || \
_XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) && \
!(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
#if defined(XP_LINUX) && !defined(ANDROID) && defined(_GNU_SOURCE)
#define HAVE_SCHED_SETAFFINITY
#endif
#ifdef MOZ_CANARY
# include <unistd.h>
# include <execinfo.h>
@ -232,11 +243,50 @@ private:
//-----------------------------------------------------------------------------
static void
SetupCurrentThreadForChaosMode()
{
if (!ChaosMode::isActive()) {
return;
}
#ifdef XP_LINUX
// PR_SetThreadPriority doesn't really work since priorities >
// PR_PRIORITY_NORMAL can't be set by non-root users. Instead we'll just use
// setpriority(2) to set random 'nice values'. In regular Linux this is only
// a dynamic adjustment so it still doesn't really do what we want, but tools
// like 'rr' can be more aggressive about honoring these values.
// Some of these calls may fail due to trying to lower the priority
// (e.g. something may have already called setpriority() for this thread).
// This makes it hard to have non-main threads with higher priority than the
// main thread, but that's hard to fix. Tools like rr can choose to honor the
// requested values anyway.
// Use just 4 priorities so there's a reasonable chance of any two threads
// having equal priority.
setpriority(PRIO_PROCESS, 0, ChaosMode::randomUint32LessThan(4));
#else
// We should set the affinity here but NSPR doesn't provide a way to expose it.
PR_SetThreadPriority(PR_GetCurrentThread(),
PRThreadPriority(ChaosMode::randomUint32LessThan(PR_PRIORITY_LAST + 1)));
#endif
#ifdef HAVE_SCHED_SETAFFINITY
// Force half the threads to CPU 0 so they compete for CPU
if (ChaosMode::randomUint32LessThan(2)) {
cpu_set_t cpus;
CPU_ZERO(&cpus);
CPU_SET(0, &cpus);
sched_setaffinity(0, sizeof(cpus), &cpus);
}
#endif
}
/*static*/ void
nsThread::ThreadFunc(void *arg)
{
nsThread *self = static_cast<nsThread *>(arg); // strong reference
self->mThread = PR_GetCurrentThread();
SetupCurrentThreadForChaosMode();
// Inform the ThreadManager
nsThreadManager::get()->RegisterCurrentThread(self);
@ -352,6 +402,7 @@ nsresult
nsThread::InitCurrentThread()
{
mThread = PR_GetCurrentThread();
SetupCurrentThreadForChaosMode();
nsThreadManager::get()->RegisterCurrentThread(this);
return NS_OK;
@ -697,7 +748,10 @@ nsThread::SetPriority(int32_t priority)
} else {
pri = PR_PRIORITY_NORMAL;
}
PR_SetThreadPriority(mThread, pri);
// If chaos mode is active, retain the randomly chosen priority
if (!ChaosMode::isActive()) {
PR_SetThreadPriority(mThread, pri);
}
return NS_OK;
}