Bug 1311466 - Part 8: Implement basic functionality for preprocessing results before they are sent for synchronous deserialization; r=asuth

This commit is contained in:
Jan Varga 2016-10-25 21:19:06 +02:00
parent 828a986c64
commit 9d0d2c5654
11 changed files with 899 additions and 179 deletions

View File

@ -34,6 +34,8 @@
#include "nsIDocument.h"
#include "nsIDOMEvent.h"
#include "nsIEventTarget.h"
#include "nsIFileStreams.h"
#include "nsNetCID.h"
#include "nsPIDOMWindow.h"
#include "nsThreadUtils.h"
#include "nsTraceRefcnt.h"
@ -590,22 +592,23 @@ protected:
void
DeserializeStructuredCloneFiles(
IDBDatabase* aDatabase,
const SerializedStructuredCloneReadInfo& aCloneReadInfo,
nsTArray<StructuredCloneFile>& aFiles)
IDBDatabase* aDatabase,
const nsTArray<SerializedStructuredCloneFile>& aSerializedFiles,
const nsTArray<RefPtr<JS::WasmModule>>* aModules,
nsTArray<StructuredCloneFile>& aFiles)
{
MOZ_ASSERT_IF(aModules, !aModules->IsEmpty());
MOZ_ASSERT(aFiles.IsEmpty());
const nsTArray<SerializedStructuredCloneFile>& serializedFiles =
aCloneReadInfo.files();
if (!aSerializedFiles.IsEmpty()) {
uint32_t moduleIndex = 0;
if (!serializedFiles.IsEmpty()) {
const uint32_t count = serializedFiles.Length();
const uint32_t count = aSerializedFiles.Length();
aFiles.SetCapacity(count);
for (uint32_t index = 0; index < count; index++) {
const SerializedStructuredCloneFile& serializedFile =
serializedFiles[index];
aSerializedFiles[index];
const BlobOrMutableFile& blobOrMutableFile = serializedFile.file();
@ -687,6 +690,20 @@ DeserializeStructuredCloneFiles(
}
case StructuredCloneFile::eWasmBytecode: {
if (aModules) {
MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::Tnull_t);
StructuredCloneFile* file = aFiles.AppendElement();
MOZ_ASSERT(file);
file->mType = serializedFile.type();
MOZ_ASSERT(moduleIndex < aModules->Length());
file->mWasmModule = aModules->ElementAt(moduleIndex);
break;
}
MOZ_ASSERT(blobOrMutableFile.type() ==
BlobOrMutableFile::TPBlobChild);
@ -710,6 +727,20 @@ DeserializeStructuredCloneFiles(
}
case StructuredCloneFile::eWasmCompiled: {
if (aModules) {
MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::Tnull_t);
StructuredCloneFile* file = aFiles.AppendElement();
MOZ_ASSERT(file);
file->mType = serializedFile.type();
MOZ_ASSERT(moduleIndex < aModules->Length());
file->mWasmModule = aModules->ElementAt(moduleIndex++);
break;
}
MOZ_ASSERT(blobOrMutableFile.type() == BlobOrMutableFile::Tnull_t ||
blobOrMutableFile.type() ==
BlobOrMutableFile::TPBlobChild);
@ -910,6 +941,27 @@ DispatchSuccessEvent(ResultHelper* aResultHelper,
}
}
PRFileDesc*
GetFileDescriptorFromStream(nsIInputStream* aStream)
{
MOZ_ASSERT(aStream);
nsCOMPtr<nsIFileMetadata> fileMetadata = do_QueryInterface(aStream);
if (NS_WARN_IF(!fileMetadata)) {
return nullptr;
}
PRFileDesc* fileDesc;
nsresult rv = fileMetadata->GetFileDescriptor(&fileDesc);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
MOZ_ASSERT(fileDesc);
return fileDesc;
}
class WorkerPermissionChallenge;
// This class calles WorkerPermissionChallenge::OperationCompleted() in the
@ -1143,6 +1195,79 @@ WorkerPermissionRequestChildProcessActor::Recv__delete__(
} // namespace
/*******************************************************************************
* Actor class declarations
******************************************************************************/
// CancelableRunnable is used to make workers happy.
class BackgroundRequestChild::PreprocessHelper final
: public CancelableRunnable
{
typedef std::pair<nsCOMPtr<nsIInputStream>,
nsCOMPtr<nsIInputStream>> StreamPair;
nsCOMPtr<nsIEventTarget> mOwningThread;
nsTArray<StreamPair> mStreamPairs;
nsTArray<RefPtr<JS::WasmModule>> mModules;
BackgroundRequestChild* mActor;
nsresult mResultCode;
public:
PreprocessHelper(BackgroundRequestChild* aActor)
: mOwningThread(NS_GetCurrentThread())
, mActor(aActor)
, mResultCode(NS_OK)
{
AssertIsOnOwningThread();
MOZ_ASSERT(aActor);
aActor->AssertIsOnOwningThread();
}
bool
IsOnOwningThread() const
{
MOZ_ASSERT(mOwningThread);
bool current;
return NS_SUCCEEDED(mOwningThread->IsOnCurrentThread(&current)) && current;
}
void
AssertIsOnOwningThread() const
{
MOZ_ASSERT(IsOnOwningThread());
}
void
ClearActor()
{
AssertIsOnOwningThread();
mActor = nullptr;
}
nsresult
Init(const nsTArray<StructuredCloneFile>& aFiles);
nsresult
Dispatch();
private:
~PreprocessHelper()
{ }
void
RunOnOwningThread();
nsresult
RunOnStreamTransportThread();
NS_DECL_NSIRUNNABLE
virtual nsresult
Cancel() override;
};
/*******************************************************************************
* Local class implementations
******************************************************************************/
@ -2411,6 +2536,36 @@ BackgroundRequestChild::~BackgroundRequestChild()
MOZ_COUNT_DTOR(indexedDB::BackgroundRequestChild);
}
void
BackgroundRequestChild::OnPreprocessFinished(
const nsTArray<RefPtr<JS::WasmModule>>& aModules)
{
AssertIsOnOwningThread();
MOZ_ASSERT(!aModules.IsEmpty());
MOZ_ASSERT(mPreprocessHelper);
MOZ_ASSERT(!mModules);
mModules = new nsTArray<RefPtr<JS::WasmModule>>;
*mModules = Move(aModules);
MOZ_ALWAYS_TRUE(SendContinue(ObjectStoreGetPreprocessResponse()));
mPreprocessHelper = nullptr;
}
void
BackgroundRequestChild::OnPreprocessFailed(nsresult aErrorCode)
{
AssertIsOnOwningThread();
MOZ_ASSERT(NS_FAILED(aErrorCode));
MOZ_ASSERT(mPreprocessHelper);
MOZ_ASSERT(!mModules);
MOZ_ALWAYS_TRUE(SendContinue(aErrorCode));
mPreprocessHelper = nullptr;
}
void
BackgroundRequestChild::HandleResponse(nsresult aResponse)
{
@ -2455,7 +2610,8 @@ BackgroundRequestChild::HandleResponse(
StructuredCloneReadInfo cloneReadInfo(Move(serializedCloneInfo));
DeserializeStructuredCloneFiles(mTransaction->Database(),
aResponse,
aResponse.files(),
mModules,
cloneReadInfo.mFiles);
ResultHelper helper(mRequest, mTransaction, &cloneReadInfo);
@ -2487,7 +2643,10 @@ BackgroundRequestChild::HandleResponse(
// Get the files
nsTArray<StructuredCloneFile> files;
DeserializeStructuredCloneFiles(database, serializedCloneInfo, files);
DeserializeStructuredCloneFiles(database,
serializedCloneInfo.files(),
nullptr,
files);
// Move relevant data into the cloneReadInfo
*cloneReadInfo = Move(serializedCloneInfo);
@ -2529,6 +2688,12 @@ BackgroundRequestChild::ActorDestroy(ActorDestroyReason aWhy)
MaybeCollectGarbageOnIPCMessage();
if (mPreprocessHelper) {
mPreprocessHelper->ClearActor();
mPreprocessHelper = nullptr;
}
if (mTransaction) {
mTransaction->AssertIsOnOwningThread();
@ -2629,6 +2794,218 @@ BackgroundRequestChild::Recv__delete__(const RequestResponse& aResponse)
return true;
}
bool
BackgroundRequestChild::RecvPreprocess(const PreprocessParams& aParams)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mTransaction);
MaybeCollectGarbageOnIPCMessage();
IDBDatabase* database = mTransaction->Database();
if (aParams.type() != PreprocessParams::TObjectStoreGetPreprocessParams) {
MOZ_ASSERT(false, "Fix me!");
return false;
}
ObjectStoreGetPreprocessParams params =
aParams.get_ObjectStoreGetPreprocessParams();
nsTArray<StructuredCloneFile> files;
DeserializeStructuredCloneFiles(database,
params.preprocessInfo().files(),
nullptr,
files);
mPreprocessHelper = new PreprocessHelper(this);
nsresult rv = mPreprocessHelper->Init(files);
if (NS_WARN_IF(NS_FAILED(rv))) {
return SendContinue(rv);
}
rv = mPreprocessHelper->Dispatch();
if (NS_WARN_IF(NS_FAILED(rv))) {
return SendContinue(rv);
}
return true;
}
nsresult
BackgroundRequestChild::
PreprocessHelper::Init(const nsTArray<StructuredCloneFile>& aFiles)
{
AssertIsOnOwningThread();
MOZ_ASSERT(!aFiles.IsEmpty());
uint32_t count = aFiles.Length();
// We should receive even number of files.
MOZ_ASSERT(count % 2 == 0);
// Let's process it as pairs.
count = count / 2;
nsTArray<StreamPair> streamPairs;
for (uint32_t index = 0; index < count; index++) {
uint32_t bytecodeIndex = index * 2;
uint32_t compiledIndex = bytecodeIndex + 1;
const StructuredCloneFile& bytecodeFile = aFiles[bytecodeIndex];
const StructuredCloneFile& compiledFile = aFiles[compiledIndex];
MOZ_ASSERT(bytecodeFile.mType == StructuredCloneFile::eWasmBytecode);
MOZ_ASSERT(bytecodeFile.mBlob);
MOZ_ASSERT(compiledFile.mType == StructuredCloneFile::eWasmCompiled);
ErrorResult errorResult;
nsCOMPtr<nsIInputStream> bytecodeStream;
bytecodeFile.mBlob->GetInternalStream(getter_AddRefs(bytecodeStream),
errorResult);
if (NS_WARN_IF(errorResult.Failed())) {
return errorResult.StealNSResult();
}
nsCOMPtr<nsIInputStream> compiledStream;
if (compiledFile.mBlob) {
compiledFile.mBlob->GetInternalStream(getter_AddRefs(compiledStream),
errorResult);
if (NS_WARN_IF(errorResult.Failed())) {
return errorResult.StealNSResult();
}
}
streamPairs.AppendElement(StreamPair(bytecodeStream, compiledStream));
}
mStreamPairs = Move(streamPairs);
return NS_OK;
}
nsresult
BackgroundRequestChild::
PreprocessHelper::Dispatch()
{
AssertIsOnOwningThread();
// 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);
nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
void
BackgroundRequestChild::
PreprocessHelper::RunOnOwningThread()
{
AssertIsOnOwningThread();
if (mActor) {
if (NS_SUCCEEDED(mResultCode)) {
mActor->OnPreprocessFinished(mModules);
} else {
mActor->OnPreprocessFailed(mResultCode);
}
}
}
nsresult
BackgroundRequestChild::
PreprocessHelper::RunOnStreamTransportThread()
{
MOZ_ASSERT(!IsOnOwningThread());
MOZ_ASSERT(!mStreamPairs.IsEmpty());
MOZ_ASSERT(mModules.IsEmpty());
const uint32_t count = mStreamPairs.Length();
for (uint32_t index = 0; index < count; index++) {
const StreamPair& streamPair = mStreamPairs[index];
const nsCOMPtr<nsIInputStream>& bytecodeStream = streamPair.first;
MOZ_ASSERT(bytecodeStream);
PRFileDesc* bytecodeFileDesc = GetFileDescriptorFromStream(bytecodeStream);
if (NS_WARN_IF(!bytecodeFileDesc)) {
return NS_ERROR_FAILURE;
}
const nsCOMPtr<nsIInputStream>& compiledStream = streamPair.second;
PRFileDesc* compiledFileDesc;
if (compiledStream) {
compiledFileDesc = GetFileDescriptorFromStream(compiledStream);
if (NS_WARN_IF(!bytecodeFileDesc)) {
return NS_ERROR_FAILURE;
}
} else {
compiledFileDesc = nullptr;
}
JS::BuildIdCharVector buildId;
bool ok = GetBuildId(&buildId);
if (NS_WARN_IF(!ok)) {
return NS_ERROR_FAILURE;
}
RefPtr<JS::WasmModule> module = JS::DeserializeWasmModule(bytecodeFileDesc,
compiledFileDesc,
Move(buildId),
nullptr,
0,
0);
if (NS_WARN_IF(!module)) {
return NS_ERROR_FAILURE;
}
mModules.AppendElement(module);
}
mStreamPairs.Clear();
return NS_OK;
}
NS_IMETHODIMP
BackgroundRequestChild::
PreprocessHelper::Run()
{
if (IsOnOwningThread()) {
RunOnOwningThread();
} else {
nsresult rv = RunOnStreamTransportThread();
if (NS_WARN_IF(NS_FAILED(rv))) {
MOZ_ASSERT(mResultCode == NS_OK);
mResultCode = rv;
}
MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
}
return NS_OK;
}
NS_IMETHODIMP
BackgroundRequestChild::
PreprocessHelper::Cancel()
{
return NS_OK;
}
/*******************************************************************************
* BackgroundCursorChild
******************************************************************************/
@ -2826,7 +3203,8 @@ BackgroundCursorChild::HandleResponse(
cloneReadInfo.mDatabase = mTransaction->Database();
DeserializeStructuredCloneFiles(mTransaction->Database(),
response.cloneInfo(),
response.cloneInfo().files(),
nullptr,
cloneReadInfo.mFiles);
RefPtr<IDBCursor> newCursor;
@ -2889,7 +3267,8 @@ BackgroundCursorChild::HandleResponse(const IndexCursorResponse& aResponse)
cloneReadInfo.mDatabase = mTransaction->Database();
DeserializeStructuredCloneFiles(mTransaction->Database(),
aResponse.cloneInfo(),
aResponse.cloneInfo().files(),
nullptr,
cloneReadInfo.mFiles);
RefPtr<IDBCursor> newCursor;

View File

@ -29,6 +29,10 @@ class nsIEventTarget;
struct nsID;
struct PRThread;
namespace JS {
struct WasmModule;
} // namespace JS
namespace mozilla {
namespace ipc {
@ -640,7 +644,11 @@ class BackgroundRequestChild final
friend class BackgroundVersionChangeTransactionChild;
friend IDBTransaction;
class PreprocessHelper;
RefPtr<IDBTransaction> mTransaction;
RefPtr<PreprocessHelper> mPreprocessHelper;
nsAutoPtr<nsTArray<RefPtr<JS::WasmModule>>> mModules;
private:
// Only created by IDBTransaction.
@ -651,6 +659,12 @@ private:
// BackgroundVersionChangeTransactionChild.
~BackgroundRequestChild();
void
OnPreprocessFinished(const nsTArray<RefPtr<JS::WasmModule>>& aModules);
void
OnPreprocessFailed(nsresult aErrorCode);
void
HandleResponse(nsresult aResponse);
@ -678,6 +692,9 @@ private:
virtual bool
Recv__delete__(const RequestResponse& aResponse) override;
virtual bool
RecvPreprocess(const PreprocessParams& aParams) override;
};
class BackgroundCursorChild final

View File

@ -5926,13 +5926,15 @@ protected:
uint32_t aDataIndex,
uint32_t aFileIdsIndex,
FileManager* aFileManager,
StructuredCloneReadInfo* aInfo)
StructuredCloneReadInfo* aInfo,
bool* aHasWasm)
{
return GetStructuredCloneReadInfoFromSource(aStatement,
aDataIndex,
aFileIdsIndex,
aFileManager,
aInfo);
aInfo,
aHasWasm);
}
static nsresult
@ -5942,11 +5944,13 @@ protected:
FileManager* aFileManager,
StructuredCloneReadInfo* aInfo)
{
bool dummy;
return GetStructuredCloneReadInfoFromSource(aValues,
aDataIndex,
aFileIdsIndex,
aFileManager,
aInfo);
aInfo,
&dummy);
}
static nsresult
@ -6010,20 +6014,23 @@ private:
uint32_t aDataIndex,
uint32_t aFileIdsIndex,
FileManager* aFileManager,
StructuredCloneReadInfo* aInfo);
StructuredCloneReadInfo* aInfo,
bool* aHasWasm);
static nsresult
GetStructuredCloneReadInfoFromBlob(const uint8_t* aBlobData,
uint32_t aBlobDataLength,
FileManager* aFileManager,
const nsAString& aFileIds,
StructuredCloneReadInfo* aInfo);
StructuredCloneReadInfo* aInfo,
bool* aHasWasm);
static nsresult
GetStructuredCloneReadInfoFromExternalBlob(uint64_t aIntData,
FileManager* aFileManager,
const nsAString& aFileIds,
StructuredCloneReadInfo* aInfo);
StructuredCloneReadInfo* aInfo,
bool* aHasWasm);
// Not to be overridden by subclasses.
NS_DECL_MOZISTORAGEPROGRESSHANDLER
@ -6049,8 +6056,19 @@ public:
class TransactionDatabaseOperationBase
: public DatabaseOperationBase
{
enum class InternalState
{
Initial,
DatabaseWork,
SendingPreprocess,
WaitingForContinue,
SendingResults,
Completed
};
RefPtr<TransactionBase> mTransaction;
const int64_t mTransactionLoggingSerialNumber;
InternalState mInternalState;
const bool mTransactionIsAborted;
public:
@ -6062,6 +6080,13 @@ public:
{ }
#endif
uint64_t
StartOnConnectionPool(const nsID& aBackgroundChildLoggingId,
const nsACString& aDatabaseId,
int64_t aLoggingSerialNumber,
const nsTArray<nsString>& aObjectStoreNames,
bool aIsWriteTransaction);
void
DispatchToConnectionPool();
@ -6073,6 +6098,9 @@ public:
return mTransaction;
}
void
NoteContinueReceived();
// May be overridden by subclasses if they need to perform work on the
// background thread before being dispatched. Returning false will kill the
// child actors and prevent dispatch.
@ -6105,6 +6133,19 @@ protected:
virtual nsresult
DoDatabaseWork(DatabaseConnection* aConnection) = 0;
// May be overriden in subclasses. Called on the background thread to decide
// if the subclass needs to send any preprocess info to the child actor.
virtual bool
HasPreprocessInfo();
// May be overriden in subclasses. Called on the background thread to allow
// the subclass to serialize its preprocess info and send it to the child
// actor. A successful return value will trigger a wait for a
// NoteContinueReceived callback on the background thread while a failure
// value will trigger a SendFailureResult callback.
virtual nsresult
SendPreprocessInfo();
// Must be overridden in subclasses. Called on the background thread to allow
// the subclass to serialize its results and send them to the child actor. A
// failed return value will trigger a SendFailureResult callback.
@ -6120,7 +6161,16 @@ protected:
private:
void
RunOnOwningThread();
SendToConnectionPool();
void
SendPreprocess();
void
SendResults();
void
SendPreprocessInfoOrResults(bool aSendPreprocessInfo);
// Not to be overridden by subclasses.
NS_DECL_NSIRUNNABLE
@ -6198,7 +6248,6 @@ private:
class WaitForTransactionsHelper final
: public Runnable
{
nsCOMPtr<nsIEventTarget> mOwningThread;
const nsCString mDatabaseId;
nsCOMPtr<nsIRunnable> mCallback;
@ -6213,8 +6262,7 @@ class WaitForTransactionsHelper final
public:
WaitForTransactionsHelper(const nsCString& aDatabaseId,
nsIRunnable* aCallback)
: mOwningThread(NS_GetCurrentThread())
, mDatabaseId(aDatabaseId)
: mDatabaseId(aDatabaseId)
, mCallback(aCallback)
, mState(State::Initial)
{
@ -8137,6 +8185,9 @@ private:
// IPDL methods.
virtual void
ActorDestroy(ActorDestroyReason aWhy) override;
virtual bool
RecvContinue(const PreprocessResponse& aResponse) override;
};
class ObjectStoreAddOrPutRequestOp final
@ -8291,6 +8342,7 @@ class ObjectStoreGetRequestOp final
PBackgroundParent* mBackgroundParent;
const uint32_t mLimit;
const bool mGetAll;
bool mHasWasm;
private:
// Only created by TransactionBase.
@ -8308,6 +8360,12 @@ private:
virtual nsresult
DoDatabaseWork(DatabaseConnection* aConnection) override;
virtual bool
HasPreprocessInfo() override;
virtual nsresult
SendPreprocessInfo() override;
virtual void
GetResponse(RequestResponse& aResponse) override;
};
@ -9647,9 +9705,11 @@ DeserializeStructuredCloneFile(FileManager* aFileManager,
nsresult
DeserializeStructuredCloneFiles(FileManager* aFileManager,
const nsAString& aText,
nsTArray<StructuredCloneFile>& aResult)
nsTArray<StructuredCloneFile>& aResult,
bool* aHasWasm)
{
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(aHasWasm);
nsCharSeparatedTokenizerTemplate<TokenizerIgnoreNothing>
tokenizer(aText, ' ');
@ -9668,7 +9728,12 @@ DeserializeStructuredCloneFiles(FileManager* aFileManager,
return rv;
}
if (file->mType == StructuredCloneFile::eWasmCompiled) {
if (file->mType == StructuredCloneFile::eWasmBytecode) {
MOZ_ASSERT(file->mValid);
*aHasWasm = true;
}
else if (file->mType == StructuredCloneFile::eWasmCompiled) {
if (!directory) {
directory = aFileManager->GetCheckedDirectory();
if (NS_WARN_IF(!directory)) {
@ -9700,6 +9765,8 @@ DeserializeStructuredCloneFiles(FileManager* aFileManager,
MOZ_ASSERT(file->mValid);
file->mValid = JS::CompiledWasmModuleAssumptionsMatch(fileDesc,
Move(buildId));
*aHasWasm = true;
}
}
@ -9733,6 +9800,7 @@ SerializeStructuredCloneFiles(
PBackgroundParent* aBackgroundActor,
Database* aDatabase,
const nsTArray<StructuredCloneFile>& aFiles,
bool aForPreprocess,
FallibleTArray<SerializedStructuredCloneFile>& aResult)
{
AssertIsOnBackgroundThread();
@ -9761,6 +9829,12 @@ SerializeStructuredCloneFiles(
for (uint32_t index = 0; index < count; index++) {
const StructuredCloneFile& file = aFiles[index];
if (aForPreprocess &&
file.mType != StructuredCloneFile::eWasmBytecode &&
file.mType != StructuredCloneFile::eWasmCompiled) {
continue;
}
const int64_t fileId = file.mFileInfo->Id();
MOZ_ASSERT(fileId > 0);
@ -9842,13 +9916,13 @@ SerializeStructuredCloneFiles(
case StructuredCloneFile::eWasmBytecode:
case StructuredCloneFile::eWasmCompiled: {
if (file.mType == StructuredCloneFile::eWasmCompiled && !file.mValid) {
if (!aForPreprocess || !file.mValid) {
SerializedStructuredCloneFile* serializedFile =
aResult.AppendElement(fallible);
MOZ_ASSERT(serializedFile);
serializedFile->file() = null_t();
serializedFile->type() = StructuredCloneFile::eWasmCompiled;
serializedFile->type() = file.mType;
} else {
RefPtr<BlobImpl> impl = new BlobImplStoredFile(nativeFile,
file.mFileInfo,
@ -11457,7 +11531,8 @@ UpdateRefcountFunction::ProcessValue(mozIStorageValueArray* aValues,
}
nsTArray<StructuredCloneFile> files;
rv = DeserializeStructuredCloneFiles(mFileManager, ids, files);
bool dummy;
rv = DeserializeStructuredCloneFiles(mFileManager, ids, files, &dummy);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -14390,12 +14465,11 @@ Database::RecvPBackgroundIDBTransactionConstructor(
RefPtr<StartTransactionOp> startOp = new StartTransactionOp(transaction);
uint64_t transactionId =
gConnectionPool->Start(GetLoggingInfo()->Id(),
mMetadata->mDatabaseId,
transaction->LoggingSerialNumber(),
aObjectStoreNames,
aMode != IDBTransaction::READ_ONLY,
startOp);
startOp->StartOnConnectionPool(GetLoggingInfo()->Id(),
mMetadata->mDatabaseId,
transaction->LoggingSerialNumber(),
aObjectStoreNames,
aMode != IDBTransaction::READ_ONLY);
transaction->SetActive(transactionId);
@ -16593,6 +16667,7 @@ Cursor::SendResponseInternal(
nsresult rv = SerializeStructuredCloneFiles(mBackgroundParent,
mDatabase,
files,
/* aForPreprocess */ false,
serializedFiles);
if (NS_WARN_IF(NS_FAILED(rv))) {
aResponse = ClampResultCode(rv);
@ -19269,7 +19344,8 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromSource(
uint32_t aDataIndex,
uint32_t aFileIdsIndex,
FileManager* aFileManager,
StructuredCloneReadInfo* aInfo)
StructuredCloneReadInfo* aInfo,
bool* aHasWasm)
{
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(aSource);
@ -19312,7 +19388,8 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromSource(
rv = GetStructuredCloneReadInfoFromExternalBlob(intData,
aFileManager,
fileIds,
aInfo);
aInfo,
aHasWasm);
} else {
const uint8_t* blobData;
uint32_t blobDataLength;
@ -19326,7 +19403,8 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromSource(
blobDataLength,
aFileManager,
fileIds,
aInfo);
aInfo,
aHasWasm);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -19342,7 +19420,8 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob(
uint32_t aBlobDataLength,
FileManager* aFileManager,
const nsAString& aFileIds,
StructuredCloneReadInfo* aInfo)
StructuredCloneReadInfo* aInfo,
bool* aHasWasm)
{
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(aFileManager);
@ -19378,8 +19457,10 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromBlob(
}
if (!aFileIds.IsVoid()) {
nsresult rv =
DeserializeStructuredCloneFiles(aFileManager, aFileIds, aInfo->mFiles);
nsresult rv = DeserializeStructuredCloneFiles(aFileManager,
aFileIds,
aInfo->mFiles,
aHasWasm);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -19394,7 +19475,8 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob(
uint64_t aIntData,
FileManager* aFileManager,
const nsAString& aFileIds,
StructuredCloneReadInfo* aInfo)
StructuredCloneReadInfo* aInfo,
bool* aHasWasm)
{
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(aFileManager);
@ -19408,7 +19490,10 @@ DatabaseOperationBase::GetStructuredCloneReadInfoFromExternalBlob(
nsresult rv;
if (!aFileIds.IsVoid()) {
rv = DeserializeStructuredCloneFiles(aFileManager, aFileIds, aInfo->mFiles);
rv = DeserializeStructuredCloneFiles(aFileManager,
aFileIds,
aInfo->mFiles,
aHasWasm);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -21955,12 +22040,12 @@ OpenDatabaseOp::DispatchToWorkThread()
RefPtr<VersionChangeOp> versionChangeOp = new VersionChangeOp(this);
uint64_t transactionId =
gConnectionPool->Start(backgroundChildLoggingId,
mVersionChangeTransaction->DatabaseId(),
loggingSerialNumber,
objectStoreNames,
/* aIsWriteTransaction */ true,
versionChangeOp);
versionChangeOp->StartOnConnectionPool(
backgroundChildLoggingId,
mVersionChangeTransaction->DatabaseId(),
loggingSerialNumber,
objectStoreNames,
/* aIsWriteTransaction */ true);
mVersionChangeOp = versionChangeOp;
@ -23087,6 +23172,7 @@ TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
aTransaction->GetLoggingInfo()->NextRequestSN())
, mTransaction(aTransaction)
, mTransactionLoggingSerialNumber(aTransaction->LoggingSerialNumber())
, mInternalState(InternalState::Initial)
, mTransactionIsAborted(aTransaction->IsAborted())
{
MOZ_ASSERT(aTransaction);
@ -23100,6 +23186,7 @@ TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
aLoggingSerialNumber)
, mTransaction(aTransaction)
, mTransactionLoggingSerialNumber(aTransaction->LoggingSerialNumber())
, mInternalState(InternalState::Initial)
, mTransactionIsAborted(aTransaction->IsAborted())
{
MOZ_ASSERT(aTransaction);
@ -23107,6 +23194,7 @@ TransactionDatabaseOperationBase::TransactionDatabaseOperationBase(
TransactionDatabaseOperationBase::~TransactionDatabaseOperationBase()
{
MOZ_ASSERT(mInternalState == InternalState::Completed);
MOZ_ASSERT(!mTransaction,
"TransactionDatabaseOperationBase::Cleanup() was not called by a "
"subclass!");
@ -23123,20 +23211,43 @@ TransactionDatabaseOperationBase::AssertIsOnConnectionThread() const
#endif // DEBUG
uint64_t
TransactionDatabaseOperationBase::StartOnConnectionPool(
const nsID& aBackgroundChildLoggingId,
const nsACString& aDatabaseId,
int64_t aLoggingSerialNumber,
const nsTArray<nsString>& aObjectStoreNames,
bool aIsWriteTransaction)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mInternalState == InternalState::Initial);
// Must set mInternalState before dispatching otherwise we will race with the
// connection thread.
mInternalState = InternalState::DatabaseWork;
return gConnectionPool->Start(aBackgroundChildLoggingId,
aDatabaseId,
aLoggingSerialNumber,
aObjectStoreNames,
aIsWriteTransaction,
this);
}
void
TransactionDatabaseOperationBase::DispatchToConnectionPool()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mInternalState == InternalState::Initial);
gConnectionPool->Dispatch(mTransaction->TransactionId(), this);
mTransaction->NoteActiveRequest();
Unused << this->Run();
}
void
TransactionDatabaseOperationBase::RunOnConnectionThread()
{
MOZ_ASSERT(!IsOnBackgroundThread());
MOZ_ASSERT(mInternalState == InternalState::DatabaseWork);
MOZ_ASSERT(mTransaction);
MOZ_ASSERT(NS_SUCCEEDED(mResultCode));
@ -23203,15 +23314,87 @@ TransactionDatabaseOperationBase::RunOnConnectionThread()
}
}
// Must set mInternalState before dispatching otherwise we will race with the
// owning thread.
if (HasPreprocessInfo()) {
mInternalState = InternalState::SendingPreprocess;
} else {
mInternalState = InternalState::SendingResults;
}
MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(this, NS_DISPATCH_NORMAL));
}
bool
TransactionDatabaseOperationBase::HasPreprocessInfo()
{
return false;
}
nsresult
TransactionDatabaseOperationBase::SendPreprocessInfo()
{
return NS_OK;
}
void
TransactionDatabaseOperationBase::RunOnOwningThread()
TransactionDatabaseOperationBase::NoteContinueReceived()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mInternalState == InternalState::WaitingForContinue);
mInternalState = InternalState::SendingResults;
Unused << this->Run();
}
void
TransactionDatabaseOperationBase::SendToConnectionPool()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mInternalState == InternalState::Initial);
// Must set mInternalState before dispatching otherwise we will race with the
// connection thread.
mInternalState = InternalState::DatabaseWork;
gConnectionPool->Dispatch(mTransaction->TransactionId(), this);
mTransaction->NoteActiveRequest();
}
void
TransactionDatabaseOperationBase::SendPreprocess()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mInternalState == InternalState::SendingPreprocess);
SendPreprocessInfoOrResults(/* aSendPreprocessInfo */ true);
}
void
TransactionDatabaseOperationBase::SendResults()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mInternalState == InternalState::SendingResults);
SendPreprocessInfoOrResults(/* aSendPreprocessInfo */ false);
}
void
TransactionDatabaseOperationBase::SendPreprocessInfoOrResults(
bool aSendPreprocessInfo)
{
AssertIsOnOwningThread();
MOZ_ASSERT(mInternalState == InternalState::SendingPreprocess ||
mInternalState == InternalState::SendingResults);
MOZ_ASSERT(mTransaction);
// Only needed if we're being called from within NoteContinueReceived() since
// this TransactionDatabaseOperationBase is only held alive by the IPDL.
// SendSuccessResult/SendFailureResult releases that last reference.
RefPtr<TransactionDatabaseOperationBase> kungFuDeathGrip;
if (NS_WARN_IF(IsActorDestroyed())) {
// Don't send any notifications if the actor was destroyed already.
if (NS_SUCCEEDED(mResultCode)) {
@ -23219,13 +23402,22 @@ TransactionDatabaseOperationBase::RunOnOwningThread()
mResultCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
} else {
if (!aSendPreprocessInfo) {
kungFuDeathGrip = this;
}
if (mTransaction->IsInvalidated() || mTransaction->IsAborted()) {
// Aborted transactions always see their requests fail with ABORT_ERR,
// even if the request succeeded or failed with another error.
mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
} else if (NS_SUCCEEDED(mResultCode)) {
// This may release the IPDL reference.
mResultCode = SendSuccessResult();
if (aSendPreprocessInfo) {
// This should not release the IPDL reference.
mResultCode = SendPreprocessInfo();
} else {
// This may release the IPDL reference.
mResultCode = SendSuccessResult();
}
}
if (NS_FAILED(mResultCode)) {
@ -23237,17 +23429,24 @@ TransactionDatabaseOperationBase::RunOnOwningThread()
}
}
if (mLoggingSerialNumber) {
mTransaction->NoteFinishedRequest();
}
if (aSendPreprocessInfo && NS_SUCCEEDED(mResultCode)) {
mInternalState = InternalState::WaitingForContinue;
} else {
if (mLoggingSerialNumber) {
mTransaction->NoteFinishedRequest();
}
Cleanup();
Cleanup();
mInternalState = InternalState::Completed;
}
}
bool
TransactionDatabaseOperationBase::Init(TransactionBase* aTransaction)
{
AssertIsOnBackgroundThread();
MOZ_ASSERT(mInternalState == InternalState::Initial);
MOZ_ASSERT(aTransaction);
return true;
@ -23257,6 +23456,7 @@ void
TransactionDatabaseOperationBase::Cleanup()
{
AssertIsOnOwningThread();
MOZ_ASSERT(mInternalState == InternalState::SendingResults);
MOZ_ASSERT(mTransaction);
mTransaction = nullptr;
@ -23265,15 +23465,26 @@ TransactionDatabaseOperationBase::Cleanup()
NS_IMETHODIMP
TransactionDatabaseOperationBase::Run()
{
MOZ_ASSERT(mTransaction);
switch (mInternalState) {
case InternalState::Initial:
SendToConnectionPool();
return NS_OK;
if (IsOnBackgroundThread()) {
RunOnOwningThread();
} else {
RunOnConnectionThread();
case InternalState::DatabaseWork:
RunOnConnectionThread();
return NS_OK;
case InternalState::SendingPreprocess:
SendPreprocess();
return NS_OK;
case InternalState::SendingResults:
SendResults();
return NS_OK;
default:
MOZ_CRASH("Bad state!");
}
return NS_OK;
}
TransactionBase::
@ -25470,6 +25681,28 @@ NormalTransactionOp::ActorDestroy(ActorDestroyReason aWhy)
NoteActorDestroyed();
}
bool
NormalTransactionOp::RecvContinue(const PreprocessResponse& aResponse)
{
AssertIsOnOwningThread();
switch (aResponse.type()) {
case PreprocessResponse::Tnsresult:
mResultCode = aResponse.get_nsresult();
break;
case PreprocessResponse::TObjectStoreGetPreprocessResponse:
break;
default:
MOZ_CRASH("Should never get here!");
}
NoteContinueReceived();
return true;
}
ObjectStoreAddOrPutRequestOp::ObjectStoreAddOrPutRequestOp(
TransactionBase* aTransaction,
const RequestParams& aParams)
@ -26333,6 +26566,7 @@ ObjectStoreGetRequestOp::ObjectStoreGetRequestOp(TransactionBase* aTransaction,
, mBackgroundParent(aTransaction->GetBackgroundParent())
, mLimit(aGetAll ? aParams.get_ObjectStoreGetAllParams().limit() : 1)
, mGetAll(aGetAll)
, mHasWasm(false)
{
MOZ_ASSERT(aParams.type() == RequestParams::TObjectStoreGetParams ||
aParams.type() == RequestParams::TObjectStoreGetAllParams);
@ -26359,6 +26593,7 @@ ObjectStoreGetRequestOp::ConvertResponse(
nsresult rv = SerializeStructuredCloneFiles(mBackgroundParent,
mDatabase,
info.mFiles,
/* aForPreprocess */ false,
serializedFiles);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@ -26437,7 +26672,8 @@ ObjectStoreGetRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
rv = GetStructuredCloneReadInfoFromStatement(stmt, 1, 0,
mDatabase->GetFileManager(),
cloneInfo);
cloneInfo,
&mHasWasm);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -26452,6 +26688,53 @@ ObjectStoreGetRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
return NS_OK;
}
bool
ObjectStoreGetRequestOp::HasPreprocessInfo()
{
return mHasWasm;
}
nsresult
ObjectStoreGetRequestOp::SendPreprocessInfo()
{
AssertIsOnOwningThread();
MOZ_ASSERT(!IsActorDestroyed());
MOZ_ASSERT(!mResponse.IsEmpty());
if (mGetAll) {
MOZ_ASSERT(false, "Fix me!");
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
StructuredCloneReadInfo& cloneInfo = mResponse[0];
FallibleTArray<SerializedStructuredCloneFile> serializedFiles;
nsresult rv = SerializeStructuredCloneFiles(mBackgroundParent,
mDatabase,
cloneInfo.mFiles,
/* aForPreprocess */ true,
serializedFiles);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
WasmModulePreprocessInfo preprocessInfo;
MOZ_ASSERT(preprocessInfo.files().IsEmpty());
preprocessInfo.files().SwapElements(serializedFiles);
PreprocessParams params = ObjectStoreGetPreprocessParams(preprocessInfo);
if (NS_WARN_IF(!PBackgroundIDBRequestParent::SendPreprocess(params))) {
IDB_REPORT_INTERNAL_ERR();
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
return NS_OK;
}
void
ObjectStoreGetRequestOp::GetResponse(RequestResponse& aResponse)
{
@ -27035,9 +27318,11 @@ IndexGetRequestOp::DoDatabaseWork(DatabaseConnection* aConnection)
return NS_ERROR_OUT_OF_MEMORY;
}
bool dummy;
rv = GetStructuredCloneReadInfoFromStatement(stmt, 1, 0,
mDatabase->GetFileManager(),
cloneInfo);
cloneInfo,
&dummy);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -27082,6 +27367,7 @@ IndexGetRequestOp::GetResponse(RequestResponse& aResponse)
nsresult rv = SerializeStructuredCloneFiles(mBackgroundParent,
mDatabase,
info.mFiles,
/* aForPreprocess */ false,
serializedFiles);
if (NS_WARN_IF(NS_FAILED(rv))) {
aResponse = rv;
@ -27117,6 +27403,7 @@ IndexGetRequestOp::GetResponse(RequestResponse& aResponse)
SerializeStructuredCloneFiles(mBackgroundParent,
mDatabase,
info.mFiles,
/* aForPreprocess */ false,
serializedFiles);
if (NS_WARN_IF(NS_FAILED(rv))) {
aResponse = rv;
@ -27406,11 +27693,13 @@ CursorOpBase::PopulateResponseFromStatement(
switch (mCursor->mType) {
case OpenCursorParams::TObjectStoreOpenCursorParams: {
StructuredCloneReadInfo cloneInfo;
bool dummy;
rv = GetStructuredCloneReadInfoFromStatement(aStmt,
2,
1,
mCursor->mFileManager,
&cloneInfo);
&cloneInfo,
&dummy);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -27449,11 +27738,13 @@ CursorOpBase::PopulateResponseFromStatement(
}
StructuredCloneReadInfo cloneInfo;
bool dummy;
rv = GetStructuredCloneReadInfoFromStatement(aStmt,
4,
3,
mCursor->mFileManager,
&cloneInfo);
&cloneInfo,
&dummy);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}

View File

@ -190,25 +190,6 @@ GenerateRequest(JSContext* aCx, IDBObjectStore* aObjectStore)
return request.forget();
}
PRFileDesc*
GetFileDescriptorFromStream(nsIInputStream* aStream)
{
nsCOMPtr<nsIFileMetadata> fileMetadata = do_QueryInterface(aStream);
if (NS_WARN_IF(!fileMetadata)) {
return nullptr;
}
PRFileDesc* fileDesc;
nsresult rv = fileMetadata->GetFileDescriptor(&fileDesc);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
MOZ_ASSERT(fileDesc);
return fileDesc;
}
bool
StructuredCloneWriteCallback(JSContext* aCx,
JSStructuredCloneWriter* aWriter,
@ -396,6 +377,9 @@ StructuredCloneWriteCallback(JSContext* aCx,
const uint32_t index = cloneWriteInfo->mFiles.Length();
// The ordering of the bytecode and compiled file is significant and must
// never be changed. These two files must always form a pair
// [eWasmBytecode, eWasmCompiled]. Everything else depends on it!
if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_WASM, /* flags */ 0) ||
!JS_WriteUint32Pair(aWriter, index, index + 1)) {
return false;
@ -745,66 +729,16 @@ public:
static bool
CreateAndWrapWasmModule(JSContext* aCx,
StructuredCloneFile& aBytecodeFile,
StructuredCloneFile& aCompiledFile,
StructuredCloneFile& aFile,
const WasmModuleData& aData,
JS::MutableHandle<JSObject*> aResult)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aBytecodeFile.mType == StructuredCloneFile::eWasmBytecode);
MOZ_ASSERT(aBytecodeFile.mBlob);
MOZ_ASSERT(aCompiledFile.mType == StructuredCloneFile::eWasmCompiled);
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eWasmCompiled);
MOZ_ASSERT(!aFile.mBlob);
MOZ_ASSERT(aFile.mWasmModule);
ErrorResult errorResult;
nsCOMPtr<nsIInputStream> bytecodeStream;
aBytecodeFile.mBlob->GetInternalStream(getter_AddRefs(bytecodeStream),
errorResult);
if (NS_WARN_IF(errorResult.Failed())) {
return false;
}
PRFileDesc* bytecodeFileDesc = GetFileDescriptorFromStream(bytecodeStream);
if (NS_WARN_IF(!bytecodeFileDesc)) {
return false;
}
// The compiled stream must scoped here!
nsCOMPtr<nsIInputStream> compiledStream;
PRFileDesc* compiledFileDesc;
if (aCompiledFile.mBlob) {
aCompiledFile.mBlob->GetInternalStream(getter_AddRefs(compiledStream),
errorResult);
if (NS_WARN_IF(errorResult.Failed())) {
return false;
}
compiledFileDesc = GetFileDescriptorFromStream(compiledStream);
if (NS_WARN_IF(!compiledFileDesc)) {
return false;
}
} else {
compiledFileDesc = nullptr;
}
JS::BuildIdCharVector buildId;
bool ok = GetBuildId(&buildId);
if (NS_WARN_IF(!ok)) {
return false;
}
RefPtr<JS::WasmModule> module = JS::DeserializeWasmModule(bytecodeFileDesc,
compiledFileDesc,
Move(buildId),
nullptr,
0,
0);
if (NS_WARN_IF(!module)) {
return false;
}
JS::Rooted<JSObject*> moduleObj(aCx, module->createObject(aCx));
JS::Rooted<JSObject*> moduleObj(aCx, aFile.mWasmModule->createObject(aCx));
if (NS_WARN_IF(!moduleObj)) {
return false;
}
@ -907,8 +841,7 @@ public:
static bool
CreateAndWrapWasmModule(JSContext* aCx,
StructuredCloneFile& aBytecodeFile,
StructuredCloneFile& aCompiledFile,
StructuredCloneFile& aFile,
const WasmModuleData& aData,
JS::MutableHandle<JSObject*> aResult)
{
@ -980,14 +913,12 @@ public:
static bool
CreateAndWrapWasmModule(JSContext* aCx,
StructuredCloneFile& aBytecodeFile,
StructuredCloneFile& aCompiledFile,
StructuredCloneFile& aFile,
const WasmModuleData& aData,
JS::MutableHandle<JSObject*> aResult)
{
MOZ_ASSERT(aCx);
MOZ_ASSERT(aBytecodeFile.mType == StructuredCloneFile::eBlob);
MOZ_ASSERT(aCompiledFile.mType == StructuredCloneFile::eBlob);
MOZ_ASSERT(aFile.mType == StructuredCloneFile::eBlob);
MOZ_ASSERT(false, "This should never be possible!");
@ -1039,14 +970,10 @@ CommonStructuredCloneReadCallback(JSContext* aCx,
return nullptr;
}
StructuredCloneFile& bytecodeFile =
cloneReadInfo->mFiles[data.bytecodeIndex];
StructuredCloneFile& compiledFile =
cloneReadInfo->mFiles[data.compiledIndex];
StructuredCloneFile& file = cloneReadInfo->mFiles[data.compiledIndex];
if (NS_WARN_IF(!Traits::CreateAndWrapWasmModule(aCx,
bytecodeFile,
compiledFile,
file,
data,
&result))) {
return nullptr;

View File

@ -11,6 +11,10 @@
#include "nsCOMPtr.h"
#include "nsTArray.h"
namespace JS {
struct WasmModule;
} // namespace JS
namespace mozilla {
namespace dom {
@ -36,6 +40,7 @@ struct StructuredCloneFile
RefPtr<Blob> mBlob;
RefPtr<IDBMutableFile> mMutableFile;
RefPtr<JS::WasmModule> mWasmModule;
RefPtr<FileInfo> mFileInfo;
FileType mType;
// This is currently specific to eWasmCompiled files.

View File

@ -106,12 +106,51 @@ union RequestResponse
IndexCountResponse;
};
struct WasmModulePreprocessInfo
{
SerializedStructuredCloneFile[] files;
};
struct ObjectStoreGetPreprocessParams
{
WasmModulePreprocessInfo preprocessInfo;
};
union PreprocessParams
{
ObjectStoreGetPreprocessParams;
};
struct ObjectStoreGetPreprocessResponse
{
};
// The nsresult is used if an error occurs for any preprocess request type.
// The specific response types are sent on success.
union PreprocessResponse
{
nsresult;
ObjectStoreGetPreprocessResponse;
};
protocol PBackgroundIDBRequest
{
manager PBackgroundIDBTransaction or PBackgroundIDBVersionChangeTransaction;
parent:
async Continue(PreprocessResponse response);
child:
async __delete__(RequestResponse response);
// Preprocess is used in cases where response processing needs to do something
// asynchronous off of the child actor's thread before returning the actual
// result to user code. This is necessary because RequestResponse processing
// occurs in __delete__ and the PBackgroundIDBRequest implementations'
// life-cycles are controlled by IPC and are not otherwise reference counted.
// By introducing the (optional) Preprocess/Continue steps reference counting
// or the introduction of additional runnables are avoided.
async Preprocess(PreprocessParams params);
};
} // namespace indexedDB

View File

@ -85,17 +85,17 @@ function getNullFile(name, size)
return getFile(name, "binary/null", getView(size));
}
function isWasmSupported()
// This needs to be async to make it available on workers too.
function getWasmBinary(text)
{
let testingFunctions = SpecialPowers.Cu.getJSTestingFunctions();
return testingFunctions.wasmIsSupported();
let binary = getWasmBinarySync(text);
SimpleTest.executeSoon(function() {
testGenerator.send(binary);
});
}
function getWasmModule(text)
function getWasmModule(binary)
{
let testingFunctions = SpecialPowers.Cu.getJSTestingFunctions();
let wasmTextToBinary = SpecialPowers.unwrap(testingFunctions.wasmTextToBinary);
let binary = wasmTextToBinary(text);
let module = new WebAssembly.Module(binary);
return module;
}
@ -210,7 +210,7 @@ function verifyWasmModule(module1, module2)
let exp2 = wasmExtractCode(module2);
let code1 = exp1.code;
let code2 = exp2.code;
ok(code1 instanceof Uint8Array, "Instance of Uint8Array");
todo(code1 instanceof Uint8Array, "Instance of Uint8Array");
ok(code1.length == code2.length, "Correct length");
verifyBuffers(code1, code2);
continueToNextStep();

View File

@ -76,7 +76,8 @@ function testHarnessSteps() {
["dom.indexedDB.testing", true],
["dom.indexedDB.experimental", true],
["dom.archivereader.enabled", true],
["dom.workers.latestJSVersion", true]
["dom.workers.latestJSVersion", true],
["javascript.options.wasm", true]
]
},
nextTestHarnessStep
@ -145,7 +146,7 @@ function testHarnessSteps() {
break;
case "loaded":
worker.postMessage({ op: "start" });
worker.postMessage({ op: "start", wasmSupported: isWasmSupported() });
break;
case "done":
@ -163,6 +164,11 @@ function testHarnessSteps() {
});
break;
case "getWasmBinary":
worker.postMessage({ op: "getWasmBinaryDone",
wasmBinary: getWasmBinarySync(message.text) });
break;
default:
ok(false,
"Received a bad message from worker: " + JSON.stringify(message));
@ -348,9 +354,25 @@ function scheduleGC()
SpecialPowers.exactGC(continueToNextStep);
}
function isWasmSupported()
{
let testingFunctions = SpecialPowers.Cu.getJSTestingFunctions();
return testingFunctions.wasmIsSupported();
}
function getWasmBinarySync(text)
{
let testingFunctions = SpecialPowers.Cu.getJSTestingFunctions();
let wasmTextToBinary = SpecialPowers.unwrap(testingFunctions.wasmTextToBinary);
let binary = wasmTextToBinary(text);
return binary;
}
function workerScript() {
"use strict";
self.wasmSupported = false;
self.repr = function(_thing_) {
if (typeof(_thing_) == "undefined") {
return "undefined";
@ -538,6 +560,28 @@ function workerScript() {
return true;
};
self.isWasmSupported = function() {
return self.wasmSupported;
}
self.getWasmBinarySync = function(_text_) {
self.ok(false, "This can't be used on workers");
}
self.getWasmBinary = function(_text_) {
self.postMessage({ op: "getWasmBinary", text: _text_ });
}
self.getWasmModule = function(_binary_) {
let module = new WebAssembly.Module(_binary_);
return module;
}
self.verifyWasmModule = function(_module) {
self.todo(false, "Need a verifyWasmModule implementation on workers");
self.continueToNextStep();
}
self.onmessage = function(_event_) {
let message = _event_.data;
switch (message.op) {
@ -548,6 +592,7 @@ function workerScript() {
break;
case "start":
self.wasmSupported = message.wasmSupported;
executeSoon(function() {
info("Worker: starting tests");
testGenerator.next();
@ -561,6 +606,11 @@ function workerScript() {
}
break;
case "getWasmBinaryDone":
info("Worker: get wasm binary done");
testGenerator.send(message.wasmBinary);
break;
default:
throw new Error("Received a bad message from parent: " +
JSON.stringify(message));

View File

@ -392,7 +392,6 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_view_put_get_values.html]
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_wasm_put_get_values.html]
#skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
skip-if = true
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Bug 931116
[test_serviceworker.html]
skip-if = buildapp == 'b2g'

View File

@ -3,8 +3,6 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
var disableWorkerTest = "Need a way to set temporary prefs from a worker";
var testGenerator = testSteps();
function testSteps()
@ -16,19 +14,16 @@ function testSteps()
const wasmData = { key: 1, wasm: null };
if (this.window) {
SpecialPowers.pushPrefEnv({ "set": [["javascript.options.wasm", true]] },
continueToNextStep);
yield undefined;
} else {
enableWasm();
}
if (!isWasmSupported()) {
finishTest();
yield undefined;
}
getWasmBinary('(module (func (nop)))');
let binary = yield undefined;
wasmData.wasm = getWasmModule(binary);
info("Opening database");
let request = indexedDB.open(name);
@ -53,8 +48,6 @@ function testSteps()
info("Storing wasm");
wasmData.wasm = getWasmModule('(module (func (nop)))');
let objectStore = db.transaction([objectStoreName], "readwrite")
.objectStore(objectStoreName);
request = objectStore.add(wasmData.wasm, wasmData.key);

View File

@ -50,6 +50,7 @@ if (!this.runTest) {
enableTesting();
enableExperimental();
enableWasm();
}
Cu.importGlobalProperties(["indexedDB", "Blob", "File", "FileReader"]);
@ -62,6 +63,7 @@ if (!this.runTest) {
function finishTest()
{
if (SpecialPowers.isMainProcess()) {
resetWasm();
resetExperimental();
resetTesting();
@ -214,6 +216,11 @@ function enableWasm()
SpecialPowers.setBoolPref("javascript.options.wasm", true);
}
function resetWasm()
{
SpecialPowers.clearUserPref("javascript.options.wasm");
}
function gc()
{
Cu.forceGC();
@ -374,10 +381,23 @@ function isWasmSupported()
return testingFunctions.wasmIsSupported();
}
function getWasmModule(text)
function getWasmBinarySync(text)
{
let testingFunctions = Cu.getJSTestingFunctions();
let binary = testingFunctions.wasmTextToBinary(text);
return binary;
}
function getWasmBinary(text)
{
let binary = getWasmBinarySync(text);
executeSoon(function() {
testGenerator.send(binary);
});
}
function getWasmModule(binary)
{
let module = new WebAssembly.Module(binary);
return module;
}