Bug 1561876 - Remove support for de-serializing WebAssembly.Modules in IDB; r=asuth

This patch removes support for de-serialization of WebAssembly.Modules. The
preprocessing which was added just for WebAssembly.Modules is not removed since
it can be reused for more efficient de-serialization of big structured clones
which are stored as standalone files. (standalone files can be read and
uncompressed in content process instead of the parent process). So this patch
also adjusts the preprocessing to support that. However the preprocessing is not
fully implemented (we lack support for indexes and cursors) and there's a
theoretical problem with ordering of IDB requests when preprocessing is
involved, so this feature is kept behind a pref for now.

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

--HG--
rename : dom/indexedDB/test/unit/test_wasm_recompile.js => dom/indexedDB/test/unit/test_wasm_get_values.js
rename : dom/indexedDB/test/unit/wasm_recompile_profile.zip => dom/indexedDB/test/unit/wasm_get_values_profile.zip
This commit is contained in:
Jan Varga 2019-07-03 12:23:33 +02:00
Родитель 0ffa9e372d
Коммит e12ce7d680
14 изменённых файлов: 475 добавлений и 572 удалений

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

@ -19,9 +19,11 @@
#include "IDBTransaction.h"
#include "IndexedDatabase.h"
#include "IndexedDatabaseInlines.h"
#include <mozIIPCBlobInputStream.h>
#include "mozilla/BasicEvents.h"
#include "mozilla/CycleCollectedJSRuntime.h"
#include "mozilla/Maybe.h"
#include "mozilla/SnappyUncompressInputStream.h"
#include "mozilla/TypeTraits.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h"
@ -73,6 +75,16 @@ namespace dom {
namespace indexedDB {
namespace {
/*******************************************************************************
* Constants
******************************************************************************/
const uint32_t kFileCopyBufferSize = 32768;
} // namespace
/*******************************************************************************
* ThreadLocal
******************************************************************************/
@ -496,14 +508,11 @@ class PermissionRequestMainProcessHelper final : public PermissionRequestBase {
void DeserializeStructuredCloneFiles(
IDBDatabase* aDatabase,
const nsTArray<SerializedStructuredCloneFile>& aSerializedFiles,
const nsTArray<RefPtr<JS::WasmModule>>* aModuleSet,
nsTArray<StructuredCloneFile>& aFiles) {
MOZ_ASSERT_IF(aModuleSet, !aModuleSet->IsEmpty());
bool aForPreprocess, nsTArray<StructuredCloneFile>& aFiles) {
MOZ_ASSERT(aFiles.IsEmpty());
MOZ_ASSERT_IF(aForPreprocess, aSerializedFiles.Length() == 1);
if (!aSerializedFiles.IsEmpty()) {
uint32_t moduleIndex = 0;
const uint32_t count = aSerializedFiles.Length();
aFiles.SetCapacity(count);
@ -511,6 +520,9 @@ void DeserializeStructuredCloneFiles(
const SerializedStructuredCloneFile& serializedFile =
aSerializedFiles[index];
MOZ_ASSERT_IF(aForPreprocess, serializedFile.type() ==
StructuredCloneFile::eStructuredClone);
const BlobOrMutableFile& blobOrMutableFile = serializedFile.file();
switch (serializedFile.type()) {
@ -579,55 +591,47 @@ void DeserializeStructuredCloneFiles(
}
case StructuredCloneFile::eStructuredClone: {
StructuredCloneFile* file = aFiles.AppendElement();
MOZ_ASSERT(file);
if (aForPreprocess) {
MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::TIPCBlob);
file->mType = StructuredCloneFile::eStructuredClone;
const IPCBlob& ipcBlob = blobOrMutableFile.get_IPCBlob();
break;
}
RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(ipcBlob);
MOZ_ASSERT(blobImpl);
case StructuredCloneFile::eWasmBytecode: {
if (aModuleSet) {
RefPtr<Blob> blob =
Blob::Create(aDatabase->GetOwnerGlobal(), blobImpl);
StructuredCloneFile* file = aFiles.AppendElement();
MOZ_ASSERT(file);
file->mType = StructuredCloneFile::eStructuredClone;
file->mBlob.swap(blob);
} else {
MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::Tnull_t);
StructuredCloneFile* file = aFiles.AppendElement();
MOZ_ASSERT(file);
file->mType = StructuredCloneFile::eWasmBytecode;
MOZ_ASSERT(moduleIndex < aModuleSet->Length());
file->mWasmModule = aModuleSet->ElementAt(moduleIndex);
moduleIndex++;
break;
file->mType = StructuredCloneFile::eStructuredClone;
}
MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::TIPCBlob);
const IPCBlob& ipcBlob = blobOrMutableFile.get_IPCBlob();
RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(ipcBlob);
MOZ_ASSERT(blobImpl);
RefPtr<Blob> blob =
Blob::Create(aDatabase->GetOwnerGlobal(), blobImpl);
StructuredCloneFile* file = aFiles.AppendElement();
MOZ_ASSERT(file);
file->mType = StructuredCloneFile::eWasmBytecode;
file->mBlob.swap(blob);
break;
}
case StructuredCloneFile::eWasmBytecode:
case StructuredCloneFile::eWasmCompiled: {
MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::Tnull_t);
StructuredCloneFile* file = aFiles.AppendElement();
MOZ_ASSERT(file);
file->mType = StructuredCloneFile::eWasmCompiled;
file->mType = serializedFile.type();
// Don't set mBlob, support for storing WebAssembly.Modules has been
// removed in bug 1469395. Support for de-serialization of
// WebAssembly.Modules has been removed in bug 1561876. Full removal
// is tracked in bug 1487479.
break;
}
@ -1284,29 +1288,42 @@ class BackgroundRequestChild::PreprocessHelper final
: public CancelableRunnable,
public nsIInputStreamCallback,
public nsIFileMetadataCallback {
enum class State {
// Just created on the owning thread, dispatched to the thread pool. Next
// step is either Finishing if stream was ready to be read or
// WaitingForStreamReady if the stream is not ready.
Initial,
// Waiting for stream to be ready on a thread pool thread. Next state is
// Finishing.
WaitingForStreamReady,
// Waiting to finish/finishing on the owning thread. Next step is Completed.
Finishing,
// All done.
Completed
};
nsCOMPtr<nsIEventTarget> mOwningEventTarget;
nsTArray<nsCOMPtr<nsIInputStream>> mStreams;
nsTArray<RefPtr<JS::WasmModule>> mModuleSet;
BackgroundRequestChild* mActor;
// This is populated when the processing of the stream runs.
PRFileDesc* mCurrentBytecodeFileDesc;
RefPtr<TaskQueue> mTaskQueue;
nsCOMPtr<nsIEventTarget> mTaskQueueEventTarget;
uint32_t mModuleSetIndex;
nsCOMPtr<nsIInputStream> mStream;
UniquePtr<JSStructuredCloneData> mCloneData;
BackgroundRequestChild* mActor;
uint32_t mCloneDataIndex;
nsresult mResultCode;
State mState;
public:
PreprocessHelper(uint32_t aModuleSetIndex, BackgroundRequestChild* aActor)
PreprocessHelper(uint32_t aCloneDataIndex, BackgroundRequestChild* aActor)
: CancelableRunnable(
"indexedDB::BackgroundRequestChild::PreprocessHelper"),
mOwningEventTarget(aActor->GetActorEventTarget()),
mActor(aActor),
mCurrentBytecodeFileDesc(nullptr),
mModuleSetIndex(aModuleSetIndex),
mResultCode(NS_OK) {
mCloneDataIndex(aCloneDataIndex),
mResultCode(NS_OK),
mState(State::Initial) {
AssertIsOnOwningThread();
MOZ_ASSERT(aActor);
aActor->AssertIsOnOwningThread();
@ -1328,33 +1345,29 @@ class BackgroundRequestChild::PreprocessHelper final
mActor = nullptr;
}
nsresult Init(const nsTArray<StructuredCloneFile>& aFiles);
nsresult Init(const StructuredCloneFile& aFile);
nsresult Dispatch();
private:
~PreprocessHelper() {
MOZ_ASSERT(mState == State::Initial || mState == State::Completed);
if (mTaskQueue) {
mTaskQueue->BeginShutdown();
}
}
void RunOnOwningThread();
nsresult Start();
void ProcessCurrentStream();
nsresult ProcessStream();
nsresult WaitForStreamReady(nsIInputStream* aInputStream);
void ContinueWithStatus(nsresult aStatus);
nsresult DataIsReady(nsIInputStream* aInputStream);
void Finish();
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIRUNNABLE
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSIFILEMETADATACALLBACK
virtual nsresult Cancel() override;
};
/*******************************************************************************
@ -2537,7 +2550,7 @@ BackgroundRequestChild::BackgroundRequestChild(IDBRequest* aRequest)
: BackgroundRequestChildBase(aRequest),
mTransaction(aRequest->GetTransaction()),
mRunningPreprocessHelpers(0),
mCurrentModuleSetIndex(0),
mCurrentCloneDataIndex(0),
mPreprocessResultCode(NS_OK),
mGetAll(false) {
MOZ_ASSERT(mTransaction);
@ -2575,27 +2588,27 @@ void BackgroundRequestChild::MaybeSendContinue() {
}
void BackgroundRequestChild::OnPreprocessFinished(
uint32_t aModuleSetIndex, nsTArray<RefPtr<JS::WasmModule>>& aModuleSet) {
uint32_t aCloneDataIndex, UniquePtr<JSStructuredCloneData> aCloneData) {
AssertIsOnOwningThread();
MOZ_ASSERT(aModuleSetIndex < mPreprocessHelpers.Length());
MOZ_ASSERT(!aModuleSet.IsEmpty());
MOZ_ASSERT(mPreprocessHelpers[aModuleSetIndex]);
MOZ_ASSERT(mModuleSets[aModuleSetIndex].IsEmpty());
MOZ_ASSERT(aCloneDataIndex < mPreprocessHelpers.Length());
MOZ_ASSERT(aCloneData);
MOZ_ASSERT(mPreprocessHelpers[aCloneDataIndex]);
MOZ_ASSERT(!mCloneDatas[aCloneDataIndex]);
mModuleSets[aModuleSetIndex].SwapElements(aModuleSet);
mCloneDatas[aCloneDataIndex] = std::move(aCloneData);
MaybeSendContinue();
mPreprocessHelpers[aModuleSetIndex] = nullptr;
mPreprocessHelpers[aCloneDataIndex] = nullptr;
}
void BackgroundRequestChild::OnPreprocessFailed(uint32_t aModuleSetIndex,
void BackgroundRequestChild::OnPreprocessFailed(uint32_t aCloneDataIndex,
nsresult aErrorCode) {
AssertIsOnOwningThread();
MOZ_ASSERT(aModuleSetIndex < mPreprocessHelpers.Length());
MOZ_ASSERT(aCloneDataIndex < mPreprocessHelpers.Length());
MOZ_ASSERT(NS_FAILED(aErrorCode));
MOZ_ASSERT(mPreprocessHelpers[aModuleSetIndex]);
MOZ_ASSERT(mModuleSets[aModuleSetIndex].IsEmpty());
MOZ_ASSERT(mPreprocessHelpers[aCloneDataIndex]);
MOZ_ASSERT(!mCloneDatas[aCloneDataIndex]);
if (NS_SUCCEEDED(mPreprocessResultCode)) {
mPreprocessResultCode = aErrorCode;
@ -2603,18 +2616,18 @@ void BackgroundRequestChild::OnPreprocessFailed(uint32_t aModuleSetIndex,
MaybeSendContinue();
mPreprocessHelpers[aModuleSetIndex] = nullptr;
mPreprocessHelpers[aCloneDataIndex] = nullptr;
}
const nsTArray<RefPtr<JS::WasmModule>>*
BackgroundRequestChild::GetNextModuleSet(const StructuredCloneReadInfo& aInfo) {
if (!aInfo.mHasPreprocessInfo) {
return nullptr;
}
UniquePtr<JSStructuredCloneData> BackgroundRequestChild::GetNextCloneData() {
AssertIsOnOwningThread();
MOZ_ASSERT(mCurrentCloneDataIndex < mCloneDatas.Length());
MOZ_ASSERT(mCloneDatas[mCurrentCloneDataIndex]);
MOZ_ASSERT(mCurrentModuleSetIndex < mModuleSets.Length());
MOZ_ASSERT(!mModuleSets[mCurrentModuleSetIndex].IsEmpty());
return &mModuleSets[mCurrentModuleSetIndex++];
UniquePtr<JSStructuredCloneData> cloneData;
mCloneDatas[mCurrentCloneDataIndex++].swap(cloneData);
return cloneData;
}
void BackgroundRequestChild::HandleResponse(nsresult aResponse) {
@ -2653,9 +2666,14 @@ void BackgroundRequestChild::HandleResponse(
StructuredCloneReadInfo cloneReadInfo(std::move(serializedCloneInfo));
DeserializeStructuredCloneFiles(mTransaction->Database(), aResponse.files(),
GetNextModuleSet(cloneReadInfo),
/* aForPreprocess */ false,
cloneReadInfo.mFiles);
if (cloneReadInfo.mHasPreprocessInfo) {
UniquePtr<JSStructuredCloneData> cloneData = GetNextCloneData();
cloneReadInfo.mData = std::move(*cloneData);
}
ResultHelper helper(mRequest, mTransaction, &cloneReadInfo);
DispatchSuccessEvent(&helper);
@ -2687,9 +2705,14 @@ void BackgroundRequestChild::HandleResponse(
// Get the files
nsTArray<StructuredCloneFile> files;
DeserializeStructuredCloneFiles(database, serializedCloneInfo.files(),
GetNextModuleSet(*cloneReadInfo), files);
/* aForPreprocess */ false, files);
cloneReadInfo->mFiles = std::move(files);
if (cloneReadInfo->mHasPreprocessInfo) {
UniquePtr<JSStructuredCloneData> cloneData = GetNextCloneData();
cloneReadInfo->mData = std::move(*cloneData);
}
}
}
@ -2717,7 +2740,7 @@ void BackgroundRequestChild::HandleResponse(uint64_t aResponse) {
}
nsresult BackgroundRequestChild::HandlePreprocess(
const WasmModulePreprocessInfo& aPreprocessInfo) {
const PreprocessInfo& aPreprocessInfo) {
AssertIsOnOwningThread();
IDBDatabase* database = mTransaction->Database();
@ -2725,13 +2748,15 @@ nsresult BackgroundRequestChild::HandlePreprocess(
mPreprocessHelpers.SetLength(1);
nsTArray<StructuredCloneFile> files;
DeserializeStructuredCloneFiles(database, aPreprocessInfo.files(), nullptr,
files);
DeserializeStructuredCloneFiles(database, aPreprocessInfo.files(),
/* aForPreprocess */ true, files);
MOZ_ASSERT(files.Length() == 1);
RefPtr<PreprocessHelper>& preprocessHelper = mPreprocessHelpers[0];
preprocessHelper = new PreprocessHelper(0, this);
nsresult rv = preprocessHelper->Init(files);
nsresult rv = preprocessHelper->Init(files[0]);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2743,13 +2768,13 @@ nsresult BackgroundRequestChild::HandlePreprocess(
mRunningPreprocessHelpers++;
mModuleSets.SetLength(1);
mCloneDatas.SetLength(1);
return NS_OK;
}
nsresult BackgroundRequestChild::HandlePreprocess(
const nsTArray<WasmModulePreprocessInfo>& aPreprocessInfos) {
const nsTArray<PreprocessInfo>& aPreprocessInfos) {
AssertIsOnOwningThread();
IDBDatabase* database = mTransaction->Database();
@ -2762,16 +2787,18 @@ nsresult BackgroundRequestChild::HandlePreprocess(
// and has the potential to cause some annoying browser hiccups.
// Consider using a single thread or a very small threadpool.
for (uint32_t index = 0; index < count; index++) {
const WasmModulePreprocessInfo& preprocessInfo = aPreprocessInfos[index];
const PreprocessInfo& preprocessInfo = aPreprocessInfos[index];
nsTArray<StructuredCloneFile> files;
DeserializeStructuredCloneFiles(database, preprocessInfo.files(), nullptr,
files);
DeserializeStructuredCloneFiles(database, preprocessInfo.files(),
/* aForPreprocess */ true, files);
MOZ_ASSERT(files.Length() == 1);
RefPtr<PreprocessHelper>& preprocessHelper = mPreprocessHelpers[index];
preprocessHelper = new PreprocessHelper(index, this);
nsresult rv = preprocessHelper->Init(files);
nsresult rv = preprocessHelper->Init(files[0]);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2784,7 +2811,7 @@ nsresult BackgroundRequestChild::HandlePreprocess(
mRunningPreprocessHelpers++;
}
mModuleSets.SetLength(count);
mCloneDatas.SetLength(count);
mGetAll = true;
@ -2949,51 +2976,44 @@ mozilla::ipc::IPCResult BackgroundRequestChild::RecvPreprocess(
}
nsresult BackgroundRequestChild::PreprocessHelper::Init(
const nsTArray<StructuredCloneFile>& aFiles) {
const StructuredCloneFile& aFile) {
AssertIsOnOwningThread();
MOZ_ASSERT(!aFiles.IsEmpty());
MOZ_ASSERT(aFile.mBlob);
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eStructuredClone);
MOZ_ASSERT(mState == State::Initial);
nsTArray<nsCOMPtr<nsIInputStream>> streams;
for (uint32_t index = 0; index < aFiles.Length(); index++) {
const StructuredCloneFile& bytecodeFile = aFiles[index];
// The stream transport service is used for asynchronous processing. It has a
// threadpool with a high cap of 25 threads. Fortunately, the service can be
// used on workers too.
nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
MOZ_ASSERT(bytecodeFile.mType == StructuredCloneFile::eWasmBytecode);
MOZ_ASSERT(bytecodeFile.mBlob);
// We use a TaskQueue here in order to be sure that the events are dispatched
// in the correct order. This is not guaranteed in case we use the I/O thread
// directly.
mTaskQueue = new TaskQueue(target.forget());
mTaskQueueEventTarget = mTaskQueue->WrapAsEventTarget();
ErrorResult errorResult;
ErrorResult errorResult;
nsCOMPtr<nsIInputStream> bytecodeStream;
bytecodeFile.mBlob->CreateInputStream(getter_AddRefs(bytecodeStream),
errorResult);
if (NS_WARN_IF(errorResult.Failed())) {
return errorResult.StealNSResult();
}
streams.AppendElement(bytecodeStream);
nsCOMPtr<nsIInputStream> stream;
aFile.mBlob->CreateInputStream(getter_AddRefs(stream), errorResult);
if (NS_WARN_IF(errorResult.Failed())) {
return errorResult.StealNSResult();
}
mStreams = std::move(streams);
mStream = std::move(stream);
mCloneData = MakeUnique<JSStructuredCloneData>(
JS::StructuredCloneScope::DifferentProcessForIndexedDB);
return NS_OK;
}
nsresult BackgroundRequestChild::PreprocessHelper::Dispatch() {
AssertIsOnOwningThread();
if (!mTaskQueue) {
// The stream transport service is used for asynchronous processing. It has
// a threadpool with a high cap of 25 threads. Fortunately, the service can
// be used on workers too.
nsCOMPtr<nsIEventTarget> target =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
MOZ_ASSERT(target);
// We use a TaskQueue here in order to be sure that the events are
// dispatched in the correct order. This is not guaranteed in case we use
// the I/O thread directly.
mTaskQueue = new TaskQueue(target.forget());
mTaskQueueEventTarget = mTaskQueue->WrapAsEventTarget();
}
MOZ_ASSERT(mState == State::Initial);
nsresult rv = mTaskQueueEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -3003,105 +3023,16 @@ nsresult BackgroundRequestChild::PreprocessHelper::Dispatch() {
return NS_OK;
}
void BackgroundRequestChild::PreprocessHelper::RunOnOwningThread() {
AssertIsOnOwningThread();
if (mActor) {
if (NS_SUCCEEDED(mResultCode)) {
mActor->OnPreprocessFinished(mModuleSetIndex, mModuleSet);
MOZ_ASSERT(mModuleSet.IsEmpty());
} else {
mActor->OnPreprocessFailed(mModuleSetIndex, mResultCode);
}
}
}
class MemUnmap {
uint32_t mSize = 0;
public:
MemUnmap() = default;
explicit MemUnmap(uint32_t aSize) : mSize(aSize) {}
void operator()(uint8_t* aP) {
MOZ_ASSERT(mSize);
PR_MemUnmap(aP, mSize);
}
};
using UniqueMapping = UniquePtr<uint8_t, MemUnmap>;
static UniqueMapping MapFile(PRFileDesc* aFile, PRFileInfo* aInfo) {
if (PR_GetOpenFileInfo(aFile, aInfo) != PR_SUCCESS) {
return nullptr;
}
PRFileMap* map = PR_CreateFileMap(aFile, aInfo->size, PR_PROT_READONLY);
if (!map) {
return nullptr;
}
// PRFileMap objects do not need to be kept alive after the memory has been
// mapped, so unconditionally close the PRFileMap, regardless of whether
// PR_MemMap succeeds.
uint8_t* memory = (uint8_t*)PR_MemMap(map, 0, aInfo->size);
PR_CloseFileMap(map);
return UniqueMapping(memory, MemUnmap(aInfo->size));
}
void BackgroundRequestChild::PreprocessHelper::ProcessCurrentStream() {
nsresult BackgroundRequestChild::PreprocessHelper::Start() {
MOZ_ASSERT(!IsOnOwningThread());
MOZ_ASSERT(!mStreams.IsEmpty());
MOZ_ASSERT(mStream);
MOZ_ASSERT(mState == State::Initial);
// We still don't have the current bytecode FileDesc.
if (!mCurrentBytecodeFileDesc) {
const nsCOMPtr<nsIInputStream>& bytecodeStream = mStreams[0];
MOZ_ASSERT(bytecodeStream);
nsresult rv;
mCurrentBytecodeFileDesc = GetFileDescriptorFromStream(bytecodeStream);
if (!mCurrentBytecodeFileDesc) {
nsresult rv = WaitForStreamReady(bytecodeStream);
if (NS_WARN_IF(NS_FAILED(rv))) {
ContinueWithStatus(rv);
}
return;
}
}
MOZ_ASSERT(mCurrentBytecodeFileDesc);
PRFileInfo bytecodeInfo;
UniqueMapping bytecodeMapping =
MapFile(mCurrentBytecodeFileDesc, &bytecodeInfo);
if (NS_WARN_IF(!bytecodeMapping)) {
ContinueWithStatus(NS_ERROR_FAILURE);
return;
}
RefPtr<JS::WasmModule> module =
JS::DeserializeWasmModule(bytecodeMapping.get(), bytecodeInfo.size);
if (NS_WARN_IF(!module)) {
ContinueWithStatus(NS_ERROR_FAILURE);
return;
}
mModuleSet.AppendElement(module);
mStreams.RemoveElementAt(0);
ContinueWithStatus(NS_OK);
}
nsresult BackgroundRequestChild::PreprocessHelper::WaitForStreamReady(
nsIInputStream* aInputStream) {
MOZ_ASSERT(!IsOnOwningThread());
MOZ_ASSERT(aInputStream);
nsCOMPtr<nsIAsyncFileMetadata> asyncFileMetadata =
do_QueryInterface(aInputStream);
if (asyncFileMetadata) {
nsresult rv =
asyncFileMetadata->AsyncFileMetadataWait(this, mTaskQueueEventTarget);
PRFileDesc* fileDesc = GetFileDescriptorFromStream(mStream);
if (fileDesc) {
rv = ProcessStream();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -3109,12 +3040,24 @@ nsresult BackgroundRequestChild::PreprocessHelper::WaitForStreamReady(
return NS_OK;
}
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aInputStream);
mState = State::WaitingForStreamReady;
nsCOMPtr<nsIAsyncFileMetadata> asyncFileMetadata = do_QueryInterface(mStream);
if (asyncFileMetadata) {
rv = asyncFileMetadata->AsyncFileMetadataWait(this, mTaskQueueEventTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(mStream);
if (!asyncStream) {
return NS_ERROR_NO_INTERFACE;
}
nsresult rv = asyncStream->AsyncWait(this, 0, 0, mTaskQueueEventTarget);
rv = asyncStream->AsyncWait(this, 0, 0, mTaskQueueEventTarget);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -3122,33 +3065,75 @@ nsresult BackgroundRequestChild::PreprocessHelper::WaitForStreamReady(
return NS_OK;
}
void BackgroundRequestChild::PreprocessHelper::ContinueWithStatus(
nsresult aStatus) {
nsresult BackgroundRequestChild::PreprocessHelper::ProcessStream() {
MOZ_ASSERT(!IsOnOwningThread());
MOZ_ASSERT(mStream);
MOZ_ASSERT(mState == State::Initial ||
mState == State::WaitingForStreamReady);
// Let's reset the value for the next operation.
mCurrentBytecodeFileDesc = nullptr;
// We need to get the internal stream (which is an nsFileInputStream) because
// SnappyUncompressInputStream doesn't support reading from async input
// streams.
nsCOMPtr<nsIEventTarget> eventTarget;
nsCOMPtr<mozIIPCBlobInputStream> blobInputStream = do_QueryInterface(mStream);
MOZ_ASSERT(blobInputStream);
if (NS_WARN_IF(NS_FAILED(aStatus))) {
// If the previous operation failed, we don't continue the processing of the
// other streams.
MOZ_ASSERT(mResultCode == NS_OK);
mResultCode = aStatus;
nsCOMPtr<nsIInputStream> internalInputStream =
blobInputStream->GetInternalStream();
MOZ_ASSERT(internalInputStream);
eventTarget = mOwningEventTarget;
} else if (mStreams.IsEmpty()) {
// If all the streams have been processed, we can go back to the owning
// thread.
eventTarget = mOwningEventTarget;
} else {
// Continue the processing.
eventTarget = mTaskQueueEventTarget;
RefPtr<SnappyUncompressInputStream> snappyInputStream =
new SnappyUncompressInputStream(internalInputStream);
nsresult rv;
do {
char buffer[kFileCopyBufferSize];
uint32_t numRead;
rv = snappyInputStream->Read(buffer, sizeof(buffer), &numRead);
if (NS_WARN_IF(NS_FAILED(rv))) {
break;
}
if (!numRead) {
break;
}
if (NS_WARN_IF(!mCloneData->AppendBytes(buffer, numRead))) {
rv = NS_ERROR_OUT_OF_MEMORY;
break;
}
} while (true);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
nsresult rv = eventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
Unused << NS_WARN_IF(NS_FAILED(rv));
mState = State::Finishing;
rv = mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
void BackgroundRequestChild::PreprocessHelper::Finish() {
AssertIsOnOwningThread();
if (mActor) {
if (NS_SUCCEEDED(mResultCode)) {
mActor->OnPreprocessFinished(mCloneDataIndex, std::move(mCloneData));
MOZ_ASSERT(!mCloneData);
} else {
mActor->OnPreprocessFailed(mCloneDataIndex, mResultCode);
}
}
mState = State::Completed;
}
NS_IMPL_ISUPPORTS_INHERITED(BackgroundRequestChild::PreprocessHelper,
@ -3157,10 +3142,40 @@ NS_IMPL_ISUPPORTS_INHERITED(BackgroundRequestChild::PreprocessHelper,
NS_IMETHODIMP
BackgroundRequestChild::PreprocessHelper::Run() {
if (IsOnOwningThread()) {
RunOnOwningThread();
} else {
ProcessCurrentStream();
nsresult rv;
switch (mState) {
case State::Initial:
rv = Start();
break;
case State::WaitingForStreamReady:
rv = ProcessStream();
break;
case State::Finishing:
Finish();
return NS_OK;
default:
MOZ_CRASH("Bad state!");
}
if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::Finishing) {
if (NS_SUCCEEDED(mResultCode)) {
mResultCode = rv;
}
// Must set mState before dispatching otherwise we will race with the owning
// thread.
mState = State::Finishing;
if (IsOnOwningThread()) {
Finish();
} else {
MOZ_ALWAYS_SUCCEEDS(
mOwningEventTarget->Dispatch(this, NS_DISPATCH_NORMAL));
}
}
return NS_OK;
@ -3169,42 +3184,25 @@ BackgroundRequestChild::PreprocessHelper::Run() {
NS_IMETHODIMP
BackgroundRequestChild::PreprocessHelper::OnInputStreamReady(
nsIAsyncInputStream* aStream) {
return DataIsReady(aStream);
MOZ_ASSERT(!IsOnOwningThread());
MOZ_ASSERT(mState == State::WaitingForStreamReady);
MOZ_ALWAYS_SUCCEEDS(this->Run());
return NS_OK;
}
NS_IMETHODIMP
BackgroundRequestChild::PreprocessHelper::OnFileMetadataReady(
nsIAsyncFileMetadata* aObject) {
nsCOMPtr<nsIInputStream> stream = do_QueryInterface(aObject);
MOZ_ASSERT(stream, "It was a stream before!");
return DataIsReady(stream);
}
nsresult BackgroundRequestChild::PreprocessHelper::DataIsReady(
nsIInputStream* aStream) {
MOZ_ASSERT(!IsOnOwningThread());
MOZ_ASSERT(aStream);
MOZ_ASSERT(!mStreams.IsEmpty());
MOZ_ASSERT(mState == State::WaitingForStreamReady);
// We still don't have the current bytecode FileDesc.
if (!mCurrentBytecodeFileDesc) {
mCurrentBytecodeFileDesc = GetFileDescriptorFromStream(aStream);
if (!mCurrentBytecodeFileDesc) {
ContinueWithStatus(NS_ERROR_FAILURE);
return NS_OK;
}
MOZ_ALWAYS_SUCCEEDS(this->Run());
// Let's continue with the processing of the current stream.
ProcessCurrentStream();
return NS_OK;
}
MOZ_CRASH("If we have both fileDescs why are we here?");
return NS_OK;
}
nsresult BackgroundRequestChild::PreprocessHelper::Cancel() { return NS_OK; }
/*******************************************************************************
* BackgroundCursorChild
******************************************************************************/
@ -3369,9 +3367,9 @@ void BackgroundCursorChild::HandleResponse(
StructuredCloneReadInfo cloneReadInfo(std::move(response.cloneInfo()));
cloneReadInfo.mDatabase = mTransaction->Database();
DeserializeStructuredCloneFiles(mTransaction->Database(),
response.cloneInfo().files(), nullptr,
cloneReadInfo.mFiles);
DeserializeStructuredCloneFiles(
mTransaction->Database(), response.cloneInfo().files(),
/* aForPreprocess */ false, cloneReadInfo.mFiles);
RefPtr<IDBCursor> newCursor;
@ -3428,9 +3426,9 @@ void BackgroundCursorChild::HandleResponse(
StructuredCloneReadInfo cloneReadInfo(std::move(response.cloneInfo()));
cloneReadInfo.mDatabase = mTransaction->Database();
DeserializeStructuredCloneFiles(mTransaction->Database(),
aResponse.cloneInfo().files(), nullptr,
cloneReadInfo.mFiles);
DeserializeStructuredCloneFiles(
mTransaction->Database(), aResponse.cloneInfo().files(),
/* aForPreprocess */ false, cloneReadInfo.mFiles);
RefPtr<IDBCursor> newCursor;

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

@ -30,10 +30,6 @@
class nsIEventTarget;
struct nsID;
namespace JS {
struct WasmModule;
} // namespace JS
namespace mozilla {
namespace ipc {
@ -570,9 +566,9 @@ class BackgroundRequestChild final : public BackgroundRequestChildBase,
RefPtr<IDBTransaction> mTransaction;
nsTArray<RefPtr<PreprocessHelper>> mPreprocessHelpers;
nsTArray<nsTArray<RefPtr<JS::WasmModule>>> mModuleSets;
nsTArray<UniquePtr<JSStructuredCloneData>> mCloneDatas;
uint32_t mRunningPreprocessHelpers;
uint32_t mCurrentModuleSetIndex;
uint32_t mCurrentCloneDataIndex;
nsresult mPreprocessResultCode;
bool mGetAll;
@ -586,13 +582,12 @@ class BackgroundRequestChild final : public BackgroundRequestChildBase,
void MaybeSendContinue();
void OnPreprocessFinished(uint32_t aModuleSetIndex,
nsTArray<RefPtr<JS::WasmModule>>& aModuleSet);
void OnPreprocessFinished(uint32_t aCloneDataIndex,
UniquePtr<JSStructuredCloneData> aCloneData);
void OnPreprocessFailed(uint32_t aModuleSetIndex, nsresult aErrorCode);
const nsTArray<RefPtr<JS::WasmModule>>* GetNextModuleSet(
const StructuredCloneReadInfo& aInfo);
UniquePtr<JSStructuredCloneData> GetNextCloneData();
void HandleResponse(nsresult aResponse);
@ -609,10 +604,9 @@ class BackgroundRequestChild final : public BackgroundRequestChildBase,
void HandleResponse(uint64_t aResponse);
nsresult HandlePreprocess(const WasmModulePreprocessInfo& aPreprocessInfo);
nsresult HandlePreprocess(const PreprocessInfo& aPreprocessInfo);
nsresult HandlePreprocess(
const nsTArray<WasmModulePreprocessInfo>& aPreprocessInfos);
nsresult HandlePreprocess(const nsTArray<PreprocessInfo>& aPreprocessInfos);
// IPDL methods are only called by IPDL.
virtual void ActorDestroy(ActorDestroyReason aWhy) override;

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

@ -8454,10 +8454,9 @@ nsresult DeserializeStructuredCloneFile(FileManager* aFileManager,
return NS_OK;
}
nsresult DeserializeStructuredCloneFiles(FileManager* aFileManager,
const nsAString& aText,
nsTArray<StructuredCloneFile>& aResult,
bool* aHasPreprocessInfo) {
nsresult DeserializeStructuredCloneFiles(
FileManager* aFileManager, const nsAString& aText,
nsTArray<StructuredCloneFile>& aResult) {
MOZ_ASSERT(!IsOnBackgroundThread());
nsCharSeparatedTokenizerTemplate<TokenizerIgnoreNothing> tokenizer(aText,
@ -8475,20 +8474,6 @@ nsresult DeserializeStructuredCloneFiles(FileManager* aFileManager,
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (!aHasPreprocessInfo) {
continue;
}
if (file->mType == StructuredCloneFile::eWasmBytecode) {
*aHasPreprocessInfo = true;
} else if (file->mType == StructuredCloneFile::eWasmCompiled) {
MOZ_ASSERT(aResult.Length() > 1);
MOZ_ASSERT(aResult[aResult.Length() - 2].mType ==
StructuredCloneFile::eWasmBytecode);
*aHasPreprocessInfo = true;
}
}
return NS_OK;
@ -8540,7 +8525,7 @@ nsresult SerializeStructuredCloneFiles(
for (uint32_t index = 0; index < count; index++) {
const StructuredCloneFile& file = aFiles[index];
if (aForPreprocess && file.mType != StructuredCloneFile::eWasmBytecode) {
if (aForPreprocess && file.mType != StructuredCloneFile::eStructuredClone) {
continue;
}
@ -8615,23 +8600,12 @@ nsresult SerializeStructuredCloneFiles(
}
case StructuredCloneFile::eStructuredClone: {
SerializedStructuredCloneFile* file = aResult.AppendElement(fallible);
MOZ_ASSERT(file);
file->file() = null_t();
file->type() = StructuredCloneFile::eStructuredClone;
break;
}
case StructuredCloneFile::eWasmBytecode: {
if (!aForPreprocess) {
SerializedStructuredCloneFile* serializedFile =
aResult.AppendElement(fallible);
MOZ_ASSERT(serializedFile);
SerializedStructuredCloneFile* file = aResult.AppendElement(fallible);
MOZ_ASSERT(file);
serializedFile->file() = null_t();
serializedFile->type() = StructuredCloneFile::eWasmBytecode;
file->file() = null_t();
file->type() = StructuredCloneFile::eStructuredClone;
} else {
RefPtr<FileBlobImpl> impl = new FileBlobImpl(nativeFile);
impl->SetFileId(file.mFileInfo->Id());
@ -8650,7 +8624,7 @@ nsresult SerializeStructuredCloneFiles(
MOZ_ASSERT(serializedFile);
serializedFile->file() = ipcBlob;
serializedFile->type() = StructuredCloneFile::eWasmBytecode;
serializedFile->type() = StructuredCloneFile::eStructuredClone;
aDatabase->MapBlob(ipcBlob, file.mFileInfo);
}
@ -8658,13 +8632,20 @@ nsresult SerializeStructuredCloneFiles(
break;
}
case StructuredCloneFile::eWasmBytecode:
case StructuredCloneFile::eWasmCompiled: {
SerializedStructuredCloneFile* serializedFile =
aResult.AppendElement(fallible);
MOZ_ASSERT(serializedFile);
// Set file() to null, support for storing WebAssembly.Modules has been
// removed in bug 1469395. Support for de-serialization of
// WebAssembly.Modules modules has been removed in bug 1561876. Full
// removal is tracked in bug 1487479.
serializedFile->file() = null_t();
serializedFile->type() = StructuredCloneFile::eWasmCompiled;
serializedFile->type() = file.mType;
break;
}
@ -10358,7 +10339,7 @@ nsresult DatabaseConnection::UpdateRefcountFunction::ProcessValue(
}
nsTArray<StructuredCloneFile> files;
rv = DeserializeStructuredCloneFiles(mFileManager, ids, files, nullptr);
rv = DeserializeStructuredCloneFiles(mFileManager, ids, files);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -13776,23 +13757,8 @@ bool TransactionBase::VerifyRequestParams(
}
case StructuredCloneFile::eStructuredClone:
ASSERT_UNLESS_FUZZING();
return false;
case StructuredCloneFile::eWasmBytecode:
case StructuredCloneFile::eWasmCompiled:
if (NS_WARN_IF(
file.type() !=
DatabaseOrMutableFile::TPBackgroundIDBDatabaseFileParent)) {
ASSERT_UNLESS_FUZZING();
return false;
}
if (NS_WARN_IF(!file.get_PBackgroundIDBDatabaseFileParent())) {
ASSERT_UNLESS_FUZZING();
return false;
}
break;
case StructuredCloneFile::eEndGuard:
ASSERT_UNLESS_FUZZING();
return false;
@ -18219,8 +18185,8 @@ nsresult DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob(
}
if (!aFileIds.IsVoid()) {
nsresult rv = DeserializeStructuredCloneFiles(
aFileManager, aFileIds, aInfo->mFiles, &aInfo->mHasPreprocessInfo);
nsresult rv =
DeserializeStructuredCloneFiles(aFileManager, aFileIds, aInfo->mFiles);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -18243,8 +18209,7 @@ nsresult DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob(
nsresult rv;
if (!aFileIds.IsVoid()) {
rv = DeserializeStructuredCloneFiles(aFileManager, aFileIds, aInfo->mFiles,
&aInfo->mHasPreprocessInfo);
rv = DeserializeStructuredCloneFiles(aFileManager, aFileIds, aInfo->mFiles);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -18259,6 +18224,11 @@ nsresult DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob(
return NS_ERROR_UNEXPECTED;
}
if (IndexedDatabaseManager::PreprocessingEnabled()) {
aInfo->mHasPreprocessInfo = true;
return NS_OK;
}
StructuredCloneFile& file = aInfo->mFiles[index];
MOZ_ASSERT(file.mFileInfo);
MOZ_ASSERT(file.mType == StructuredCloneFile::eStructuredClone);
@ -24132,9 +24102,7 @@ bool ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction) {
const FileAddInfo& fileAddInfo = fileAddInfos[index];
MOZ_ASSERT(fileAddInfo.type() == StructuredCloneFile::eBlob ||
fileAddInfo.type() == StructuredCloneFile::eMutableFile ||
fileAddInfo.type() == StructuredCloneFile::eWasmBytecode ||
fileAddInfo.type() == StructuredCloneFile::eWasmCompiled);
fileAddInfo.type() == StructuredCloneFile::eMutableFile);
const DatabaseOrMutableFile& file = fileAddInfo.file();
@ -24172,22 +24140,6 @@ bool ObjectStoreAddOrPutRequestOp::Init(TransactionBase* aTransaction) {
break;
}
case StructuredCloneFile::eWasmBytecode:
case StructuredCloneFile::eWasmCompiled: {
MOZ_ASSERT(file.type() ==
DatabaseOrMutableFile::TPBackgroundIDBDatabaseFileParent);
storedFileInfo->mFileActor = static_cast<DatabaseFile*>(
file.get_PBackgroundIDBDatabaseFileParent());
MOZ_ASSERT(storedFileInfo->mFileActor);
storedFileInfo->mFileInfo = storedFileInfo->mFileActor->GetFileInfo();
MOZ_ASSERT(storedFileInfo->mFileInfo);
storedFileInfo->mType = fileAddInfo.type();
break;
}
default:
MOZ_CRASH("Should never get here!");
}
@ -24651,8 +24603,8 @@ void MoveData<SerializedStructuredCloneReadInfo>(
}
template <>
void MoveData<WasmModulePreprocessInfo>(StructuredCloneReadInfo& aInfo,
WasmModulePreprocessInfo& aResult) {}
void MoveData<PreprocessInfo>(StructuredCloneReadInfo& aInfo,
PreprocessInfo& aResult) {}
template <bool aForPreprocess, typename T>
nsresult ObjectStoreGetRequestOp::ConvertResponse(
@ -24761,7 +24713,7 @@ nsresult ObjectStoreGetRequestOp::GetPreprocessParams(
if (mGetAll) {
aParams = ObjectStoreGetAllPreprocessParams();
FallibleTArray<WasmModulePreprocessInfo> falliblePreprocessInfos;
FallibleTArray<PreprocessInfo> falliblePreprocessInfos;
if (NS_WARN_IF(!falliblePreprocessInfos.SetLength(mPreprocessInfoCount,
fallible))) {
return NS_ERROR_OUT_OF_MEMORY;
@ -24781,7 +24733,7 @@ nsresult ObjectStoreGetRequestOp::GetPreprocessParams(
}
}
nsTArray<WasmModulePreprocessInfo>& preprocessInfos =
nsTArray<PreprocessInfo>& preprocessInfos =
aParams.get_ObjectStoreGetAllPreprocessParams().preprocessInfos();
falliblePreprocessInfos.SwapElements(preprocessInfos);
@ -24791,7 +24743,7 @@ nsresult ObjectStoreGetRequestOp::GetPreprocessParams(
aParams = ObjectStoreGetPreprocessParams();
WasmModulePreprocessInfo& preprocessInfo =
PreprocessInfo& preprocessInfo =
aParams.get_ObjectStoreGetPreprocessParams().preprocessInfo();
nsresult rv = ConvertResponse<true>(mResponse[0], preprocessInfo);

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

@ -689,26 +689,16 @@ class ValueDeserializationHelper {
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eWasmBytecode);
MOZ_ASSERT(!aFile.mBlob);
// If we don't have a WasmModule, we are probably using it for an index
// creation, but Wasm module can't be used in index creation, so just make a
// dummy object.
if (!aFile.mWasmModule) {
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
// Just create a plain object here, support for de-serialization of
// WebAssembly.Modules has been removed in bug 1561876. Full removal is
// tracked in bug 1487479.
if (NS_WARN_IF(!obj)) {
return false;
}
aResult.set(obj);
return true;
}
JS::Rooted<JSObject*> moduleObj(aCx, aFile.mWasmModule->createObject(aCx));
if (NS_WARN_IF(!moduleObj)) {
JS::Rooted<JSObject*> obj(aCx, JS_NewPlainObject(aCx));
if (NS_WARN_IF(!obj)) {
return false;
}
aResult.set(moduleObj);
aResult.set(obj);
return true;
}
};
@ -804,7 +794,7 @@ JSObject* CopyingStructuredCloneReadCallback(JSContext* aCx,
MOZ_ASSERT(aTag != SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE);
if (aTag == SCTAG_DOM_BLOB || aTag == SCTAG_DOM_FILE ||
aTag == SCTAG_DOM_MUTABLEFILE || aTag == SCTAG_DOM_WASM) {
aTag == SCTAG_DOM_MUTABLEFILE) {
auto* cloneInfo =
static_cast<IDBObjectStore::StructuredCloneInfo*>(aClosure);
@ -854,28 +844,14 @@ JSObject* CopyingStructuredCloneReadCallback(JSContext* aCx,
return result;
}
if (aTag == SCTAG_DOM_MUTABLEFILE) {
MOZ_ASSERT(file.mType == StructuredCloneFile::eMutableFile);
MOZ_ASSERT(file.mType == StructuredCloneFile::eMutableFile);
JS::Rooted<JS::Value> wrappedMutableFile(aCx);
if (NS_WARN_IF(!ToJSValue(aCx, file.mMutableFile, &wrappedMutableFile))) {
return nullptr;
}
result.set(&wrappedMutableFile.toObject());
return result;
}
MOZ_ASSERT(file.mType == StructuredCloneFile::eWasmBytecode);
JS::Rooted<JSObject*> wrappedModule(aCx,
file.mWasmModule->createObject(aCx));
if (NS_WARN_IF(!wrappedModule)) {
JS::Rooted<JS::Value> wrappedMutableFile(aCx);
if (NS_WARN_IF(!ToJSValue(aCx, file.mMutableFile, &wrappedMutableFile))) {
return nullptr;
}
result.set(wrappedModule);
result.set(&wrappedMutableFile.toObject());
return result;
}

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

@ -11,10 +11,6 @@
#include "nsCOMPtr.h"
#include "nsTArray.h"
namespace JS {
struct WasmModule;
} // namespace JS
namespace mozilla {
namespace dom {
@ -39,7 +35,6 @@ struct StructuredCloneFile {
RefPtr<Blob> mBlob;
RefPtr<IDBMutableFile> mMutableFile;
RefPtr<JS::WasmModule> mWasmModule;
RefPtr<FileInfo> mFileInfo;
FileType mType;

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

@ -123,6 +123,7 @@ const char kPrefMaxSerilizedMsgSize[] =
IDB_PREF_BRANCH_ROOT "maxSerializedMsgSize";
const char kPrefErrorEventToSelfError[] =
IDB_PREF_BRANCH_ROOT "errorEventToSelfError";
const char kPreprocessingPref[] = IDB_PREF_BRANCH_ROOT "preprocessing";
#define IDB_PREF_LOGGING_BRANCH_ROOT IDB_PREF_BRANCH_ROOT "logging."
@ -147,6 +148,7 @@ Atomic<bool> gFileHandleEnabled(false);
Atomic<bool> gPrefErrorEventToSelfError(false);
Atomic<int32_t> gDataThresholdBytes(0);
Atomic<int32_t> gMaxSerializedMsgSize(0);
Atomic<bool> gPreprocessingEnabled(false);
void AtomicBoolPrefChangedCallback(const char* aPrefName,
Atomic<bool>* aClosure) {
@ -281,6 +283,10 @@ nsresult IndexedDatabaseManager::Init() {
Preferences::RegisterCallbackAndCall(MaxSerializedMsgSizePrefChangeCallback,
kPrefMaxSerilizedMsgSize);
Preferences::RegisterCallbackAndCall(AtomicBoolPrefChangedCallback,
kPreprocessingPref,
&gPreprocessingEnabled);
nsAutoCString acceptLang;
Preferences::GetLocalizedCString("intl.accept_languages", acceptLang);
@ -336,6 +342,9 @@ void IndexedDatabaseManager::Destroy() {
Preferences::UnregisterCallback(MaxSerializedMsgSizePrefChangeCallback,
kPrefMaxSerilizedMsgSize);
Preferences::UnregisterCallback(AtomicBoolPrefChangedCallback,
kPreprocessingPref, &gPreprocessingEnabled);
delete this;
}
@ -617,6 +626,15 @@ uint32_t IndexedDatabaseManager::MaxSerializedMsgSize() {
return gMaxSerializedMsgSize;
}
// static
bool IndexedDatabaseManager::PreprocessingEnabled() {
MOZ_ASSERT(gDBManager,
"PreprocessingEnabled() called before indexedDB has been "
"initialized!");
return gPreprocessingEnabled;
}
void IndexedDatabaseManager::ClearBackgroundActor() {
MOZ_ASSERT(NS_IsMainThread());

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

@ -95,6 +95,8 @@ class IndexedDatabaseManager final {
static uint32_t MaxSerializedMsgSize();
static bool PreprocessingEnabled();
void ClearBackgroundActor();
already_AddRefed<FileManager> GetFileManager(PersistenceType aPersistenceType,

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

@ -109,19 +109,19 @@ union RequestResponse
IndexCountResponse;
};
struct WasmModulePreprocessInfo
struct PreprocessInfo
{
SerializedStructuredCloneFile[] files;
};
struct ObjectStoreGetPreprocessParams
{
WasmModulePreprocessInfo preprocessInfo;
PreprocessInfo preprocessInfo;
};
struct ObjectStoreGetAllPreprocessParams
{
WasmModulePreprocessInfo[] preprocessInfos;
PreprocessInfo[] preprocessInfos;
};
union PreprocessParams

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

@ -16,11 +16,26 @@ function* testSteps() {
const viewData = { key: 1, view: getRandomView(100000) };
for (let external of [false, true]) {
if (external) {
info("Setting data threshold pref");
const tests = [
{
external: false,
preprocessing: false,
},
{
external: true,
preprocessing: false,
},
{
external: true,
preprocessing: true,
},
];
for (let test of tests) {
if (test.external) {
if (this.window) {
info("Setting data threshold pref");
SpecialPowers.pushPrefEnv(
{ set: [["dom.indexedDB.dataThreshold", 0]] },
continueToNextStep
@ -31,6 +46,20 @@ function* testSteps() {
}
}
if (test.preprocessing) {
if (this.window) {
info("Setting preprocessing pref");
SpecialPowers.pushPrefEnv(
{ set: [["dom.indexedDB.preprocessing", true]] },
continueToNextStep
);
yield undefined;
} else {
enablePreprocessing();
}
}
info("Opening database");
let request = indexedDB.open(name);
@ -88,7 +117,7 @@ function* testSteps() {
getCurrentUsage(grabFileUsageAndContinueHandler);
let fileUsage = yield undefined;
if (external) {
if (test.external) {
ok(fileUsage > 0, "File usage is not zero");
} else {
ok(fileUsage == 0, "File usage is zero");
@ -100,6 +129,21 @@ function* testSteps() {
request.onerror = errorHandler;
request.onsuccess = continueToNextStepSync;
yield undefined;
if (this.window) {
info("Resetting prefs");
SpecialPowers.popPrefEnv(continueToNextStep);
yield undefined;
} else {
if (test.external) {
resetDataThreshold();
}
if (test.preprocessing) {
resetPreprocessing();
}
}
}
finishTest();

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

@ -0,0 +1,58 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function* testSteps() {
const name = "test_wasm_recompile.js";
const objectStoreName = "Wasm";
const wasmData = { key: 1 };
// The goal of this test is to prove that stored wasm is never deserialized.
info("Installing profile");
clearAllDatabases(continueToNextStepSync);
yield undefined;
// The profile was created with a mythical build (buildId: 20180309213541,
// cpuId: X64=0x2). It contains one stored wasm module (file id 1 - bytecode
// and file id 2 - compiled/machine code). The file create_db.js in the
// package was run locally (specifically it was temporarily added to
// xpcshell-parent-process.ini and then executed:
// mach xpcshell-test dom/indexedDB/test/unit/create_db.js
installPackagedProfile("wasm_get_values_profile");
info("Opening database");
let request = indexedDB.open(name);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = continueToNextStepSync;
yield undefined;
// success
let db = request.result;
db.onerror = errorHandler;
info("Getting wasm");
request = db
.transaction([objectStoreName])
.objectStore(objectStoreName)
.get(wasmData.key);
request.onsuccess = continueToNextStepSync;
yield undefined;
info("Verifying wasm");
let isWasmModule = request.result instanceof WebAssembly.Module;
ok(!isWasmModule, "Object is not wasm module");
finishTest();
yield undefined;
}

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

@ -1,140 +0,0 @@
/**
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var testGenerator = testSteps();
function* testSteps() {
const name = "test_wasm_recompile.js";
const objectStoreName = "Wasm";
const wasmData = { key: 1, wasm: null };
// The goal of this test is to prove that wasm is recompiled and the on-disk
// copy updated.
if (!isWasmSupported()) {
finishTest();
yield undefined;
}
getWasmBinary(
'(module (func $f (result i32) (i32.const 42)) (func (export "run") (result i32) (call $f)))'
);
let binary = yield undefined;
wasmData.wasm = getWasmModule(binary);
info("Installing profile");
clearAllDatabases(continueToNextStepSync);
yield undefined;
// The profile was created with a mythical build (buildId: 20180309213541,
// cpuId: X64=0x2). It contains one stored wasm module (file id 1 - bytecode
// and file id 2 - compiled/machine code). The file create_db.js in the
// package was run locally (specifically it was temporarily added to
// xpcshell-parent-process.ini and then executed:
// mach xpcshell-test dom/indexedDB/test/unit/create_db.js
installPackagedProfile("wasm_recompile_profile");
let filesDir = getChromeFilesDir();
let file = filesDir.clone();
file.append("2");
info("Reading out contents of compiled blob");
File.createFromNsIFile(file).then(grabEventAndContinueHandler);
let domFile = yield undefined;
let fileReader = new FileReader();
fileReader.onload = continueToNextStepSync;
fileReader.readAsArrayBuffer(domFile);
yield undefined;
let compiledBuffer = fileReader.result;
info("Opening database");
let request = indexedDB.open(name);
request.onerror = errorHandler;
request.onupgradeneeded = unexpectedSuccessHandler;
request.onsuccess = continueToNextStepSync;
yield undefined;
// success
let db = request.result;
db.onerror = errorHandler;
info("Getting wasm");
request = db
.transaction([objectStoreName])
.objectStore(objectStoreName)
.get(wasmData.key);
request.onsuccess = continueToNextStepSync;
yield undefined;
info("Verifying wasm module");
verifyWasmModule(request.result, wasmData.wasm);
yield undefined;
info("Reading out contents of new compiled blob");
File.createFromNsIFile(file).then(grabEventAndContinueHandler);
domFile = yield undefined;
fileReader = new FileReader();
fileReader.onload = continueToNextStepSync;
fileReader.readAsArrayBuffer(domFile);
yield undefined;
let newCompiledBuffer = fileReader.result;
info("Verifying that re-storing of re-compiled code has been disabled");
ok(compareBuffers(newCompiledBuffer, compiledBuffer), "Blobs don't differ");
info("Getting wasm again");
request = db
.transaction([objectStoreName])
.objectStore(objectStoreName)
.get(wasmData.key);
request.onsuccess = continueToNextStepSync;
yield undefined;
info("Verifying wasm module");
verifyWasmModule(request.result, wasmData.wasm);
yield undefined;
info("Reading out contents of new compiled blob again");
File.createFromNsIFile(file).then(grabEventAndContinueHandler);
domFile = yield undefined;
fileReader = new FileReader();
fileReader.onload = continueToNextStepSync;
fileReader.readAsArrayBuffer(domFile);
yield undefined;
let newCompiledBuffer2 = fileReader.result;
info("Verifying blob didn't change");
ok(
compareBuffers(newCompiledBuffer2, newCompiledBuffer),
"Blob didn't change"
);
finishTest();
yield undefined;
}

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

@ -494,16 +494,6 @@ function verifyView(view1, view2) {
continueToNextStep();
}
function verifyWasmModule(module1, module2) {
// We assume the given modules have no imports and export a single function
// named 'run'.
var instance1 = new WebAssembly.Instance(module1);
var instance2 = new WebAssembly.Instance(module2);
is(instance1.exports.run(), instance2.exports.run(), "same run() result");
continueToNextStep();
}
function grabFileUsageAndContinueHandler(request) {
testGenerator.next(request.result.fileUsage);
}
@ -531,11 +521,26 @@ function setDataThreshold(threshold) {
SpecialPowers.setIntPref("dom.indexedDB.dataThreshold", threshold);
}
function resetDataThreshold() {
info("Clearing data threshold pref");
SpecialPowers.clearUserPref("dom.indexedDB.dataThreshold");
}
function setMaxSerializedMsgSize(aSize) {
info("Setting maximal size of a serialized message to " + aSize);
SpecialPowers.setIntPref("dom.indexedDB.maxSerializedMsgSize", aSize);
}
function enablePreprocessing() {
info("Setting preprocessing pref");
SpecialPowers.setBoolPref("dom.indexedDB.preprocessing", true);
}
function resetPreprocessing() {
info("Clearing preprocessing pref");
SpecialPowers.clearUserPref("dom.indexedDB.preprocessing");
}
function getPrincipal(url) {
let uri = Services.io.newURI(url);
return Services.scriptSecurityManager.createContentPrincipal(uri, {});

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

@ -26,7 +26,7 @@ support-files =
schema23upgrade_profile.zip
snappyUpgrade_profile.zip
storagePersistentUpgrade_profile.zip
wasm_recompile_profile.zip
wasm_get_values_profile.zip
xpcshell-shared.ini
[include:xpcshell-shared.ini]
@ -66,5 +66,6 @@ skip-if = os == "android"
# bug 951017: intermittent failure on Android x86 emulator
skip-if = os == "android" && processor == "x86"
[test_unexpectedDirectory.js]
[test_view_put_get_values.js]
[test_wasm_get_values.js]
[test_wasm_put_get_values.js]
[test_wasm_recompile.js]