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

This commit is contained in:
Ryan VanderMeulen 2015-04-28 15:43:20 -04:00
commit 1241218f33
134 changed files with 2068 additions and 1752 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="bdd03caf084e1b9279155bd232bc718a38c47cbc"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="bdd03caf084e1b9279155bd232bc718a38c47cbc"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "e5c1905b0144a855537fd857d62ec7a3393bb334",
"git_revision": "6e35b0948c42a4398b8a5916015de167121683a1",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "97f0671809608b83775857fce9a7f7eba056d5d3",
"revision": "14e42674734ab45c745a6b431cac067fab6f7a77",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="bdd03caf084e1b9279155bd232bc718a38c47cbc"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="e5c1905b0144a855537fd857d62ec7a3393bb334"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="6e35b0948c42a4398b8a5916015de167121683a1"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -734,7 +734,6 @@ BrowserGlue.prototype = {
LightweightThemeManager.addBuiltInTheme({
id: "firefox-devedition@mozilla.org",
name: themeName,
accentcolor: "transparent",
headerURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.header.png",
iconURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.icon.png",
author: vendorShortName,

View File

@ -1415,6 +1415,8 @@ WebConsoleFrame.prototype = {
let severity = 'error';
if (aScriptError.warning || aScriptError.strict) {
severity = 'warning';
} else if (aScriptError.info) {
severity = 'log';
}
let category = 'js';

View File

@ -8954,11 +8954,8 @@ dnl ========================================================
# builds. Bugs to enable:
#
# Android: bug 864843
# B2G: bug 866301
if test "$MOZ_WIDGET_TOOLKIT" = "android" ||
test "$MOZ_BUILD_APP" = "b2g" ||
test "$MOZ_BUILD_APP" = "b2g/dev"; then
if test "$MOZ_WIDGET_TOOLKIT" = "android"; then
_INTL_API=no
else
_INTL_API=yes

View File

@ -497,7 +497,21 @@ enum BluetoothHandsfreeWbsConfig {
};
class BluetoothSignal;
typedef mozilla::Observer<BluetoothSignal> BluetoothSignalObserver;
class BluetoothSignalObserver : public mozilla::Observer<BluetoothSignal>
{
public:
BluetoothSignalObserver() : mSignalRegistered(false)
{ }
void SetSignalRegistered(bool aSignalRegistered)
{
mSignalRegistered = aSignalRegistered;
}
protected:
bool mSignalRegistered;
};
// Enums for object types, currently used for shared function lookups
// (get/setproperty, etc...). Possibly discernable via dbus paths, but this

View File

@ -96,6 +96,34 @@ GeneratePathFromGattId(const BluetoothGattId& aId,
GeneratePathFromGattId(aId, aPath, uuidStr);
}
void
RegisterBluetoothSignalHandler(const nsAString& aPath,
BluetoothSignalObserver* aHandler)
{
MOZ_ASSERT(!aPath.IsEmpty());
MOZ_ASSERT(aHandler);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->RegisterBluetoothSignalHandler(aPath, aHandler);
aHandler->SetSignalRegistered(true);
}
void
UnregisterBluetoothSignalHandler(const nsAString& aPath,
BluetoothSignalObserver* aHandler)
{
MOZ_ASSERT(!aPath.IsEmpty());
MOZ_ASSERT(aHandler);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->UnregisterBluetoothSignalHandler(aPath, aHandler);
aHandler->SetSignalRegistered(false);
}
/**
* |SetJsObject| is an internal function used by |BroadcastSystemMessage| only
*/

View File

@ -77,6 +77,32 @@ void
GeneratePathFromGattId(const BluetoothGattId& aId,
nsAString& aPath);
//
// Register/Unregister bluetooth signal handlers
//
/**
* Register the bluetooth signal handler.
*
* @param aPath Path of the signal to be registered.
* @param aHandler The message handler object to be added into the observer
* list. Note that this function doesn't take references to it.
*/
void
RegisterBluetoothSignalHandler(const nsAString& aPath,
BluetoothSignalObserver* aHandler);
/**
* Unregister the bluetooth signal handler.
*
* @param aPath Path of the signal to be unregistered.
* @param aHandler The message handler object to be removed from the observer
* list. Note that this function doesn't take references to it.
*/
void
UnregisterBluetoothSignalHandler(const nsAString& aPath,
BluetoothSignalObserver* aHandler);
//
// Broadcast system message
//

View File

@ -43,7 +43,7 @@ EnsureBluetoothSocketHalLoad()
}
class mozilla::dom::bluetooth::DroidSocketImpl : public ipc::UnixFdWatcher
, protected SocketIOBase
, protected DataSocketIO
{
public:
/* The connection status in DroidSocketImpl indicates the current
@ -75,7 +75,6 @@ public:
DroidSocketImpl(MessageLoop* aIOLoop, BluetoothSocket* aConsumer)
: ipc::UnixFdWatcher(aIOLoop)
, SocketIOBase(MAX_READ_SIZE)
, mConsumer(aConsumer)
, mShuttingDownOnIOThread(false)
, mConnectionStatus(SOCKET_IS_DISCONNECTED)
@ -135,16 +134,28 @@ public:
AddWatchers(WRITE_WATCHER, false);
}
SocketConsumerBase* GetConsumer()
BluetoothSocket* GetBluetoothSocket()
{
return mConsumer.get();
}
DataSocket* GetDataSocket()
{
return GetBluetoothSocket();
}
SocketBase* GetSocketBase()
{
return GetConsumer();
return GetDataSocket();
}
// Methods for |DataSocket|
//
nsresult QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer);
void ConsumeBuffer();
void DiscardBuffer();
/**
* Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
* directly from main thread. All non-main-thread accesses should happen with
@ -153,6 +164,8 @@ public:
RefPtr<BluetoothSocket> mConsumer;
private:
class ReceiveRunnable;
/**
* libevent triggered functions that reads data from socket when available and
* guarenteed non-blocking. Only to be called on IO thread.
@ -180,6 +193,11 @@ private:
bool mShuttingDownOnIOThread;
ConnectionStatus mConnectionStatus;
/**
* I/O buffer for received data
*/
nsAutoPtr<UnixSocketRawData> mBuffer;
};
class SocketConnectTask final : public SocketIOTask<DroidSocketImpl>
@ -492,6 +510,69 @@ DroidSocketImpl::OnSocketCanConnectWithoutBlocking(int aFd)
}
}
nsresult
DroidSocketImpl::QueryReceiveBuffer(
UnixSocketIOBuffer** aBuffer)
{
MOZ_ASSERT(aBuffer);
if (!mBuffer) {
mBuffer = new UnixSocketRawData(MAX_READ_SIZE);
}
*aBuffer = mBuffer.get();
return NS_OK;
}
/**
* |ReceiveRunnable| transfers data received on the I/O thread
* to an instance of |BluetoothSocket| on the main thread.
*/
class DroidSocketImpl::ReceiveRunnable final
: public SocketIORunnable<DroidSocketImpl>
{
public:
ReceiveRunnable(DroidSocketImpl* aIO, UnixSocketBuffer* aBuffer)
: SocketIORunnable<DroidSocketImpl>(aIO)
, mBuffer(aBuffer)
{ }
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
DroidSocketImpl* io = SocketIORunnable<DroidSocketImpl>::GetIO();
if (NS_WARN_IF(io->IsShutdownOnMainThread())) {
// Since we've already explicitly closed and the close
// happened before this, this isn't really an error.
return NS_OK;
}
BluetoothSocket* bluetoothSocket = io->GetBluetoothSocket();
MOZ_ASSERT(bluetoothSocket);
bluetoothSocket->ReceiveSocketData(mBuffer);
return NS_OK;
}
private:
nsAutoPtr<UnixSocketBuffer> mBuffer;
};
void
DroidSocketImpl::ConsumeBuffer()
{
NS_DispatchToMainThread(new ReceiveRunnable(this, mBuffer.forget()));
}
void
DroidSocketImpl::DiscardBuffer()
{
// Nothing to do.
}
BluetoothSocket::BluetoothSocket(BluetoothSocketObserver* aObserver,
BluetoothSocketType aType,
bool aAuth,

View File

@ -8,7 +8,7 @@
#define mozilla_dom_bluetooth_BluetoothSocket_h
#include "BluetoothCommon.h"
#include "mozilla/ipc/SocketBase.h"
#include "mozilla/ipc/DataSocket.h"
BEGIN_BLUETOOTH_NAMESPACE
@ -16,7 +16,7 @@ class BluetoothSocketObserver;
class BluetoothSocketResultHandler;
class DroidSocketImpl;
class BluetoothSocket : public mozilla::ipc::SocketConsumerBase
class BluetoothSocket : public mozilla::ipc::DataSocket
{
public:
BluetoothSocket(BluetoothSocketObserver* aObserver,
@ -34,13 +34,19 @@ public:
void CloseSocket() override;
/**
* Method to be called whenever data is received. This is only called on the
* main thread.
*
* @param aBuffer Data received from the socket.
*/
void ReceiveSocketData(nsAutoPtr<mozilla::ipc::UnixSocketBuffer>& aBuffer);
void SendSocketData(mozilla::ipc::UnixSocketIOBuffer* aBuffer) override;
virtual void OnConnectSuccess() override;
virtual void OnConnectError() override;
virtual void OnDisconnect() override;
virtual void ReceiveSocketData(
nsAutoPtr<mozilla::ipc::UnixSocketBuffer>& aBuffer) override;
inline void GetAddress(nsAString& aDeviceAddress)
{

View File

@ -37,8 +37,8 @@ class BluetoothService;
* BluetoothParent
******************************************************************************/
class BluetoothParent : public PBluetoothParent,
public mozilla::Observer<BluetoothSignal>
class BluetoothParent : public PBluetoothParent
, public BluetoothSignalObserver
{
friend class mozilla::dom::ContentParent;

View File

@ -6,6 +6,7 @@
#include "BluetoothReplyRunnable.h"
#include "BluetoothService.h"
#include "BluetoothUtils.h"
#include "DOMRequest.h"
#include "nsIDocument.h"
#include "nsIPrincipal.h"
@ -29,9 +30,30 @@ using namespace mozilla::dom;
USING_BLUETOOTH_NAMESPACE
NS_IMPL_CYCLE_COLLECTION_INHERITED(BluetoothAdapter, DOMEventTargetHelper,
mDevices, mDiscoveryHandleInUse,
mPairingReqs)
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDevices)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDiscoveryHandleInUse)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPairingReqs)
/**
* Unregister the bluetooth signal handler after unlinked.
*
* This is needed to avoid ending up with exposing a deleted object to JS or
* accessing deleted objects while receiving signals from parent process
* after unlinked. Please see Bug 1138267 for detail informations.
*/
UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDevices)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDiscoveryHandleInUse)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPairingReqs)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
// QueryInterface implementation for BluetoothAdapter
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter)
@ -210,17 +232,12 @@ BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
SetPropertyByValue(values[i]);
}
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
}
BluetoothAdapter::~BluetoothAdapter()
{
BluetoothService* bs = BluetoothService::Get();
// We can be null on shutdown, where this might happen
NS_ENSURE_TRUE_VOID(bs);
bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
}
void
@ -228,9 +245,7 @@ BluetoothAdapter::DisconnectFromOwner()
{
DOMEventTargetHelper::DisconnectFromOwner();
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_ADAPTER), this);
}
void
@ -321,9 +336,8 @@ BluetoothAdapter::Create(nsPIDOMWindow* aWindow, const BluetoothValue& aValue)
void
BluetoothAdapter::Notify(const BluetoothSignal& aData)
{
InfallibleTArray<BluetoothNamedValue> arr;
BT_LOGD("[A] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
NS_ENSURE_TRUE_VOID(mSignalRegistered);
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("PropertyChanged")) {

View File

@ -184,7 +184,7 @@ private:
~BluetoothAdapter();
/**
* Set adapter properties according to properties array
* Set adapter properties according to properties array.
*
* @param aValue [in] Properties array to set with
*/

View File

@ -21,10 +21,29 @@ using namespace mozilla::dom;
USING_BLUETOOTH_NAMESPACE
NS_IMPL_CYCLE_COLLECTION_INHERITED(BluetoothDevice,
DOMEventTargetHelper,
mCod,
mGatt)
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDevice)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothDevice,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCod)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mGatt)
/**
* Unregister the bluetooth signal handler after unlinked.
*
* This is needed to avoid ending up with exposing a deleted object to JS or
* accessing deleted objects while receiving signals from parent process
* after unlinked. Please see Bug 1138267 for detail informations.
*/
UnregisterBluetoothSignalHandler(tmp->mAddress, tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothDevice,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCod)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGatt)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDevice)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
@ -91,27 +110,19 @@ BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aWindow,
SetPropertyByValue(values[i]);
}
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->RegisterBluetoothSignalHandler(mAddress, this);
RegisterBluetoothSignalHandler(mAddress, this);
}
BluetoothDevice::~BluetoothDevice()
{
BluetoothService* bs = BluetoothService::Get();
// bs can be null on shutdown, where destruction might happen.
NS_ENSURE_TRUE_VOID(bs);
bs->UnregisterBluetoothSignalHandler(mAddress, this);
UnregisterBluetoothSignalHandler(mAddress, this);
}
void
BluetoothDevice::DisconnectFromOwner()
{
DOMEventTargetHelper::DisconnectFromOwner();
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->UnregisterBluetoothSignalHandler(mAddress, this);
UnregisterBluetoothSignalHandler(mAddress, this);
}
BluetoothDeviceType
@ -199,6 +210,7 @@ void
BluetoothDevice::Notify(const BluetoothSignal& aData)
{
BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
NS_ENSURE_TRUE_VOID(mSignalRegistered);
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("PropertyChanged")) {

View File

@ -21,9 +21,26 @@ using namespace mozilla::dom;
USING_BLUETOOTH_NAMESPACE
NS_IMPL_CYCLE_COLLECTION_INHERITED(BluetoothGatt,
DOMEventTargetHelper,
mServices)
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothGatt)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothGatt,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mServices)
/**
* Unregister the bluetooth signal handler after unlinked.
*
* This is needed to avoid ending up with exposing a deleted object to JS or
* accessing deleted objects while receiving signals from parent process
* after unlinked. Please see Bug 1138267 for detail informations.
*/
UnregisterBluetoothSignalHandler(tmp->mAppUuid, tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothGatt,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServices)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothGatt)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
@ -56,7 +73,7 @@ BluetoothGatt::~BluetoothGatt()
bs->UnregisterGattClientInternal(mClientIf, result);
}
bs->UnregisterBluetoothSignalHandler(mAppUuid, this);
UnregisterBluetoothSignalHandler(mAppUuid, this);
}
void
@ -94,7 +111,7 @@ BluetoothGatt::DisconnectFromOwner()
bs->UnregisterGattClientInternal(mClientIf, result);
}
bs->UnregisterBluetoothSignalHandler(mAppUuid, this);
UnregisterBluetoothSignalHandler(mAppUuid, this);
}
already_AddRefed<Promise>
@ -122,7 +139,7 @@ BluetoothGatt::Connect(ErrorResult& aRv)
BT_ENSURE_TRUE_REJECT(!mAppUuid.IsEmpty(),
promise,
NS_ERROR_DOM_OPERATION_ERR);
bs->RegisterBluetoothSignalHandler(mAppUuid, this);
RegisterBluetoothSignalHandler(mAppUuid, this);
}
UpdateConnectionState(BluetoothConnectionState::Connecting);
@ -323,6 +340,7 @@ void
BluetoothGatt::Notify(const BluetoothSignal& aData)
{
BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
NS_ENSURE_TRUE_VOID(mSignalRegistered);
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("ClientRegistered")) {

View File

@ -20,8 +20,34 @@ using namespace mozilla::dom;
USING_BLUETOOTH_NAMESPACE
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(
BluetoothGattCharacteristic, mOwner, mService, mDescriptors)
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothGattCharacteristic)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BluetoothGattCharacteristic)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mService)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDescriptors)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
/**
* Unregister the bluetooth signal handler after unlinked.
*
* This is needed to avoid ending up with exposing a deleted object to JS or
* accessing deleted objects while receiving signals from parent process
* after unlinked. Please see Bug 1138267 for detail informations.
*/
nsString path;
GeneratePathFromGattId(tmp->mCharId, path);
UnregisterBluetoothSignalHandler(path, tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BluetoothGattCharacteristic)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mService)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDescriptors)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BluetoothGattCharacteristic)
NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothGattCharacteristic)
NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothGattCharacteristic)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothGattCharacteristic)
@ -42,24 +68,18 @@ BluetoothGattCharacteristic::BluetoothGattCharacteristic(
MOZ_ASSERT(aOwner);
MOZ_ASSERT(mService);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
// Generate bluetooth signal path and a string representation to provide uuid
// of this characteristic to applications
nsString path;
GeneratePathFromGattId(mCharId, path, mUuidStr);
bs->RegisterBluetoothSignalHandler(path, this);
RegisterBluetoothSignalHandler(path, this);
}
BluetoothGattCharacteristic::~BluetoothGattCharacteristic()
{
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
nsString path;
GeneratePathFromGattId(mCharId, path);
bs->UnregisterBluetoothSignalHandler(path, this);
UnregisterBluetoothSignalHandler(path, this);
}
already_AddRefed<Promise>
@ -150,6 +170,7 @@ void
BluetoothGattCharacteristic::Notify(const BluetoothSignal& aData)
{
BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
NS_ENSURE_TRUE_VOID(mSignalRegistered);
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("DescriptorsDiscovered")) {

View File

@ -19,8 +19,32 @@ using namespace mozilla::dom;
USING_BLUETOOTH_NAMESPACE
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(
BluetoothGattDescriptor, mOwner, mCharacteristic)
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothGattDescriptor)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BluetoothGattDescriptor)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCharacteristic)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
/**
* Unregister the bluetooth signal handler after unlinked.
*
* This is needed to avoid ending up with exposing a deleted object to JS or
* accessing deleted objects while receiving signals from parent process
* after unlinked. Please see Bug 1138267 for detail informations.
*/
nsString path;
GeneratePathFromGattId(tmp->mDescriptorId, path);
UnregisterBluetoothSignalHandler(path, tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BluetoothGattDescriptor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCharacteristic)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BluetoothGattDescriptor)
NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothGattDescriptor)
NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothGattDescriptor)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothGattDescriptor)
@ -39,24 +63,18 @@ BluetoothGattDescriptor::BluetoothGattDescriptor(
MOZ_ASSERT(aOwner);
MOZ_ASSERT(aCharacteristic);
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
// Generate bluetooth signal path and a string representation to provide uuid
// of this descriptor to applications
nsString path;
GeneratePathFromGattId(mDescriptorId, path, mUuidStr);
bs->RegisterBluetoothSignalHandler(path, this);
RegisterBluetoothSignalHandler(path, this);
}
BluetoothGattDescriptor::~BluetoothGattDescriptor()
{
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
nsString path;
GeneratePathFromGattId(mDescriptorId, path);
bs->UnregisterBluetoothSignalHandler(path, this);
UnregisterBluetoothSignalHandler(path, this);
}
void
@ -72,6 +90,7 @@ void
BluetoothGattDescriptor::Notify(const BluetoothSignal& aData)
{
BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
NS_ENSURE_TRUE_VOID(mSignalRegistered);
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("DescriptorValueUpdated")) {

View File

@ -17,8 +17,34 @@ using namespace mozilla::dom;
USING_BLUETOOTH_NAMESPACE
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(
BluetoothGattService, mOwner, mIncludedServices, mCharacteristics)
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothGattService)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(BluetoothGattService)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIncludedServices)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCharacteristics)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
/**
* Unregister the bluetooth signal handler after unlinked.
*
* This is needed to avoid ending up with exposing a deleted object to JS or
* accessing deleted objects while receiving signals from parent process
* after unlinked. Please see Bug 1138267 for detail informations.
*/
nsString path;
GeneratePathFromGattId(tmp->mServiceId.mId, path);
UnregisterBluetoothSignalHandler(path, tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(BluetoothGattService)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIncludedServices)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCharacteristics)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(BluetoothGattService)
NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothGattService)
NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothGattService)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothGattService)
@ -36,24 +62,18 @@ BluetoothGattService::BluetoothGattService(
MOZ_ASSERT(aOwner);
MOZ_ASSERT(!mAppUuid.IsEmpty());
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
// Generate bluetooth signal path and a string representation to provide
// uuid of this service to applications
nsString path;
GeneratePathFromGattId(mServiceId.mId, path, mUuidStr);
bs->RegisterBluetoothSignalHandler(path, this);
RegisterBluetoothSignalHandler(path, this);
}
BluetoothGattService::~BluetoothGattService()
{
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
nsString path;
GeneratePathFromGattId(mServiceId.mId, path);
bs->UnregisterBluetoothSignalHandler(path, this);
UnregisterBluetoothSignalHandler(path, this);
}
void
@ -95,6 +115,7 @@ void
BluetoothGattService::Notify(const BluetoothSignal& aData)
{
BT_LOGD("[D] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
NS_ENSURE_TRUE_VOID(mSignalRegistered);
BluetoothValue v = aData.value();
if (aData.name().EqualsLiteral("IncludedServicesDiscovered")) {

View File

@ -5,11 +5,12 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "base/basictypes.h"
#include "BluetoothManager.h"
#include "BluetoothAdapter.h"
#include "BluetoothService.h"
#include "BluetoothReplyRunnable.h"
#include "BluetoothService.h"
#include "BluetoothUtils.h"
#include "mozilla/dom/bluetooth/BluetoothAdapter.h"
#include "mozilla/dom/bluetooth/BluetoothManager.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/BluetoothManager2Binding.h"
#include "mozilla/Services.h"
@ -22,7 +23,27 @@ using namespace mozilla;
USING_BLUETOOTH_NAMESPACE
// QueryInterface implementation for BluetoothManager
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothManager,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAdapters)
/**
* Unregister the bluetooth signal handler after unlinked.
*
* This is needed to avoid ending up with exposing a deleted object to JS or
* accessing deleted objects while receiving signals from parent process
* after unlinked. Please see Bug 1138267 for detail informations.
*/
UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), tmp);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothManager,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAdapters)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothManager)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
@ -92,7 +113,7 @@ BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow)
{
MOZ_ASSERT(aWindow);
ListenToBluetoothSignal(true);
RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this);
BT_API2_LOGR("aWindow %p", aWindow);
// Query adapters list from bluetooth backend
@ -105,27 +126,14 @@ BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow)
BluetoothManager::~BluetoothManager()
{
ListenToBluetoothSignal(false);
UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this);
}
void
BluetoothManager::DisconnectFromOwner()
{
DOMEventTargetHelper::DisconnectFromOwner();
ListenToBluetoothSignal(false);
}
void
BluetoothManager::ListenToBluetoothSignal(bool aStart)
{
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
if (aStart) {
bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this);
} else {
bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this);
}
UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this);
}
BluetoothAdapter*
@ -265,6 +273,7 @@ void
BluetoothManager::Notify(const BluetoothSignal& aData)
{
BT_LOGD("[M] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
NS_ENSURE_TRUE_VOID(mSignalRegistered);
if (aData.name().EqualsLiteral("AdapterAdded")) {
HandleAdapterAdded(aData.value());

View File

@ -25,6 +25,8 @@ class BluetoothManager final : public DOMEventTargetHelper
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothManager,
DOMEventTargetHelper)
/****************************************************************************
* Event Handlers
@ -79,13 +81,6 @@ private:
BluetoothManager(nsPIDOMWindow* aWindow);
~BluetoothManager();
/**
* Start/Stop listening to bluetooth signal.
*
* @param aStart [in] Whether to start or stop listening to bluetooth signal
*/
void ListenToBluetoothSignal(bool aStart);
/**
* Check whether default adapter exists.
*/

View File

@ -4,12 +4,13 @@
* 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/. */
#include "BluetoothService.h"
#include "BluetoothUtils.h"
#include "mozilla/dom/bluetooth/BluetoothPairingListener.h"
#include "mozilla/dom/bluetooth/BluetoothPairingHandle.h"
#include "mozilla/dom/bluetooth/BluetoothTypes.h"
#include "mozilla/dom/BluetoothPairingEvent.h"
#include "mozilla/dom/BluetoothPairingListenerBinding.h"
#include "BluetoothService.h"
USING_BLUETOOTH_NAMESPACE
@ -42,11 +43,8 @@ BluetoothPairingListener::Create(nsPIDOMWindow* aWindow)
BluetoothPairingListener::~BluetoothPairingListener()
{
BluetoothService* bs = BluetoothService::Get();
// It can be nullptr on shutdown.
NS_ENSURE_TRUE_VOID(bs);
bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
this);
UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
this);
}
void
@ -118,11 +116,8 @@ void
BluetoothPairingListener::DisconnectFromOwner()
{
DOMEventTargetHelper::DisconnectFromOwner();
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
this);
UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
this);
}
void
@ -153,10 +148,8 @@ BluetoothPairingListener::TryListeningToBluetoothSignal()
}
// Start listening to bluetooth signal to handle pairing requests
BluetoothService* bs = BluetoothService::Get();
NS_ENSURE_TRUE_VOID(bs);
bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
this);
RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_PAIRING_LISTENER),
this);
mHasListenedToSignal = true;
}

