Bug 1030481 - Remove nsIMutable, r=smaug

nsIMutable is used only by DOM Blob/File. But Blobs are immutable by spec.
FileBlobImpl has a couple of lazy member values, but those are called when
the object is cloned in order to be sent to a different thread/process.

Differential Revision: https://phabricator.services.mozilla.com/D58946

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Andrea Marchesini 2020-01-07 15:02:00 +00:00
Родитель daa53ea029
Коммит 2616cac8b3
20 изменённых файлов: 63 добавлений и 189 удалений

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

@ -464,8 +464,6 @@ JSObject* ReadBlob(JSContext* aCx, uint32_t aIndex,
// pointer while destructors are running.
RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[aIndex];
MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
RefPtr<Blob> blob = Blob::Create(aHolder->GlobalDuringRead(), blobImpl);
if (NS_WARN_IF(!blob)) {
return nullptr;
@ -492,7 +490,6 @@ bool WriteBlob(JSStructuredCloneWriter* aWriter, Blob* aBlob,
}
RefPtr<BlobImpl> blobImpl = aBlob->Impl();
MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
// We store the position of the blobImpl in the array as index.
if (JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB,
@ -604,8 +601,6 @@ JSObject* ReadFileList(JSContext* aCx, JSStructuredCloneReader* aReader,
RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[pos];
MOZ_ASSERT(blobImpl->IsFile());
MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
RefPtr<File> file = File::Create(aHolder->GlobalDuringRead(), blobImpl);
if (NS_WARN_IF(!file)) {
return nullptr;
@ -645,7 +640,6 @@ bool WriteFileList(JSStructuredCloneWriter* aWriter, FileList* aFileList,
for (uint32_t i = 0; i < aFileList->Length(); ++i) {
RefPtr<BlobImpl> blobImpl = aFileList->Item(i)->Impl();
MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
blobImpls.AppendElement(blobImpl);
}
@ -686,7 +680,6 @@ JSObject* ReadFormData(JSContext* aCx, JSStructuredCloneReader* aReader,
MOZ_ASSERT(indexOrLengthOfString < aHolder->BlobImpls().Length());
RefPtr<BlobImpl> blobImpl = aHolder->BlobImpls()[indexOrLengthOfString];
MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
RefPtr<Blob> blob = Blob::Create(aHolder->GlobalDuringRead(), blobImpl);
if (NS_WARN_IF(!blob)) {
@ -785,7 +778,6 @@ bool WriteFormData(JSStructuredCloneWriter* aWriter, FormData* aFormData,
}
RefPtr<BlobImpl> blobImpl = aValue.GetAsBlob()->Impl();
MOZ_ALWAYS_SUCCEEDS(blobImpl->SetMutable(false));
closure->mHolder->BlobImpls().AppendElement(blobImpl);
return true;

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

@ -98,32 +98,6 @@ nsresult BaseBlobImpl::GetSendInfo(nsIInputStream** aBody,
return NS_OK;
}
nsresult BaseBlobImpl::GetMutable(bool* aMutable) const {
*aMutable = !mImmutable;
return NS_OK;
}
nsresult BaseBlobImpl::SetMutable(bool aMutable) {
nsresult rv = NS_OK;
NS_ENSURE_ARG(!mImmutable || !aMutable);
if (!mImmutable && !aMutable) {
// Force the content type and size to be cached
nsAutoString dummyString;
GetType(dummyString);
ErrorResult error;
GetSize(error);
if (NS_WARN_IF(error.Failed())) {
return error.StealNSResult();
}
}
mImmutable = !aMutable;
return rv;
}
/* static */
uint64_t BaseBlobImpl::NextSerialNumber() {
static Atomic<uint64_t> nextSerialNumber;

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

@ -19,7 +19,6 @@ class BaseBlobImpl : public BlobImpl {
int64_t aLastModifiedDate)
: mBlobImplType(aBlobImplType),
mIsFile(true),
mImmutable(false),
mContentType(aContentType),
mName(aName),
mStart(0),
@ -34,7 +33,6 @@ class BaseBlobImpl : public BlobImpl {
const nsAString& aContentType, uint64_t aLength)
: mBlobImplType(aBlobImplType),
mIsFile(true),
mImmutable(false),
mContentType(aContentType),
mName(aName),
mStart(0),
@ -49,7 +47,6 @@ class BaseBlobImpl : public BlobImpl {
uint64_t aLength)
: mBlobImplType(aBlobImplType),
mIsFile(false),
mImmutable(false),
mContentType(aContentType),
mStart(0),
mLength(aLength),
@ -63,7 +60,6 @@ class BaseBlobImpl : public BlobImpl {
uint64_t aStart, uint64_t aLength)
: mBlobImplType(aBlobImplType),
mIsFile(false),
mImmutable(false),
mContentType(aContentType),
mStart(aStart),
mLength(aLength),
@ -126,10 +122,6 @@ class BaseBlobImpl : public BlobImpl {
nsACString& aContentType,
nsACString& aCharset) override;
virtual nsresult GetMutable(bool* aMutable) const override;
virtual nsresult SetMutable(bool aMutable) override;
virtual void SetLazyData(const nsAString& aName,
const nsAString& aContentType, uint64_t aLength,
int64_t aLastModifiedDate) override {
@ -167,7 +159,6 @@ class BaseBlobImpl : public BlobImpl {
const nsString mBlobImplType;
bool mIsFile;
bool mImmutable;
nsString mContentType;
nsString mName;

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

@ -40,9 +40,8 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Blob)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMutable)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_ENTRY_CONCRETE(Blob)
NS_INTERFACE_MAP_ENTRY(nsIMutable)
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
NS_INTERFACE_MAP_END
@ -206,12 +205,6 @@ nsresult Blob::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
return mImpl->GetSendInfo(aBody, aContentLength, aContentType, aCharset);
}
NS_IMETHODIMP
Blob::GetMutable(bool* aMutable) { return mImpl->GetMutable(aMutable); }
NS_IMETHODIMP
Blob::SetMutable(bool aMutable) { return mImpl->SetMutable(aMutable); }
JSObject* Blob::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
return Blob_Binding::Wrap(aCx, this, aGivenProto);
}

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

@ -14,7 +14,6 @@
#include "mozilla/dom/BodyConsumer.h"
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
#include "nsIMutable.h"
#include "nsWrapperCache.h"
#include "nsWeakReference.h"
@ -36,14 +35,10 @@ class Promise;
} \
}
class Blob : public nsIMutable,
public nsSupportsWeakReference,
public nsWrapperCache {
class Blob : public nsSupportsWeakReference, public nsWrapperCache {
public:
NS_DECL_NSIMUTABLE
NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(Blob, nsIMutable)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Blob)
NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOM_BLOB_IID)
typedef OwningArrayBufferViewOrArrayBufferOrBlobOrUSVString BlobPart;
@ -158,7 +153,7 @@ size_t BindingJSObjectMallocBytes(Blob* aBlob);
} // namespace mozilla
inline nsISupports* ToSupports(mozilla::dom::Blob* aBlob) {
return static_cast<nsIMutable*>(aBlob);
return static_cast<nsISupportsWeakReference*>(aBlob);
}
#endif // mozilla_dom_Blob_h

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

@ -89,10 +89,6 @@ class BlobImpl : public nsISupports {
nsACString& aContentType,
nsACString& aCharset) = 0;
virtual nsresult GetMutable(bool* aMutable) const = 0;
virtual nsresult SetMutable(bool aMutable) = 0;
virtual void SetLazyData(const nsAString& aName,
const nsAString& aContentType, uint64_t aLength,
int64_t aLastModifiedDate) = 0;

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

@ -15,11 +15,6 @@ already_AddRefed<BlobImpl> EmptyBlobImpl::CreateSlice(
ErrorResult& aRv) {
MOZ_ASSERT(!aStart && !aLength);
RefPtr<BlobImpl> impl = new EmptyBlobImpl(aContentType);
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(impl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
return impl.forget();
}

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

@ -18,16 +18,12 @@ class EmptyBlobImpl final : public BaseBlobImpl {
explicit EmptyBlobImpl(const nsAString& aContentType)
: BaseBlobImpl(NS_LITERAL_STRING("EmptyBlobImpl"), aContentType,
0 /* aLength */) {
mImmutable = true;
}
0 /* aLength */) {}
EmptyBlobImpl(const nsAString& aName, const nsAString& aContentType,
int64_t aLastModifiedDate)
: BaseBlobImpl(NS_LITERAL_STRING("EmptyBlobImpl"), aName, aContentType, 0,
aLastModifiedDate) {
mImmutable = true;
}
aLastModifiedDate) {}
virtual void CreateInputStream(nsIInputStream** aStream,
ErrorResult& aRv) override;

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

@ -21,6 +21,7 @@ namespace dom {
FileBlobImpl::FileBlobImpl(nsIFile* aFile)
: BaseBlobImpl(NS_LITERAL_STRING("FileBlobImpl"), EmptyString(),
EmptyString(), UINT64_MAX, INT64_MAX),
mMutex("FileBlobImpl::mMutex"),
mFile(aFile),
mFileId(-1),
mWholeFile(true) {
@ -37,6 +38,7 @@ FileBlobImpl::FileBlobImpl(const nsAString& aName,
nsIFile* aFile)
: BaseBlobImpl(NS_LITERAL_STRING("FileBlobImpl"), aName, aContentType,
aLength, UINT64_MAX),
mMutex("FileBlobImpl::mMutex"),
mFile(aFile),
mFileId(-1),
mWholeFile(true) {
@ -50,6 +52,7 @@ FileBlobImpl::FileBlobImpl(const nsAString& aName,
nsIFile* aFile, int64_t aLastModificationDate)
: BaseBlobImpl(NS_LITERAL_STRING("FileBlobImpl"), aName, aContentType,
aLength, aLastModificationDate),
mMutex("FileBlobImpl::mMutex"),
mFile(aFile),
mFileId(-1),
mWholeFile(true) {
@ -62,6 +65,7 @@ FileBlobImpl::FileBlobImpl(nsIFile* aFile, const nsAString& aName,
const nsAString& aContentType,
const nsAString& aBlobImplType)
: BaseBlobImpl(aBlobImplType, aName, aContentType, UINT64_MAX, INT64_MAX),
mMutex("FileBlobImpl::mMutex"),
mFile(aFile),
mFileId(-1),
mWholeFile(true) {
@ -79,12 +83,12 @@ FileBlobImpl::FileBlobImpl(const FileBlobImpl* aOther, uint64_t aStart,
uint64_t aLength, const nsAString& aContentType)
: BaseBlobImpl(NS_LITERAL_STRING("FileBlobImpl"), aContentType,
aOther->mStart + aStart, aLength),
mMutex("FileBlobImpl::mMutex"),
mFile(aOther->mFile),
mFileId(-1),
mWholeFile(false) {
MOZ_ASSERT(mFile, "must have file");
MOZ_ASSERT(XRE_IsParentProcess());
mImmutable = aOther->mImmutable;
mMozFullPath = aOther->mMozFullPath;
}
@ -100,6 +104,8 @@ void FileBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
ErrorResult& aRv) {
MOZ_ASSERT(mIsFile, "Should only be called on files");
MutexAutoLock lock(mMutex);
if (!mMozFullPath.IsVoid()) {
aFilename = mMozFullPath;
return;
@ -114,6 +120,8 @@ void FileBlobImpl::GetMozFullPathInternal(nsAString& aFilename,
}
uint64_t FileBlobImpl::GetSize(ErrorResult& aRv) {
MutexAutoLock lock(mMutex);
if (BaseBlobImpl::IsSizeUnknown()) {
MOZ_ASSERT(mWholeFile,
"Should only use lazy size when using the whole file");
@ -134,14 +142,14 @@ uint64_t FileBlobImpl::GetSize(ErrorResult& aRv) {
return mLength;
}
namespace {
class GetTypeRunnable final : public WorkerMainThreadRunnable {
class FileBlobImpl::GetTypeRunnable final : public WorkerMainThreadRunnable {
public:
GetTypeRunnable(WorkerPrivate* aWorkerPrivate, BlobImpl* aBlobImpl)
GetTypeRunnable(WorkerPrivate* aWorkerPrivate, FileBlobImpl* aBlobImpl,
const MutexAutoLock& aProofOfLock)
: WorkerMainThreadRunnable(aWorkerPrivate,
NS_LITERAL_CSTRING("FileBlobImpl :: GetType")),
mBlobImpl(aBlobImpl) {
mBlobImpl(aBlobImpl),
mProofOfLock(aProofOfLock) {
MOZ_ASSERT(aBlobImpl);
aWorkerPrivate->AssertIsOnWorkerThread();
}
@ -150,19 +158,24 @@ class GetTypeRunnable final : public WorkerMainThreadRunnable {
MOZ_ASSERT(NS_IsMainThread());
nsAutoString type;
mBlobImpl->GetType(type);
mBlobImpl->GetTypeInternal(type, mProofOfLock);
return true;
}
private:
~GetTypeRunnable() = default;
RefPtr<BlobImpl> mBlobImpl;
RefPtr<FileBlobImpl> mBlobImpl;
const MutexAutoLock& mProofOfLock;
};
} // anonymous namespace
void FileBlobImpl::GetType(nsAString& aType) {
MutexAutoLock lock(mMutex);
GetTypeInternal(aType, lock);
}
void FileBlobImpl::GetTypeInternal(nsAString& aType,
const MutexAutoLock& aProofOfLock) {
aType.Truncate();
if (mContentType.IsVoid()) {
@ -178,31 +191,31 @@ void FileBlobImpl::GetType(nsAString& aType) {
}
RefPtr<GetTypeRunnable> runnable =
new GetTypeRunnable(workerPrivate, this);
new GetTypeRunnable(workerPrivate, this, aProofOfLock);
ErrorResult rv;
runnable->Dispatch(Canceling, rv);
if (NS_WARN_IF(rv.Failed())) {
rv.SuppressException();
return;
}
} else {
nsresult rv;
nsCOMPtr<nsIMIMEService> mimeService =
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
return;
}
nsresult rv;
nsCOMPtr<nsIMIMEService> mimeService =
do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
nsAutoCString mimeType;
rv = mimeService->GetTypeFromFile(mFile, mimeType);
if (NS_FAILED(rv)) {
mimeType.Truncate();
}
nsAutoCString mimeType;
rv = mimeService->GetTypeFromFile(mFile, mimeType);
if (NS_FAILED(rv)) {
mimeType.Truncate();
AppendUTF8toUTF16(mimeType, mContentType);
mContentType.SetIsVoid(false);
}
AppendUTF8toUTF16(mimeType, mContentType);
mContentType.SetIsVoid(false);
}
aType = mContentType;
@ -210,6 +223,9 @@ void FileBlobImpl::GetType(nsAString& aType) {
int64_t FileBlobImpl::GetLastModified(ErrorResult& aRv) {
MOZ_ASSERT(mIsFile, "Should only be called on files");
MutexAutoLock lock(mMutex);
if (BaseBlobImpl::IsDateUnknown()) {
PRTime msecs;
aRv = mFile->GetLastModifiedTime(&msecs);

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

@ -8,6 +8,7 @@
#define mozilla_dom_FileBlobImpl_h
#include "mozilla/dom/BaseBlobImpl.h"
#include "mozilla/Mutex.h"
class nsIFile;
@ -72,6 +73,18 @@ class FileBlobImpl : public BaseBlobImpl {
const nsAString& aContentType,
ErrorResult& aRv) override;
class GetTypeRunnable;
void GetTypeInternal(nsAString& aType, const MutexAutoLock& aProofOfLock);
// FileBlobImpl is the only BlobImpl with a few getter methods with lazy
// initialization. Because any BlobImpl must work thread-safe, we use a mutex.
// This is the list of the getter methods and the corresponding lazy members:
// - GetMozFullPathInternal - mMozFullPath
// - GetSize - mLength
// - GetType - mContentType
// - GetLastModified - mLastModificationDate
Mutex mMutex;
nsCOMPtr<nsIFile> mFile;
nsString mMozFullPath;
int64_t mFileId;

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

@ -147,7 +147,6 @@ class MemoryBlobImpl final : public BaseBlobImpl {
aOther->mStart + aStart, aLength),
mDataOwner(aOther->mDataOwner) {
MOZ_ASSERT(mDataOwner && mDataOwner->mData, "must have data");
mImmutable = aOther->mImmutable;
}
~MemoryBlobImpl() {}

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

@ -283,33 +283,6 @@ void MultipartBlobImpl::SetLengthAndModifiedDate(ErrorResult& aRv) {
}
}
nsresult MultipartBlobImpl::SetMutable(bool aMutable) {
nsresult rv;
// This looks a little sketchy since BlobImpl objects are supposed to be
// threadsafe. However, we try to enforce that all BlobImpl objects must be
// set to immutable *before* being passed to another thread, so this should
// be safe.
if (!aMutable && !mImmutable && !mBlobImpls.IsEmpty()) {
for (uint32_t index = 0, count = mBlobImpls.Length(); index < count;
index++) {
rv = mBlobImpls[index]->SetMutable(aMutable);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
}
rv = BaseBlobImpl::SetMutable(aMutable);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
MOZ_ASSERT_IF(!aMutable, mImmutable);
return NS_OK;
}
bool MultipartBlobImpl::MayBeClonedToOtherThreads() const {
for (uint32_t i = 0; i < mBlobImpls.Length(); ++i) {
if (!mBlobImpls[i]->MayBeClonedToOtherThreads()) {

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

@ -59,8 +59,6 @@ class MultipartBlobImpl final : public BaseBlobImpl {
return mBlobImpls.Length() ? &mBlobImpls : nullptr;
}
virtual nsresult SetMutable(bool aMutable) override;
void SetName(const nsAString& aName) { mName = aName; }
virtual bool MayBeClonedToOtherThreads() const override;

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

@ -50,9 +50,7 @@ StreamBlobImpl::StreamBlobImpl(already_AddRefed<nsIInputStream> aInputStream,
: BaseBlobImpl(aBlobImplType, aContentType, aLength),
mInputStream(std::move(aInputStream)),
mIsDirectory(false),
mFileId(-1) {
mImmutable = true;
}
mFileId(-1) {}
StreamBlobImpl::StreamBlobImpl(already_AddRefed<nsIInputStream> aInputStream,
const nsAString& aName,
@ -63,9 +61,7 @@ StreamBlobImpl::StreamBlobImpl(already_AddRefed<nsIInputStream> aInputStream,
aLastModifiedDate),
mInputStream(std::move(aInputStream)),
mIsDirectory(false),
mFileId(-1) {
mImmutable = true;
}
mFileId(-1) {}
StreamBlobImpl::~StreamBlobImpl() { UnregisterWeakMemoryReporter(this); }

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

@ -123,14 +123,6 @@ class BlobImplSnapshot final : public BlobImpl, public PIBlobImplSnapshot {
aCharset);
}
virtual nsresult GetMutable(bool* aMutable) const override {
return mBlobImpl->GetMutable(aMutable);
}
virtual nsresult SetMutable(bool aMutable) override {
return mBlobImpl->SetMutable(aMutable);
}
virtual void SetLazyData(const nsAString& aName,
const nsAString& aContentType, uint64_t aLength,
int64_t aLastModifiedDate) override {

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

@ -29,10 +29,6 @@ class CreateURLRunnable : public WorkerMainThreadRunnable {
mBlobImpl(aBlobImpl),
mURL(aURL) {
MOZ_ASSERT(aBlobImpl);
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(aBlobImpl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
}
bool MainThreadRun() override {
@ -40,10 +36,6 @@ class CreateURLRunnable : public WorkerMainThreadRunnable {
AssertIsOnMainThread();
DebugOnly<bool> isMutable;
MOZ_ASSERT(NS_SUCCEEDED(mBlobImpl->GetMutable(&isMutable)));
MOZ_ASSERT(!isMutable);
nsCOMPtr<nsIPrincipal> principal = mWorkerPrivate->GetPrincipal();
nsAutoCString url;
@ -163,11 +155,6 @@ void URLWorker::CreateObjectURL(const GlobalObject& aGlobal, Blob& aBlob,
RefPtr<BlobImpl> blobImpl = aBlob.Impl();
MOZ_ASSERT(blobImpl);
aRv = blobImpl->SetMutable(false);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
RefPtr<CreateURLRunnable> runnable =
new CreateURLRunnable(workerPrivate, blobImpl, aResult);

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

@ -1893,14 +1893,6 @@ void XMLHttpRequestWorker::Send(
RefPtr<Blob> blob = &aData.Value().GetAsBlob();
MOZ_ASSERT(blob);
RefPtr<BlobImpl> blobImpl = blob->Impl();
MOZ_ASSERT(blobImpl);
aRv = blobImpl->SetMutable(false);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
JS::Rooted<JS::Value> value(aCx);
if (!GetOrCreateDOMReflector(aCx, blob, &value)) {
aRv.Throw(NS_ERROR_FAILURE);

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

@ -18,7 +18,6 @@ XPIDL_SOURCES += [
'nsIMemoryInfoDumper.idl',
'nsIMemoryReporter.idl',
'nsIMessageLoop.idl',
'nsIMutable.idl',
'nsISecurityConsoleMessage.idl',
'nsISupports.idl',
'nsIUUIDGenerator.idl',

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

@ -1,22 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "nsISupports.idl"
/**
* nsIMutable defines an interface to be implemented by objects which
* can be made immutable.
*/
[scriptable, uuid(321578d0-03c1-4d95-8821-021ac612d18d)]
interface nsIMutable : nsISupports
{
/**
* Control whether or not this object can be modified. If the flag is
* false, no modification is allowed. Once the flag has been set to false,
* it cannot be reset back to true -- attempts to do so throw
* NS_ERROR_INVALID_ARG.
*/
attribute boolean mutable;
};

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

@ -77,7 +77,6 @@
#include "nsIInputStream.h"
#include "nsIInterfaceRequestor.h"
#include "nsILineInputStream.h"
#include "nsIMutable.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIOutputStream.h"