Merge the last PGO-green inbound changeset to m-c.

This commit is contained in:
Ryan VanderMeulen 2012-11-03 09:23:43 -04:00
commit 52ef3171c3
102 changed files with 987 additions and 326 deletions

View File

@ -59,9 +59,9 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(nsAccessiblePivot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsAccessiblePivot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mRoot, nsIAccessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mPosition, nsIAccessible)
uint32_t i, length = tmp->mObservers.Length(); \
uint32_t i, length = tmp->mObservers.Length();
for (i = 0; i < length; ++i) {
cb.NoteXPCOMChild(tmp->mObservers.ElementAt(i).get());
cb.NoteXPCOMChild(tmp->mObservers[i]);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END

View File

@ -586,4 +586,4 @@ pref("network.activity.blipIntervalMilliseconds", 250);
pref("general.useragent.override.facebook.com", "\(Mobile#(Android; Mobile");
pref("general.useragent.override.youtube.com", "\(Mobile#(Android; Mobile");
pref("jsloader.reuseGlobal", false);
pref("jsloader.reuseGlobal", true);

View File

@ -20,7 +20,6 @@ Browser context menu tests.
SpecialPowers.Cu.import("resource://gre/modules/InlineSpellChecker.jsm", window);
const Cc = SpecialPowers.Components.classes;
const Ci = SpecialPowers.Ci;
function openContextMenuFor(element, shiftkey, shouldWaitForFocus) {

View File

@ -61,7 +61,7 @@ VariablesView.prototype = {
*/
empty: function VV_empty(aTimeout = LAZY_EMPTY_DELAY) {
// If there are no items in this container, emptying is useless.
if (!this._store.size()) {
if (!this._store.size) {
return;
}
// Check if this empty operation may be executed lazily.
@ -110,7 +110,7 @@ VariablesView.prototype = {
this._parent.removeChild(prevList);
this._parent.appendChild(currList);
if (!this._store.size()) {
if (!this._store.size) {
this._appendEmptyNotice();
}
}.bind(this), aTimeout);

View File

@ -812,7 +812,7 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
*/
_fetchSources: function DVGS__fetchSources(aFetchCallback, aFetchedCallback, aLocations) {
// If all the sources were already fetched, then don't do anything.
if (this._cache.size() == aLocations.length) {
if (this._cache.size == aLocations.length) {
aFetchedCallback();
return;
}
@ -840,7 +840,7 @@ create({ constructor: GlobalSearchView, proto: MenuContainer.prototype }, {
this._cache.set(aLocation, aContents);
// Check if all sources were fetched and stored in the cache.
if (this._cache.size() == this._sourcesCount) {
if (this._cache.size == this._sourcesCount) {
this._onFetchSourcesFinished();
}
},
@ -1151,7 +1151,7 @@ GlobalResults.prototype = {
/**
* Gets the number of source results in this store.
*/
get itemCount() this._store.size(),
get itemCount() this._store.size,
_store: null
};

View File

@ -134,7 +134,7 @@ function testLocationChange()
window.addEventListener("Debugger:GlobalSearch:CacheCleared", function _onCacheCleared(aEvent) {
window.removeEventListener(aEvent.type, _onCacheCleared);
is(gSearchView._cache.size(), 0,
is(gSearchView._cache.size, 0,
"The scripts sources cache for global searching should be cleared after a page navigation.")
cacheCleared = true;

View File

@ -138,14 +138,14 @@ this.DOMApplicationRegistry = {
},
// Registers all the activities and system messages.
registerAppsHandlers: function registerAppsHandlers() {
registerAppsHandlers: function registerAppsHandlers(aRunUpdate) {
this.notifyAppsRegistryStart();
let ids = [];
for (let id in this.webapps) {
ids.push({ id: id });
}
#ifdef MOZ_SYS_MSG
this._processManifestForIds(ids);
this._processManifestForIds(ids, aRunUpdate);
#else
// Read the CSPs. If MOZ_SYS_MSG is defined this is done on
// _processManifestForIds so as to not reading the manifests
@ -291,7 +291,7 @@ this.DOMApplicationRegistry = {
this.updateOfflineCacheForApp(id);
}
}
this.registerAppsHandlers();
this.registerAppsHandlers(runUpdate);
}).bind(this);
this.loadCurrentRegistry((function() {
@ -351,7 +351,7 @@ this.DOMApplicationRegistry = {
// |aEntryPoint| is either the entry_point name or the null in which case we
// use the root of the manifest.
_createActivitiesToRegister: function(aManifest, aApp, aEntryPoint) {
_createActivitiesToRegister: function(aManifest, aApp, aEntryPoint, aRunUpdate) {
let activitiesToRegister = [];
let root = aManifest;
if (aEntryPoint && aManifest.entry_points[aEntryPoint]) {
@ -369,14 +369,16 @@ this.DOMApplicationRegistry = {
description.href = manifest.launch_path;
}
description.href = manifest.resolveFromOrigin(description.href);
activitiesToRegister.push({ "manifest": aApp.manifestURL,
"name": activity,
"title": manifest.name,
"icon": manifest.iconURLForSize(128),
"description": description });
let launchPath =
Services.io.newURI(manifest.resolveFromOrigin(description.href), null, null);
if (aRunUpdate) {
activitiesToRegister.push({ "manifest": aApp.manifestURL,
"name": activity,
"title": manifest.name,
"icon": manifest.iconURLForSize(128),
"description": description });
}
let launchPath = Services.io.newURI(description.href, null, null);
let manifestURL = Services.io.newURI(aApp.manifestURL, null, null);
msgmgr.registerPage("activity", launchPath, manifestURL);
}
@ -385,14 +387,14 @@ this.DOMApplicationRegistry = {
// |aAppsToRegister| contains an array of apps to be registered, where
// each element is an object in the format of {manifest: foo, app: bar}.
_registerActivitiesForApps: function(aAppsToRegister) {
_registerActivitiesForApps: function(aAppsToRegister, aRunUpdate) {
// Collect the activities to be registered for root and entry_points.
let activitiesToRegister = [];
aAppsToRegister.forEach(function (aApp) {
let manifest = aApp.manifest;
let app = aApp.app;
activitiesToRegister.push.apply(activitiesToRegister,
this._createActivitiesToRegister(manifest, app, null));
this._createActivitiesToRegister(manifest, app, null, aRunUpdate));
if (!manifest.entry_points) {
return;
@ -400,18 +402,23 @@ this.DOMApplicationRegistry = {
for (let entryPoint in manifest.entry_points) {
activitiesToRegister.push.apply(activitiesToRegister,
this._createActivitiesToRegister(manifest, app, entryPoint));
this._createActivitiesToRegister(manifest, app, entryPoint, aRunUpdate));
}
}, this);
if (!aRunUpdate || activitiesToRegister.length == 0) {
this.notifyAppsRegistryReady();
return;
}
// Send the array carrying all the activities to be registered.
cpmm.sendAsyncMessage("Activities:Register", activitiesToRegister);
},
// Better to directly use |_registerActivitiesForApps()| if we have
// multiple apps to be registered for activities.
_registerActivities: function(aManifest, aApp) {
this._registerActivitiesForApps([{ manifest: aManifest, app: aApp }]);
_registerActivities: function(aManifest, aApp, aRunUpdate) {
this._registerActivitiesForApps([{ manifest: aManifest, app: aApp }], aRunUpdate);
},
// |aEntryPoint| is either the entry_point name or the null in which case we
@ -466,7 +473,7 @@ this.DOMApplicationRegistry = {
this._unregisterActivitiesForApps([{ manifest: aManifest, app: aApp }]);
},
_processManifestForIds: function(aIds) {
_processManifestForIds: function(aIds, aRunUpdate) {
this._readManifests(aIds, (function registerManifests(aResults) {
let appsToRegister = [];
aResults.forEach(function registerManifest(aResult) {
@ -477,7 +484,7 @@ this.DOMApplicationRegistry = {
this._registerSystemMessages(manifest, app);
appsToRegister.push({ manifest: manifest, app: app });
}, this);
this._registerActivitiesForApps(appsToRegister);
this._registerActivitiesForApps(appsToRegister, aRunUpdate);
}).bind(this));
},
#endif
@ -821,6 +828,11 @@ this.DOMApplicationRegistry = {
let id = this._appIdForManifestURL(app.manifestURL);
// Clean up the deprecated manifest cache if needed.
if (id in this._manifestCache) {
delete this._manifestCache[id];
}
// Move the application.zip and manifest.webapp files out of TmpD
let tmpDir = FileUtils.getDir("TmpD", ["webapps", id], true, true);
let manFile = tmpDir.clone();
@ -915,13 +927,17 @@ this.DOMApplicationRegistry = {
debug("updateHostedApp");
let id = this._appId(app.origin);
if (id in this._manifestCache) {
delete this._manifestCache[id];
}
// Update the web apps' registration.
this.notifyAppsRegistryStart();
#ifdef MOZ_SYS_MSG
this._readManifests([{ id: id }], (function unregisterManifest(aResult) {
this._unregisterActivities(aResult[0].manifest, app);
this._registerSystemMessages(aManifest, app);
this._registerActivities(aManifest, app);
this._registerActivities(aManifest, app, true);
}).bind(this));
#else
// Nothing else to do but notifying we're ready.
@ -1142,7 +1158,7 @@ this.DOMApplicationRegistry = {
this.notifyAppsRegistryStart();
#ifdef MOZ_SYS_MSG
this._registerSystemMessages(app.manifest, app);
this._registerActivities(app.manifest, app);
this._registerActivities(app.manifest, app, true);
#else
// Nothing else to do but notifying we're ready.
this.notifyAppsRegistryReady();
@ -1229,6 +1245,9 @@ this.DOMApplicationRegistry = {
/**
* Asynchronously reads a list of manifests
*/
_manifestCache: {},
_readManifests: function(aData, aFinalCallback, aIndex) {
if (!aData.length) {
aFinalCallback(aData);
@ -1238,6 +1257,16 @@ this.DOMApplicationRegistry = {
let index = aIndex || 0;
let id = aData[index].id;
// Use the cached manifest instead of reading the file again from disk.
if (id in this._manifestCache) {
aData[index].manifest = this._manifestCache[id];
if (index == aData.length - 1)
aFinalCallback(aData);
else
this._readManifests(aData, aFinalCallback, index + 1);
return;
}
// the manifest file used to be named manifest.json, so fallback on this.
let baseDir = (this.webapps[id].removable ? DIRECTORY_NAME : "coreAppsDir");
let file = FileUtils.getFile(baseDir, ["webapps", id, "manifest.webapp"], true);
@ -1249,7 +1278,7 @@ this.DOMApplicationRegistry = {
}
this._loadJSONAsync(file, (function(aJSON) {
aData[index].manifest = aJSON;
aData[index].manifest = this._manifestCache[id] = aJSON;
if (index == aData.length - 1)
aFinalCallback(aData);
else
@ -1406,6 +1435,11 @@ this.DOMApplicationRegistry = {
if (!this.webapps[id].removable)
return;
// Clean up the deprecated manifest cache if needed.
if (id in this._manifestCache) {
delete this._manifestCache[id];
}
// Clear private data first.
this._clearPrivateData(app.localId, false);
@ -1621,6 +1655,11 @@ this.DOMApplicationRegistry = {
if (!this.webapps[record.id] || !this.webapps[record.id].removable)
continue;
// Clean up the deprecated manifest cache if needed.
if (record.id in this._manifestCache) {
delete this._manifestCache[record.id];
}
let origin = this.webapps[record.id].origin;
delete this.webapps[record.id];
let dir = this._getAppDir(record.id);
@ -1667,6 +1706,10 @@ this.DOMApplicationRegistry = {
} catch (e) {
}
}
// Clear the manifest cache.
this._manifestCache = { };
this._saveApps(aCallback);
},

View File

@ -1755,6 +1755,8 @@ nsFocusManager::Focus(nsPIDOMWindow* aWindow,
// if switching to a new document, first fire the focus event on the
// document and then the window.
if (aIsNewDocument) {
nsIMEStateManager::OnChangeFocus(presShell->GetPresContext(), nullptr,
GetFocusMoveActionCause(aFlags));
nsIDocument* doc = aWindow->GetExtantDoc();
if (doc)
SendFocusOrBlurEvent(NS_FOCUS_CONTENT, presShell, doc,

View File

@ -25,7 +25,7 @@
#include "nsIOutputStream.h"
#include "nsNetUtil.h"
#define TARGET_FOLDER "/sdcard/download/bluetooth/"
#define TARGET_FOLDER "/sdcard/downloads/bluetooth/"
USING_BLUETOOTH_NAMESPACE
using namespace mozilla;
@ -44,7 +44,9 @@ public:
bool Init()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
if (NS_FAILED(obs->AddObserver(this,
NS_XPCOM_SHUTDOWN_OBSERVER_ID,
false))) {
NS_WARNING("Failed to add shutdown observer!");
return false;
}
@ -162,6 +164,7 @@ BluetoothOppManager::BluetoothOppManager() : mConnected(false)
, mWaitingForConfirmationFlag(false)
{
mConnectedDeviceAddress.AssignLiteral("00:00:00:00:00:00");
mSocketStatus = GetConnectionStatus();
}
BluetoothOppManager::~BluetoothOppManager()
@ -194,7 +197,7 @@ BluetoothOppManager::Connect(const nsAString& aDeviceObjectPath,
}
nsString serviceUuidStr =
NS_ConvertUTF8toUTF16(mozilla::dom::bluetooth::BluetoothServiceUuidStr::ObjectPush);
NS_ConvertUTF8toUTF16(BluetoothServiceUuidStr::ObjectPush);
nsRefPtr<BluetoothReplyRunnable> runnable = aRunnable;
@ -244,12 +247,13 @@ BluetoothOppManager::Listen()
true,
true,
this);
mSocketStatus = GetConnectionStatus();
return NS_FAILED(rv) ? false : true;
}
bool
BluetoothOppManager::SendFile(BlobParent* aActor,
BluetoothReplyRunnable* aRunnable)
BluetoothOppManager::SendFile(BlobParent* aActor)
{
if (mBlob) {
// Means there's a sending process. Reply error.
@ -270,24 +274,19 @@ BluetoothOppManager::SendFile(BlobParent* aActor,
}
bool
BluetoothOppManager::StopSendingFile(BluetoothReplyRunnable* aRunnable)
BluetoothOppManager::StopSendingFile()
{
if (!mBlob) {
return false;
}
mAbortFlag = true;
return true;
}
void
BluetoothOppManager::ConfirmReceivingFile(bool aConfirm,
BluetoothReplyRunnable* aRunnable)
bool
BluetoothOppManager::ConfirmReceivingFile(bool aConfirm)
{
if (!mWaitingForConfirmationFlag) {
NS_WARNING("We are not waiting for a confirmation now.");
return;
return false;
}
NS_ASSERTION(mPacketLeftLength == 0,
@ -299,6 +298,8 @@ BluetoothOppManager::ConfirmReceivingFile(bool aConfirm,
if (aConfirm) {
StartFileTransfer(mConnectedDeviceAddress, true,
sFileName, sFileLength, sContentType);
} else {
DeleteReceivedFile();
}
if (mPutFinal || !aConfirm) {
@ -306,6 +307,8 @@ BluetoothOppManager::ConfirmReceivingFile(bool aConfirm,
FileTransferComplete(mConnectedDeviceAddress, aConfirm, true, sFileName,
sSentFileLength, sContentType);
}
return true;
}
void
@ -347,6 +350,28 @@ BluetoothOppManager::AfterOppDisconnected()
mConnectedDeviceAddress.AssignLiteral("00:00:00:00:00:00");
}
void
BluetoothOppManager::DeleteReceivedFile()
{
nsString path;
path.AssignLiteral(TARGET_FOLDER);
path += sFileName;
nsCOMPtr<nsIFile> f;
nsresult rv = NS_NewLocalFile(path + sFileName, false, getter_AddRefs(f));
if (NS_FAILED(rv)) {
NS_WARNING("Couldn't find received file, nothing to delete.");
return;
}
if (mOutputStream) {
mOutputStream->Close();
mOutputStream = nullptr;
}
f->Remove(false);
}
// Virtual function of class SocketConsumer
void
BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
@ -520,10 +545,9 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
pktHeaders.GetContentType(sContentType);
pktHeaders.GetLength(&sFileLength);
path += sFileName;
nsCOMPtr<nsIFile> f;
nsresult rv = NS_NewLocalFile(path, false, getter_AddRefs(f));
nsresult rv;
rv = NS_NewLocalFile(path + sFileName, false, getter_AddRefs(f));
if (NS_FAILED(rv)) {
NS_WARNING("Couldn't new a local file");
}
@ -533,6 +557,13 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
NS_WARNING("Couldn't create the file");
}
/*
* The function CreateUnique() may create a file with a different file
* name from the original sFileName. Therefore we have to retrieve
* the file name again.
*/
f->GetLeafName(sFileName);
NS_NewLocalFileOutputStream(getter_AddRefs(mOutputStream), f);
if (!mOutputStream) {
NS_WARNING("Couldn't new an output stream");
@ -581,7 +612,9 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
"Invalid packet length");
mPacketLeftLength -= receivedLength;
mOutputStream->Write((char*)&aMessage->mData[0], receivedLength, &wrote);
mOutputStream->Write((char*)&aMessage->mData[0],
receivedLength,
&wrote);
NS_ASSERTION(receivedLength == wrote, "Writing to the file failed");
}
@ -598,12 +631,17 @@ BluetoothOppManager::ReceiveSocketData(UnixSocketRawData* aMessage)
ReceivingFileConfirmation(mConnectedDeviceAddress, sFileName,
sFileLength, sContentType);
} else {
ReplyToPut(mPutFinal, true);
ReplyToPut(mPutFinal, mAbortFlag ? false : true);
if (mPutFinal) {
if (mAbortFlag) {
mReceiving = false;
FileTransferComplete(mConnectedDeviceAddress, true, true, sFileName,
sSentFileLength, sContentType);
FileTransferComplete(mConnectedDeviceAddress, false, true,
sFileName, sSentFileLength, sContentType);
DeleteReceivedFile();
} else if (mPutFinal) {
mReceiving = false;
FileTransferComplete(mConnectedDeviceAddress, true, true,
sFileName, sSentFileLength, sContentType);
}
}
}
@ -625,7 +663,7 @@ BluetoothOppManager::SendConnectRequest()
req[3] = 0x10; // version=1.0
req[4] = 0x00; // flag=0x00
req[5] = BluetoothOppManager::MAX_PACKET_LENGTH >> 8;
req[6] = BluetoothOppManager::MAX_PACKET_LENGTH;
req[6] = (uint8_t)BluetoothOppManager::MAX_PACKET_LENGTH;
index += AppendHeaderConnectionId(&req[index], mConnectionId);
SetObexPacketInfo(req, ObexRequestCode::Connect, index);
@ -642,9 +680,10 @@ BluetoothOppManager::SendPutHeaderRequest(const nsAString& aFileName,
{
uint8_t* req = new uint8_t[mRemoteMaxPacketLength];
const PRUnichar* fileNamePtr = aFileName.BeginReading();
uint32_t len = aFileName.Length();
int len = aFileName.Length();
uint8_t* fileName = new uint8_t[(len + 1) * 2];
const PRUnichar* fileNamePtr = aFileName.BeginReading();
for (int i = 0; i < len; i++) {
fileName[i * 2] = (uint8_t)(fileNamePtr[i] >> 8);
fileName[i * 2 + 1] = (uint8_t)fileNamePtr[i];
@ -751,7 +790,7 @@ BluetoothOppManager::ReplyToConnect()
req[3] = 0x10; // version=1.0
req[4] = 0x00; // flag=0x00
req[5] = BluetoothOppManager::MAX_PACKET_LENGTH >> 8;
req[6] = BluetoothOppManager::MAX_PACKET_LENGTH;
req[6] = (uint8_t)BluetoothOppManager::MAX_PACKET_LENGTH;
SetObexPacketInfo(req, ObexResponseCode::Success, index);
@ -798,7 +837,9 @@ BluetoothOppManager::ReplyToPut(bool aFinal, bool aContinue)
if (aFinal) {
SetObexPacketInfo(req, ObexResponseCode::Unauthorized, index);
} else {
SetObexPacketInfo(req, ObexResponseCode::Unauthorized & (~FINAL_BIT), index);
SetObexPacketInfo(req,
ObexResponseCode::Unauthorized & (~FINAL_BIT),
index);
}
}
@ -949,7 +990,7 @@ BluetoothOppManager::ReceivingFileConfirmation(const nsString& aAddress,
parameters.AppendElement(BluetoothNamedValue(name, v));
if (!BroadcastSystemMessage(type, parameters)) {
NS_WARNING("Failed to broadcast [bluetooth-opp-receiving-file-confirmation]");
NS_WARNING("Failed to send [bluetooth-opp-receiving-file-confirmation]");
return;
}
}
@ -960,11 +1001,16 @@ BluetoothOppManager::OnConnectSuccess()
// Cache device address since we can't get socket address when a remote
// device disconnect with us.
GetSocketAddr(mConnectedDeviceAddress);
mSocketStatus = GetConnectionStatus();
}
void
BluetoothOppManager::OnConnectError()
{
CloseSocket();
mSocketStatus = GetConnectionStatus();
Listen();
}
void
@ -974,4 +1020,8 @@ BluetoothOppManager::OnDisconnect()
// closing socket without sending OBEX disconnect request first. So we
// call AfterOppDisconnected here to ensure all variables will be cleaned.
AfterOppDisconnected();
if (mSocketStatus == SocketConnectionStatus::SOCKET_CONNECTED) {
Listen();
}
}

View File

@ -10,7 +10,6 @@
#include "BluetoothCommon.h"
#include "mozilla/dom/ipc/Blob.h"
#include "mozilla/ipc/UnixSocket.h"
#include "nsIDOMFile.h"
class nsIOutputStream;
class nsIInputStream;
@ -51,10 +50,9 @@ public:
void Disconnect();
bool Listen();
bool SendFile(BlobParent* aBlob,
BluetoothReplyRunnable* aRunnable);
bool StopSendingFile(BluetoothReplyRunnable* aRunnable);
void ConfirmReceivingFile(bool aConfirm, BluetoothReplyRunnable* aRunnable);
bool SendFile(BlobParent* aBlob);
bool StopSendingFile();
bool ConfirmReceivingFile(bool aConfirm);
void SendConnectRequest();
void SendPutHeaderRequest(const nsAString& aFileName, int aFileSize);
@ -85,6 +83,7 @@ private:
const nsString& aFileName,
uint32_t aFileLength,
const nsString& aContentType);
void DeleteReceivedFile();
void ReplyToConnect();
void ReplyToDisconnect();
void ReplyToPut(bool aFinal, bool aContinue);
@ -107,6 +106,7 @@ private:
bool mPutFinal;
bool mWaitingForConfirmationFlag;
int mUpdateProgressCounter;
enum mozilla::ipc::SocketConnectionStatus mSocketStatus;
nsCOMPtr<nsIDOMBlob> mBlob;
nsCOMPtr<nsIThread> mReadFileThread;

View File

@ -273,13 +273,13 @@ public:
virtual void
Disconnect(uint16_t aProfileId, BluetoothReplyRunnable* aRunnable) = 0;
virtual bool
virtual void
SendFile(const nsAString& aDeviceAddress,
BlobParent* aBlobParent,
BlobChild* aBlobChild,
BluetoothReplyRunnable* aRunnable) = 0;
virtual bool
virtual void
StopSendingFile(const nsAString& aDeviceAddress,
BluetoothReplyRunnable* aRunnable) = 0;

View File

@ -9,63 +9,63 @@
BEGIN_BLUETOOTH_NAMESPACE
int
AppendHeaderName(uint8_t* retBuf, const char* name, int length)
AppendHeaderName(uint8_t* aRetBuf, const char* aName, int aLength)
{
int headerLength = length + 3;
int headerLength = aLength + 3;
retBuf[0] = ObexHeaderId::Name;
retBuf[1] = (headerLength & 0xFF00) >> 8;
retBuf[2] = headerLength & 0x00FF;
aRetBuf[0] = ObexHeaderId::Name;
aRetBuf[1] = (headerLength & 0xFF00) >> 8;
aRetBuf[2] = headerLength & 0x00FF;
memcpy(&retBuf[3], name, length);
memcpy(&aRetBuf[3], aName, aLength);
return headerLength;
}
int
AppendHeaderBody(uint8_t* retBuf, uint8_t* data, int length)
AppendHeaderBody(uint8_t* aRetBuf, uint8_t* aData, int aLength)
{
int headerLength = length + 3;
int headerLength = aLength + 3;
retBuf[0] = ObexHeaderId::Body;
retBuf[1] = (headerLength & 0xFF00) >> 8;
retBuf[2] = headerLength & 0x00FF;
aRetBuf[0] = ObexHeaderId::Body;
aRetBuf[1] = (headerLength & 0xFF00) >> 8;
aRetBuf[2] = headerLength & 0x00FF;
memcpy(&retBuf[3], data, length);
memcpy(&aRetBuf[3], aData, aLength);
return headerLength;
}
int
AppendHeaderLength(uint8_t* retBuf, int objectLength)
AppendHeaderLength(uint8_t* aRetBuf, int aObjectLength)
{
retBuf[0] = ObexHeaderId::Length;
retBuf[1] = (objectLength & 0xFF000000) >> 24;
retBuf[2] = (objectLength & 0x00FF0000) >> 16;
retBuf[3] = (objectLength & 0x0000FF00) >> 8;
retBuf[4] = objectLength & 0x000000FF;
aRetBuf[0] = ObexHeaderId::Length;
aRetBuf[1] = (aObjectLength & 0xFF000000) >> 24;
aRetBuf[2] = (aObjectLength & 0x00FF0000) >> 16;
aRetBuf[3] = (aObjectLength & 0x0000FF00) >> 8;
aRetBuf[4] = aObjectLength & 0x000000FF;
return 5;
}
int
AppendHeaderConnectionId(uint8_t* retBuf, int connectionId)
AppendHeaderConnectionId(uint8_t* aRetBuf, int aConnectionId)
{
retBuf[0] = ObexHeaderId::ConnectionId;
retBuf[1] = (connectionId & 0xFF000000) >> 24;
retBuf[2] = (connectionId & 0x00FF0000) >> 16;
retBuf[3] = (connectionId & 0x0000FF00) >> 8;
retBuf[4] = connectionId & 0x000000FF;
aRetBuf[0] = ObexHeaderId::ConnectionId;
aRetBuf[1] = (aConnectionId & 0xFF000000) >> 24;
aRetBuf[2] = (aConnectionId & 0x00FF0000) >> 16;
aRetBuf[3] = (aConnectionId & 0x0000FF00) >> 8;
aRetBuf[4] = aConnectionId & 0x000000FF;
return 5;
}
void
SetObexPacketInfo(uint8_t* retBuf, uint8_t opcode, int packetLength)
SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength)
{
retBuf[0] = opcode;
retBuf[1] = (packetLength & 0xFF00) >> 8;
retBuf[2] = packetLength & 0x00FF;
aRetBuf[0] = aOpcode;
aRetBuf[1] = (aPacketLength & 0xFF00) >> 8;
aRetBuf[2] = aPacketLength & 0x00FF;
}
int

View File

@ -195,11 +195,11 @@ public:
}
};
int AppendHeaderName(uint8_t* retBuf, const char* name, int length);
int AppendHeaderBody(uint8_t* retBuf, uint8_t* data, int length);
int AppendHeaderLength(uint8_t* retBuf, int objectLength);
int AppendHeaderConnectionId(uint8_t* retBuf, int connectionId);
void SetObexPacketInfo(uint8_t* retBuf, uint8_t opcode, int packetLength);
int AppendHeaderName(uint8_t* aRetBuf, const char* aName, int aLength);
int AppendHeaderBody(uint8_t* aRetBuf, uint8_t* aData, int aLength);
int AppendHeaderLength(uint8_t* aRetBuf, int aObjectLength);
int AppendHeaderConnectionId(uint8_t* aRetBuf, int aConnectionId);
void SetObexPacketInfo(uint8_t* aRetBuf, uint8_t aOpcode, int aPacketLength);
int ParseHeadersAndFindBody(uint8_t* aHeaderStart,
int aTotalLength,
ObexHeaderSet* aRetHanderSet);

View File

@ -529,10 +529,12 @@ BluetoothRequestParent::DoRequest(const SendFileRequest& aRequest)
MOZ_ASSERT(mService);
MOZ_ASSERT(mRequestType == Request::TSendFileRequest);
return mService->SendFile(aRequest.devicePath(),
(BlobParent*)aRequest.blobParent(),
(BlobChild*)aRequest.blobChild(),
mReplyRunnable.get());
mService->SendFile(aRequest.devicePath(),
(BlobParent*)aRequest.blobParent(),
(BlobChild*)aRequest.blobChild(),
mReplyRunnable.get());
return true;
}
bool
@ -541,8 +543,10 @@ BluetoothRequestParent::DoRequest(const StopSendingFileRequest& aRequest)
MOZ_ASSERT(mService);
MOZ_ASSERT(mRequestType == Request::TStopSendingFileRequest);
return mService->StopSendingFile(aRequest.devicePath(),
mReplyRunnable.get());
mService->StopSendingFile(aRequest.devicePath(),
mReplyRunnable.get());
return true;
}
bool

View File

@ -323,7 +323,7 @@ BluetoothServiceChildProcess::Disconnect(
SendRequest(aRunnable, DisconnectRequest(aProfileId));
}
bool
void
BluetoothServiceChildProcess::SendFile(
const nsAString& aDeviceAddress,
BlobParent* aBlobParent,
@ -332,17 +332,15 @@ BluetoothServiceChildProcess::SendFile(
{
SendRequest(aRunnable,
SendFileRequest(nsString(aDeviceAddress), nullptr, aBlobChild));
return true;
}
bool
void
BluetoothServiceChildProcess::StopSendingFile(
const nsAString& aDeviceAddress,
BluetoothReplyRunnable* aRunnable)
{
SendRequest(aRunnable,
StopSendingFileRequest(nsString(aDeviceAddress)));
return true;
}
void

View File

@ -139,13 +139,13 @@ public:
Disconnect(const uint16_t aProfileId,
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
virtual bool
virtual void
SendFile(const nsAString& aDeviceAddress,
BlobParent* aBlobParent,
BlobChild* aBlobChild,
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
virtual bool
virtual void
StopSendingFile(const nsAString& aDeviceAddress,
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;

View File

@ -2368,7 +2368,8 @@ void
BluetoothDBusService::Disconnect(const uint16_t aProfileId,
BluetoothReplyRunnable* aRunnable)
{
if (aProfileId == (uint16_t)(BluetoothServiceUuid::Handsfree >> 32)) {
if (aProfileId == (uint16_t)(BluetoothServiceUuid::Handsfree >> 32) ||
aProfileId == (uint16_t)(BluetoothServiceUuid::Headset >> 32)) {
BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
hfp->Disconnect();
} else if (aProfileId == (uint16_t)(BluetoothServiceUuid::ObjectPush >> 32)) {
@ -2557,7 +2558,7 @@ BluetoothDBusService::GetScoSocket(const nsAString& aAddress,
return NS_OK;
}
bool
void
BluetoothDBusService::SendFile(const nsAString& aDeviceAddress,
BlobParent* aBlobParent,
BlobChild* aBlobChild,
@ -2570,12 +2571,17 @@ BluetoothDBusService::SendFile(const nsAString& aDeviceAddress,
// has been determined when calling 'Connect()'. Nevertheless, keep
// it for future use.
BluetoothOppManager* opp = BluetoothOppManager::Get();
opp->SendFile(aBlobParent, aRunnable);
BluetoothValue v = true;
nsString errorStr;
return true;
if (!opp->SendFile(aBlobParent)) {
errorStr.AssignLiteral("Calling SendFile() failed");
}
DispatchBluetoothReply(aRunnable, v, errorStr);
}
bool
void
BluetoothDBusService::StopSendingFile(const nsAString& aDeviceAddress,
BluetoothReplyRunnable* aRunnable)
{
@ -2586,9 +2592,14 @@ BluetoothDBusService::StopSendingFile(const nsAString& aDeviceAddress,
// has been determined when calling 'Connect()'. Nevertheless, keep
// it for future use.
BluetoothOppManager* opp = BluetoothOppManager::Get();
opp->StopSendingFile(aRunnable);
BluetoothValue v = true;
nsString errorStr;
return true;
if (!opp->StopSendingFile()) {
errorStr.AssignLiteral("Calling StopSendingFile() failed");
}
DispatchBluetoothReply(aRunnable, v, errorStr);
}
void
@ -2603,7 +2614,14 @@ BluetoothDBusService::ConfirmReceivingFile(const nsAString& aDeviceAddress,
// has been determined when calling 'Connect()'. Nevertheless, keep
// it for future use.
BluetoothOppManager* opp = BluetoothOppManager::Get();
opp->ConfirmReceivingFile(aConfirm, aRunnable);
BluetoothValue v = true;
nsString errorStr;
if (!opp->ConfirmReceivingFile(aConfirm)) {
errorStr.AssignLiteral("Calling ConfirmReceivingFile() failed");
}
DispatchBluetoothReply(aRunnable, v, errorStr);
}
nsresult

View File

@ -142,13 +142,13 @@ public:
virtual void
Disconnect(const uint16_t aProfileId, BluetoothReplyRunnable* aRunnable);
virtual bool
virtual void
SendFile(const nsAString& aDeviceAddress,
BlobParent* aBlobParent,
BlobChild* aBlobChild,
BluetoothReplyRunnable* aRunnable);
virtual bool
virtual void
StopSendingFile(const nsAString& aDeviceAddress,
BluetoothReplyRunnable* aRunnable);

View File

@ -42,7 +42,6 @@ function checkStylesheets() {
function runTest() {
const Ci = SpecialPowers.Ci;
const Cc = SpecialPowers.Components.classes;
/** Found while fixing bug 440614 **/
var editframe = window.frames[0];

View File

@ -111,6 +111,8 @@ class OrderedHashTable
return false;
}
// clear() requires that members are assigned only after all allocation
// has succeeded, and that this->ranges is left untouched.
hashTable = tableAlloc;
data = dataAlloc;
dataLength = 0;
@ -218,6 +220,42 @@ class OrderedHashTable
return true;
}
/*
* Remove all entries.
*
* Returns false on OOM, leaving the OrderedHashTable and any live Ranges
* in the old state.
*
* The effect on live Ranges is the same as removing all entries; in
* particular, those Ranges are still live and will see any entries added
* after a successful clear().
*/
bool clear() {
if (dataLength != 0) {
Data **oldHashTable = hashTable;
Data *oldData = data;
uint32_t oldDataLength = dataLength;
hashTable = NULL;
if (!init()) {
// init() only mutates members on success; see comment above.
hashTable = oldHashTable;
return false;
}
alloc.free_(oldHashTable);
freeData(oldData, oldDataLength);
for (Range *r = ranges; r; r = r->next)
r->onClear();
}
MOZ_ASSERT(hashTable);
MOZ_ASSERT(data);
MOZ_ASSERT(dataLength == 0);
MOZ_ASSERT(liveCount == 0);
return true;
}
/*
* Ranges are used to iterate over OrderedHashTables.
*
@ -337,6 +375,12 @@ class OrderedHashTable
i = count;
}
/* The hash table calls this when cleared. */
void onClear() {
MOZ_ASSERT(valid());
i = count = 0;
}
bool valid() const {
return next != this;
}
@ -476,9 +520,13 @@ class OrderedHashTable
return 1 << (HashNumberSizeBits - hashShift);
}
void freeData(Data *data, uint32_t length) {
static void destroyData(Data *data, uint32_t length) {
for (Data *p = data + length; p != data; )
(--p)->~Data();
}
void freeData(Data *data, uint32_t length) {
destroyData(data, length);
alloc.free_(data);
}
@ -642,6 +690,7 @@ class OrderedHashMap
Entry *get(const Key &key) { return impl.get(key); }
bool put(const Key &key, const Value &value) { return impl.put(Entry(key, value)); }
bool remove(const Key &key, bool *foundp) { return impl.remove(key, foundp); }
bool clear() { return impl.clear(); }
};
template <class T, class OrderedHashPolicy, class AllocPolicy>
@ -668,6 +717,7 @@ class OrderedHashSet
Range all() { return impl.all(); }
bool put(const T &value) { return impl.put(value); }
bool remove(const T &value, bool *foundp) { return impl.remove(value, foundp); }
bool clear() { return impl.clear(); }
};
} // namespace js
@ -897,19 +947,24 @@ Class MapObject::class_ = {
mark
};
JSPropertySpec MapObject::properties[] = {
JS_PSG("size", size, 0),
JS_PS_END
};
JSFunctionSpec MapObject::methods[] = {
JS_FN("size", size, 0, 0),
JS_FN("get", get, 1, 0),
JS_FN("has", has, 1, 0),
JS_FN("set", set, 2, 0),
JS_FN("delete", delete_, 1, 0),
JS_FN("iterator", iterator, 0, 0),
JS_FN("clear", clear, 0, 0),
JS_FS_END
};
static JSObject *
InitClass(JSContext *cx, Handle<GlobalObject*> global, Class *clasp, JSProtoKey key, Native construct,
JSFunctionSpec *methods)
JSPropertySpec *properties, JSFunctionSpec *methods)
{
Rooted<JSObject*> proto(cx, global->createBlankPrototype(cx, clasp));
if (!proto)
@ -919,7 +974,7 @@ InitClass(JSContext *cx, Handle<GlobalObject*> global, Class *clasp, JSProtoKey
Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(key, cx), 1));
if (!ctor ||
!LinkConstructorAndPrototype(cx, ctor, proto) ||
!DefinePropertiesAndBrand(cx, proto, NULL, methods) ||
!DefinePropertiesAndBrand(cx, proto, properties, methods) ||
!DefineConstructorAndPrototype(cx, global, key, ctor, proto))
{
return NULL;
@ -931,7 +986,7 @@ JSObject *
MapObject::initClass(JSContext *cx, JSObject *obj)
{
Rooted<GlobalObject*> global(cx, &obj->asGlobal());
return InitClass(cx, global, &class_, JSProto_Map, construct, methods);
return InitClass(cx, global, &class_, JSProto_Map, construct, properties, methods);
}
template <class Range>
@ -1147,8 +1202,10 @@ MapObject::delete_impl(JSContext *cx, CallArgs args)
ValueMap &map = extract(args);
ARG0_KEY(cx, args, key);
bool found;
if (!map.remove(key, &found))
if (!map.remove(key, &found)) {
js_ReportOutOfMemory(cx);
return false;
}
args.rval().setBoolean(found);
return true;
}
@ -1179,6 +1236,25 @@ MapObject::iterator(JSContext *cx, unsigned argc, Value *vp)
return CallNonGenericMethod(cx, is, iterator_impl, args);
}
bool
MapObject::clear_impl(JSContext *cx, CallArgs args)
{
Rooted<MapObject*> mapobj(cx, &args.thisv().toObject().asMap());
if (!mapobj->getData()->clear()) {
js_ReportOutOfMemory(cx);
return false;
}
args.rval().setUndefined();
return true;
}
JSBool
MapObject::clear(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod(cx, is, clear_impl, args);
}
JSObject *
js_InitMapClass(JSContext *cx, HandleObject obj)
{
@ -1338,12 +1414,17 @@ Class SetObject::class_ = {
mark
};
JSPropertySpec SetObject::properties[] = {
JS_PSG("size", size, 0),
JS_PS_END
};
JSFunctionSpec SetObject::methods[] = {
JS_FN("size", size, 0, 0),
JS_FN("has", has, 1, 0),
JS_FN("add", add, 1, 0),
JS_FN("delete", delete_, 1, 0),
JS_FN("iterator", iterator, 0, 0),
JS_FN("clear", clear, 0, 0),
JS_FS_END
};
@ -1351,7 +1432,7 @@ JSObject *
SetObject::initClass(JSContext *cx, JSObject *obj)
{
Rooted<GlobalObject*> global(cx, &obj->asGlobal());
return InitClass(cx, global, &class_, JSProto_Set, construct, methods);
return InitClass(cx, global, &class_, JSProto_Set, construct, properties, methods);
}
void
@ -1488,8 +1569,10 @@ SetObject::delete_impl(JSContext *cx, CallArgs args)
ValueSet &set = extract(args);
ARG0_KEY(cx, args, key);
bool found;
if (!set.remove(key, &found))
if (!set.remove(key, &found)) {
js_ReportOutOfMemory(cx);
return false;
}
args.rval().setBoolean(found);
return true;
}
@ -1520,6 +1603,25 @@ SetObject::iterator(JSContext *cx, unsigned argc, Value *vp)
return CallNonGenericMethod(cx, is, iterator_impl, args);
}
bool
SetObject::clear_impl(JSContext *cx, CallArgs args)
{
Rooted<SetObject*> setobj(cx, &args.thisv().toObject().asSet());
if (!setobj->getData()->clear()) {
js_ReportOutOfMemory(cx);
return false;
}
args.rval().setUndefined();
return true;
}
JSBool
SetObject::clear(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod(cx, is, clear_impl, args);
}
JSObject *
js_InitSetClass(JSContext *cx, HandleObject obj)
{

View File

@ -84,6 +84,7 @@ class MapObject : public JSObject {
static JSObject *initClass(JSContext *cx, JSObject *obj);
static Class class_;
private:
static JSPropertySpec properties[];
static JSFunctionSpec methods[];
ValueMap *getData() { return static_cast<ValueMap *>(getPrivate()); }
static ValueMap & extract(CallReceiver call);
@ -105,6 +106,8 @@ class MapObject : public JSObject {
static JSBool delete_(JSContext *cx, unsigned argc, Value *vp);
static bool iterator_impl(JSContext *cx, CallArgs args);
static JSBool iterator(JSContext *cx, unsigned argc, Value *vp);
static bool clear_impl(JSContext *cx, CallArgs args);
static JSBool clear(JSContext *cx, unsigned argc, Value *vp);
};
class SetObject : public JSObject {
@ -112,6 +115,7 @@ class SetObject : public JSObject {
static JSObject *initClass(JSContext *cx, JSObject *obj);
static Class class_;
private:
static JSPropertySpec properties[];
static JSFunctionSpec methods[];
ValueSet *getData() { return static_cast<ValueSet *>(getPrivate()); }
static ValueSet & extract(CallReceiver call);
@ -131,6 +135,8 @@ class SetObject : public JSObject {
static JSBool delete_(JSContext *cx, unsigned argc, Value *vp);
static bool iterator_impl(JSContext *cx, CallArgs args);
static JSBool iterator(JSContext *cx, unsigned argc, Value *vp);
static bool clear_impl(JSContext *cx, CallArgs args);
static JSBool clear(JSContext *cx, unsigned argc, Value *vp);
};
} /* namespace js */

View File

@ -631,6 +631,12 @@ class Rooted : public RootedBase<T>
Rooted(const Rooted &) MOZ_DELETE;
};
#if !(defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING))
// Defined in vm/String.h.
template <>
class Rooted<JSStableString *>;
#endif
template <typename T>
bool
Return<T>::operator==(const Rooted<T> &other)

View File

@ -0,0 +1,8 @@
// Clearing an empty Map has no effect.
var m = Map();
for (var i = 0; i < 2; i++) {
m.clear();
assertEq(m.size, 0);
assertEq(m.has(undefined), false);
}

View File

@ -0,0 +1,17 @@
// Clearing a Map removes its entries; the Map remains usable afterwards.
var m = Map([["a", "b"], ["b", "c"]]);
assertEq(m.size, 2);
m.clear();
assertEq(m.size, 0);
assertEq(m.has("a"), false);
assertEq(m.get("a"), undefined);
assertEq(m.delete("a"), false);
assertEq(m.has("b"), false);
for (var pair of m)
throw "FAIL"; // shouldn't be any pairs
m.set("c", "d");
assertEq(m.size, 1);
assertEq(m.has("a"), false);
assertEq(m.has("b"), false);

View File

@ -0,0 +1,10 @@
// Clearing a Map with a nontrivial number of elements works.
var m = Map();
for (var i = 0; i < 100; i++)
m.set(i, i);
assertEq(m.size, i);
m.clear();
assertEq(m.size, 0);
m.set("a", 1);
assertEq(m.get("a"), 1);

View File

@ -0,0 +1,10 @@
// Clearing a Map after deleting some entries works.
var m = Map([["a", 1], ["b", 2], ["c", 3], ["d", 4]]);
for (var [k, v] of m)
if (k !== "c")
m.delete(k);
m.clear();
assertEq(m.size, 0);
assertEq(m.has("c"), false);
assertEq(m.has("d"), false);

View File

@ -0,0 +1,14 @@
// Map.clear is unaffected by deleting/monkeypatching Map.prototype.{delete,iterator}.
var data = [["a", 1], ["b", 2]];
var m1 = Map(data), m2 = Map(data);
delete Map.prototype.delete;
delete Map.prototype.iterator;
m1.clear();
assertEq(m1.size, 0);
Map.prototype.delete = function () { throw "FAIL"; };
Map.prototype.iterator = function () { throw "FAIL"; };
m2.clear();
assertEq(m2.size, 0);

View File

@ -0,0 +1,6 @@
// Clearing a Map doesn't affect expando properties.
var m = Map();
m.x = 3;
m.clear();
assertEq(m.x, 3);

View File

@ -0,0 +1,14 @@
// Clearing a Map removes any strong references to its keys and values.
load(libdir + "referencesVia.js");
var m = Map();
var k = {}, v = {};
m.set(k, v);
assertEq(referencesVia(m, "key", k), true);
assertEq(referencesVia(m, "value", v), true);
m.clear();
if (typeof findReferences == 'function') {
assertEq(referencesVia(m, "key", k), false);
assertEq(referencesVia(m, "value", v), false);
}

View File

@ -0,0 +1,23 @@
// A Map iterator does not visit entries removed by clear().
load(libdir + "asserts.js");
var m = Map();
var it = m.iterator();
m.clear();
assertThrowsValue(it.next.bind(it), StopIteration);
m = Map([["a", 1], ["b", 2], ["c", 3], ["d", 4]]);
it = m.iterator();
assertEq(it.next()[0], "a");
m.clear();
assertThrowsValue(it.next.bind(it), StopIteration);
var log = "";
m = Map([["a", 1], ["b", 2], ["c", 3], ["d", 4]]);
for (var [k, v] of m) {
log += k + v;
if (k == "b")
m.clear();
}
assertEq(log, "a1b2");

View File

@ -0,0 +1,15 @@
// A Map iterator continues to visit entries added after a clear().
load(libdir + "asserts.js");
var m = Map([["a", 1]]);
var it = m.iterator();
assertEq(it.next()[0], "a");
m.clear();
m.set("b", 2);
var pair = it.next()
assertEq(pair[0], "b");
assertEq(pair[1], 2);
assertThrowsValue(it.next.bind(it), StopIteration);

View File

@ -1,6 +1,6 @@
// The Map constructor creates an empty Map by default.
assertEq(Map().size(), 0);
assertEq((new Map).size(), 0);
assertEq(Map(undefined).size(), 0);
assertEq(new Map(undefined).size(), 0);
assertEq(Map().size, 0);
assertEq((new Map).size, 0);
assertEq(Map(undefined).size, 0);
assertEq(new Map(undefined).size, 0);

View File

@ -2,7 +2,7 @@
var arr = [["a"], ["b"], ["c"]];
var m = Map(arr);
assertEq(m.size(), 3);
assertEq(m.size, 3);
for (var [k, _] of arr) {
assertEq(m.has(k), true);
assertEq(m.get(k), undefined);

View File

@ -5,4 +5,4 @@ var m = Map(arg);
assertEq(m.get("zero"), 0);
assertEq(m.get("one"), 1);
assertEq(m.get("two"), 2);
assertEq(m.size(), 3);
assertEq(m.size, 3);

View File

@ -12,7 +12,7 @@ function data(n) {
var m = Map(data(50));
assertEq(done, true); // the constructor consumes the argument
assertEq(m.size(), 50);
assertEq(m.size, 50);
assertEq(m.get(""), 0);
assertEq(m.get("....."), 5);
assertEq(m.get(Array(49+1).join(".")), 49);

View File

@ -2,7 +2,7 @@
var arr = [1, 2, "green", "red"];
var m = Map([v, v] for (v of arr));
assertEq(m.size(), 4);
assertEq(m.size, 4);
for (var i = 0; i < 4; i++)
assertEq(m.get(arr[i]), arr[i]);

View File

@ -1,8 +1,8 @@
// The argument to Map may be a generator-iterator that produces no values.
assertEq(Map(x for (x of [])).size(), 0);
assertEq(Map(x for (x of [])).size, 0);
function none() {
if (0) yield 0;
}
assertEq(Map(none()).size(), 0);
assertEq(Map(none()).size, 0);

View File

@ -2,13 +2,13 @@
var m = Map();
m.delete(3);
assertEq(m.size(), 0);
assertEq(m.size, 0);
m.set({}, 'ok');
m.set(Math, 'ok');
assertEq(m.size(), 2);
assertEq(m.size, 2);
m.delete({});
assertEq(m.size(), 2);
assertEq(m.size, 2);
m.delete(Math);
assertEq(m.size(), 1);
assertEq(m.size, 1);
m.delete(Math);
assertEq(m.size(), 1);
assertEq(m.size, 1);

View File

@ -12,4 +12,4 @@ for (let [k, v] of map) {
force(v);
}
assertEq(log, '5;4;3;2;1;0;');
assertEq(map.size(), 6);
assertEq(map.size, 6);

View File

@ -5,7 +5,7 @@ load(libdir + "eqArrayHelper.js");
var map = Map();
for (var i = 7; i !== 1; i = i * 7 % 1117)
map.set("" + i, i);
assertEq(map.size(), 557);
assertEq(map.size, 557);
i = 7;
for (var pair of map) {

View File

@ -9,4 +9,4 @@ assertEq(pair[0], 'b');
assertEq(pair[1], 2);
assertEq(map.get('a'), 1);
assertEq(map.has('b'), false);
assertEq(map.size(), 1);
assertEq(map.size, 1);

View File

@ -18,5 +18,5 @@ for (var [k, v] of map) {
}
}
assertEq(log, 'ABCDEFGHIJKLMNOPQRST');
assertEq(map.size(), 1); // Only the last entry remains.
assertEq(map.size, 1); // Only the last entry remains.
assertEq(map.get('T'), 19);

View File

@ -11,7 +11,7 @@ var iter = map.iterator();
assertEq(iter.next()[0], 0);
for (var i = 0; i < 30; i++)
map.delete(i);
assertEq(map.size(), 2);
assertEq(map.size, 2);
for (var i = 32; i < 100; i++)
map.set(i, i); // eventually triggers compaction

View File

@ -0,0 +1,10 @@
// A closed Map iterator does not visit new entries added after a clear().
load(libdir + "asserts.js");
var m = Map();
var it = m.iterator();
assertThrowsValue(it.next.bind(it), StopIteration); // close the iterator
m.clear();
m.set("a", 1);
assertThrowsValue(it.next.bind(it), StopIteration);

View File

@ -2,13 +2,13 @@
var m = Map();
m.set('a', 0);
assertEq(m.size(), 1);
assertEq(m.size, 1);
m.set('a', 0);
assertEq(m.size(), 1);
assertEq(m.size, 1);
m.set('a', undefined);
assertEq(m.size(), 1);
assertEq(m.size, 1);
m.set('b', 2);
assertEq(m.size(), 2);
assertEq(m.size, 2);
m.set('a', 1);
assertEq(m.size(), 2);
assertEq(m.size, 2);

View File

@ -2,5 +2,5 @@
var m1 = Map(), m2 = Map();
m1.set("x", 3);
assertEq(m1.size(), 1);
assertEq(m2.size(), 0);
assertEq(m1.size, 1);
assertEq(m2.size, 0);

View File

@ -27,8 +27,15 @@ function checkMethod(name, arity) {
assertEq(desc.value.length, arity);
}
checkMethod("size", 0);
checkMethod("get", 1);
checkMethod("has", 1);
checkMethod("set", 2);
checkMethod("delete", 1);
var desc = Object.getOwnPropertyDescriptor(Map.prototype, "size");
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
assertEq(typeof desc.get, 'function');
assertEq(desc.get.length, 0);
assertEq(desc.set, undefined);
checkMethod("clear", 0);

View File

@ -8,12 +8,15 @@ function testcase(obj, fn) {
assertThrowsInstanceOf(function () { fn.apply(obj, args); }, TypeError);
}
var Map_size_getter = Object.getOwnPropertyDescriptor(Map.prototype, "size").get;
function test(obj) {
testcase(obj, Map.prototype.size);
testcase(obj, Map.prototype.get, "x");
testcase(obj, Map.prototype.has, "x");
testcase(obj, Map.prototype.set, "x", 1);
testcase(obj, Map.prototype.delete, "x");
testcase(obj, Map.prototype.clear);
testcase(obj, Map_size_getter);
}
test(Map.prototype);

View File

@ -1,11 +1,11 @@
// set.add(v) increments set.size() iff the set did not already contain v.
// set.add(v) increments set.size iff the set did not already contain v.
var s = Set();
for (var i = 0; i < 10; i++) {
assertEq(s.size(), i);
assertEq(s.size, i);
s.add(i);
}
for (var i = 0; i < 10; i++) {
assertEq(s.size(), 10);
assertEq(s.size, 10);
s.add(i);
}

View File

@ -0,0 +1,8 @@
// Clearing an empty Set has no effect.
var s = Set();
for (var i = 0; i < 2; i++) {
s.clear();
assertEq(s.size, 0);
assertEq(s.has(undefined), false);
}

View File

@ -0,0 +1,16 @@
// Clearing a Set removes its elements; the Set remains usable afterwards.
var s = Set(["x", "y", "z", "z", "y"]);
assertEq(s.size, 3);
s.clear();
assertEq(s.size, 0);
assertEq(s.has("x"), false);
assertEq(s.delete("x"), false);
assertEq(s.has("z"), false);
for (var v of s)
throw "FAIL"; // shouldn't be any elements
s.add("y");
assertEq(s.size, 1);
assertEq(s.has("x"), false);
assertEq(s.has("z"), false);

View File

@ -0,0 +1,10 @@
// Clearing a Set with a nontrivial number of elements works.
var s = Set();
for (var i = 0; i < 100; i++)
s.add(i);
assertEq(s.size, i);
s.clear();
assertEq(s.size, 0);
s.add(12);
assertEq(s.has(12), true);

View File

@ -0,0 +1,10 @@
// Clearing a Set after deleting some entries works.
var s = Set(["a", "b", "c", "d"]);
for (var v of s)
if (v !== "c")
s.delete(v);
s.clear();
assertEq(s.size, 0);
assertEq(s.has("c"), false);
assertEq(s.has("d"), false);

View File

@ -0,0 +1,14 @@
// Set.clear is unaffected by deleting/monkeypatching Set.prototype.{delete,iterator}.
var data = ["a", 1, {}];
var s1 = Set(data), s2 = Set(data);
delete Set.prototype.delete;
delete Set.prototype.iterator;
s1.clear();
assertEq(s1.size, 0);
Set.prototype.delete = function () { throw "FAIL"; };
Set.prototype.iterator = function () { throw "FAIL"; };
s2.clear();
assertEq(s2.size, 0);

View File

@ -0,0 +1,6 @@
// Clearing a Set doesn't affect expando properties.
var s = Set();
s.x = 3;
s.clear();
assertEq(s.x, 3);

View File

@ -0,0 +1,11 @@
// Clearing a Set removes any strong references to its elements.
load(libdir + "referencesVia.js");
var s = Set();
var obj = {};
s.add(obj);
assertEq(referencesVia(s, "key", obj), true);
s.clear();
if (typeof findReferences == 'function')
assertEq(referencesVia(s, "key", obj), false);

View File

@ -0,0 +1,23 @@
// A Set iterator does not visit entries removed by clear().
load(libdir + "asserts.js");
var s = Set();
var it = s.iterator();
s.clear();
assertThrowsValue(it.next.bind(it), StopIteration);
s = Set(["a", "b", "c", "d"]);
it = s.iterator();
assertEq(it.next()[0], "a");
s.clear();
assertThrowsValue(it.next.bind(it), StopIteration);
var log = "";
s = Set(["a", "b", "c", "d"]);
for (var v of s) {
log += v;
if (v == "b")
s.clear();
}
assertEq(log, "ab");

View File

@ -0,0 +1,11 @@
// A Set iterator continues to visit entries added after a clear().
load(libdir + "asserts.js");
var s = Set(["a"]);
var it = s.iterator();
assertEq(it.next(), "a");
s.clear();
s.add("b");
assertEq(it.next(), "b");
assertThrowsValue(it.next.bind(it), StopIteration);

View File

@ -0,0 +1,10 @@
// A closed Set iterator does not visit new entries added after a clear().
load(libdir + "asserts.js");
var s = Set();
var it = s.iterator();
assertThrowsValue(it.next.bind(it), StopIteration); // close the iterator
s.clear();
s.add("a");
assertThrowsValue(it.next.bind(it), StopIteration);

View File

@ -1,6 +1,6 @@
// The Set constructor creates an empty Set by default.
assertEq(Set().size(), 0);
assertEq((new Set).size(), 0);
assertEq(Set(undefined).size(), 0);
assertEq(new Set(undefined).size(), 0);
assertEq(Set().size, 0);
assertEq((new Set).size, 0);
assertEq(Set(undefined).size, 0);
assertEq(new Set(undefined).size, 0);

View File

@ -1,17 +1,17 @@
// The Set constructor can take an argument that is an array.
var s = Set([]);
assertEq(s.size(), 0);
assertEq(s.size, 0);
assertEq(s.has(undefined), false);
s = Set(["one", "two", "three"]);
assertEq(s.size(), 3);
assertEq(s.size, 3);
assertEq(s.has("one"), true);
assertEq(s.has("eleventeen"), false);
var a = [{}, {}, {}];
s = Set(a);
assertEq(s.size(), 3);
assertEq(s.size, 3);
for (let obj of a)
assertEq(s.has(obj), true);
assertEq(s.has({}), false);

View File

@ -1,11 +1,11 @@
// The argument to Set may contain a value multiple times. Duplicates are discarded.
assertEq(Set(["testing", "testing", 123]).size(), 2);
assertEq(Set(["testing", "testing", 123]).size, 2);
var values = [undefined, null, false, NaN, 0, -0, 6.022e23, -Infinity, "", "xyzzy", {}, Math.sin];
for (let v of values) {
var a = [v, {}, {}, {}, v, {}, v, v];
var s = Set(a);
assertEq(s.size(), 5);
assertEq(s.size, 5);
assertEq(s.has(v), true);
}

View File

@ -6,7 +6,7 @@ function hexData(n) {
}
var s = Set(hexData(256));
assertEq(s.size(), 256);
assertEq(s.size, 256);
assertEq(s.has("0"), true);
assertEq(s.has(0), false);
assertEq(s.has("ff"), true);

View File

@ -1,7 +1,7 @@
// The argument to Set can be a generator-expression.
var s = Set(k * k for (k of [1, 2, 3, 4]));
assertEq(s.size(), 4);
assertEq(s.size, 4);
assertEq(s.has(1), true);
assertEq(s.has(4), true);
assertEq(s.has(9), true);

View File

@ -1,15 +1,15 @@
// set.delete(v) decrements set.size() iff the set contained v.
// set.delete(v) decrements set.size iff the set contained v.
var s = Set();
for (var i = 0; i < 10; i++)
s.add(i);
for (var i = 10; i > 0; i--) {
assertEq(s.size(), i);
assertEq(s.size, i);
assertEq(s.delete(i), false);
assertEq(s.size(), i);
assertEq(s.size, i);
assertEq(s.delete(i - 1), true);
assertEq(s.size(), i - 1);
assertEq(s.size, i - 1);
assertEq(s.delete(i - 1), false);
assertEq(s.size(), i - 1);
assertEq(s.size, i - 1);
}

View File

@ -2,7 +2,7 @@
var arr = [{}, {}, {}, [], /xyz/, new Date];
var set = Set(arr);
assertEq(set.size(), arr.length);
assertEq(set.size, arr.length);
var i = 0;
for (var x of set)

View File

@ -8,4 +8,4 @@ for (let x of set) {
set.add(x - 1);
}
assertEq(log, '5;4;3;2;1;0;');
assertEq(set.size(), 6);
assertEq(set.size, 6);

View File

@ -4,7 +4,7 @@ var set = Set();
var i;
for (i = 7; i !== 1; i = i * 7 % 1117)
set.add(i);
assertEq(set.size(), 557);
assertEq(set.size, 557);
i = 7;
for (var v of set) {

View File

@ -18,5 +18,5 @@ for (var x of set) {
}
}
assertEq(log, str);
assertEq(set.size(), 1); // Elements 0 to 24 are removed, leaving only 25 (Z).
assertEq(set.size, 1); // Elements 0 to 24 are removed, leaving only 25 (Z).
assertEq(set.has('Z'), true);

View File

@ -11,7 +11,7 @@ var iter = set.iterator();
assertEq(iter.next(), 0);
for (var i = 0; i < 30; i++)
set.delete(i);
assertEq(set.size(), 2);
assertEq(set.size, 2);
for (var i = 32; i < 100; i++)
set.add(i); // eventually triggers compaction

View File

@ -3,5 +3,5 @@
var s1 = Set(), s2 = Set();
for (var i = 0; i < 30; i++)
s1.add(i);
assertEq(s1.size(), 30);
assertEq(s2.size(), 0);
assertEq(s1.size, 30);
assertEq(s2.size, 0);

View File

@ -30,3 +30,11 @@ function checkMethod(name, arity) {
checkMethod("has", 1);
checkMethod("add", 1);
checkMethod("delete", 1);
var desc = Object.getOwnPropertyDescriptor(Set.prototype, "size");
assertEq(desc.enumerable, false);
assertEq(desc.configurable, true);
assertEq(typeof desc.get, 'function');
assertEq(desc.get.length, 0);
assertEq(desc.set, undefined);
checkMethod("clear", 0);

View File

@ -8,10 +8,14 @@ function testcase(obj, fn) {
assertThrowsInstanceOf(function () { fn.apply(obj, args); }, TypeError);
}
var Set_size_getter = Object.getOwnPropertyDescriptor(Set.prototype, "size").get;
function test(obj) {
testcase(obj, Set.prototype.has, 12);
testcase(obj, Set.prototype.add, 12);
testcase(obj, Set.prototype.delete, 12);
testcase(obj, Set.prototype.clear);
testcase(obj, Set_size_getter);
}
test(Set.prototype);

View File

@ -1,5 +1,7 @@
load(libdir + "asserts.js");
var g = newGlobal('new-compartment');
assertThrowsInstanceOf(function () { Map.prototype.size.apply(g, []); }, g.TypeError);
assertThrowsInstanceOf(function () { Set.prototype.size.apply(g, []); }, g.TypeError);
for (var cls of [Map, Set]) {
var getter = Object.getOwnPropertyDescriptor(cls.prototype, "size").get;
assertThrowsInstanceOf(function () { getter.apply(g, []); }, g.TypeError);
}

View File

@ -0,0 +1,5 @@
eval(" function x() {}" + Array(241).join(" "));
for (var i = 0; i < 100; i++) {
gczeal(4, 2);
String(x);
}

View File

@ -1197,6 +1197,10 @@ class AutoStringRooter : private AutoGCRooter {
return &str;
}
JSString * const * addr() const {
return &str;
}
friend void AutoGCRooter::trace(JSTracer *trc);
private:

View File

@ -201,6 +201,7 @@ typedef struct JSTracer JSTracer;
#ifdef __cplusplus
class JSFlatString;
class JSStableString; // long story
class JSString;
#else
typedef struct JSFlatString JSFlatString;

View File

@ -43,12 +43,6 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
LAST_USED_FLAG = CROSS_COMPARTMENT
};
typedef enum {
PermitObjectAccess,
PermitPropertyAccess,
DenyAccess
} Permission;
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *proto,
JSObject *parent, Wrapper *handler);

View File

@ -557,6 +557,64 @@ class JSStableString : public JSFlatString
JS_STATIC_ASSERT(sizeof(JSStableString) == sizeof(JSString));
#if !(defined(JSGC_ROOT_ANALYSIS) || defined(JSGC_USE_EXACT_ROOTING))
namespace js {
/*
* Specialization of Rooted<T> to explicitly root the string rather than
* relying on conservative stack scanning.
*
* In exact-gc builds, Rooted<T> already keeps the T reachable, so this hack is
* ifdef'd out. In non-exact-gc builds, conservative scanning would ordinarily
* pick up the slack. However in the case where the Rooted pointer is no longer
* used, but some subobject or malloc'd memory with the same lifetime may be
* used, conservative scanning can fail. JSStableString's chars() method makes
* it particularly attractive to use that way, so we explicitly keep the
* JSString gc-reachable for the full lifetime of the Rooted<JSStableString *>.
*
* It would suffice simply to force the pointer to remain on the stack, a la
* JS::Anchor<T>, but for some reason using that voodoo here seems to cause
* some compilers (clang, VC++ with PGO) to generate incorrect code.
*/
template <>
class Rooted<JSStableString *>
{
public:
Rooted(JSContext *cx, JSStableString *initial = NULL
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
: rooter(cx, initial)
{
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
}
operator JSStableString *() const { return get(); }
JSStableString * operator ->() const { return get(); }
JSStableString ** address() { return reinterpret_cast<JSStableString **>(rooter.addr()); }
JSStableString * const * address() const {
return reinterpret_cast<JSStableString * const *>(rooter.addr());
}
JSStableString * get() const { return static_cast<JSStableString *>(rooter.string()); }
Rooted & operator =(JSStableString *value)
{
JS_ASSERT(!RootMethods<JSStableString *>::poisoned(value));
rooter.setString(value);
return *this;
}
Rooted & operator =(const Rooted &value)
{
rooter.setString(value.get());
return *this;
}
private:
JS::AutoStringRooter rooter;
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
Rooted(const Rooted &) MOZ_DELETE;
};
}
#endif
class JSExtensibleString : public JSFlatString
{
/* Vacuous and therefore unimplemented. */

View File

@ -1,5 +1,6 @@
const Cu = Components.utils;
function run_test() {
var Cu = Components.utils;
var sb1 = Cu.Sandbox("http://www.blah.com");
var sb2 = Cu.Sandbox("http://www.blah.com");
var sb3 = Cu.Sandbox(this);
@ -13,25 +14,19 @@ function run_test() {
// non-chrome accessing chrome Components
sb1.C = Components;
rv = Cu.evalInSandbox("C.utils", sb1);
do_check_eq(rv, undefined);
rv = Cu.evalInSandbox("C.interfaces", sb1);
do_check_neq(rv, undefined);
checkThrows("C.utils", sb1);
checkThrows("C.classes", sb1);
// non-chrome accessing own Components
rv = Cu.evalInSandbox("Components.utils", sb1);
do_check_eq(rv, undefined);
rv = Cu.evalInSandbox("Components.interfaces", sb1);
do_check_neq(rv, undefined);
checkThrows("Components.utils", sb1);
checkThrows("Components.classes", sb1);
// non-chrome same origin
var C2 = Cu.evalInSandbox("Components", sb2);
do_check_neq(rv, C2.utils);
do_check_neq(rv, C2.utils);
sb1.C2 = C2;
rv = Cu.evalInSandbox("C2.utils", sb1);
do_check_eq(rv, undefined);
rv = Cu.evalInSandbox("C2.interfaces", sb1);
do_check_neq(rv, undefined);
checkThrows("C2.utils", sb1);
checkThrows("C2.classes", sb1);
// chrome accessing chrome
sb3.C = Components;
@ -40,9 +35,11 @@ function run_test() {
// non-chrome cross origin
sb4.C2 = C2;
rv = Cu.evalInSandbox("C2.interfaces", sb1);
do_check_neq(rv, undefined);
rv = Cu.evalInSandbox("C2.utils", sb1);
do_check_eq(rv, undefined);
checkThrows("C2.utils", sb1);
checkThrows("C2.classes", sb1);
}
function checkThrows(expression, sb) {
var result = Cu.evalInSandbox('(function() { try { ' + expression + '; return "allowed"; } catch (e) { return e.toString(); }})();', sb);
do_check_true(!!/denied/.exec(result));
}

View File

@ -329,17 +329,6 @@ AccessCheck::deny(JSContext *cx, jsid id)
enum Access { READ = (1<<0), WRITE = (1<<1), NO_ACCESS = 0 };
static bool
Deny(JSContext *cx, jsid id, Wrapper::Action act)
{
// Refuse to perform the action and just return the default value.
if (act == Wrapper::GET)
return true;
// If its a set, deny it and throw an exception.
AccessCheck::deny(cx, id);
return false;
}
static bool
IsInSandbox(JSContext *cx, JSObject *obj)
{
@ -349,19 +338,15 @@ IsInSandbox(JSContext *cx, JSObject *obj)
}
bool
ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act,
Permission &perm)
ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act)
{
JSObject *wrappedObject = Wrapper::wrappedObject(wrapper);
if (act == Wrapper::CALL) {
perm = PermitObjectAccess;
if (act == Wrapper::CALL)
return true;
}
perm = DenyAccess;
if (act == Wrapper::PUNCTURE)
return Deny(cx, id, act);
return false;
jsid exposedPropsId = GetRTIdByIndex(cx, XPCJSRuntime::IDX_EXPOSEDPROPS);
@ -380,7 +365,6 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
JS_IsTypedArrayObject(wrappedObject, cx)) &&
((JSID_IS_INT(id) && JSID_TO_INT(id) >= 0) ||
(JSID_IS_STRING(id) && JS_FlatStringEqualsAscii(JSID_TO_FLAT_STRING(id), "length")))) {
perm = PermitPropertyAccess;
return true; // Allow
}
@ -405,26 +389,20 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
}
}
perm = PermitPropertyAccess;
return true;
}
return Deny(cx, id, act);
return false;
}
if (id == JSID_VOID) {
// This will force the caller to call us back for individual property accesses.
perm = PermitPropertyAccess;
if (id == JSID_VOID)
return true;
}
JS::Value exposedProps;
if (!JS_LookupPropertyById(cx, wrappedObject, exposedPropsId, &exposedProps))
return false;
if (exposedProps.isNullOrUndefined()) {
JSAutoCompartment wrapperAC(cx, wrapper);
return Deny(cx, id, act);
}
if (exposedProps.isNullOrUndefined())
return false;
if (!exposedProps.isObject()) {
JS_ReportError(cx, "__exposedProps__ must be undefined, null, or an Object");
@ -440,10 +418,8 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
if (!JS_GetPropertyDescriptorById(cx, hallpass, id, JSRESOLVE_QUALIFIED, &desc)) {
return false; // Error
}
if (desc.obj == NULL || !(desc.attrs & JSPROP_ENUMERATE)) {
JSAutoCompartment wrapperAC(cx, wrapper);
return Deny(cx, id, act);
}
if (!desc.obj || !(desc.attrs & JSPROP_ENUMERATE))
return false;
if (!JSVAL_IS_STRING(desc.value)) {
JS_ReportError(cx, "property must be a string");
@ -487,19 +463,15 @@ ExposedPropertiesOnly::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper:
if ((act == Wrapper::SET && !(access & WRITE)) ||
(act != Wrapper::SET && !(access & READ))) {
JSAutoCompartment wrapperAC(cx, wrapper);
return Deny(cx, id, act);
return false;
}
perm = PermitPropertyAccess;
return true; // Allow
return true;
}
bool
ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act,
Permission &perm)
ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper::Action act)
{
perm = DenyAccess;
JSAutoCompartment ac(cx, wrapper);
if (JSID_IS_STRING(id) && act == Wrapper::GET) {
@ -510,7 +482,6 @@ ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper
JS_FlatStringEqualsAscii(flatId, "interfacesByID") ||
JS_FlatStringEqualsAscii(flatId, "results"))
{
perm = PermitPropertyAccess;
return true;
}
}
@ -519,11 +490,10 @@ ComponentsObjectPolicy::check(JSContext *cx, JSObject *wrapper, jsid id, Wrapper
// so we need this dynamic check. This can go away when we expose Components
// as SpecialPowers.wrap(Components) during automation.
if (xpc::IsUniversalXPConnectEnabled(cx)) {
perm = PermitPropertyAccess;
return true;
}
return Deny(cx, id, act);
return false;
}
}

View File

@ -39,33 +39,16 @@ class AccessCheck {
};
struct Policy {
typedef js::Wrapper::Permission Permission;
static const Permission PermitObjectAccess = js::Wrapper::PermitObjectAccess;
static const Permission PermitPropertyAccess = js::Wrapper::PermitPropertyAccess;
static const Permission DenyAccess = js::Wrapper::DenyAccess;
};
// This policy permits access to all properties.
struct Permissive : public Policy {
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act,
Permission &perm) {
perm = PermitObjectAccess;
return true;
}
};
// This policy only permits access to the object if the subject can touch
// system objects.
struct OnlyIfSubjectIsSystem : public Policy {
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act,
Permission &perm) {
if (AccessCheck::isSystemOnlyAccessPermitted(cx)) {
perm = PermitObjectAccess;
return true;
}
perm = DenyAccess;
JSAutoCompartment ac(cx, wrapper);
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
return AccessCheck::isSystemOnlyAccessPermitted(cx);
}
static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
AccessCheck::deny(cx, id);
return false;
}
@ -74,17 +57,12 @@ struct OnlyIfSubjectIsSystem : public Policy {
// This policy only permits access to properties that are safe to be used
// across origins.
struct CrossOriginAccessiblePropertiesOnly : public Policy {
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act,
Permission &perm) {
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
// Location objects should always use LocationPolicy.
MOZ_ASSERT(!WrapperFactory::IsLocationObject(js::UnwrapObject(wrapper)));
if (AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act)) {
perm = PermitPropertyAccess;
return true;
}
perm = DenyAccess;
JSAutoCompartment ac(cx, wrapper);
return AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act);
}
static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
AccessCheck::deny(cx, id);
return false;
}
@ -114,23 +92,19 @@ struct CrossOriginAccessiblePropertiesOnly : public Policy {
// state of the outer window to determine whether we happen to be same-origin
// at the moment.
struct LocationPolicy : public Policy {
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act,
Permission &perm) {
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act) {
// We should only be dealing with Location objects here.
MOZ_ASSERT(WrapperFactory::IsLocationObject(js::UnwrapObject(wrapper)));
// Default to deny.
perm = DenyAccess;
// Location object security is complicated enough. Don't allow punctures.
if (act != js::Wrapper::PUNCTURE &&
(AccessCheck::isCrossOriginAccessPermitted(cx, wrapper, id, act) ||
AccessCheck::isLocationObjectSameOrigin(cx, wrapper))) {
perm = PermitPropertyAccess;
return true;
}
JSAutoCompartment ac(cx, wrapper);
return false;
}
static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
AccessCheck::deny(cx, id);
return false;
}
@ -139,14 +113,26 @@ struct LocationPolicy : public Policy {
// This policy only permits access to properties if they appear in the
// objects exposed properties list.
struct ExposedPropertiesOnly : public Policy {
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act,
Permission &perm);
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act);
static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
// For gets, silently fail.
if (act == js::Wrapper::GET)
return true;
// For sets,throw an exception.
AccessCheck::deny(cx, id);
return false;
}
};
// Components specific policy
struct ComponentsObjectPolicy : public Policy {
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act,
Permission &perm);
static bool check(JSContext *cx, JSObject *wrapper, jsid id, js::Wrapper::Action act);
static bool deny(JSContext *cx, jsid id, js::Wrapper::Action act) {
AccessCheck::deny(cx, id);
return false;
}
};
}

View File

@ -29,12 +29,6 @@ FilteringWrapper<Base, Policy>::~FilteringWrapper()
{
}
typedef Wrapper::Permission Permission;
static const Permission PermitObjectAccess = Wrapper::PermitObjectAccess;
static const Permission PermitPropertyAccess = Wrapper::PermitPropertyAccess;
static const Permission DenyAccess = Wrapper::DenyAccess;
template <typename Policy>
static bool
Filter(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
@ -42,11 +36,10 @@ Filter(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
size_t w = 0;
for (size_t n = 0; n < props.length(); ++n) {
jsid id = props[n];
Permission perm;
if (!Policy::check(cx, wrapper, id, Wrapper::GET, perm))
return false; // Error
if (perm != DenyAccess)
if (Policy::check(cx, wrapper, id, Wrapper::GET))
props[w++] = id;
else if (JS_IsExceptionPending(cx))
return false;
}
props.resize(w);
return true;
@ -92,14 +85,16 @@ bool
FilteringWrapper<Base, Policy>::enter(JSContext *cx, JSObject *wrapper, jsid id,
Wrapper::Action act, bool *bp)
{
Permission perm;
if (!Policy::check(cx, wrapper, id, act, perm)) {
*bp = false;
if (!Policy::check(cx, wrapper, id, act)) {
if (JS_IsExceptionPending(cx)) {
*bp = false;
return false;
}
JSAutoCompartment ac(cx, wrapper);
*bp = Policy::deny(cx, id, act);
return false;
}
*bp = true;
if (perm == DenyAccess)
return false;
return Base::enter(cx, wrapper, id, act, bp);
}

View File

@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait">
<path id="path"/>
<text>
<textPath xlink:href="#path">f</textPath>
<textPath xlink:href="#path">f</textPath>
</text>
<script>
function boom()
{
var path = document.getElementById("path");
path.parentNode.removeChild(path);
document.documentElement.removeAttribute("class");
}
window.addEventListener("load", boom, false);
</script>
</svg>

After

Width:  |  Height:  |  Size: 493 B

View File

@ -0,0 +1,8 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<path id="path" d="M0 100 h50" stroke="black"/>
<text>
<textPath xlink:href="#path">abc</textPath>
<textPath xlink:href="#path">def</textPath>
</text>
</svg>

After

Width:  |  Height:  |  Size: 261 B

View File

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg"
class="reftest-wait">
<defs><path id="x"/></defs>
<script>
function boom()
{
document.getElementById("x").style.transform = "translate(0px)";
document.documentElement.removeAttribute("class");
}
window.addEventListener("load", boom, false);
</script>
</svg>

After

Width:  |  Height:  |  Size: 315 B

View File

@ -106,6 +106,8 @@ load 610594-1.html
load 610954-1.html
load 612662-1.svg
load 612662-2.svg
load 612736-1.svg
load 612736-2.svg
load 614367-1.svg
load 620034-1.html
load 621598-1.svg
@ -134,6 +136,6 @@ load 767056-1.svg
load 768351.svg
load 780963-1.html
load 757751-1.svg
load 784061-1.svg
load 790072.svg
load 791826-1.svg

View File

@ -223,6 +223,7 @@ abstract public class BrowserApp extends GeckoApp
registerEventListener("Feedback:OpenPlayStore");
registerEventListener("Feedback:MaybeLater");
registerEventListener("Dex:Load");
registerEventListener("Telemetry:Gather");
}
@Override
@ -237,6 +238,7 @@ abstract public class BrowserApp extends GeckoApp
unregisterEventListener("Feedback:OpenPlayStore");
unregisterEventListener("Feedback:MaybeLater");
unregisterEventListener("Dex:Load");
unregisterEventListener("Telemetry:Gather");
}
@Override
@ -428,6 +430,11 @@ abstract public class BrowserApp extends GeckoApp
menu.findItem(R.id.settings).setEnabled(true);
}
});
} else if (event.equals("Telemetry:Gather")) {
Telemetry.HistogramAdd("PLACES_PAGES_COUNT", BrowserDB.getCount(getContentResolver(), "history"));
Telemetry.HistogramAdd("PLACES_BOOKMARKS_COUNT", BrowserDB.getCount(getContentResolver(), "bookmarks"));
Telemetry.HistogramAdd("FENNEC_FAVICONS_COUNT", BrowserDB.getCount(getContentResolver(), "favicons"));
Telemetry.HistogramAdd("FENNEC_THUMBNAILS_COUNT", BrowserDB.getCount(getContentResolver(), "thumbnails"));
} else if (event.equals("Dex:Load")) {
String zipFile = message.getString("zipfile");
String implClass = message.getString("impl");

View File

@ -90,6 +90,8 @@ public class BrowserDB {
public void registerBookmarkObserver(ContentResolver cr, ContentObserver observer);
public void registerHistoryObserver(ContentResolver cr, ContentObserver observer);
public int getCount(ContentResolver cr, String database);
}
static {
@ -227,4 +229,8 @@ public class BrowserDB {
public static void unregisterContentObserver(ContentResolver cr, ContentObserver observer) {
cr.unregisterContentObserver(observer);
}
public static int getCount(ContentResolver cr, String database) {
return sDb.getCount(cr, database);
}
}

View File

@ -177,6 +177,38 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
return new LocalDBCursor(c);
}
public int getCount(ContentResolver cr, String database) {
Cursor cursor = null;
int count = 0;
String constraint = null;
try {
Uri uri = null;
if ("history".equals(database)) {
uri = mHistoryUriWithProfile;
constraint = Combined.VISITS + " > 0";
} else if ("bookmarks".equals(database)) {
uri = mBookmarksUriWithProfile;
// ignore folders, tags, keywords, separators, etc.
constraint = Bookmarks.TYPE + " = " + Bookmarks.TYPE_BOOKMARK;
} else if ("thumbnails".equals(database)) {
uri = mImagesUriWithProfile;
constraint = Combined.THUMBNAIL + " IS NOT NULL";
} else if ("favicons".equals(database)) {
uri = mImagesUriWithProfile;
constraint = Combined.FAVICON + " IS NOT NULL";
}
if (uri != null) {
cursor = cr.query(uri, null, constraint, null, null);
count = cursor.getCount();
}
} finally {
if (cursor != null)
cursor.close();
}
debug("Got count " + count + " for " + database);
return count;
}
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
return filterAllSites(cr,
new String[] { Combined._ID,

View File

@ -184,6 +184,7 @@ var BrowserApp = {
Services.obs.addObserver(this, "Passwords:Init", false);
Services.obs.addObserver(this, "FormHistory:Init", false);
Services.obs.addObserver(this, "ToggleProfiling", false);
Services.obs.addObserver(this, "gather-telemetry", false);
Services.obs.addObserver(this, "sessionstore-state-purge-complete", false);
@ -1145,6 +1146,8 @@ var BrowserApp = {
} else {
profiler.StartProfiler(100000, 25, ["stackwalk"], 1);
}
} else if (aTopic == "gather-telemetry") {
sendMessageToJava({ gecko: { type: "Telemetry:Gather" }});
} else if (aTopic == "Session:Restore") {
let data = JSON.parse(aData);
this.restoreSession(data.restoringOOM, data.sessionString);

View File

@ -158,7 +158,7 @@ add_test(function test_invalid_request_method() {
allowed.add(method);
}
do_check_eq(allowed.size(), 3);
do_check_eq(allowed.size, 3);
for (let method of ["GET", "PUT", "DELETE"]) {
do_check_true(allowed.has(method));
}

View File

@ -2,7 +2,7 @@
* 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/. */
var EXPORTED_SYMBOLS = ["MockPermissionPrompt"];
this.EXPORTED_SYMBOLS = ["MockPermissionPrompt"];
const Cc = Components.classes;
const Ci = Components.interfaces;

View File

@ -131,7 +131,7 @@ var inMemoryPrefsProto = {
if (this._prefCache[aGroup].has(aName)) {
this._prefCache[aGroup].delete(aName);
if (this._prefCache[aGroup].size() == 0) {
if (this._prefCache[aGroup].size == 0) {
// remove empty group
delete this._prefCache[aGroup];
}

View File

@ -1754,6 +1754,20 @@
"n_buckets": 10,
"description": "PLACES: Number of keywords"
},
"FENNEC_FAVICONS_COUNT": {
"kind": "exponential",
"high": "2000",
"n_buckets": 10,
"cpp_guard": "ANDROID",
"description": "FENNEC: (Places) Number of favicons stored"
},
"FENNEC_THUMBNAILS_COUNT": {
"kind": "exponential",
"high": "2000",
"n_buckets": 10,
"cpp_guard": "ANDROID",
"description": "FENNEC: (Places) Number of thumbnails stored"
},
"PLACES_SORTED_BOOKMARKS_PERC": {
"kind": "linear",
"high": "100",

View File

@ -36,7 +36,7 @@ function dumpn(str)
let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader);
loader.loadSubScript("chrome://global/content/devtools/dbg-transport.js");
loader.loadSubScript("chrome://global/content/devtools/dbg-transport.js", this);
/**
* Add simple event notification to a prototype object. Any object that has

View File

@ -5,7 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
Cu.import("resource://gre/modules/NetUtil.jsm");
Components.utils.import("resource://gre/modules/NetUtil.jsm");
/**
* An adapter that handles data transfers between the debugger client and

View File

@ -18,6 +18,15 @@
return false;
}
function CcDenied() {
try {
Components.classes;
return false;
} catch (e) {
return !!/denied/.exec(e);
}
}
// Build an object with test results (true = pass)
let results = {
windowTop: window.top == window,
@ -28,7 +37,7 @@
.docCharsetIsForced;
}),
ccAccess: SpecialPowers.Components.classes == null,
ccAccess: !!CcDenied(),
};
let resultsJSON = JSON.stringify(results);

View File

@ -78,9 +78,9 @@ nsPluginInstallerWizard.prototype.pluginInfoReceived = function (aPluginRequestI
progressMeter.setAttribute("mode", "determined");
progressMeter.setAttribute("value",
((this.WSPluginCounter / this.mPluginRequests.size()) * 100) + "%");
((this.WSPluginCounter / this.mPluginRequests.size) * 100) + "%");
if (this.WSPluginCounter == this.mPluginRequests.size()) {
if (this.WSPluginCounter == this.mPluginRequests.size) {
// check if no plugins were found
if (this.mPluginInfoArrayLength == 0) {
this.advancePage("lastpage");

View File

@ -134,7 +134,7 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
{
function test(aTest)
{
function moveFocus(aTest)
function moveFocus(aTest, aFocusEventHandler)
{
if (aInDesignMode) {
if (document.activeElement) {
@ -149,10 +149,14 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
}
var previousFocusedElement = gFM.focusedElement;
var element = document.getElementById(aTest.id);
var focusEventTarget = element;
if (element.contentDocument) {
focusEventTarget = element.contentDocument;
element = element.contentDocument.documentElement;
}
focusEventTarget.addEventListener("focus", aFocusEventHandler, true);
element.focus();
focusEventTarget.removeEventListener("focus", aFocusEventHandler, true);
var focusedElement = gFM.focusedElement;
if (focusedElement) {
var bindingParent = document.getBindingParent(focusedElement);
@ -186,9 +190,28 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
// IME Enabled state testing
var enabled = gUtils.IME_STATUS_ENABLED;
if (kIMEEnabledSupported) {
if (!moveFocus(aTest)) {
var focusEventCount = 0;
function onFocus(aEvent)
{
focusEventCount++;
is(gUtils.IMEStatus, aTest.expectedEnabled,
aDescription + ": " + aTest.description + ", wrong enabled state at focus event");
}
if (!moveFocus(aTest, onFocus)) {
return;
}
if (aTest.focusable) {
if (aTest.focusEventNotFired) {
todo(focusEventCount > 0,
aDescription + ": " + aTest.description + ", focus event is never fired");
} else {
ok(focusEventCount > 0,
aDescription + ": " + aTest.description + ", focus event is never fired");
}
}
enabled = gUtils.IMEStatus;
inputtype = gUtils.focusedInputType;
is(enabled, aTest.expectedEnabled,
@ -254,10 +277,12 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
{ id: "checkbox",
description: "input[type=checkbox]",
focusable: !aInDesignMode,
focusEventNotFired: aIsEditable && !aInDesignMode,
expectedEnabled: kEnabledStateOnNonEditableElement },
{ id: "radio",
description: "input[type=radio]",
focusable: !aInDesignMode,
focusEventNotFired: aIsEditable && !aInDesignMode,
expectedEnabled: kEnabledStateOnNonEditableElement },
{ id: "submit",
description: "input[type=submit]",
@ -270,6 +295,7 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
{ id: "file",
description: "input[type=file]",
focusable: !aInDesignMode,
focusEventNotFired: aIsEditable && !aInDesignMode,
expectedEnabled: kEnabledStateOnNonEditableElement },
{ id: "button",
description: "input[type=button]",
@ -321,10 +347,12 @@ function runBasicTest(aIsEditable, aInDesignMode, aDescription)
{ id: "select",
description: "select (dropdown list)",
focusable: !aInDesignMode,
focusEventNotFired: aIsEditable && !aInDesignMode,
expectedEnabled: kEnabledStateOnNonEditableElement },
{ id: "select_multiple",
description: "select (list box)",
focusable: !aInDesignMode,
focusEventNotFired: aIsEditable && !aInDesignMode,
expectedEnabled: kEnabledStateOnNonEditableElement },
// a element

Some files were not shown because too many files have changed in this diff Show More