View File

@ -37,8 +37,8 @@ class BluetoothService;
* BluetoothParent
******************************************************************************/
class BluetoothParent : public PBluetoothParent,
public mozilla::Observer<BluetoothSignal>
class BluetoothParent : public PBluetoothParent
, public BluetoothSignalObserver
{
friend class mozilla::dom::ContentParent;

View File

@ -25,7 +25,7 @@ static const size_t MAX_READ_SIZE = 1 << 16;
class BluetoothSocket::BluetoothSocketIO final
: public UnixSocketWatcher
, protected SocketIOBase
, protected DataSocketIO
{
public:
BluetoothSocketIO(MessageLoop* mIOLoop,
@ -34,9 +34,11 @@ public:
const nsACString& aAddress);
~BluetoothSocketIO();
void GetSocketAddr(nsAString& aAddrStr) const;
SocketConsumerBase* GetConsumer();
SocketBase* GetSocketBase();
void GetSocketAddr(nsAString& aAddrStr) const;
BluetoothSocket* GetBluetoothSocket();
DataSocket* GetDataSocket();
SocketBase* GetSocketBase();
// Shutdown state
//
@ -80,7 +82,16 @@ public:
void OnSocketCanReceiveWithoutBlocking() override;
void OnSocketCanSendWithoutBlocking() override;
// Methods for |DataSocket|
//
nsresult QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer);
void ConsumeBuffer();
void DiscardBuffer();
private:
class ReceiveRunnable;
void FireSocketError();
// Set up flags on file descriptor.
@ -122,6 +133,11 @@ private:
* Task member for delayed connect task. Should only be access on main thread.
*/
CancelableTask* mDelayedConnectTask;
/**
* I/O buffer for received data
*/
nsAutoPtr<UnixSocketRawData> mBuffer;
};
BluetoothSocket::BluetoothSocketIO::BluetoothSocketIO(
@ -130,7 +146,6 @@ BluetoothSocket::BluetoothSocketIO::BluetoothSocketIO(
UnixSocketConnector* aConnector,
const nsACString& aAddress)
: UnixSocketWatcher(mIOLoop)
, SocketIOBase(MAX_READ_SIZE)
, mConsumer(aConsumer)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
@ -158,16 +173,22 @@ BluetoothSocket::BluetoothSocketIO::GetSocketAddr(nsAString& aAddrStr) const
mConnector->GetSocketAddr(mAddr, aAddrStr);
}
SocketConsumerBase*
BluetoothSocket::BluetoothSocketIO::GetConsumer()
BluetoothSocket*
BluetoothSocket::BluetoothSocketIO::GetBluetoothSocket()
{
return mConsumer.get();
}
DataSocket*
BluetoothSocket::BluetoothSocketIO::GetDataSocket()
{
return GetBluetoothSocket();
}
SocketBase*
BluetoothSocket::BluetoothSocketIO::GetSocketBase()
{
return GetConsumer();
return GetDataSocket();
}
bool
@ -475,6 +496,69 @@ BluetoothSocket::BluetoothSocketIO::SetSocketFlags(int aFd)
return true;
}
nsresult
BluetoothSocket::BluetoothSocketIO::QueryReceiveBuffer(
UnixSocketIOBuffer** aBuffer)
{
MOZ_ASSERT(aBuffer);
if (!mBuffer) {
mBuffer = new UnixSocketRawData(MAX_READ_SIZE);
}
*aBuffer = mBuffer.get();
return NS_OK;
}
/**
* |ReceiveRunnable| transfers data received on the I/O thread
* to an instance of |BluetoothSocket| on the main thread.
*/
class BluetoothSocket::BluetoothSocketIO::ReceiveRunnable final
: public SocketIORunnable<BluetoothSocketIO>
{
public:
ReceiveRunnable(BluetoothSocketIO* aIO, UnixSocketBuffer* aBuffer)
: SocketIORunnable<BluetoothSocketIO>(aIO)
, mBuffer(aBuffer)
{ }
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
BluetoothSocketIO* io = SocketIORunnable<BluetoothSocketIO>::GetIO();
if (NS_WARN_IF(io->IsShutdownOnMainThread())) {
// Since we've already explicitly closed and the close
// happened before this, this isn't really an error.
return NS_OK;
}
BluetoothSocket* bluetoothSocket = io->GetBluetoothSocket();
MOZ_ASSERT(bluetoothSocket);
bluetoothSocket->ReceiveSocketData(mBuffer);
return NS_OK;
}
private:
nsAutoPtr<UnixSocketBuffer> mBuffer;
};
void
BluetoothSocket::BluetoothSocketIO::ConsumeBuffer()
{
NS_DispatchToMainThread(new ReceiveRunnable(this, mBuffer.forget()));
}
void
BluetoothSocket::BluetoothSocketIO::DiscardBuffer()
{
// Nothing to do.
}
//
// Socket tasks
//

View File

@ -9,7 +9,7 @@
#include "BluetoothCommon.h"
#include <stdlib.h>
#include "mozilla/ipc/SocketBase.h"
#include "mozilla/ipc/DataSocket.h"
#include "mozilla/ipc/UnixSocketWatcher.h"
#include "mozilla/RefPtr.h"
#include "nsAutoPtr.h"
@ -21,7 +21,7 @@ BEGIN_BLUETOOTH_NAMESPACE
class BluetoothSocketObserver;
class BluetoothUnixSocketConnector;
class BluetoothSocket final : public mozilla::ipc::SocketConsumerBase
class BluetoothSocket final : public mozilla::ipc::DataSocket
{
public:
BluetoothSocket(BluetoothSocketObserver* aObserver,
@ -44,14 +44,20 @@ public:
virtual void OnConnectSuccess() override;
virtual void OnConnectError() override;
virtual void OnDisconnect() override;
virtual void ReceiveSocketData(
nsAutoPtr<mozilla::ipc::UnixSocketBuffer>& aBuffer) override;
inline void GetAddress(nsAString& aDeviceAddress)
{
GetSocketAddr(aDeviceAddress);
}
/**
* Method to be called whenever data is received. This is only called on the
* main thread.
*
* @param aBuffer Data received from the socket.
*/
void ReceiveSocketData(nsAutoPtr<mozilla::ipc::UnixSocketBuffer>& aBuffer);
/**
* Queue data to be sent to the socket on the IO thread. Can only be called on
* originating thread.

View File

@ -68,7 +68,8 @@ ProcessURL(nsAString& aUrl, bool* aSchemeValidOut,
if (aSchemeValidOut) {
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
*aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") ||
scheme.LowerCaseEqualsLiteral("https");
scheme.LowerCaseEqualsLiteral("https") ||
scheme.LowerCaseEqualsLiteral("app");
}
uint32_t queryPos;

View File

@ -504,7 +504,7 @@ FMRadio::EnableAudioChannelAgent()
NS_IMETHODIMP
FMRadio::CanPlayChanged(int32_t aCanPlay)
{
SetCanPlay(aCanPlay == AudioChannelState::AUDIO_CHANNEL_STATE_NORMAL);
SetCanPlay(!(aCanPlay == AudioChannelState::AUDIO_CHANNEL_STATE_MUTED));
return NS_OK;
}

View File

@ -13,9 +13,6 @@
// Service instantiation
#include "ipc/IccIPCService.h"
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
// TODO: Bug 815526, deprecate RILContentHelper.
#include "nsIRadioInterfaceLayer.h"
#include "nsRadioInterfaceLayer.h"
#include "nsIGonkIccService.h"
#endif
#include "nsXULAppAPI.h" // For XRE_GetProcessType()
@ -148,13 +145,7 @@ NS_CreateIccService()
service = new mozilla::dom::icc::IccIPCService();
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
} else {
// TODO: Bug 815526, deprecate RILContentHelper.
nsCOMPtr <nsIRadioInterfaceLayer> ril =
do_GetService(NS_RADIOINTERFACELAYER_CONTRACTID);
nsCOMPtr <nsIRadioInterfaceLayer_new> ril_new(do_QueryInterface(ril));
service = (ril_new) ? do_GetService(GONK_ICC_SERVICE_CONTRACTID)
: do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
service = do_GetService(GONK_ICC_SERVICE_CONTRACTID);
#endif
}

View File

@ -25,6 +25,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
"@mozilla.org/ril;1",
"nsIRadioInterfaceLayer");
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
"nsIGonkMobileConnectionService");
let DEBUG = RIL.DEBUG_RIL;
function debug(s) {
dump("IccService: " + s);
@ -73,7 +77,7 @@ function IccService() {
let numClients = gRadioInterfaceLayer.numRadioInterfaces;
for (let i = 0; i < numClients; i++) {
this._iccs.push(new Icc(gRadioInterfaceLayer.getRadioInterface(i)));
this._iccs.push(new Icc(i));
}
this._updateDebugFlag();
@ -145,7 +149,7 @@ IccService.prototype = {
}
let icc = this.getIccByServiceId(aServiceId);
icc._imsi = aImsi;
icc.imsi = aImsi || null;
},
/**
@ -166,15 +170,16 @@ IccService.prototype = {
}
};
function Icc(aRadioInterface) {
this._radioInterface = aRadioInterface;
function Icc(aClientId) {
this._clientId = aClientId;
this._radioInterface = gRadioInterfaceLayer.getRadioInterface(aClientId);
this._listeners = [];
}
Icc.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIcc]),
_clientId: 0,
_radioInterface: null,
_imsi: null,
_listeners: null,
_updateCardState: function(aCardState) {
@ -192,24 +197,52 @@ Icc.prototype = {
}
},
/**
* A utility function to compare objects. The srcInfo may contain
* "rilMessageType", should ignore it.
*/
_isInfoChanged: function(srcInfo, destInfo) {
if (!destInfo) {
return true;
}
for (let key in srcInfo) {
if (key === "rilMessageType") {
continue;
}
if (srcInfo[key] !== destInfo[key]) {
return true;
}
}
return false;
},
/**
* We need to consider below cases when update iccInfo:
* 1. Should clear iccInfo to null if there is no card detected.
* 2. Need to create corresponding object based on iccType.
*/
_updateIccInfo: function(aIccInfo) {
let oldSpn = this.iccInfo ? this.iccInfo.spn : null;
// Card is not detected, clear iccInfo to null.
if (!aIccInfo || !aIccInfo.iccid) {
if (this.iccInfo) {
if (DEBUG) {
debug("Card is not detected, clear iccInfo to null.");
}
this.imsi = null;
this.iccInfo = null;
this._deliverListenerEvent("notifyIccInfoChanged");
}
return;
}
if (!this._isInfoChanged(aIccInfo, this.iccInfo)) {
return;
}
// If iccInfo is null, new corresponding object based on iccType.
if (!this.iccInfo ||
this.iccInfo.iccType != aIccInfo.iccType) {
@ -233,6 +266,23 @@ Icc.prototype = {
aIccInfo.mcc.toString());
} catch (e) {}
}
// Update lastKnownHomeNetwork.
if (aIccInfo.mcc && aIccInfo.mnc) {
let lastKnownHomeNetwork = aIccInfo.mcc + "-" + aIccInfo.mnc;
// Append spn information if available.
if (aIccInfo.spn) {
lastKnownHomeNetwork += "-" + aIccInfo.spn;
}
gMobileConnectionService.notifyLastHomeNetworkChanged(this._clientId,
lastKnownHomeNetwork);
}
// If spn becomes available, we should check roaming again.
if (!oldSpn && aIccInfo.spn) {
gMobileConnectionService.notifySpnAvailable(this._clientId);
}
},
_deliverListenerEvent: function(aName, aArgs) {
@ -305,6 +355,7 @@ Icc.prototype = {
*/
iccInfo: null,
cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
imsi: null,
registerListener: function(aListener) {
if (this._listeners.indexOf(aListener) >= 0) {
@ -379,7 +430,7 @@ Icc.prototype = {
switch (aMvnoType) {
case Ci.nsIIcc.CARD_MVNO_TYPE_IMSI:
let imsi = this._imsi;
let imsi = this.imsi;
if (!imsi) {
aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
break;

View File

@ -97,7 +97,7 @@ NS_CreateIccService();
/**
* XPCOM component that provides the access to the selected ICC.
*/
[scriptable, uuid(38a5bbe2-add6-11e4-ba9e-e390d1d19195)]
[scriptable, uuid(20a99186-e4cb-11e4-a5f9-938abcf7c826)]
interface nsIIcc : nsISupports
{
/**
@ -214,6 +214,11 @@ interface nsIIcc : nsISupports
*/
readonly attribute unsigned long cardState;
/**
* IMSI of this ICC.
*/
readonly attribute DOMString imsi;
/**
* Get the status of an ICC lock (e.g. the PIN lock).
*

View File

@ -182,6 +182,13 @@ IccChild::GetCardState(uint32_t* aCardState)
return NS_OK;
}
NS_IMETHODIMP
IccChild::GetImsi(nsAString & aImsi)
{
NS_WARNING("IMSI shall not directly be fetched in child process.");
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
IccChild::GetCardLockEnabled(uint32_t aLockType,
nsIIccCallback* aRequestReply)

View File

@ -240,13 +240,12 @@ class MemoryReportRequestChild : public PMemoryReportRequestChild,
public:
NS_DECL_ISUPPORTS
MemoryReportRequestChild(uint32_t aGeneration, bool aAnonymize,
MemoryReportRequestChild(bool aAnonymize,
const MaybeFileDesc& aDMDFile);
NS_IMETHOD Run() override;
private:
virtual ~MemoryReportRequestChild();
uint32_t mGeneration;
bool mAnonymize;
FileDescriptor mDMDFile;
};
@ -254,8 +253,8 @@ private:
NS_IMPL_ISUPPORTS(MemoryReportRequestChild, nsIRunnable)
MemoryReportRequestChild::MemoryReportRequestChild(
uint32_t aGeneration, bool aAnonymize, const MaybeFileDesc& aDMDFile)
: mGeneration(aGeneration), mAnonymize(aAnonymize)
bool aAnonymize, const MaybeFileDesc& aDMDFile)
: mAnonymize(aAnonymize)
{
MOZ_COUNT_CTOR(MemoryReportRequestChild);
if (aDMDFile.type() == MaybeFileDesc::TFileDescriptor) {
@ -867,48 +866,37 @@ ContentChild::AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
const MaybeFileDesc& aDMDFile)
{
MemoryReportRequestChild *actor =
new MemoryReportRequestChild(aGeneration, aAnonymize, aDMDFile);
new MemoryReportRequestChild(aAnonymize, aDMDFile);
actor->AddRef();
return actor;
}
// This is just a wrapper for InfallibleTArray<MemoryReport> that implements
// nsISupports, so it can be passed to nsIMemoryReporter::CollectReports.
class MemoryReportsWrapper final : public nsISupports {
~MemoryReportsWrapper() {}
public:
NS_DECL_ISUPPORTS
explicit MemoryReportsWrapper(InfallibleTArray<MemoryReport>* r) : mReports(r) { }
InfallibleTArray<MemoryReport> *mReports;
};
NS_IMPL_ISUPPORTS0(MemoryReportsWrapper)
class MemoryReportCallback final : public nsIMemoryReporterCallback
{
public:
NS_DECL_ISUPPORTS
explicit MemoryReportCallback(const nsACString& aProcess)
: mProcess(aProcess)
explicit MemoryReportCallback(MemoryReportRequestChild* aActor,
const nsACString& aProcess)
: mActor(aActor)
, mProcess(aProcess)
{
}
NS_IMETHOD Callback(const nsACString& aProcess, const nsACString &aPath,
int32_t aKind, int32_t aUnits, int64_t aAmount,
const nsACString& aDescription,
nsISupports* aiWrappedReports) override
nsISupports* aUnused) override
{
MemoryReportsWrapper *wrappedReports =
static_cast<MemoryReportsWrapper *>(aiWrappedReports);
MemoryReport memreport(mProcess, nsCString(aPath), aKind, aUnits,
aAmount, nsCString(aDescription));
wrappedReports->mReports->AppendElement(memreport);
mActor->SendReport(memreport);
return NS_OK;
}
private:
~MemoryReportCallback() {}
nsRefPtr<MemoryReportRequestChild> mActor;
const nsCString mProcess;
};
NS_IMPL_ISUPPORTS(
@ -944,21 +932,18 @@ NS_IMETHODIMP MemoryReportRequestChild::Run()
ContentChild *child = static_cast<ContentChild*>(Manager());
nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
InfallibleTArray<MemoryReport> reports;
nsCString process;
child->GetProcessName(process);
child->AppendProcessId(process);
// Run the reporters. The callback will turn each measurement into a
// MemoryReport.
nsRefPtr<MemoryReportsWrapper> wrappedReports =
new MemoryReportsWrapper(&reports);
nsRefPtr<MemoryReportCallback> cb = new MemoryReportCallback(process);
mgr->GetReportsForThisProcessExtended(cb, wrappedReports, mAnonymize,
nsRefPtr<MemoryReportCallback> cb =
new MemoryReportCallback(this, process);
mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize,
FileDescriptorToFILE(mDMDFile, "wb"));
bool sent = Send__delete__(this, mGeneration, reports);
bool sent = Send__delete__(this);
return sent ? NS_OK : NS_ERROR_FAILURE;
}

View File

@ -405,45 +405,65 @@ bool ContentParent::sNuwaReady = false;
class MemoryReportRequestParent : public PMemoryReportRequestParent
{
public:
MemoryReportRequestParent();
explicit MemoryReportRequestParent(uint32_t aGeneration);
virtual ~MemoryReportRequestParent();
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
virtual bool Recv__delete__(const uint32_t& aGeneration, InfallibleTArray<MemoryReport>&& aReport) override;
virtual bool RecvReport(const MemoryReport& aReport) override;
virtual bool Recv__delete__() override;
private:
const uint32_t mGeneration;
// Non-null if we haven't yet called EndChildReport() on it.
nsRefPtr<nsMemoryReporterManager> mReporterManager;
ContentParent* Owner()
{
return static_cast<ContentParent*>(Manager());
}
};
MemoryReportRequestParent::MemoryReportRequestParent()
MemoryReportRequestParent::MemoryReportRequestParent(uint32_t aGeneration)
: mGeneration(aGeneration)
{
MOZ_COUNT_CTOR(MemoryReportRequestParent);
mReporterManager = nsMemoryReporterManager::GetOrCreate();
NS_WARN_IF(!mReporterManager);
}
bool
MemoryReportRequestParent::RecvReport(const MemoryReport& aReport)
{
if (mReporterManager) {
mReporterManager->HandleChildReport(mGeneration, aReport);
}
return true;
}
bool
MemoryReportRequestParent::Recv__delete__()
{
// Notifying the reporter manager is done in ActorDestroy, because
// it needs to happen even if the child process exits mid-report.
// (The reporter manager will time out eventually, but let's avoid
// that if possible.)
return true;
}
void
MemoryReportRequestParent::ActorDestroy(ActorDestroyReason aWhy)
{
// Implement me! Bug 1005154
}
bool
MemoryReportRequestParent::Recv__delete__(const uint32_t& generation,
nsTArray<MemoryReport>&& childReports)
{
nsRefPtr<nsMemoryReporterManager> mgr =
nsMemoryReporterManager::GetOrCreate();
if (mgr) {
mgr->HandleChildReports(generation, childReports);
if (mReporterManager) {
mReporterManager->EndChildReport(mGeneration, aWhy == Deletion);
mReporterManager = nullptr;
}
return true;
}
MemoryReportRequestParent::~MemoryReportRequestParent()
{
MOZ_ASSERT(!mReporterManager);
MOZ_COUNT_DTOR(MemoryReportRequestParent);
}
@ -3549,7 +3569,8 @@ ContentParent::AllocPMemoryReportRequestParent(const uint32_t& aGeneration,
const bool &aMinimizeMemoryUsage,
const MaybeFileDesc &aDMDFile)
{
MemoryReportRequestParent* parent = new MemoryReportRequestParent();
MemoryReportRequestParent* parent =
new MemoryReportRequestParent(aGeneration);
return parent;
}

View File

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
@ -20,8 +20,9 @@ struct MemoryReport {
protocol PMemoryReportRequest {
manager PContent;
parent:
__delete__(uint32_t generation, MemoryReport[] report);
parent:
Report(MemoryReport aReport);
__delete__();
};
}

View File

@ -51,7 +51,7 @@ PRLogModuleInfo* gAudioOffloadPlayerLog;
#endif
// maximum time in paused state when offloading audio decompression.
// When elapsed, the AudioSink is destroyed to allow the audio DSP to power down.
// When elapsed, the GonkAudioSink is destroyed to allow the audio DSP to power down.
static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll;
AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) :
@ -473,28 +473,28 @@ void AudioOffloadPlayer::NotifyAudioTearDown()
}
// static
size_t AudioOffloadPlayer::AudioSinkCallback(AudioSink* aAudioSink,
size_t AudioOffloadPlayer::AudioSinkCallback(GonkAudioSink* aAudioSink,
void* aBuffer,
size_t aSize,
void* aCookie,
AudioSink::cb_event_t aEvent)
GonkAudioSink::cb_event_t aEvent)
{
AudioOffloadPlayer* me = (AudioOffloadPlayer*) aCookie;
switch (aEvent) {
case AudioSink::CB_EVENT_FILL_BUFFER:
case GonkAudioSink::CB_EVENT_FILL_BUFFER:
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Notify Audio position changed"));
me->NotifyPositionChanged();
return me->FillBuffer(aBuffer, aSize);
case AudioSink::CB_EVENT_STREAM_END:
case GonkAudioSink::CB_EVENT_STREAM_END:
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Notify Audio EOS"));
me->mReachedEOS = true;
me->NotifyAudioEOS();
break;
case AudioSink::CB_EVENT_TEAR_DOWN:
case GonkAudioSink::CB_EVENT_TEAR_DOWN:
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Notify Tear down event"));
me->NotifyAudioTearDown();
break;
@ -697,7 +697,7 @@ MediaDecoderOwner::NextFrameStatus AudioOffloadPlayer::GetNextFrameStatus()
}
}
void AudioOffloadPlayer::SendMetaDataToHal(sp<AudioSink>& aSink,
void AudioOffloadPlayer::SendMetaDataToHal(sp<GonkAudioSink>& aSink,
const sp<MetaData>& aMeta)
{
int32_t sampleRate = 0;

View File

@ -50,11 +50,11 @@ class WakeLock;
* it to the sink
*
* Also this class passes state changes (play/pause/seek) from
* MediaOmxCommonDecoder to AudioSink as well as provide AudioSink status
* MediaOmxCommonDecoder to GonkAudioSink as well as provide GonkAudioSink status
* (position changed, playback ended, seek complete, audio tear down) back to
* MediaOmxCommonDecoder
*
* It acts as a bridge between MediaOmxCommonDecoder and AudioSink during
* It acts as a bridge between MediaOmxCommonDecoder and GonkAudioSink during
* offload playback
*/
@ -80,7 +80,7 @@ public:
// Caller retains ownership of "aSource".
virtual void SetSource(const android::sp<MediaSource> &aSource) override;
// Start the source if it's not already started and open the AudioSink to
// Start the source if it's not already started and open the GonkAudioSink to
// create an offloaded audio track
virtual status_t Start(bool aSourceAlreadyStarted = false) override;
@ -106,7 +106,7 @@ public:
void Reset();
private:
// Set when audio source is started and audioSink is initialized
// Set when audio source is started and GonkAudioSink is initialized
// Used only in main thread
bool mStarted;
@ -170,7 +170,7 @@ private:
// Audio sink wrapper to access offloaded audio tracks
// Used in main thread and offload callback thread
// Race conditions are protected in underlying Android::AudioTrack class
android::sp<AudioSink> mAudioSink;
android::sp<GonkAudioSink> mAudioSink;
// Buffer used to get date from audio source. Used in offload callback thread
MediaBuffer* mInputBuffer;
@ -183,7 +183,7 @@ private:
// Timer to trigger position changed events
nsCOMPtr<nsITimer> mTimeUpdateTimer;
// Timer to reset AudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS.
// Timer to reset GonkAudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS.
// It is triggered in Pause() and canceled when there is a Play() within
// OFFLOAD_PAUSE_MAX_USECS. Used only from main thread so no lock is needed.
nsCOMPtr<nsITimer> mResetTimer;
@ -203,12 +203,12 @@ private:
// case of error
size_t FillBuffer(void *aData, size_t aSize);
// Called by AudioSink when it needs data, to notify EOS or tear down event
static size_t AudioSinkCallback(AudioSink *aAudioSink,
// Called by GonkAudioSink when it needs data, to notify EOS or tear down event
static size_t AudioSinkCallback(GonkAudioSink *aAudioSink,
void *aData,
size_t aSize,
void *aMe,
AudioSink::cb_event_t aEvent);
GonkAudioSink::cb_event_t aEvent);
bool IsSeeking();
@ -254,8 +254,8 @@ private:
// MediaDecoder to re-evaluate offloading options
void NotifyAudioTearDown();
// Send information from MetaData to the HAL via AudioSink
void SendMetaDataToHal(android::sp<AudioSink>& aSink,
// Send information from MetaData to the HAL via GonkAudioSink
void SendMetaDataToHal(android::sp<GonkAudioSink>& aSink,
const android::sp<MetaData>& aMeta);
AudioOffloadPlayer(const AudioOffloadPlayer &);

View File

@ -24,7 +24,7 @@
#include <utils/Mutex.h>
#include <AudioTrack.h>
#include "AudioSink.h"
#include "GonkAudioSink.h"
namespace mozilla {
@ -34,7 +34,7 @@ namespace mozilla {
* Android::AudioTrack
* Similarly to ease handling offloaded tracks, part of AudioOutput is used here
*/
class AudioOutput : public AudioSink
class AudioOutput : public GonkAudioSink
{
typedef android::Mutex Mutex;
typedef android::String8 String8;

View File

@ -17,8 +17,8 @@
* limitations under the License.
*/
#ifndef AUDIO_SINK_H_
#define AUDIO_SINK_H_
#ifndef GONK_AUDIO_SINK_H_
#define GONK_AUDIO_SINK_H_
#include <utils/Errors.h>
#include <utils/String8.h>
@ -39,7 +39,7 @@ namespace mozilla {
* Stripped version of Android KK MediaPlayerBase::AudioSink class
*/
class AudioSink : public android::RefBase
class GonkAudioSink : public android::RefBase
{
typedef android::String8 String8;
typedef android::status_t status_t;
@ -54,12 +54,12 @@ public:
};
// Callback returns the number of bytes actually written to the buffer.
typedef size_t (*AudioCallback)(AudioSink* aAudioSink,
typedef size_t (*AudioCallback)(GonkAudioSink* aAudioSink,
void* aBuffer,
size_t aSize,
void* aCookie,
cb_event_t aEvent);
virtual ~AudioSink() {}
virtual ~GonkAudioSink() {}
virtual ssize_t FrameSize() const = 0;
virtual status_t GetPosition(uint32_t* aPosition) const = 0;
virtual status_t SetVolume(float aVolume) const = 0;
@ -86,4 +86,4 @@ public:
} // namespace mozilla
#endif // AUDIO_SINK_H_
#endif // GONK_AUDIO_SINK_H_

View File

@ -26,7 +26,7 @@ if CONFIG['MOZ_AUDIO_OFFLOAD']:
EXPORTS += [
'AudioOffloadPlayer.h',
'AudioOutput.h',
'AudioSink.h',
'GonkAudioSink.h',
]
SOURCES += [
'AudioOffloadPlayer.cpp',

View File

@ -56,6 +56,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
"@mozilla.org/network/manager;1",
"nsINetworkManager");
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
"@mozilla.org/icc/iccservice;1",
"nsIIccService");
XPCOMUtils.defineLazyGetter(this, "gRadioInterfaceLayer", function() {
let ril = { numRadioInterfaces: 0 };
try {
@ -387,9 +391,8 @@ MobileConnectionProvider.prototype = {
* really the case. See bug 787967
*/
_checkRoamingBetweenOperators: function(aNetworkInfo) {
// TODO: Bug 864489 - B2G RIL: use ipdl as IPC in MozIccManager
// Should get iccInfo from GonkIccProvider.
let iccInfo = this._radioInterface.rilContext.iccInfo;
let icc = gIccService.getIccByServiceId(this._clientId);
let iccInfo = icc ? icc.iccInfo : null;
let operator = aNetworkInfo.network;
let state = aNetworkInfo.state;

View File

@ -134,6 +134,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gpps",
"@mozilla.org/network/protocol-proxy-service;1",
"nsIProtocolProxyService");
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
"@mozilla.org/icc/iccservice;1",
"nsIIccService");
XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
@ -347,7 +351,7 @@ MmsConnection.prototype = {
// Get the proper IccInfo based on the current card type.
try {
let iccInfo = null;
let baseIccInfo = this.radioInterface.rilContext.iccInfo;
let baseIccInfo = this.getIccInfo();
if (baseIccInfo.iccType === 'ruim' || baseIccInfo.iccType === 'csim') {
iccInfo = baseIccInfo.QueryInterface(Ci.nsICdmaIccInfo);
number = iccInfo.mdn;
@ -365,11 +369,27 @@ MmsConnection.prototype = {
return number;
},
/**
* A utility function to get IccInfo of the SIM card (if installed).
*/
getIccInfo: function() {
let icc = gIccService.getIccByServiceId(this.serviceId);
return icc ? icc.iccInfo : null;
},
/**
* A utility function to get CardState of the SIM card (if installed).
*/
getCardState: function() {
let icc = gIccService.getIccByServiceId(this.serviceId);
return icc ? icc.cardState : Ci.nsIIcc.CARD_STATE_UNKNOWN;
},
/**
* A utility function to get the ICC ID of the SIM card (if installed).
*/
getIccId: function() {
let iccInfo = this.radioInterface.rilContext.iccInfo;
let iccInfo = this.getIccInfo();
if (!iccInfo) {
return null;
@ -404,8 +424,7 @@ MmsConnection.prototype = {
if (getRadioDisabledState()) {
if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
errorStatus = _HTTP_STATUS_RADIO_DISABLED;
} else if (this.radioInterface.rilContext.cardState !=
Ci.nsIIcc.CARD_STATE_READY) {
} else if (this.getCardState() != Ci.nsIIcc.CARD_STATE_READY) {
if (DEBUG) debug("Error! SIM card is not ready when sending MMS.");
errorStatus = _HTTP_STATUS_NO_SIM_CARD;
}

View File

@ -76,9 +76,13 @@ XPCOMUtils.defineLazyGetter(this, "gWAP", function() {
});
XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
"@mozilla.org/cellbroadcast/gonkservice;1",
"@mozilla.org/cellbroadcast/cellbroadcastservice;1",
"nsIGonkCellBroadcastService");
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
"@mozilla.org/icc/iccservice;1",
"nsIIccService");
XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
"nsIMobileConnectionService");
@ -158,7 +162,7 @@ SmsService.prototype = {
// Get the proper IccInfo based on the current card type.
try {
let iccInfo = null;
let baseIccInfo = gRadioInterfaces[aServiceId].rilContext.iccInfo;
let baseIccInfo = this._getIccInfo(aServiceId);
if (baseIccInfo.iccType === 'ruim' || baseIccInfo.iccType === 'csim') {
iccInfo = baseIccInfo.QueryInterface(Ci.nsICdmaIccInfo);
number = iccInfo.mdn;
@ -176,8 +180,18 @@ SmsService.prototype = {
return number;
},
_getIccInfo: function(aServiceId) {
let icc = gIccService.getIccByServiceId(aServiceId);
return icc ? icc.iccInfo : null;
},
_getCardState: function(aServiceId) {
let icc = gIccService.getIccByServiceId(aServiceId);
return icc ? icc.cardState : Ci.nsIIcc.CARD_STATE_UNKNOWN;
},
_getIccId: function(aServiceId) {
let iccInfo = gRadioInterfaces[aServiceId].rilContext.iccInfo;
let iccInfo = this._getIccInfo(aServiceId);
if (!iccInfo) {
return null;
@ -887,8 +901,7 @@ SmsService.prototype = {
radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED) {
if (DEBUG) debug("Error! Radio is disabled when sending SMS.");
errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
} else if (gRadioInterfaces[aServiceId].rilContext.cardState !=
Ci.nsIIcc.CARD_STATE_READY) {
} else if (this._getCardState(aServiceId) != Ci.nsIIcc.CARD_STATE_READY) {
if (DEBUG) debug("Error! SIM card is not ready when sending SMS.");
errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
}

View File

@ -69,6 +69,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "messenger",
"@mozilla.org/system-message-internal;1",
"nsISystemMessagesInternal");
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
"@mozilla.org/icc/iccservice;1",
"nsIIccService");
this.NetworkStatsService = {
init: function() {
debug("Service started");
@ -253,11 +257,12 @@ this.NetworkStatsService = {
let networks = {};
let numRadioInterfaces = gRil.numRadioInterfaces;
for (let i = 0; i < numRadioInterfaces; i++) {
let icc = gIccService.getIccByServiceId(i);
let radioInterface = gRil.getRadioInterface(i);
if (radioInterface.rilContext.iccInfo) {
let netId = this.getNetworkId(radioInterface.rilContext.iccInfo.iccid,
if (icc && icc.iccInfo) {
let netId = this.getNetworkId(icc.iccInfo.iccid,
NET_TYPE_MOBILE);
networks[netId] = { id : radioInterface.rilContext.iccInfo.iccid,
networks[netId] = { id : icc.iccInfo.iccid,
type: NET_TYPE_MOBILE };
}
}

View File

@ -371,7 +371,7 @@ DOMSVGLength::SetValueAsString(const nsAString& aValue, ErrorResult& aRv)
}
if (mVal) {
mVal->SetBaseValueString(aValue, mSVGElement, true);
aRv = mVal->SetBaseValueString(aValue, mSVGElement, true);
return;
}

View File

@ -3,7 +3,7 @@
https://bugzilla.mozilla.org/show_bug.cgi?id=539697
-->
<head>
<title>Test SVGTransform behavior</title>
<title>Test valueAsString behavior</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@ -35,6 +35,7 @@ function run()
try {
c.r.baseVal.valueAsString = 'rubbish';
ok(false, 'setting a length to rubbish should fail');
} catch (e) {
is(e.name, 'SyntaxError', 'syntax error expected');
is(e.code, DOMException.SYNTAX_ERR, 'syntax error expected');
@ -46,6 +47,7 @@ function run()
try {
m.orientAngle.baseVal.valueAsString = 'rubbish';
ok(false, 'setting an angle to rubbish should fail');
} catch (e) {
is(e.name, 'SyntaxError', 'syntax error expected');
is(e.code, DOMException.SYNTAX_ERR, 'syntax error expected');

View File

@ -43,6 +43,7 @@
#include "nsIMobileCellInfo.h"
#include "nsIMobileNetworkInfo.h"
#include "nsIRadioInterfaceLayer.h"
#include "nsIIccService.h"
#endif
#ifdef AGPS_TYPE_INVALID
@ -476,31 +477,35 @@ GonkGPSGeolocationProvider::RequestSetID(uint32_t flags)
AGpsSetIDType type = AGPS_SETID_TYPE_NONE;
nsCOMPtr<nsIRilContext> rilCtx;
mRadioInterface->GetRilContext(getter_AddRefs(rilCtx));
nsCOMPtr<nsIIccService> iccService =
do_GetService(ICC_SERVICE_CONTRACTID);
NS_ENSURE_TRUE_VOID(iccService);
if (rilCtx) {
nsAutoString id;
if (flags & AGPS_RIL_REQUEST_SETID_IMSI) {
type = AGPS_SETID_TYPE_IMSI;
rilCtx->GetImsi(id);
}
nsCOMPtr<nsIIcc> icc;
iccService->GetIccByServiceId(mRilDataServiceId, getter_AddRefs(icc));
NS_ENSURE_TRUE_VOID(icc);
if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) {
nsCOMPtr<nsIIccInfo> iccInfo;
rilCtx->GetIccInfo(getter_AddRefs(iccInfo));
if (iccInfo) {
nsCOMPtr<nsIGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
if (gsmIccInfo) {
type = AGPS_SETID_TYPE_MSISDN;
gsmIccInfo->GetMsisdn(id);
}
nsAutoString id;
if (flags & AGPS_RIL_REQUEST_SETID_IMSI) {
type = AGPS_SETID_TYPE_IMSI;
icc->GetImsi(id);
}
if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) {
nsCOMPtr<nsIIccInfo> iccInfo;
icc->GetIccInfo(getter_AddRefs(iccInfo));
if (iccInfo) {
nsCOMPtr<nsIGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
if (gsmIccInfo) {
type = AGPS_SETID_TYPE_MSISDN;
gsmIccInfo->GetMsisdn(id);
}
}
NS_ConvertUTF16toUTF8 idBytes(id);
mAGpsRilInterface->set_set_id(type, idBytes.get());
}
NS_ConvertUTF16toUTF8 idBytes(id);
mAGpsRilInterface->set_set_id(type, idBytes.get());
}
void

View File

@ -44,11 +44,6 @@ const RILCONTENTHELPER_CID =
Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
const RIL_IPC_MSG_NAMES = [
"RIL:CardStateChanged",
"RIL:IccInfoChanged",
"RIL:GetCardLockResult",
"RIL:SetUnlockCardLockResult",
"RIL:CardLockRetryCount",
"RIL:StkCommand",
"RIL:StkSessionEnd",
"RIL:IccOpenChannel",
@ -56,8 +51,6 @@ const RIL_IPC_MSG_NAMES = [
"RIL:IccExchangeAPDU",
"RIL:ReadIccContacts",
"RIL:UpdateIccContact",
"RIL:MatchMvno",
"RIL:GetServiceState"
];
/* global cpmm */
@ -87,63 +80,14 @@ XPCOMUtils.defineLazyGetter(this, "gNumRadioInterfaces", function() {
return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces);
});
function IccInfo() {}
IccInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccInfo]),
// nsIIccInfo
iccType: null,
iccid: null,
mcc: null,
mnc: null,
spn: null,
isDisplayNetworkNameRequired: false,
isDisplaySpnRequired: false
};
function GsmIccInfo() {}
GsmIccInfo.prototype = {
__proto__: IccInfo.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
Ci.nsIIccInfo]),
// nsIGsmIccInfo
msisdn: null
};
function CdmaIccInfo() {}
CdmaIccInfo.prototype = {
__proto__: IccInfo.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsICdmaIccInfo,
Ci.nsIIccInfo]),
// nsICdmaIccInfo
mdn: null,
prlVersion: 0
};
function RILContentHelper() {
this.updateDebugFlag();
this.numClients = gNumRadioInterfaces;
if (DEBUG) debug("Number of clients: " + this.numClients);
this._iccs = [];
this.rilContexts = [];
for (let clientId = 0; clientId < this.numClients; clientId++) {
this._iccs.push(new Icc(this, clientId));
this.rilContexts[clientId] = {
cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
iccInfo: null
};
}
this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
this._windowsMap = [];
this._requestMap = [];
this._iccListeners = [];
this._iccChannelCallback = [];
@ -156,14 +100,12 @@ RILContentHelper.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccProvider,
Ci.nsIIccService,
Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
classID: RILCONTENTHELPER_CID,
classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
classDescription: "RILContentHelper",
interfaces: [Ci.nsIIccProvider,
Ci.nsIIccService]}),
interfaces: [Ci.nsIIccProvider]}),
updateDebugFlag: function() {
try {
@ -172,71 +114,8 @@ RILContentHelper.prototype = {
} catch (e) {}
},
// An utility function to copy objects.
updateInfo: function(srcInfo, destInfo) {
for (let key in srcInfo) {
destInfo[key] = srcInfo[key];
}
},
/**
* We need to consider below cases when update iccInfo:
* 1. Should clear iccInfo to null if there is no card detected.
* 2. Need to create corresponding object based on iccType.
*/
updateIccInfo: function(clientId, newInfo) {
let rilContext = this.rilContexts[clientId];
// Card is not detected, clear iccInfo to null.
if (!newInfo || !newInfo.iccid) {
if (rilContext.iccInfo) {
rilContext.iccInfo = null;
}
return;
}
// If iccInfo is null, new corresponding object based on iccType.
if (!rilContext.iccInfo) {
if (newInfo.iccType === "ruim" || newInfo.iccType === "csim") {
rilContext.iccInfo = new CdmaIccInfo();
} else if (newInfo.iccType === "sim" || newInfo.iccType === "usim") {
rilContext.iccInfo = new GsmIccInfo();
} else {
rilContext.iccInfo = new IccInfo();
}
}
this.updateInfo(newInfo, rilContext.iccInfo);
},
_windowsMap: null,
_requestMap: null,
rilContexts: null,
getRilContext: function(clientId) {
// Update ril contexts by sending IPC message to chrome only when the first
// time we require it. The information will be updated by following info
// changed messages.
this.getRilContext = function getRilContext(clientId) {
return this.rilContexts[clientId];
};
for (let cId = 0; cId < this.numClients; cId++) {
let rilContext =
cpmm.sendSyncMessage("RIL:GetRilContext", {clientId: cId})[0];
if (!rilContext) {
if (DEBUG) debug("Received null rilContext from chrome process.");
continue;
}
this.rilContexts[cId].cardState = rilContext.cardState;
this.updateIccInfo(cId, rilContext.iccInfo);
}
return this.rilContexts[clientId];
},
/**
* nsIIccProvider
*/
@ -568,61 +447,6 @@ RILContentHelper.prototype = {
let data = msg.json.data;
let clientId = msg.json.clientId;
switch (msg.name) {
case "RIL:CardStateChanged":
if (this.rilContexts[clientId].cardState != data.cardState) {
this.rilContexts[clientId].cardState = data.cardState;
this._deliverIccEvent(clientId,
"notifyCardStateChanged",
null);
}
break;
case "RIL:IccInfoChanged":
this.updateIccInfo(clientId, data);
this._deliverIccEvent(clientId,
"notifyIccInfoChanged",
null);
break;
case "RIL:GetCardLockResult": {
let requestId = data.requestId;
let callback = this._requestMap[requestId];
delete this._requestMap[requestId];
if (data.errorMsg) {
callback.notifyError(data.errorMsg);
break;
}
callback.notifySuccessWithBoolean(data.enabled);
break;
}
case "RIL:SetUnlockCardLockResult": {
let requestId = data.requestId;
let callback = this._requestMap[requestId];
delete this._requestMap[requestId];
if (data.errorMsg) {
let retryCount =
(data.retryCount !== undefined) ? data.retryCount : -1;
callback.notifyCardLockError(data.errorMsg, retryCount);
break;
}
callback.notifySuccess();
break;
}
case "RIL:CardLockRetryCount": {
let requestId = data.requestId;
let callback = this._requestMap[requestId];
delete this._requestMap[requestId];
if (data.errorMsg) {
callback.notifyError(data.errorMsg);
break;
}
callback.notifyGetCardLockRetryCount(data.retryCount);
break;
}
case "RIL:StkCommand":
this._deliverEvent(clientId, "_iccListeners", "notifyStkCommand",
[JSON.stringify(data)]);
@ -645,30 +469,6 @@ RILContentHelper.prototype = {
case "RIL:UpdateIccContact":
this.handleUpdateIccContact(data);
break;
case "RIL:MatchMvno": {
let requestId = data.requestId;
let callback = this._requestMap[requestId];
delete this._requestMap[requestId];
if (data.errorMsg) {
callback.notifyError(data.errorMsg);
break;
}
callback.notifySuccessWithBoolean(data.result);
break;
}
case "RIL:GetServiceState": {
let requestId = data.requestId;
let callback = this._requestMap[requestId];
delete this._requestMap[requestId];
if (data.errorMsg) {
callback.notifyError(data.errorMsg);
break;
}
callback.notifySuccessWithBoolean(data.result);
break;
}
}
},
@ -795,235 +595,6 @@ RILContentHelper.prototype = {
if (DEBUG) debug("listener for " + name + " threw an exception: " + e);
}
}
},
/**
* nsIIccService interface.
*/
_iccs: null, // An array of Icc instances.
getIccByServiceId: function(serviceId) {
let icc = this._iccs[serviceId];
if (!icc) {
throw Cr.NS_ERROR_UNEXPECTED;
}
return icc;
},
/**
* Bridge APIs from nsIIccService to nsIIccProvider
*/
_deliverIccEvent: function(clientId, name, args) {
let icc = this._iccs[clientId];
if (!icc) {
if (DEBUG) debug("_deliverIccEvent: Invalid clientId: " + clientId);
return;
}
icc.deliverListenerEvent(name, args);
},
getIccInfo: function(clientId) {
let context = this.getRilContext(clientId);
return context && context.iccInfo;
},
getCardState: function(clientId) {
let context = this.getRilContext(clientId);
return context && context.cardState;
},
matchMvno: function(clientId, mvnoType, mvnoData, callback) {
let requestId = UUIDGenerator.generateUUID().toString();
this._requestMap[requestId] = callback;
cpmm.sendAsyncMessage("RIL:MatchMvno", {
clientId: clientId,
data: {
requestId: requestId,
mvnoType: mvnoType,
mvnoData: mvnoData
}
});
},
getCardLockEnabled: function(clientId, lockType, callback) {
let requestId = UUIDGenerator.generateUUID().toString();
this._requestMap[requestId] = callback;
cpmm.sendAsyncMessage("RIL:GetCardLockEnabled", {
clientId: clientId,
data: {
lockType: lockType,
requestId: requestId
}
});
},
unlockCardLock: function(clientId, lockType, password, newPin, callback) {
let requestId = UUIDGenerator.generateUUID().toString();
this._requestMap[requestId] = callback;
cpmm.sendAsyncMessage("RIL:UnlockCardLock", {
clientId: clientId,
data: {
lockType: lockType,
password: password,
newPin: newPin,
requestId: requestId
}
});
},
setCardLockEnabled: function(clientId, lockType, password, enabled, callback) {
let requestId = UUIDGenerator.generateUUID().toString();
this._requestMap[requestId] = callback;
cpmm.sendAsyncMessage("RIL:SetCardLockEnabled", {
clientId: clientId,
data: {
lockType: lockType,
password: password,
enabled: enabled,
requestId: requestId
}
});
},
changeCardLockPassword: function(clientId, lockType, password, newPassword,
callback) {
let requestId = UUIDGenerator.generateUUID().toString();
this._requestMap[requestId] = callback;
cpmm.sendAsyncMessage("RIL:ChangeCardLockPassword", {
clientId: clientId,
data: {
lockType: lockType,
password: password,
newPassword: newPassword,
requestId: requestId
}
});
},
getCardLockRetryCount: function(clientId, lockType, callback) {
let requestId = UUIDGenerator.generateUUID().toString();
this._requestMap[requestId] = callback;
cpmm.sendAsyncMessage("RIL:GetCardLockRetryCount", {
clientId: clientId,
data: {
lockType: lockType,
requestId: requestId
}
});
},
getServiceStateEnabled: function(clientId, service, callback) {
let requestId = UUIDGenerator.generateUUID().toString();
this._requestMap[requestId] = callback;
cpmm.sendAsyncMessage("RIL:GetServiceState", {
clientId: clientId,
data: {
requestId: requestId,
service: service
}
});
}
};
function Icc(aIccProvider, aClientId) {
this._iccProvider = aIccProvider;
this._clientId = aClientId;
this._listeners = [];
}
Icc.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIcc]),
_iccProvider: null,
_clientId: -1,
_listeners: null,
deliverListenerEvent: function(aName, aArgs) {
let listeners = this._listeners.slice();
for (let listener of listeners) {
if (this._listeners.indexOf(listener) === -1) {
continue;
}
let handler = listener[aName];
if (typeof handler != "function") {
throw new Error("No handler for " + aName);
}
try {
handler.apply(listener, aArgs);
} catch (e) {
if (DEBUG) {
debug("listener for " + aName + " threw an exception: " + e);
}
}
}
},
/**
* nsIIcc interface.
*/
registerListener: function(aListener) {
if (this._listeners.indexOf(aListener) >= 0) {
throw Cr.NS_ERROR_UNEXPECTED;
}
this._listeners.push(aListener);
cpmm.sendAsyncMessage("RIL:RegisterIccMsg");
},
unregisterListener: function(aListener) {
let index = this._listeners.indexOf(aListener);
if (index >= 0) {
this._listeners.splice(index, 1);
}
},
get iccInfo() {
return this._iccProvider.getIccInfo(this._clientId);
},
get cardState() {
return this._iccProvider.getCardState(this._clientId);
},
getCardLockEnabled: function(aLockType, aCallback) {
this._iccProvider.getCardLockEnabled(this._clientId, aLockType, aCallback);
},
unlockCardLock: function(aLockType, aPassword, aNewPin, aCallback) {
this._iccProvider.unlockCardLock(this._clientId, aLockType,
aPassword, aNewPin, aCallback);
},
setCardLockEnabled: function(aLockType, aPassword, aEnabled, aCallback) {
this._iccProvider.setCardLockEnabled(this._clientId, aLockType,
aPassword, aEnabled, aCallback);
},
changeCardLockPassword: function(aLockType, aPassword, aNewPassword, aCallback) {
this._iccProvider.changeCardLockPassword(this._clientId, aLockType,
aPassword, aNewPassword, aCallback);
},
getCardLockRetryCount: function(aLockType, aCallback) {
this._iccProvider.getCardLockRetryCount(this._clientId, aLockType, aCallback);
},
matchMvno: function(aMvnoType, aMvnoData, aCallback) {
this._iccProvider.matchMvno(this._clientId, aMvnoType, aMvnoData, aCallback);
},
getServiceStateEnabled: function(aService, aCallback) {
this._iccProvider.getServiceStateEnabled(this._clientId, aService, aCallback);
}
};

View File

@ -89,24 +89,16 @@ const NETWORK_TYPE_MOBILE_DUN = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN;
// TODO: Bug 815526, deprecate RILContentHelper.
const RIL_IPC_ICCMANAGER_MSG_NAMES = [
"RIL:GetRilContext",
"RIL:SendStkResponse",
"RIL:SendStkMenuSelection",
"RIL:SendStkTimerExpiration",
"RIL:SendStkEventDownload",
"RIL:GetCardLockEnabled",
"RIL:UnlockCardLock",
"RIL:SetCardLockEnabled",
"RIL:ChangeCardLockPassword",
"RIL:GetCardLockRetryCount",
"RIL:IccOpenChannel",
"RIL:IccExchangeAPDU",
"RIL:IccCloseChannel",
"RIL:ReadIccContacts",
"RIL:UpdateIccContact",
"RIL:RegisterIccMsg",
"RIL:MatchMvno",
"RIL:GetServiceState"
];
// set to true in ril_consts.js to see debug messages
@ -169,7 +161,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
"nsIGonkMobileConnectionService");
XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
"@mozilla.org/cellbroadcast/gonkservice;1",
"@mozilla.org/cellbroadcast/cellbroadcastservice;1",
"nsIGonkCellBroadcastService");
XPCOMUtils.defineLazyServiceGetter(this, "gIccMessenger",
@ -881,44 +873,6 @@ try {
})());
} catch (e) {}
function IccInfo() {}
IccInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccInfo]),
// nsIIccInfo
iccType: null,
iccid: null,
mcc: null,
mnc: null,
spn: null,
isDisplayNetworkNameRequired: false,
isDisplaySpnRequired: false
};
function GsmIccInfo() {}
GsmIccInfo.prototype = {
__proto__: IccInfo.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
Ci.nsIIccInfo]),
// nsIGsmIccInfo
msisdn: null
};
function CdmaIccInfo() {}
CdmaIccInfo.prototype = {
__proto__: IccInfo.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsICdmaIccInfo,
Ci.nsIIccInfo]),
// nsICdmaIccInfo
mdn: null,
prlVersion: 0
};
function DataConnectionHandler(clientId, radioInterface) {
// Initial owning attributes.
this.clientId = clientId;
@ -1441,7 +1395,6 @@ RadioInterfaceLayer.prototype = {
interfaces: [Ci.nsIRadioInterfaceLayer]}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterfaceLayer,
Ci.nsIRadioInterfaceLayer_new, // TODO: Bug 815526, deprecate RILContentHelper.
Ci.nsIObserver]),
/**
@ -1689,12 +1642,6 @@ function RadioInterface(aClientId, aWorkerMessenger) {
};
aWorkerMessenger.registerClient(aClientId, this);
this.rilContext = {
cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
iccInfo: null,
imsi: null
};
this.operatorInfo = {};
let lock = gSettingsService.createLock();
@ -1752,42 +1699,14 @@ RadioInterface.prototype = {
Services.obs.removeObserver(this, kNetworkConnStateChangedTopic);
},
/**
* A utility function to copy objects. The srcInfo may contain
* "rilMessageType", should ignore it.
*/
updateInfo: function(srcInfo, destInfo) {
for (let key in srcInfo) {
if (key === "rilMessageType") {
continue;
}
destInfo[key] = srcInfo[key];
}
},
/**
* A utility function to compare objects. The srcInfo may contain
* "rilMessageType", should ignore it.
*/
isInfoChanged: function(srcInfo, destInfo) {
if (!destInfo) {
return true;
}
for (let key in srcInfo) {
if (key === "rilMessageType") {
continue;
}
if (srcInfo[key] !== destInfo[key]) {
return true;
}
}
return false;
getIccInfo: function() {
let icc = gIccService.getIccByServiceId(this.clientId);
return icc ? icc.iccInfo : null;
},
isCardPresent: function() {
let cardState = this.rilContext.cardState;
let icc = gIccService.getIccByServiceId(this.clientId);
let cardState = icc ? icc.cardState : Ci.nsIIcc.CARD_STATE_UNKNOWN;
return cardState !== Ci.nsIIcc.CARD_STATE_UNDETECTED &&
cardState !== Ci.nsIIcc.CARD_STATE_UNKNOWN;
},
@ -1799,29 +1718,6 @@ RadioInterface.prototype = {
*/
receiveMessage: function(msg) {
switch (msg.name) {
case "RIL:GetRilContext":
// This message is sync.
return this.rilContext;
case "RIL:GetCardLockEnabled":
this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockEnabled",
"RIL:GetCardLockResult");
break;
case "RIL:UnlockCardLock":
this.workerMessenger.sendWithIPCMessage(msg, "iccUnlockCardLock",
"RIL:SetUnlockCardLockResult");
break;
case "RIL:SetCardLockEnabled":
this.workerMessenger.sendWithIPCMessage(msg, "iccSetCardLockEnabled",
"RIL:SetUnlockCardLockResult");
break;
case "RIL:ChangeCardLockPassword":
this.workerMessenger.sendWithIPCMessage(msg, "iccChangeCardLockPassword",
"RIL:SetUnlockCardLockResult");
break;
case "RIL:GetCardLockRetryCount":
this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockRetryCount",
"RIL:CardLockRetryCount");
break;
case "RIL:SendStkResponse":
this.workerMessenger.send("sendStkTerminalResponse", msg.json.data);
break;
@ -1849,12 +1745,6 @@ RadioInterface.prototype = {
case "RIL:UpdateIccContact":
this.workerMessenger.sendWithIPCMessage(msg, "updateICCContact");
break;
case "RIL:MatchMvno":
this.matchMvno(msg.target, msg.json.data);
break;
case "RIL:GetServiceState":
this.workerMessenger.sendWithIPCMessage(msg, "getIccServiceState");
break;
}
return null;
},
@ -1924,13 +1814,9 @@ RadioInterface.prototype = {
message.radioState);
break;
case "cardstatechange":
this.rilContext.cardState = message.cardState;
gRadioEnabledController.receiveCardState(this.clientId);
gIccService.notifyCardStateChanged(this.clientId,
this.rilContext.cardState);
// TODO: Bug 815526, deprecate RILContentHelper.
gMessageManager.sendIccMessage("RIL:CardStateChanged",
this.clientId, message);
message.cardState);
gRadioEnabledController.receiveCardState(this.clientId);
break;
case "sms-received":
this.handleSmsReceived(message);
@ -1942,11 +1828,11 @@ RadioInterface.prototype = {
this.handleNitzTime(message);
break;
case "iccinfochange":
this.handleIccInfoChange(message);
gIccService.notifyIccInfoChanged(this.clientId,
message.iccid ? message : null);
break;
case "iccimsi":
this.rilContext.imsi = message.imsi;
gIccService.notifyImsiChanged(this.clientId, this.rilContext.imsi);
gIccService.notifyImsiChanged(this.clientId, message.imsi);
break;
case "iccmbdn":
this.handleIccMbdn(message);
@ -1970,85 +1856,6 @@ RadioInterface.prototype = {
}
},
// Matches the mvnoData pattern with imsi. Characters 'x' and 'X' are skipped
// and not compared. E.g., if the mvnoData passed is '310260x10xxxxxx',
// then the function returns true only if imsi has the same first 6 digits,
// 8th and 9th digit.
// TODO: Bug 815526, deprecate RILContentHelper.
isImsiMatches: function(mvnoData) {
let imsi = this.rilContext.imsi;
// This should not be an error, but a mismatch.
if (mvnoData.length > imsi.length) {
return false;
}
for (let i = 0; i < mvnoData.length; i++) {
let c = mvnoData[i];
if ((c !== 'x') && (c !== 'X') && (c !== imsi[i])) {
return false;
}
}
return true;
},
// TODO: Bug 815526, deprecate RILContentHelper.
matchMvno: function(target, message) {
if (DEBUG) this.debug("matchMvno: " + JSON.stringify(message));
if (!message || !message.mvnoData) {
message.errorMsg = RIL.GECKO_ERROR_INVALID_PARAMETER;
}
if (!message.errorMsg) {
switch (message.mvnoType) {
case RIL.GECKO_CARDMVNO_TYPE_IMSI:
if (!this.rilContext.imsi) {
message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
break;
}
message.result = this.isImsiMatches(message.mvnoData);
break;
case RIL.GECKO_CARDMVNO_TYPE_SPN:
let spn = this.rilContext.iccInfo && this.rilContext.iccInfo.spn;
if (!spn) {
message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
break;
}
message.result = spn == message.mvnoData;
break;
case RIL.GECKO_CARDMVNO_TYPE_GID:
this.workerMessenger.send("getGID1", null, (function(response) {
let gid = response.gid1;
let mvnoDataLength = message.mvnoData.length;
if (!gid) {
message.errorMsg = RIL.GECKO_ERROR_GENERIC_FAILURE;
} else if (mvnoDataLength > gid.length) {
message.result = false;
} else {
message.result =
gid.substring(0, mvnoDataLength).toLowerCase() ==
message.mvnoData.toLowerCase();
}
target.sendAsyncMessage("RIL:MatchMvno", {
clientId: this.clientId,
data: message
});
}).bind(this));
return;
default:
message.errorMsg = RIL.GECKO_ERROR_MODE_NOT_SUPPORTED;
}
}
target.sendAsyncMessage("RIL:MatchMvno", {
clientId: this.clientId,
data: message
});
},
setDataRegistration: function(attach) {
let deferred = Promise.defer();
this.workerMessenger.send("setDataRegistration",
@ -2227,71 +2034,12 @@ RadioInterface.prototype = {
null, null);
},
handleIccInfoChange: function(message) {
let oldSpn = this.rilContext.iccInfo ? this.rilContext.iccInfo.spn : null;
// TODO: Bug 815526, deprecate RILContentHelper:
// Move the logic of updating iccInfo to IccService.js.
if (!message || !message.iccid) {
// If iccInfo is already `null`, don't have to clear it and send
// RIL:IccInfoChanged.
if (!this.rilContext.iccInfo) {
return;
}
// Card is not detected, clear iccInfo to null.
this.rilContext.iccInfo = null;
} else {
if (!this.rilContext.iccInfo) {
if (message.iccType === "ruim" || message.iccType === "csim") {
this.rilContext.iccInfo = new CdmaIccInfo();
} else if (message.iccType === "sim" || message.iccType === "usim") {
this.rilContext.iccInfo = new GsmIccInfo();
} else {
this.rilContext.iccInfo = new IccInfo();
}
}
if (!this.isInfoChanged(message, this.rilContext.iccInfo)) {
return;
}
this.updateInfo(message, this.rilContext.iccInfo);
}
// RIL:IccInfoChanged corresponds to a DOM event that gets fired only
// when iccInfo has changed.
// TODO: Bug 815526, deprecate RILContentHelper.
gMessageManager.sendIccMessage("RIL:IccInfoChanged",
this.clientId,
message.iccid ? message : null);
gIccService.notifyIccInfoChanged(this.clientId,
message.iccid ? message : null);
// Update lastKnownHomeNetwork.
if (message.mcc && message.mnc) {
let lastKnownHomeNetwork = message.mcc + "-" + message.mnc;
// Append spn information if available.
if (message.spn) {
lastKnownHomeNetwork += "-" + message.spn;
}
gMobileConnectionService.notifyLastHomeNetworkChanged(this.clientId,
lastKnownHomeNetwork);
}
// If spn becomes available, we should check roaming again.
if (!oldSpn && message.spn) {
gMobileConnectionService.notifySpnAvailable(this.clientId);
}
},
handleStkProactiveCommand: function(message) {
if (DEBUG) this.debug("handleStkProactiveCommand " + JSON.stringify(message));
let iccId = this.rilContext.iccInfo && this.rilContext.iccInfo.iccid;
if (iccId) {
let iccInfo = this.getIccInfo();
if (iccInfo && iccInfo.iccid) {
gIccMessenger
.notifyStkProactiveCommand(iccId,
.notifyStkProactiveCommand(iccInfo.iccid,
gStkCmdFactory.createCommand(message));
}
// TODO: Bug 815526, deprecate RILContentHelper.
@ -2589,8 +2337,6 @@ RadioInterface.prototype = {
// nsIRadioInterface
rilContext: null,
// TODO: Bug 928861 - B2G NetworkManager: Provide a more generic function
// for connecting
setupDataCallByType: function(networkType) {
@ -3226,8 +2972,8 @@ RILNetworkInterface.prototype = {
},
get iccId() {
let iccInfo = this.dataConnectionHandler.radioInterface.rilContext.iccInfo;
return iccInfo && iccInfo.iccid;
let iccInfo = this.dataConnectionHandler.radioInterface.getIccInfo();
return iccInfo ? iccInfo.iccid : null;
},
get mmsc() {

View File

@ -21,30 +21,15 @@ interface nsIRilNetworkInterface : nsINetworkInterface
readonly attribute long mmsPort; // -1 if not set.
};
[scriptable, uuid(4441e660-4ad0-11e4-916c-0800200c9a66)]
interface nsIRilContext : nsISupports
{
/**
* One of the nsIIcc.CARD_STATE_* values.
*/
readonly attribute unsigned long cardState;
readonly attribute DOMString imsi;
readonly attribute nsIIccInfo iccInfo;
};
[scriptable, function, uuid(3bc96351-53b0-47a1-a888-c74c64b60f25)]
interface nsIRilSendWorkerMessageCallback : nsISupports
{
boolean handleResponse(in jsval response);
};
[scriptable, uuid(fe01c648-867a-11e4-915f-033b36e8177b)]
[scriptable, uuid(1a3ef88a-e4d1-11e4-8512-176220f2b32b)]
interface nsIRadioInterface : nsISupports
{
readonly attribute nsIRilContext rilContext;
/**
* PDP APIs
*
@ -79,13 +64,3 @@ interface nsIRadioInterfaceLayer : nsISupports
void setMicrophoneMuted(in boolean muted);
};
/**
* Helper Interface to define new APIs of nsIRadioInterfaceLayer during
* ril-interfaces frozen phase.
*/
[scriptable, uuid(f8ec63da-c22e-11e4-89f3-b767dae42a13)]
interface nsIRadioInterfaceLayer_new : nsIRadioInterfaceLayer
{
};

View File

@ -61,7 +61,7 @@ var ecmaGlobals =
"Int32Array",
"Int8Array",
"InternalError",
{name: "Intl", desktop: true},
{name: "Intl", android: false},
"Iterator",
"JSON",
"Map",
@ -1391,6 +1391,7 @@ function createInterfaceMap(isXBLScope) {
var isRelease = !version.contains("a");
var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
var isB2G = !isDesktop && !navigator.userAgent.contains("Android");
var isAndroid = navigator.userAgent.contains("Android");
var hasPermission = function (aPermissions) {
var result = false;
for (var p of aPermissions) {
@ -1410,6 +1411,7 @@ function createInterfaceMap(isXBLScope) {
(entry.xbl === !isXBLScope) ||
(entry.desktop === !isDesktop) ||
(entry.b2g === !isB2G) ||
(entry.android === !isAndroid) ||
(entry.release === !isRelease) ||
(entry.pref && !prefs.getBoolPref(entry.pref)) ||
(entry.permission && !hasPermission(entry.permission))) {

View File

@ -37,9 +37,9 @@ XPCOMUtils.defineLazyGetter(this, "CP", function () {
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
"@mozilla.org/system-message-internal;1",
"nsISystemMessagesInternal");
XPCOMUtils.defineLazyServiceGetter(this, "gRIL",
"@mozilla.org/ril;1",
"nsIRadioInterfaceLayer");
XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
"@mozilla.org/icc/iccservice;1",
"nsIIccService");
/**
* Helpers for WAP PDU processing.
@ -104,7 +104,8 @@ this.WapPushManager = {
let mac = params && params.mac;
authInfo = CP.Authenticator.check(data.array.subarray(data.offset),
sec, mac, function getNetworkPin() {
let imsi = gRIL.getRadioInterface(options.serviceId).rilContext.imsi;
let icc = gIccService.getIccByServiceId(options.serviceId);
let imsi = icc ? icc.imsi : null;
return CP.Authenticator.formatImsi(imsi);
});
}

View File

@ -418,21 +418,47 @@ CompareNetwork::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
if (!httpChannel) {
mManager->NetworkFinished(NS_ERROR_FAILURE);
return NS_OK;
}
if (httpChannel) {
bool requestSucceeded;
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
if (NS_WARN_IF(NS_FAILED(rv))) {
mManager->NetworkFinished(rv);
return NS_OK;
}
bool requestSucceeded;
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
if (NS_WARN_IF(NS_FAILED(rv))) {
mManager->NetworkFinished(rv);
return NS_OK;
if (!requestSucceeded) {
mManager->NetworkFinished(NS_ERROR_FAILURE);
return NS_OK;
}
}
else {
// The only supported request schemes are http, https, and app.
// Above, we check to ensure that the request is http or https
// based on the channel qi. Here we test the scheme to ensure
// that it is app. Otherwise, bail.
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
if (NS_WARN_IF(!channel)) {
mManager->NetworkFinished(NS_ERROR_FAILURE);
return NS_OK;
}
nsCOMPtr<nsIURI> uri;
rv = channel->GetURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv))) {
mManager->NetworkFinished(rv);
return NS_OK;
}
if (!requestSucceeded) {
mManager->NetworkFinished(NS_ERROR_FAILURE);
return NS_OK;
nsAutoCString scheme;
rv = uri->GetScheme(scheme);
if (NS_WARN_IF(NS_FAILED(rv))) {
mManager->NetworkFinished(rv);
return NS_OK;
}
if (!scheme.LowerCaseEqualsLiteral("app")) {
mManager->NetworkFinished(NS_ERROR_FAILURE);
return NS_OK;
}
}
// FIXME(nsm): "Extract mime type..."

View File

@ -35,7 +35,7 @@ var ecmaGlobals =
"Int32Array",
"Int8Array",
"InternalError",
{name: "Intl", b2g: false, android: false},
{name: "Intl", android: false},
"Iterator",
"JSON",
"Map",

View File

@ -35,7 +35,7 @@ var ecmaGlobals =
"Int32Array",
"Int8Array",
"InternalError",
{name: "Intl", b2g: false, android: false},
{name: "Intl", android: false},
"Iterator",
"JSON",
"Map",

View File

@ -10,6 +10,7 @@
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include "mozilla/ipc/DataSocket.h"
#include "mozilla/ipc/UnixSocketWatcher.h"
#include "nsTArray.h"
#include "nsXULAppAPI.h"

View File

@ -1838,12 +1838,15 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
if usesend or userecv:
transitionfunc.addstmt(Whitespace.NL)
transitionfunc.addstmts([
fromswitch,
# all --> Error transitions break to here
StmtExpr(ExprAssn(ExprDeref(nextvar), _errorState())),
StmtReturn(ExprLiteral.FALSE)
])
transitionfunc.addstmt(fromswitch)
# all --> Error transitions break to here. But only insert this
# block if there is any possibility of such transitions.
if self.protocol.transitionStmts:
transitionfunc.addstmts([
StmtExpr(ExprAssn(ExprDeref(nextvar), _errorState())),
StmtReturn(ExprLiteral.FALSE),
])
return transitionfunc
##--------------------------------------------------

View File

@ -0,0 +1,48 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=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/.
*/
#include "mozilla/ipc/DataSocket.h"
namespace mozilla {
namespace ipc {
//
// DataSocketIO
//
DataSocketIO::~DataSocketIO()
{ }
void
DataSocketIO::EnqueueData(UnixSocketIOBuffer* aBuffer)
{
if (!aBuffer->GetSize()) {
delete aBuffer; // delete empty data immediately
return;
}
mOutgoingQ.AppendElement(aBuffer);
}
bool
DataSocketIO::HasPendingData() const
{
return !mOutgoingQ.IsEmpty();
}
DataSocketIO::DataSocketIO()
{ }
//
// DataSocket
//
DataSocket::~DataSocket()
{ }
}
}

204
ipc/unixsocket/DataSocket.h Normal file
View File

@ -0,0 +1,204 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=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_ipc_datasocket_h
#define mozilla_ipc_datasocket_h
#include "mozilla/ipc/SocketBase.h"
namespace mozilla {
namespace ipc {
//
// DataSocket
//
/**
* |DataSocket| represents a socket that can send or receive data. This
* can be a stream-based socket, a datagram-based socket, or any other
* socket that transfers data.
*/
class DataSocket : public SocketBase
{
public:
virtual ~DataSocket();
/**
* Queue data to be sent to the socket on the IO thread. Can only be called on
* originating thread.
*
* @param aBuffer Data to be sent to socket
*/
virtual void SendSocketData(UnixSocketIOBuffer* aBuffer) = 0;
};
//
// DataSocketIO
//
/**
* |DataSocketIO| is a base class for Socket I/O classes that
* transfer data on the I/O thread. It provides methods for the
* most common read and write scenarios.
*/
class DataSocketIO : public SocketIOBase
{
public:
virtual ~DataSocketIO();
/**
* Allocates a buffer for receiving data from the socket. The method
* shall return the buffer in the arguments. The buffer is owned by the
* I/O class. |DataSocketIO| will never ask for more than one buffer
* at a time, so I/O classes can handout the same buffer on each invokation
* of this method. I/O-thread only.
*
* @param[out] aBuffer returns a pointer to the I/O buffer
* @return NS_OK on success, or an error code otherwise
*/
virtual nsresult QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer) = 0;
/**
* Marks the current socket buffer to by consumed by the I/O class. The
* class is resonsible for releasing the buffer afterwards. I/O-thread
* only.
*
* @param aIndex the socket's index
* @param[out] aBuffer the receive buffer
* @param[out] aSize the receive buffer's size
*/
virtual void ConsumeBuffer() = 0;
/**
* Marks the current socket buffer to be discarded. The I/O class is
* resonsible for releasing the buffer's memory. I/O-thread only.
*
* @param aIndex the socket's index
*/
virtual void DiscardBuffer() = 0;
void EnqueueData(UnixSocketIOBuffer* aBuffer);
bool HasPendingData() const;
template <typename T>
ssize_t ReceiveData(int aFd, T* aIO)
{
MOZ_ASSERT(aFd >= 0);
MOZ_ASSERT(aIO);
UnixSocketIOBuffer* incoming;
nsresult rv = QueryReceiveBuffer(&incoming);
if (NS_FAILED(rv)) {
/* an error occured */
nsRefPtr<nsRunnable> r = new SocketIORequestClosingRunnable<T>(aIO);
NS_DispatchToMainThread(r);
return -1;
}
ssize_t res = incoming->Receive(aFd);
if (res < 0) {
/* an I/O error occured */
DiscardBuffer();
nsRefPtr<nsRunnable> r = new SocketIORequestClosingRunnable<T>(aIO);
NS_DispatchToMainThread(r);
return -1;
} else if (!res) {
/* EOF or peer shut down sending */
DiscardBuffer();
nsRefPtr<nsRunnable> r = new SocketIORequestClosingRunnable<T>(aIO);
NS_DispatchToMainThread(r);
return 0;
}
#ifdef MOZ_TASK_TRACER
// Make unix socket creation events to be the source events of TaskTracer,
// and originate the rest correlation tasks from here.
AutoSourceEvent taskTracerEvent(SourceEventType::Unixsocket);
#endif
ConsumeBuffer();
return res;
}
template <typename T>
nsresult SendPendingData(int aFd, T* aIO)
{
MOZ_ASSERT(aFd >= 0);
MOZ_ASSERT(aIO);
while (HasPendingData()) {
UnixSocketIOBuffer* outgoing = mOutgoingQ.ElementAt(0);
ssize_t res = outgoing->Send(aFd);
if (res < 0) {
/* an I/O error occured */
nsRefPtr<nsRunnable> r = new SocketIORequestClosingRunnable<T>(aIO);
NS_DispatchToMainThread(r);
return NS_ERROR_FAILURE;
} else if (!res && outgoing->GetSize()) {
/* I/O is currently blocked; try again later */
return NS_OK;
}
if (!outgoing->GetSize()) {
mOutgoingQ.RemoveElementAt(0);
delete outgoing;
}
}
return NS_OK;
}
protected:
DataSocketIO();
private:
/**
* Raw data queue. Must be pushed/popped from I/O thread only.
*/
nsTArray<UnixSocketIOBuffer*> mOutgoingQ;
};
//
// Tasks
//
/* |SocketIOSendTask| transfers an instance of |Tdata|, such as
* |UnixSocketRawData|, to the I/O thread and queues it up for
* sending the contained data.
*/
template<typename Tio, typename Tdata>
class SocketIOSendTask final : public SocketIOTask<Tio>
{
public:
SocketIOSendTask(Tio* aIO, Tdata* aData)
: SocketIOTask<Tio>(aIO)
, mData(aData)
{
MOZ_ASSERT(aData);
}
void Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!SocketIOTask<Tio>::IsCanceled());
Tio* io = SocketIOTask<Tio>::GetIO();
MOZ_ASSERT(!io->IsShutdownOnIOThread());
io->Send(mData);
}
private:
Tdata* mData;
};
}
}
#endif

View File

@ -7,12 +7,11 @@
#include "ListenSocket.h"
#include <fcntl.h>
#include "ConnectionOrientedSocket.h"
#include "DataSocket.h"
#include "mozilla/RefPtr.h"
#include "nsXULAppAPI.h"
#include "UnixSocketConnector.h"
static const size_t MAX_READ_SIZE = 1; /* any small constant */
namespace mozilla {
namespace ipc {
@ -32,9 +31,9 @@ public:
const nsACString& aAddress);
~ListenSocketIO();
void GetSocketAddr(nsAString& aAddrStr) const;
SocketConsumerBase* GetConsumer();
SocketBase* GetSocketBase();
void GetSocketAddr(nsAString& aAddrStr) const;
DataSocket* GetDataSocket();
SocketBase* GetSocketBase();
// Shutdown state
//
@ -107,13 +106,13 @@ ListenSocketIO::ListenSocketIO(MessageLoop* mIOLoop,
ListenSocket* aListenSocket,
UnixSocketConnector* aConnector,
const nsACString& aAddress)
: UnixSocketWatcher(mIOLoop)
, SocketIOBase(MAX_READ_SIZE)
, mListenSocket(aListenSocket)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddress(aAddress)
, mCOSocketIO(nullptr)
: UnixSocketWatcher(mIOLoop)
, SocketIOBase()
, mListenSocket(aListenSocket)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddress(aAddress)
, mCOSocketIO(nullptr)
{
MOZ_ASSERT(mListenSocket);
MOZ_ASSERT(mConnector);
@ -136,6 +135,14 @@ ListenSocketIO::GetSocketAddr(nsAString& aAddrStr) const
mConnector->GetSocketAddr(mAddr, aAddrStr);
}
DataSocket*
ListenSocketIO::GetDataSocket()
{
MOZ_CRASH("Listen sockets cannot transfer data");
return nullptr;
}
SocketBase*
ListenSocketIO::GetSocketBase()
{

View File

@ -268,41 +268,15 @@ SocketBase::SetConnectionStatus(SocketConnectionStatus aConnectionStatus)
mConnectionStatus = aConnectionStatus;
}
//
// SocketConsumerBase
//
SocketConsumerBase::~SocketConsumerBase()
{ }
//
// SocketIOBase
//
SocketIOBase::SocketIOBase()
{ }
SocketIOBase::~SocketIOBase()
{ }
void
SocketIOBase::EnqueueData(UnixSocketIOBuffer* aBuffer)
{
if (!aBuffer->GetSize()) {
delete aBuffer; // delete empty data immediately
return;
}
mOutgoingQ.AppendElement(aBuffer);
}
bool
SocketIOBase::HasPendingData() const
{
return !mOutgoingQ.IsEmpty();
}
SocketIOBase::SocketIOBase(size_t aMaxReadSize)
: mMaxReadSize(aMaxReadSize)
{
MOZ_ASSERT(mMaxReadSize);
}
}
}

View File

@ -310,32 +310,6 @@ private:
uint32_t mConnectDelayMs;
};
//
// SocketConsumerBase
//
class SocketConsumerBase : public SocketBase
{
public:
virtual ~SocketConsumerBase();
/**
* Function to be called whenever data is received. This is only called on the
* main thread.
*
* @param aBuffer Data received from the socket.
*/
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer) = 0;
/**
* Queue data to be sent to the socket on the IO thread. Can only be called on
* originating thread.
*
* @param aBuffer Data to be sent to socket
*/
virtual void SendSocketData(UnixSocketIOBuffer* aBuffer) = 0;
};
//
// Socket I/O runnables
//
@ -415,43 +389,6 @@ private:
SocketEvent mEvent;
};
/* |SocketReceiveRunnable| transfers data received on the I/O thread
* to the consumer on the main thread.
*/
template <typename T>
class SocketIOReceiveRunnable final : public SocketIORunnable<T>
{
public:
SocketIOReceiveRunnable(T* aIO, UnixSocketBuffer* aBuffer)
: SocketIORunnable<T>(aIO)
, mBuffer(aBuffer)
{ }
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
T* io = SocketIORunnable<T>::GetIO();
if (io->IsShutdownOnMainThread()) {
NS_WARNING("mConsumer is null, aborting receive!");
// Since we've already explicitly closed and the close happened before
// this, this isn't really an error. Since we've warned, return OK.
return NS_OK;
}
SocketConsumerBase* consumer = io->GetConsumer();
MOZ_ASSERT(consumer);
consumer->ReceiveSocketData(mBuffer);
return NS_OK;
}
private:
nsAutoPtr<UnixSocketBuffer> mBuffer;
};
template <typename T>
class SocketIORequestClosingRunnable final : public SocketIORunnable<T>
{
@ -507,91 +444,17 @@ private:
// SocketIOBase
//
/* |SocketIOBase| is a base class for Socket I/O classes that
* perform operations on the I/O thread. It provides methods
* for the most common read and write scenarios.
/**
* |SocketIOBase| is a base class for Socket I/O classes that
* perform operations on the I/O thread.
*/
class SocketIOBase
{
public:
virtual ~SocketIOBase();
void EnqueueData(UnixSocketIOBuffer* aBuffer);
bool HasPendingData() const;
template <typename T>
ssize_t ReceiveData(int aFd, T* aIO)
{
MOZ_ASSERT(aFd >= 0);
MOZ_ASSERT(aIO);
nsAutoPtr<UnixSocketRawData> incoming(
new UnixSocketRawData(mMaxReadSize));
ssize_t res = incoming->Receive(aFd);
if (res < 0) {
/* an I/O error occured */
nsRefPtr<nsRunnable> r = new SocketIORequestClosingRunnable<T>(aIO);
NS_DispatchToMainThread(r);
return -1;
} else if (!res) {
/* EOF or peer shut down sending */
nsRefPtr<nsRunnable> r = new SocketIORequestClosingRunnable<T>(aIO);
NS_DispatchToMainThread(r);
return 0;
}
#ifdef MOZ_TASK_TRACER
// Make unix socket creation events to be the source events of TaskTracer,
// and originate the rest correlation tasks from here.
AutoSourceEvent taskTracerEvent(SourceEventType::Unixsocket);
#endif
nsRefPtr<nsRunnable> r =
new SocketIOReceiveRunnable<T>(aIO, incoming.forget());
NS_DispatchToMainThread(r);
return res;
}
template <typename T>
nsresult SendPendingData(int aFd, T* aIO)
{
MOZ_ASSERT(aFd >= 0);
MOZ_ASSERT(aIO);
while (HasPendingData()) {
UnixSocketIOBuffer* outgoing = mOutgoingQ.ElementAt(0);
ssize_t res = outgoing->Send(aFd);
if (res < 0) {
/* an I/O error occured */
nsRefPtr<nsRunnable> r = new SocketIORequestClosingRunnable<T>(aIO);
NS_DispatchToMainThread(r);
return NS_ERROR_FAILURE;
} else if (!res && outgoing->GetSize()) {
/* I/O is currently blocked; try again later */
return NS_OK;
}
if (!outgoing->GetSize()) {
mOutgoingQ.RemoveElementAt(0);
delete outgoing;
}
}
return NS_OK;
}
protected:
SocketIOBase(size_t aMaxReadSize);
private:
const size_t mMaxReadSize;
/**
* Raw data queue. Must be pushed/popped from I/O thread only.
*/
nsTArray<UnixSocketIOBuffer*> mOutgoingQ;
SocketIOBase();
};
//
@ -634,36 +497,6 @@ private:
Tio* mIO;
};
/* |SocketIOSendTask| transfers an instance of |Tdata|, such as
* |UnixSocketRawData|, to the I/O thread and queues it up for
* sending the contained data.
*/
template<typename Tio, typename Tdata>
class SocketIOSendTask final : public SocketIOTask<Tio>
{
public:
SocketIOSendTask(Tio* aIO, Tdata* aData)
: SocketIOTask<Tio>(aIO)
, mData(aData)
{
MOZ_ASSERT(aData);
}
void Run() override
{
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(!SocketIOTask<Tio>::IsCanceled());
Tio* io = SocketIOTask<Tio>::GetIO();
MOZ_ASSERT(!io->IsShutdownOnIOThread());
io->Send(mData);
}
private:
Tdata* mData;
};
/* |SocketIOShutdownTask| signals shutdown to the Socket I/O object on
* the I/O thread and sends it to the main thread for destruction.
*/

View File

@ -19,13 +19,15 @@ namespace ipc {
// StreamSocketIO
//
class StreamSocketIO final : public UnixSocketWatcher
, protected SocketIOBase
, public ConnectionOrientedSocketIO
class StreamSocketIO final
: public UnixSocketWatcher
, protected DataSocketIO
, public ConnectionOrientedSocketIO
{
public:
class ConnectTask;
class DelayedConnectTask;
class ReceiveRunnable;
StreamSocketIO(MessageLoop* mIOLoop,
StreamSocket* aStreamSocket,
@ -38,9 +40,11 @@ public:
const nsACString& aAddress);
~StreamSocketIO();
void GetSocketAddr(nsAString& aAddrStr) const;
SocketConsumerBase* GetConsumer();
SocketBase* GetSocketBase();
void GetSocketAddr(nsAString& aAddrStr) const;
StreamSocket* GetStreamSocket();
DataSocket* GetDataSocket();
SocketBase* GetSocketBase();
// StreamSocketIOBase
//
@ -85,6 +89,13 @@ public:
void OnSocketCanReceiveWithoutBlocking() override;
void OnSocketCanSendWithoutBlocking() override;
// Methods for |DataSocket|
//
nsresult QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer);
void ConsumeBuffer();
void DiscardBuffer();
private:
void FireSocketError();
@ -127,19 +138,23 @@ private:
* Task member for delayed connect task. Should only be access on main thread.
*/
CancelableTask* mDelayedConnectTask;
/**
* I/O buffer for received data
*/
nsAutoPtr<UnixSocketRawData> mBuffer;
};
StreamSocketIO::StreamSocketIO(MessageLoop* mIOLoop,
StreamSocket* aStreamSocket,
UnixSocketConnector* aConnector,
const nsACString& aAddress)
: UnixSocketWatcher(mIOLoop)
, SocketIOBase(MAX_READ_SIZE)
, mStreamSocket(aStreamSocket)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddress(aAddress)
, mDelayedConnectTask(nullptr)
: UnixSocketWatcher(mIOLoop)
, mStreamSocket(aStreamSocket)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddress(aAddress)
, mDelayedConnectTask(nullptr)
{
MOZ_ASSERT(mStreamSocket);
MOZ_ASSERT(mConnector);
@ -150,13 +165,12 @@ StreamSocketIO::StreamSocketIO(MessageLoop* mIOLoop, int aFd,
StreamSocket* aStreamSocket,
UnixSocketConnector* aConnector,
const nsACString& aAddress)
: UnixSocketWatcher(mIOLoop, aFd, aConnectionStatus)
, SocketIOBase(MAX_READ_SIZE)
, mStreamSocket(aStreamSocket)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddress(aAddress)
, mDelayedConnectTask(nullptr)
: UnixSocketWatcher(mIOLoop, aFd, aConnectionStatus)
, mStreamSocket(aStreamSocket)
, mConnector(aConnector)
, mShuttingDownOnIOThread(false)
, mAddress(aAddress)
, mDelayedConnectTask(nullptr)
{
MOZ_ASSERT(mStreamSocket);
MOZ_ASSERT(mConnector);
@ -179,8 +193,14 @@ StreamSocketIO::GetSocketAddr(nsAString& aAddrStr) const
mConnector->GetSocketAddr(mAddr, aAddrStr);
}
SocketConsumerBase*
StreamSocketIO::GetConsumer()
StreamSocket*
StreamSocketIO::GetStreamSocket()
{
return mStreamSocket.get();
}
DataSocket*
StreamSocketIO::GetDataSocket()
{
return mStreamSocket.get();
}
@ -188,7 +208,7 @@ StreamSocketIO::GetConsumer()
SocketBase*
StreamSocketIO::GetSocketBase()
{
return GetConsumer();
return GetDataSocket();
}
bool
@ -497,6 +517,68 @@ StreamSocketIO::SetSocketFlags(int aFd)
return true;
}
nsresult
StreamSocketIO::QueryReceiveBuffer(UnixSocketIOBuffer** aBuffer)
{
MOZ_ASSERT(aBuffer);
if (!mBuffer) {
mBuffer = new UnixSocketRawData(MAX_READ_SIZE);
}
*aBuffer = mBuffer.get();
return NS_OK;
}
/**
* |ReceiveRunnable| transfers data received on the I/O thread
* to an instance of |StreamSocket| on the main thread.
*/
class StreamSocketIO::ReceiveRunnable final
: public SocketIORunnable<StreamSocketIO>
{
public:
ReceiveRunnable(StreamSocketIO* aIO, UnixSocketBuffer* aBuffer)
: SocketIORunnable<StreamSocketIO>(aIO)
, mBuffer(aBuffer)
{ }
NS_IMETHOD Run() override
{
MOZ_ASSERT(NS_IsMainThread());
StreamSocketIO* io = SocketIORunnable<StreamSocketIO>::GetIO();
if (NS_WARN_IF(io->IsShutdownOnMainThread())) {
// Since we've already explicitly closed and the close
// happened before this, this isn't really an error.
return NS_OK;
}
StreamSocket* streamSocket = io->GetStreamSocket();
MOZ_ASSERT(streamSocket);
streamSocket->ReceiveSocketData(mBuffer);
return NS_OK;
}
private:
nsAutoPtr<UnixSocketBuffer> mBuffer;
};
void
StreamSocketIO::ConsumeBuffer()
{
NS_DispatchToMainThread(new ReceiveRunnable(this, mBuffer.forget()));
}
void
StreamSocketIO::DiscardBuffer()
{
// Nothing to do.
}
//
// Socket tasks
//

View File

@ -7,7 +7,7 @@
#ifndef mozilla_ipc_streamsocket_h
#define mozilla_ipc_streamsocket_h
#include "mozilla/ipc/SocketBase.h"
#include "mozilla/ipc/DataSocket.h"
#include "ConnectionOrientedSocket.h"
namespace mozilla {
@ -16,12 +16,20 @@ namespace ipc {
class StreamSocketIO;
class UnixSocketConnector;
class StreamSocket : public SocketConsumerBase
class StreamSocket : public DataSocket
, public ConnectionOrientedSocket
{
public:
StreamSocket();
/**
* Method to be called whenever data is received. This is only called on the
* main thread.
*
* @param aBuffer Data received from the socket.
*/
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketBuffer>& aBuffer) = 0;
/**
* Queue data to be sent to the socket on the IO thread. Can only be called on
* originating thread.

View File

@ -6,6 +6,7 @@
EXPORTS.mozilla.ipc += [
'ConnectionOrientedSocket.h',
'DataSocket.h',
'ListenSocket.h',
'SocketBase.h',
'StreamSocket.h',
@ -14,6 +15,7 @@ EXPORTS.mozilla.ipc += [
SOURCES += [
'ConnectionOrientedSocket.cpp',
'DataSocket.cpp',
'ListenSocket.cpp',
'SocketBase.cpp',
'StreamSocket.cpp',

View File

@ -63,15 +63,34 @@ template bool js::IsVectorObject<Int32x4>(HandleValue v);
template bool js::IsVectorObject<Float32x4>(HandleValue v);
template bool js::IsVectorObject<Float64x2>(HandleValue v);
static inline bool
ErrorBadArgs(JSContext* cx)
{
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
static inline bool
ErrorWrongTypeArg(JSContext* cx, size_t argIndex, Handle<TypeDescr*> typeDescr)
{
MOZ_ASSERT(argIndex < 10);
char charArgIndex[2];
JS_snprintf(charArgIndex, sizeof charArgIndex, "%d", argIndex);
HeapSlot& typeNameSlot = typeDescr->getReservedSlotRef(JS_DESCR_SLOT_STRING_REPR);
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR,
JS_EncodeString(cx, typeNameSlot.toString()), charArgIndex);
return false;
}
template<typename V>
bool
js::ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out)
{
typedef typename V::Elem Elem;
if (!IsVectorObject<V>(v)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR);
return false;
}
Rooted<TypeDescr*> typeDescr(cx, &V::GetTypeDescr(*cx->global()));
if (!IsVectorObject<V>(v))
return ErrorWrongTypeArg(cx, 1, typeDescr);
Elem* mem = reinterpret_cast<Elem*>(v.toObject().as<TypedObject>().typedMem());
*out = jit::SimdConstant::CreateX4(mem);
@ -622,13 +641,6 @@ struct ShiftRightLogical {
};
}
static inline bool
ErrorBadArgs(JSContext* cx)
{
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
template<typename Out>
static bool
StoreResult(JSContext* cx, CallArgs& args, typename Out::Elem* result)

View File

@ -658,14 +658,15 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE* toStmt)
if (stmt->isBlockScope) {
MOZ_ASSERT(stmt->isNestedScope);
StaticBlockObject& blockObj = stmt->staticBlock();
if (!bce->emit1(JSOP_DEBUGLEAVEBLOCK))
return false;
if (!popScopeForNonLocalExit(stmt->blockScopeIndex))
return false;
if (blockObj.needsClone()) {
if (!bce->emit1(JSOP_POPBLOCKSCOPE))
return false;
} else {
if (!bce->emit1(JSOP_DEBUGLEAVEBLOCK))
return false;
}
if (!popScopeForNonLocalExit(stmt->blockScopeIndex))
return false;
}
}
@ -877,12 +878,18 @@ BytecodeEmitter::computeLocalOffset(Handle<StaticBlockObject*> blockObj)
// Only functions have fixed var bindings.
//
// To assist the debugger, we emit a DEBUGLEAVEBLOCK opcode before leaving a
// block scope, even if the block has no aliased locals. This allows
// DebugScopes to invalidate any association between a debugger scope object,
// which can proxy access to unaliased stack locals, and the actual live frame.
// In normal, non-debug mode, this opcode does not cause any baseline code to be
// block scope, if the block has no aliased locals. This allows DebugScopes
// to invalidate any association between a debugger scope object, which can
// proxy access to unaliased stack locals, and the actual live frame. In
// normal, non-debug mode, this opcode does not cause any baseline code to be
// emitted.
//
// If the block has aliased locals, no DEBUGLEAVEBLOCK is emitted, and
// POPBLOCKSCOPE itself balances the debug scope mapping. This gets around a
// comedic situation where DEBUGLEAVEBLOCK may remove a block scope from the
// debug scope map, but the immediate following POPBLOCKSCOPE adds it back due
// to an onStep hook.
//
// Enter a nested scope with enterNestedScope. It will emit
// PUSHBLOCKSCOPE/ENTERWITH if needed, and arrange to record the PC bounds of
// the scope. Leave a nested scope with leaveNestedScope, which, for blocks,
@ -974,11 +981,16 @@ BytecodeEmitter::leaveNestedScope(StmtInfoBCE* stmt)
popStatement();
if (!emit1(stmt->isBlockScope ? JSOP_DEBUGLEAVEBLOCK : JSOP_LEAVEWITH))
return false;
if (stmt->isBlockScope && stmt->staticScope->as<StaticBlockObject>().needsClone()) {
if (!emit1(JSOP_POPBLOCKSCOPE))
if (stmt->isBlockScope) {
if (stmt->staticScope->as<StaticBlockObject>().needsClone()) {
if (!emit1(JSOP_POPBLOCKSCOPE))
return false;
} else {
if (!emit1(JSOP_DEBUGLEAVEBLOCK))
return false;
}
} else {
if (!emit1(JSOP_LEAVEWITH))
return false;
}

View File

@ -633,6 +633,15 @@ class FullParseHandler
return false;
}
bool isReturnStatement(ParseNode* node) {
return node->isKind(PNK_RETURN);
}
bool isStatementPermittedAfterReturnStatement(ParseNode *node) {
ParseNodeKind kind = node->getKind();
return kind == PNK_FUNCTION || kind == PNK_VAR || kind == PNK_BREAK || kind == PNK_THROW;
}
inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op);
void setBeginPosition(ParseNode* pn, ParseNode* oth) {
@ -659,11 +668,23 @@ class FullParseHandler
}
ParseNode* newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return new_<ListNode>(kind, op, pos());
}
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
kind == PNK_GLOBALCONST);
return new_<ListNode>(kind, op, pos());
}
/* New list with one initial child node. kid must be non-null. */
ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return new_<ListNode>(kind, op, kid);
}
ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
kind == PNK_GLOBALCONST);
return new_<ListNode>(kind, op, kid);
}

View File

@ -1670,7 +1670,7 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, FunctionType ty
if (list) {
handler.addList(list, item);
} else {
list = handler.newList(PNK_VAR, item);
list = handler.newDeclarationList(PNK_VAR, item);
if (!list)
return false;
*listp = list;
@ -2820,6 +2820,9 @@ Parser<ParseHandler>::statements()
pc->blockNode = pn;
bool canHaveDirectives = pc->atBodyLevel();
bool afterReturn = false;
bool warnedAboutStatementsAfterReturn = false;
uint32_t statementBegin;
for (;;) {
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
@ -2829,12 +2832,32 @@ Parser<ParseHandler>::statements()
}
if (tt == TOK_EOF || tt == TOK_RC)
break;
if (afterReturn) {
TokenPos pos(0, 0);
if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
return null();
statementBegin = pos.begin;
}
Node next = statement(canHaveDirectives);
if (!next) {
if (tokenStream.isEOF())
isUnexpectedEOF_ = true;
return null();
}
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler.isStatementPermittedAfterReturnStatement(next)) {
if (!reportWithOffset(ParseWarning, false, statementBegin,
JSMSG_STMT_AFTER_RETURN))
{
return null();
}
warnedAboutStatementsAfterReturn = true;
}
} else if (handler.isReturnStatement(next)) {
afterReturn = true;
}
}
if (canHaveDirectives) {
if (!maybeParseDirective(pn, next, &canHaveDirectives))
@ -3803,7 +3826,7 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool* psimple,
else if (kind == PNK_GLOBALCONST)
op = JSOP_DEFCONST;
Node pn = handler.newList(kind, op);
Node pn = handler.newDeclarationList(kind, op);
if (!pn)
return null();
@ -5168,14 +5191,37 @@ Parser<ParseHandler>::switchStatement()
if (!body)
return null();
bool afterReturn = false;
bool warnedAboutStatementsAfterReturn = false;
uint32_t statementBegin;
while (true) {
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
return null();
if (tt == TOK_RC || tt == TOK_CASE || tt == TOK_DEFAULT)
break;
if (afterReturn) {
TokenPos pos(0, 0);
if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
return null();
statementBegin = pos.begin;
}
Node stmt = statement();
if (!stmt)
return null();
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler.isStatementPermittedAfterReturnStatement(stmt)) {
if (!reportWithOffset(ParseWarning, false, statementBegin,
JSMSG_STMT_AFTER_RETURN))
{
return null();
}
warnedAboutStatementsAfterReturn = true;
}
} else if (handler.isReturnStatement(stmt)) {
afterReturn = true;
}
}
handler.addList(body, stmt);
}
@ -5319,19 +5365,7 @@ Parser<ParseHandler>::returnStatement()
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
return null();
switch (tt) {
case TOK_EOL: {
bool startsExpr;
if (!tokenStream.nextTokenStartsExpr(&startsExpr, TokenStream::Operand))
return null();
if (startsExpr) {
TokenPos pos;
if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
return null();
if (!reportWithOffset(ParseWarning, false, pos.begin, JSMSG_STMT_AFTER_SEMI_LESS))
return null();
}
// Fall through.
}
case TOK_EOL:
case TOK_EOF:
case TOK_SEMI:
case TOK_RC:

View File

@ -43,6 +43,10 @@ class SyntaxParseHandler
NodeGetProp,
NodeStringExprStatement,
NodeLValue,
NodeReturn,
NodeHoistableDeclaration,
NodeBreak,
NodeThrow,
// In rare cases a parenthesized |node| doesn't have the same semantics
// as |node|. Each such node has a special Node value, and we use a
@ -214,14 +218,14 @@ class SyntaxParseHandler
Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; }
Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
Node newContinueStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
Node newReturnStatement(Node expr, Node genrval, const TokenPos& pos) { return NodeGeneric; }
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeBreak; }
Node newReturnStatement(Node expr, Node genrval, const TokenPos& pos) { return NodeReturn; }
Node newLabeledStatement(PropertyName* label, Node stmt, uint32_t begin) {
return NodeGeneric;
}
Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeGeneric; }
Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeThrow; }
Node newTryStatement(uint32_t begin, Node body, Node catchList, Node finallyBlock) {
return NodeGeneric;
}
@ -238,7 +242,7 @@ class SyntaxParseHandler
Node catchName, Node catchGuard, Node catchBody) { return true; }
void setLastFunctionArgumentDefault(Node funcpn, Node pn) {}
Node newFunctionDefinition() { return NodeGeneric; }
Node newFunctionDefinition() { return NodeHoistableDeclaration; }
void setFunctionBody(Node pn, Node kid) {}
void setFunctionBox(Node pn, FunctionBox* funbox) {}
void addFunctionArgument(Node pn, Node argpn) {}
@ -277,11 +281,23 @@ class SyntaxParseHandler
}
Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return NodeGeneric;
}
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
kind == PNK_GLOBALCONST);
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
}
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return NodeGeneric;
}
Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
kind == PNK_GLOBALCONST);
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
}
Node newCatchList() {
return newList(PNK_CATCHLIST, JSOP_NOP);
@ -292,7 +308,8 @@ class SyntaxParseHandler
}
void addList(Node list, Node kid) {
MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedCommaExpr);
MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedCommaExpr ||
list == NodeHoistableDeclaration);
}
Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs,
@ -315,6 +332,14 @@ class SyntaxParseHandler
return node == NodeUnparenthesizedAssignment;
}
bool isReturnStatement(Node node) {
return node == NodeReturn;
}
bool isStatementPermittedAfterReturnStatement(Node pn) {
return pn == NodeHoistableDeclaration || pn == NodeBreak || pn == NodeThrow;
}
void setOp(Node pn, JSOp op) {}
void setBlockId(Node pn, unsigned blockid) {}
void setFlag(Node pn, unsigned flag) {}

View File

@ -322,33 +322,6 @@ TokenStream::TokenStream(ExclusiveContext* cx, const ReadOnlyCompileOptions& opt
isExprEnding[TOK_RP] = 1;
isExprEnding[TOK_RB] = 1;
isExprEnding[TOK_RC] = 1;
memset(isExprStarting, 0, sizeof(isExprStarting));
isExprStarting[TOK_INC] = 1;
isExprStarting[TOK_DEC] = 1;
isExprStarting[TOK_LB] = 1;
isExprStarting[TOK_LC] = 1;
isExprStarting[TOK_LP] = 1;
isExprStarting[TOK_NAME] = 1;
isExprStarting[TOK_NUMBER] = 1;
isExprStarting[TOK_STRING] = 1;
isExprStarting[TOK_TEMPLATE_HEAD] = 1;
isExprStarting[TOK_NO_SUBS_TEMPLATE] = 1;
isExprStarting[TOK_REGEXP] = 1;
isExprStarting[TOK_TRUE] = 1;
isExprStarting[TOK_FALSE] = 1;
isExprStarting[TOK_NULL] = 1;
isExprStarting[TOK_THIS] = 1;
isExprStarting[TOK_NEW] = 1;
isExprStarting[TOK_DELETE] = 1;
isExprStarting[TOK_YIELD] = 1;
isExprStarting[TOK_CLASS] = 1;
isExprStarting[TOK_ADD] = 1;
isExprStarting[TOK_SUB] = 1;
isExprStarting[TOK_TYPEOF] = 1;
isExprStarting[TOK_VOID] = 1;
isExprStarting[TOK_NOT] = 1;
isExprStarting[TOK_BITNOT] = 1;
}
#ifdef _MSC_VER
@ -658,6 +631,7 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
if (offset != NoOffset && !err.report.filename && cx->isJSContext()) {
NonBuiltinFrameIter iter(cx->asJSContext(),
FrameIter::ALL_CONTEXTS, FrameIter::GO_THROUGH_SAVED,
FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK,
cx->compartment()->principals());
if (!iter.done() && iter.scriptFilename()) {
callerFilename = true;

View File

@ -494,14 +494,6 @@ class MOZ_STACK_CLASS TokenStream
return true;
}
bool nextTokenStartsExpr(bool* startsExpr, Modifier modifier = None) {
TokenKind tt;
if (!peekToken(&tt, modifier))
return false;
*startsExpr = isExprStarting[tt];
return true;
}
bool nextTokenEndsExpr(bool* endsExpr) {
TokenKind tt;
if (!peekToken(&tt))
@ -836,7 +828,6 @@ class MOZ_STACK_CLASS TokenStream
mozilla::UniquePtr<char16_t[], JS::FreePolicy> displayURL_; // the user's requested source URL or null
mozilla::UniquePtr<char16_t[], JS::FreePolicy> sourceMapURL_; // source map's filename or null
CharBuffer tokenbuf; // current token string buffer
uint8_t isExprStarting[TOK_LIMIT];// which tokens can start exprs?
uint8_t isExprEnding[TOK_LIMIT];// which tokens definitely terminate exprs?
ExclusiveContext* const cx;
bool mutedErrors;

View File

@ -37,7 +37,7 @@ assertEq(asmLink(asmCompile(USE_ASM + 'function f(){;} return f'))(), undefined)
assertAsmTypeFail(USE_ASM + 'function f(i,j){;} return f');
assertEq(asmLink(asmCompile('"use asm";; function f(){};;; return f;;'))(), undefined);
assertAsmTypeFail(USE_ASM + 'function f(x){} return f');
assertAsmTypeFail(USE_ASM + 'function f(){return; return 1} return f');
assertAsmTypeFail(USE_ASM + 'function f(){if (0) return; return 1} return f');
assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0} return f'))(42), undefined);
assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0; return x|0} return f'))(42), 42);
assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0; return x|0;;;} return f'))(42), 42);

View File

@ -12,7 +12,7 @@ assertEq(asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; if ((i|0) == 0) i
assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; if (i) return 0; } return f");
assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; if (i) return 0; else return 1 } return f");
assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; if (i) return 0; return 1.0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { return 0; 1 } return f");
assertAsmTypeFail(USE_ASM + "function f() { if (0) return 0; 1 } return f");
assertEq(asmLink(asmCompile(USE_ASM + "function f() { while (0) {} return 0} return f"))(), 0);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { for (;0;) {} return 0} return f"))(), 0);

View File

@ -30,7 +30,7 @@ assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { retu
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { return +(inc() + 1.1) } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { return (+inc() + 1)|0 } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { var i = 0; inc(i>>>0) } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { return inc(); return } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { if (0) return inc(); return } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { inc(inc()) } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { g(inc()) } function g() {} return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { inc()|inc() } return f');

View File

@ -137,7 +137,7 @@ assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return 1 } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return false } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true; 1 } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; if (0) return true; 1 } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');

View File

@ -1,5 +1,4 @@
// Warning should be shown for expression-like statement after semicolon-less
// return (bug 1005110).
// Warning should be shown for unreachable statement after return (bug 1151931).
load(libdir + "class.js");
@ -12,7 +11,7 @@ function testWarn(code, lineNumber, columnNumber) {
eval(code);
} catch (e) {
caught = true;
assertEq(e.message, "unreachable expression after semicolon-less return statement", code);
assertEq(e.constructor, SyntaxError);
assertEq(e.lineNumber, lineNumber);
assertEq(e.columnNumber, columnNumber);
}
@ -23,7 +22,7 @@ function testWarn(code, lineNumber, columnNumber) {
Reflect.parse(code);
} catch (e) {
caught = true;
assertEq(e.message, "unreachable expression after semicolon-less return statement", code);
assertEq(e.constructor, SyntaxError);
}
assertEq(caught, true, "warning should be caught for " + code);
}
@ -46,8 +45,6 @@ function testPass(code) {
assertEq(caught, false, "warning should not be caught for " + code);
}
// not EOL
testPass(`
function f() {
return (
@ -55,16 +52,8 @@ function f() {
);
}
`);
testPass(`
function f() {
return;
1 + 2;
}
`);
// starts expression
// TOK_INC
// unary expression
testWarn(`
function f() {
var i = 0;
@ -72,8 +61,6 @@ function f() {
++i;
}
`, 5, 4);
// TOK_DEC
testWarn(`
function f() {
var i = 0;
@ -82,7 +69,7 @@ function f() {
}
`, 5, 4);
// TOK_LB
// array
testWarn(`
function f() {
return
@ -90,7 +77,7 @@ function f() {
}
`, 4, 4);
// TOK_LC
// block (object)
testWarn(`
function f() {
return
@ -109,7 +96,7 @@ function f() {
}
`, 4, 2);
// TOK_LP
// expression in paren
testWarn(`
function f() {
return
@ -117,7 +104,7 @@ function f() {
}
`, 4, 4);
// TOK_NAME
// name
testWarn(`
function f() {
return
@ -125,7 +112,7 @@ function f() {
}
`, 4, 4);
// TOK_NUMBER
// binary expression
testWarn(`
function f() {
return
@ -139,7 +126,7 @@ function f() {
}
`, 4, 4);
// TOK_STRING
// string
testWarn(`
function f() {
return
@ -159,15 +146,13 @@ function f() {
}
`, 4, 4);
// TOK_TEMPLATE_HEAD
// template string
testWarn(`
function f() {
return
\`foo\${1 + 2}\`;
}
`, 4, 4);
// TOK_NO_SUBS_TEMPLATE
testWarn(`
function f() {
return
@ -175,7 +160,7 @@ function f() {
}
`, 4, 4);
// TOK_REGEXP
// RegExp
testWarn(`
function f() {
return
@ -183,15 +168,13 @@ function f() {
}
`, 4, 4);
// TOK_TRUE
// boolean
testWarn(`
function f() {
return
true;
}
`, 4, 4);
// TOK_FALSE
testWarn(`
function f() {
return
@ -199,7 +182,7 @@ function f() {
}
`, 4, 4);
// TOK_NULL
// null
testWarn(`
function f() {
return
@ -207,7 +190,7 @@ function f() {
}
`, 4, 4);
// TOK_THIS
// this
testWarn(`
function f() {
return
@ -215,7 +198,7 @@ function f() {
}
`, 4, 4);
// TOK_NEW
// new
testWarn(`
function f() {
return
@ -223,7 +206,7 @@ function f() {
}
`, 4, 4);
// TOK_DELETE
// delete
testWarn(`
function f() {
var a = {x: 10};
@ -232,7 +215,7 @@ function f() {
}
`, 5, 4);
// TOK_YIELD
// yield
testWarn(`
function* f() {
return
@ -240,7 +223,7 @@ function* f() {
}
`, 4, 4);
// TOK_CLASS
// class
if (classesEnabled()) {
testWarn(`
function f() {
@ -250,31 +233,25 @@ function f() {
`, 4, 4);
}
// TOK_ADD
// unary expression
testWarn(`
function f() {
return
+1;
}
`, 4, 4);
// TOK_SUB
testWarn(`
function f() {
return
-1;
}
`, 4, 4);
// TOK_NOT
testWarn(`
function f() {
return
!1;
}
`, 4, 4);
// TOK_BITNOT
testWarn(`
function f() {
return
@ -282,14 +259,12 @@ function f() {
}
`, 4, 4);
// don't start expression
// TOK_EOF
// eof
testPass(`
var f = new Function("return\\n");
`);
// TOK_SEMI
// empty statement
testPass(`
function f() {
return
@ -297,7 +272,7 @@ function f() {
}
`);
// TOK_RC
// end of block
testPass(`
function f() {
{
@ -306,7 +281,7 @@ function f() {
}
`);
// TOK_FUNCTION
// function (hosted)
testPass(`
function f() {
g();
@ -315,16 +290,16 @@ function f() {
}
`);
// TOK_IF
testPass(`
// if
testWarn(`
function f() {
return
if (true)
1 + 2;
}
`);
`, 4, 2);
// TOK_ELSE
// else
testPass(`
function f() {
if (true)
@ -334,8 +309,8 @@ function f() {
}
`);
// TOK_SWITCH
testPass(`
// switch
testWarn(`
function f() {
return
switch (1) {
@ -343,9 +318,32 @@ function f() {
break;
}
}
`, 4, 2);
// return in switch
testWarn(`
function f() {
switch (1) {
case 1:
return;
1 + 2;
break;
}
}
`, 6, 6);
// break in switch
testPass(`
function f() {
switch (1) {
case 1:
return;
break;
}
}
`);
// TOK_CASE
// case
testPass(`
function f() {
switch (1) {
@ -357,7 +355,7 @@ function f() {
}
`);
// TOK_DEFAULT
// default
testPass(`
function f() {
switch (1) {
@ -369,14 +367,14 @@ function f() {
}
`);
// TOK_WHILE
testPass(`
// while
testWarn(`
function f() {
return
while (false)
1 + 2;
}
`);
`, 4, 2);
testPass(`
function f() {
do
@ -385,27 +383,27 @@ function f() {
}
`);
// TOK_DO
testPass(`
// do
testWarn(`
function f() {
return
do {
1 + 2;
} while (false);
}
`);
`, 4, 2);
// TOK_FOR
testPass(`
// for
testWarn(`
function f() {
return
for (;;) {
break;
}
}
`);
`, 4, 2);
// TOK_BREAK
// break in for
testPass(`
function f() {
for (;;) {
@ -413,19 +411,19 @@ function f() {
break;
}
}
`);
`, 5, 4);
// TOK_CONTINUE
testPass(`
// continue
testWarn(`
function f() {
for (;;) {
return
continue;
}
}
`);
`, 5, 4);
// TOK_VAR
// var (hosted)
testPass(`
function f() {
return
@ -433,43 +431,43 @@ function f() {
}
`);
// TOK_CONST
testPass(`
// const
testWarn(`
function f() {
return
const a = 1;
}
`);
`, 4, 2);
// TOK_WITH
testPass(`
// with
testWarn(`
function f() {
return
with ({}) {
1;
}
}
`);
`, 4, 2);
// TOK_RETURN
testPass(`
// return
testWarn(`
function f() {
return
return;
}
`);
`, 4, 2);
// TOK_TRY
testPass(`
// try
testWarn(`
function f() {
return
try {
} catch (e) {
}
}
`);
`, 4, 2);
// TOK_THROW
// throw
testPass(`
function f() {
return
@ -477,29 +475,37 @@ function f() {
}
`);
// TOK_DEBUGGER
testPass(`
// debugger
testWarn(`
function f() {
return
debugger;
}
`);
`, 4, 2);
// TOK_LET
testPass(`
// let
testWarn(`
function f() {
return
let a = 1;
}
`);
`, 4, 2);
// exceptional case
// skip hoisted
// It's not possible to distinguish between a label statement and an expression
// starts with identifier, by checking a token next to return.
testWarn(`
function f() {
return
a: 1;
var a = 0;
(1 + 2);
}
`, 4, 2);
`, 5, 2);
testWarn(`
function f() {
return
function f() {}
var a = 0;
(1 + 2);
}
`, 6, 2);

View File

@ -0,0 +1,21 @@
// Test that block scopes cannot be resurrected by onStep.
var g = newGlobal();
var dbg = new Debugger(g);
dbg.onDebuggerStatement = function(frame) {
frame.onStep = (function() {
frame.environment;
});
};
g.eval("debugger; for (let i = 0; i < 1; i++) (function(){});");
// If the last freshened block scope was incorrectly resurrected by onStep
// above, GCing will assert.
gc();
g.eval("debugger; { let i = 0; (function(){ i = 42; }); }");
gc();
g.eval("debugger; try { throw 42; } catch (e) { };");
gc();

View File

@ -0,0 +1,14 @@
// |jit-test| error: Error
var g = newGlobal();
g.eval('function f(a) { evaluate("f(" + " - 1);", {newContext: true}); }');
var dbg = new Debugger(g);
var frames = [];
dbg.onEnterFrame = function (frame) {
if (frames.length == 3)
return;
frames.push(frame);
for (var f of frames)
f.eval('a').return
};
g.f();

View File

@ -2,7 +2,7 @@ var g = newGlobal();
var dbg = new Debugger(g);
try {
g.eval("function f() { var array = ['a', 'b']; [1].map(function () {}); return {array}; }");
g.eval("function f() { [1].map(function () {}); const x = 42; x = 43; } f();");
} catch (e) {
// Ignore the syntax error.
}

View File

@ -0,0 +1,7 @@
// |jit-test| error: ReferenceError
{
for (var i = 0; i < 100; i++)
a += i;
let a = 1;
}

View File

@ -3010,14 +3010,24 @@ BaselineCompiler::emit_JSOP_PUSHBLOCKSCOPE()
typedef bool (*PopBlockScopeFn)(JSContext*, BaselineFrame*);
static const VMFunction PopBlockScopeInfo = FunctionInfo<PopBlockScopeFn>(jit::PopBlockScope);
typedef bool (*DebugLeaveThenPopBlockScopeFn)(JSContext*, BaselineFrame*, jsbytecode*);
static const VMFunction DebugLeaveThenPopBlockScopeInfo =
FunctionInfo<DebugLeaveThenPopBlockScopeFn>(jit::DebugLeaveThenPopBlockScope);
bool
BaselineCompiler::emit_JSOP_POPBLOCKSCOPE()
{
prepareVMCall();
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
if (compileDebugInstrumentation_) {
pushArg(ImmPtr(pc));
pushArg(R0.scratchReg());
return callVM(DebugLeaveThenPopBlockScopeInfo);
}
pushArg(R0.scratchReg());
return callVM(PopBlockScopeInfo);
}
@ -3025,7 +3035,7 @@ typedef bool (*FreshenBlockScopeFn)(JSContext*, BaselineFrame*);
static const VMFunction FreshenBlockScopeInfo =
FunctionInfo<FreshenBlockScopeFn>(jit::FreshenBlockScope);
typedef bool (*DebugLeaveThenFreshenBlockScopeFn)(JSContext*, BaselineFrame*, jsbytecode* pc);
typedef bool (*DebugLeaveThenFreshenBlockScopeFn)(JSContext*, BaselineFrame*, jsbytecode*);
static const VMFunction DebugLeaveThenFreshenBlockScopeInfo =
FunctionInfo<DebugLeaveThenFreshenBlockScopeFn>(jit::DebugLeaveThenFreshenBlockScope);

View File

@ -4796,39 +4796,24 @@ CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
callVM(CreateThisWithProtoInfo, lir);
}
typedef JSObject* (*NewGCObjectFn)(JSContext* cx, gc::AllocKind allocKind,
gc::InitialHeap initialHeap, size_t ndynamic,
const js::Class* clasp);
static const VMFunction NewGCObjectInfo =
FunctionInfo<NewGCObjectFn>(js::jit::NewGCObject);
void
CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate* lir)
{
JSObject* templateObject = lir->mir()->templateObject();
gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
gc::InitialHeap initialHeap = lir->mir()->initialHeap();
const js::Class* clasp = templateObject->getClass();
size_t ndynamic = 0;
if (templateObject->isNative())
ndynamic = templateObject->as<NativeObject>().numDynamicSlots();
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
OutOfLineCode* ool = oolCallVM(NewGCObjectInfo, lir,
(ArgList(), Imm32(int32_t(allocKind)), Imm32(initialHeap),
Imm32(ndynamic), ImmPtr(clasp)),
OutOfLineCode* ool = oolCallVM(NewInitObjectWithTemplateInfo, lir,
(ArgList(), ImmGCPtr(templateObject)),
StoreRegisterTo(objReg));
// Allocate. If the FreeList is empty, call to VM, which may GC.
masm.newGCThing(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
// Initialize based on the templateObject.
masm.bind(ool->rejoin());
bool initContents = !templateObject->is<PlainObject>() ||
ShouldInitFixedSlots(lir, &templateObject->as<PlainObject>());
masm.initGCThing(objReg, tempReg, templateObject, initContents);
ShouldInitFixedSlots(lir, &templateObject->as<PlainObject>());
masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry(),
initContents);
masm.bind(ool->rejoin());
}
typedef JSObject* (*NewIonArgumentsObjectFn)(JSContext* cx, JitFrameLayout* frame, HandleObject);

View File

@ -12908,6 +12908,9 @@ IonBuilder::addLexicalCheck(MDefinition* input)
// If we're guaranteed to not be JS_UNINITIALIZED_LEXICAL, no need to check.
if (input->type() == MIRType_MagicUninitializedLexical) {
// Mark the input as implicitly used so the JS_UNINITIALIZED_LEXICAL
// magic value will be preserved on bailout.
input->setImplicitlyUsedUnchecked();
lexicalCheck = MThrowUninitializedLexical::New(alloc());
current->add(lexicalCheck);
if (!resumeAfter(lexicalCheck))

View File

@ -1183,19 +1183,6 @@ MacroAssembler::allocateObject(Register result, Register temp, gc::AllocKind all
bind(&success);
}
void
MacroAssembler::newGCThing(Register result, Register temp, JSObject* templateObj,
gc::InitialHeap initialHeap, Label* fail)
{
gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
MOZ_ASSERT(gc::IsObjectAllocKind(allocKind));
size_t ndynamic = 0;
if (templateObj->isNative())
ndynamic = templateObj->as<NativeObject>().numDynamicSlots();
allocateObject(result, temp, allocKind, ndynamic, initialHeap, fail);
}
void
MacroAssembler::createGCObject(Register obj, Register temp, JSObject* templateObj,
gc::InitialHeap initialHeap, Label* fail, bool initContents,

View File

@ -802,8 +802,6 @@ class MacroAssembler : public MacroAssemblerSpecific
gc::InitialHeap initialHeap, Label* fail, bool initContents = true,
bool convertDoubleElements = false);
void newGCThing(Register result, Register temp, JSObject* templateObj,
gc::InitialHeap initialHeap, Label* fail);
void initGCThing(Register obj, Register temp, JSObject* templateObj,
bool initContents = true, bool convertDoubleElements = false);

View File

@ -86,18 +86,6 @@ InvokeFunction(JSContext* cx, HandleObject obj, uint32_t argc, Value* argv, Valu
return true;
}
JSObject*
NewGCObject(JSContext* cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap,
size_t ndynamic, const js::Class* clasp)
{
JSObject* obj = js::Allocate<JSObject>(cx, allocKind, ndynamic, initialHeap, clasp);
if (!obj)
return nullptr;
SetNewObjectMetadata(cx, obj);
return obj;
}
bool
CheckOverRecursed(JSContext* cx)
{
@ -996,6 +984,14 @@ PopBlockScope(JSContext* cx, BaselineFrame* frame)
return true;
}
bool
DebugLeaveThenPopBlockScope(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
{
MOZ_ALWAYS_TRUE(DebugLeaveBlock(cx, frame, pc));
frame->popBlock(cx);
return true;
}
bool
FreshenBlockScope(JSContext* cx, BaselineFrame* frame)
{
@ -1005,7 +1001,7 @@ FreshenBlockScope(JSContext* cx, BaselineFrame* frame)
bool
DebugLeaveThenFreshenBlockScope(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
{
DebugLeaveBlock(cx, frame, pc);
MOZ_ALWAYS_TRUE(DebugLeaveBlock(cx, frame, pc));
return frame->freshenBlock(cx);
}

View File

@ -632,8 +632,6 @@ class AutoDetectInvalidation
};
bool InvokeFunction(JSContext* cx, HandleObject obj0, uint32_t argc, Value* argv, Value* rval);
JSObject* NewGCObject(JSContext* cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap,
size_t ndynamic, const js::Class* clasp);
bool CheckOverRecursed(JSContext* cx);
bool CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
@ -728,6 +726,7 @@ bool LeaveWith(JSContext* cx, BaselineFrame* frame);
bool PushBlockScope(JSContext* cx, BaselineFrame* frame, Handle<StaticBlockObject*> block);
bool PopBlockScope(JSContext* cx, BaselineFrame* frame);
bool DebugLeaveThenPopBlockScope(JSContext* cx, BaselineFrame* frame, jsbytecode* pc);
bool FreshenBlockScope(JSContext* cx, BaselineFrame* frame);
bool DebugLeaveThenFreshenBlockScope(JSContext* cx, BaselineFrame* frame, jsbytecode* pc);
bool DebugLeaveBlock(JSContext* cx, BaselineFrame* frame, jsbytecode* pc);

View File

@ -304,12 +304,12 @@ MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND, 0, JSEXN_SYNTAXERR, "missing ; after for-
MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer")
MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 0, JSEXN_SYNTAXERR, "missing ; before statement")
MSG_DEF(JSMSG_SOURCE_TOO_LONG, 0, JSEXN_RANGEERR, "source is too long")
MSG_DEF(JSMSG_STMT_AFTER_SEMI_LESS, 0, JSEXN_SYNTAXERR, "unreachable expression after semicolon-less return statement")
MSG_DEF(JSMSG_STMT_AFTER_RETURN, 0, JSEXN_SYNTAXERR, "unreachable code after return statement")
MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements")
MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements")
MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function")
MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing } in template string")
MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 0, JSEXN_TYPEERR, "value isn't a SIMD value object")
MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 2, JSEXN_TYPEERR, "expecting a SIMD {0} object as argument {1}")
MSG_DEF(JSMSG_TOO_MANY_CASES, 0, JSEXN_INTERNALERR, "too many switch cases")
MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 0, JSEXN_SYNTAXERR, "too many catch variables")
MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 0, JSEXN_SYNTAXERR, "too many constructor arguments")

View File

@ -758,16 +758,25 @@ CreateLazyScriptsForCompartment(JSContext* cx)
// clones. See bug 1105306.
for (gc::ZoneCellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) {
JSObject* obj = i.get<JSObject>();
if (obj->compartment() == cx->compartment() && obj->is<JSFunction>()) {
JSFunction* fun = &obj->as<JSFunction>();
if (fun->isInterpretedLazy()) {
LazyScript* lazy = fun->lazyScriptOrNull();
if (lazy && lazy->sourceObject() && !lazy->maybeScript() &&
!lazy->hasUncompiledEnclosingScript())
{
if (!lazyFunctions.append(fun))
return false;
}
// Sweeping is incremental; take care to not delazify functions that
// are about to be finalized. GC things referenced by objects that are
// about to be finalized (e.g., in slots) may already be freed.
if (gc::IsAboutToBeFinalizedUnbarriered(&obj) ||
obj->compartment() != cx->compartment() ||
!obj->is<JSFunction>())
{
continue;
}
JSFunction* fun = &obj->as<JSFunction>();
if (fun->isInterpretedLazy()) {
LazyScript* lazy = fun->lazyScriptOrNull();
if (lazy && lazy->sourceObject() && !lazy->maybeScript() &&
!lazy->hasUncompiledEnclosingScript())
{
if (!lazyFunctions.append(fun))
return false;
}
}
}

View File

@ -342,9 +342,16 @@ class JSFunction : public js::NativeObject
return nonLazyScript();
}
JSScript* nonLazyScript() const {
// The state of a JSFunction whose script errored out during bytecode
// compilation. Such JSFunctions are only reachable via GC iteration and
// not from script.
bool hasUncompiledScript() const {
MOZ_ASSERT(hasScript());
MOZ_ASSERT(u.i.s.script_);
return !u.i.s.script_;
}
JSScript* nonLazyScript() const {
MOZ_ASSERT(!hasUncompiledScript());
return u.i.s.script_;
}

View File

@ -3911,7 +3911,7 @@ LazyScript::hasUncompiledEnclosingScript() const
return false;
JSFunction& fun = enclosingScope()->as<JSFunction>();
return fun.isInterpreted() && (!fun.hasScript() || !fun.nonLazyScript()->code());
return !fun.hasScript() || fun.hasUncompiledScript() || !fun.nonLazyScript()->code();
}
uint32_t

View File

@ -1,4 +1,4 @@
// |reftest| skip-if(xulRuntime.OS=="Darwin"&&isDebugBuild) -- this takes too long to over-recurse.
// |reftest| skip-if((xulRuntime.OS=="Darwin"||Android)&&isDebugBuild) -- this takes too long to over-recurse.
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/

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