mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2g-inbound
This commit is contained in:
commit
6bd3a94ee1
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"revision": "53a930e0a23a6d2b0b53baea9a609359683758ab",
|
"revision": "9960daf91c384990c4bbe7c1221905db7536596b",
|
||||||
"repo_path": "/integration/gaia-central"
|
"repo_path": "/integration/gaia-central"
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,9 @@ const CM_MAPPING = [
|
|||||||
"redo",
|
"redo",
|
||||||
"clearHistory",
|
"clearHistory",
|
||||||
"openDialog",
|
"openDialog",
|
||||||
"refresh"
|
"refresh",
|
||||||
|
"getOption",
|
||||||
|
"setOption"
|
||||||
];
|
];
|
||||||
|
|
||||||
const { cssProperties, cssValues, cssColors } = getCSSKeywords();
|
const { cssProperties, cssValues, cssColors } = getCSSKeywords();
|
||||||
@ -288,8 +290,7 @@ Editor.prototype = {
|
|||||||
* See Editor.modes for the list of all suppoert modes.
|
* See Editor.modes for the list of all suppoert modes.
|
||||||
*/
|
*/
|
||||||
getMode: function () {
|
getMode: function () {
|
||||||
let cm = editors.get(this);
|
return this.getOption("mode");
|
||||||
return cm.getOption("mode");
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -297,8 +298,7 @@ Editor.prototype = {
|
|||||||
* See Editor.modes for the list of all suppoert modes.
|
* See Editor.modes for the list of all suppoert modes.
|
||||||
*/
|
*/
|
||||||
setMode: function (value) {
|
setMode: function (value) {
|
||||||
let cm = editors.get(this);
|
this.setOption("mode", value);
|
||||||
cm.setOption("mode", value);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -649,8 +649,7 @@ Editor.prototype = {
|
|||||||
* True if the editor is in the read-only mode, false otherwise.
|
* True if the editor is in the read-only mode, false otherwise.
|
||||||
*/
|
*/
|
||||||
isReadOnly: function () {
|
isReadOnly: function () {
|
||||||
let cm = editors.get(this);
|
return this.getOption("readOnly");
|
||||||
return cm.getOption("readOnly");
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -11,6 +11,11 @@ function test() {
|
|||||||
let src = win.document.querySelector("iframe").getAttribute("src");
|
let src = win.document.querySelector("iframe").getAttribute("src");
|
||||||
ok(~src.indexOf(".CodeMirror"), "correct iframe is there");
|
ok(~src.indexOf(".CodeMirror"), "correct iframe is there");
|
||||||
|
|
||||||
|
// getOption/setOption
|
||||||
|
ok(ed.getOption("styleActiveLine"), "getOption works");
|
||||||
|
ed.setOption("styleActiveLine", false);
|
||||||
|
ok(!ed.getOption("styleActiveLine"), "setOption works");
|
||||||
|
|
||||||
// Language modes
|
// Language modes
|
||||||
is(ed.getMode(), Editor.modes.text, "getMode");
|
is(ed.getMode(), Editor.modes.text, "getMode");
|
||||||
ed.setMode(Editor.modes.js);
|
ed.setMode(Editor.modes.js);
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -8821,6 +8821,10 @@ void
|
|||||||
nsDocument::ScrollToRef()
|
nsDocument::ScrollToRef()
|
||||||
{
|
{
|
||||||
if (mScrolledToRefAlready) {
|
if (mScrolledToRefAlready) {
|
||||||
|
nsCOMPtr<nsIPresShell> shell = GetShell();
|
||||||
|
if (shell) {
|
||||||
|
shell->ScrollToAnchor();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "js/RootingAPI.h"
|
#include "js/RootingAPI.h"
|
||||||
#include "jsfriendapi.h"
|
#include "jsfriendapi.h"
|
||||||
|
#include "mozilla/Assertions.h"
|
||||||
#include "mozilla/CondVar.h"
|
#include "mozilla/CondVar.h"
|
||||||
#include "mozilla/dom/asmjscache/PAsmJSCacheEntryChild.h"
|
#include "mozilla/dom/asmjscache/PAsmJSCacheEntryChild.h"
|
||||||
#include "mozilla/dom/asmjscache/PAsmJSCacheEntryParent.h"
|
#include "mozilla/dom/asmjscache/PAsmJSCacheEntryParent.h"
|
||||||
@ -20,11 +21,13 @@
|
|||||||
#include "mozilla/dom/quota/QuotaManager.h"
|
#include "mozilla/dom/quota/QuotaManager.h"
|
||||||
#include "mozilla/dom/quota/QuotaObject.h"
|
#include "mozilla/dom/quota/QuotaObject.h"
|
||||||
#include "mozilla/dom/quota/UsageInfo.h"
|
#include "mozilla/dom/quota/UsageInfo.h"
|
||||||
|
#include "mozilla/HashFunctions.h"
|
||||||
#include "mozilla/unused.h"
|
#include "mozilla/unused.h"
|
||||||
#include "nsIAtom.h"
|
#include "nsIAtom.h"
|
||||||
#include "nsIFile.h"
|
#include "nsIFile.h"
|
||||||
#include "nsIPrincipal.h"
|
#include "nsIPrincipal.h"
|
||||||
#include "nsIRunnable.h"
|
#include "nsIRunnable.h"
|
||||||
|
#include "nsISimpleEnumerator.h"
|
||||||
#include "nsIThread.h"
|
#include "nsIThread.h"
|
||||||
#include "nsIXULAppInfo.h"
|
#include "nsIXULAppInfo.h"
|
||||||
#include "nsJSPrincipals.h"
|
#include "nsJSPrincipals.h"
|
||||||
@ -33,7 +36,8 @@
|
|||||||
#include "prio.h"
|
#include "prio.h"
|
||||||
#include "private/pprio.h"
|
#include "private/pprio.h"
|
||||||
|
|
||||||
#define ASMJSCACHE_FILE_NAME "module"
|
#define ASMJSCACHE_METADATA_FILE_NAME "metadata"
|
||||||
|
#define ASMJSCACHE_ENTRY_FILE_NAME_BASE "module"
|
||||||
|
|
||||||
using mozilla::dom::quota::AssertIsOnIOThread;
|
using mozilla::dom::quota::AssertIsOnIOThread;
|
||||||
using mozilla::dom::quota::OriginOrPatternString;
|
using mozilla::dom::quota::OriginOrPatternString;
|
||||||
@ -42,8 +46,12 @@ using mozilla::dom::quota::QuotaManager;
|
|||||||
using mozilla::dom::quota::QuotaObject;
|
using mozilla::dom::quota::QuotaObject;
|
||||||
using mozilla::dom::quota::UsageInfo;
|
using mozilla::dom::quota::UsageInfo;
|
||||||
using mozilla::unused;
|
using mozilla::unused;
|
||||||
|
using mozilla::HashString;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, PR_Close);
|
||||||
|
|
||||||
namespace dom {
|
namespace dom {
|
||||||
namespace asmjscache {
|
namespace asmjscache {
|
||||||
|
|
||||||
@ -55,6 +63,81 @@ IsMainProcess()
|
|||||||
return XRE_GetProcessType() == GeckoProcessType_Default;
|
return XRE_GetProcessType() == GeckoProcessType_Default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Anything smaller should compile fast enough that caching will just add
|
||||||
|
// overhead.
|
||||||
|
static const size_t sMinCachedModuleLength = 10000;
|
||||||
|
|
||||||
|
// The number of characters to hash into the Metadata::Entry::mFastHash.
|
||||||
|
static const unsigned sNumFastHashChars = 4096;
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
WriteMetadataFile(nsIFile* aMetadataFile, const Metadata& aMetadata)
|
||||||
|
{
|
||||||
|
int32_t openFlags = PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE;
|
||||||
|
|
||||||
|
JS::BuildIdCharVector buildId;
|
||||||
|
bool ok = GetBuildId(&buildId);
|
||||||
|
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
|
ScopedPRFileDesc fd;
|
||||||
|
nsresult rv = aMetadataFile->OpenNSPRFileDesc(openFlags, 0644, &fd.rwget());
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
uint32_t length = buildId.length();
|
||||||
|
int32_t bytesWritten = PR_Write(fd, &length, sizeof(length));
|
||||||
|
NS_ENSURE_TRUE(bytesWritten == sizeof(length), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
bytesWritten = PR_Write(fd, buildId.begin(), length);
|
||||||
|
NS_ENSURE_TRUE(bytesWritten == int32_t(length), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
bytesWritten = PR_Write(fd, &aMetadata, sizeof(aMetadata));
|
||||||
|
NS_ENSURE_TRUE(bytesWritten == sizeof(aMetadata), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
ReadMetadataFile(nsIFile* aMetadataFile, Metadata& aMetadata)
|
||||||
|
{
|
||||||
|
int32_t openFlags = PR_RDONLY;
|
||||||
|
|
||||||
|
ScopedPRFileDesc fd;
|
||||||
|
nsresult rv = aMetadataFile->OpenNSPRFileDesc(openFlags, 0644, &fd.rwget());
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// Read the buildid and check that it matches the current buildid
|
||||||
|
|
||||||
|
JS::BuildIdCharVector currentBuildId;
|
||||||
|
bool ok = GetBuildId(¤tBuildId);
|
||||||
|
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
|
uint32_t length;
|
||||||
|
int32_t bytesRead = PR_Read(fd, &length, sizeof(length));
|
||||||
|
NS_ENSURE_TRUE(bytesRead == sizeof(length), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
NS_ENSURE_TRUE(currentBuildId.length() == length, NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
JS::BuildIdCharVector fileBuildId;
|
||||||
|
ok = fileBuildId.resize(length);
|
||||||
|
NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY);
|
||||||
|
|
||||||
|
bytesRead = PR_Read(fd, fileBuildId.begin(), length);
|
||||||
|
NS_ENSURE_TRUE(bytesRead == int32_t(length), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < length; i++) {
|
||||||
|
if (currentBuildId[i] != fileBuildId[i]) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the Metadata struct
|
||||||
|
|
||||||
|
bytesRead = PR_Read(fd, &aMetadata, sizeof(aMetadata));
|
||||||
|
NS_ENSURE_TRUE(bytesRead == sizeof(aMetadata), NS_ERROR_UNEXPECTED);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
// FileDescriptorHolder owns a file descriptor and its memory mapping.
|
// FileDescriptorHolder owns a file descriptor and its memory mapping.
|
||||||
// FileDescriptorHolder is derived by all three runnable classes (that is,
|
// FileDescriptorHolder is derived by all three runnable classes (that is,
|
||||||
// (Single|Parent|Child)ProcessRunnable. To avoid awkward workarouds,
|
// (Single|Parent|Child)ProcessRunnable. To avoid awkward workarouds,
|
||||||
@ -309,10 +392,10 @@ public:
|
|||||||
// the lifetime of the MainProcessRunnable.
|
// the lifetime of the MainProcessRunnable.
|
||||||
MainProcessRunnable(nsIPrincipal* aPrincipal,
|
MainProcessRunnable(nsIPrincipal* aPrincipal,
|
||||||
OpenMode aOpenMode,
|
OpenMode aOpenMode,
|
||||||
size_t aSizeToWrite)
|
WriteParams aWriteParams)
|
||||||
: mPrincipal(aPrincipal),
|
: mPrincipal(aPrincipal),
|
||||||
mOpenMode(aOpenMode),
|
mOpenMode(aOpenMode),
|
||||||
mSizeToWrite(aSizeToWrite),
|
mWriteParams(aWriteParams),
|
||||||
mNeedAllowNextSynchronizedOp(false),
|
mNeedAllowNextSynchronizedOp(false),
|
||||||
mState(eInitial)
|
mState(eInitial)
|
||||||
{
|
{
|
||||||
@ -326,9 +409,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// This method is be called by the derived class (either on the JS
|
// This method is called by the derived class (either on the JS compilation
|
||||||
// compilation thread or the main thread) when JS engine is finished
|
// thread or the main thread) when a cache entry has been selected to open.
|
||||||
// reading/writing the cache entry.
|
void
|
||||||
|
OpenForRead(unsigned aModuleIndex)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mState == eWaitingToOpenCacheFileForRead);
|
||||||
|
MOZ_ASSERT(mOpenMode == eOpenForRead);
|
||||||
|
|
||||||
|
mModuleIndex = aModuleIndex;
|
||||||
|
mState = eReadyToOpenCacheFileForRead;
|
||||||
|
DispatchToIOThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method is called by the derived class (either on the JS compilation
|
||||||
|
// thread or the main thread) when the JS engine is finished reading/writing
|
||||||
|
// the cache entry.
|
||||||
void
|
void
|
||||||
Close()
|
Close()
|
||||||
{
|
{
|
||||||
@ -342,16 +438,22 @@ protected:
|
|||||||
void
|
void
|
||||||
Fail()
|
Fail()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mState == eInitial || mState == eWaitingToOpen ||
|
MOZ_ASSERT(mState != eOpened &&
|
||||||
mState == eReadyToOpen || mState == eNotifying);
|
mState != eClosing &&
|
||||||
|
mState != eFailing &&
|
||||||
|
mState != eFinished);
|
||||||
|
|
||||||
mState = eFailing;
|
mState = eFailing;
|
||||||
NS_DispatchToMainThread(this);
|
NS_DispatchToMainThread(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Called by MainProcessRunnable on the main thread after metadata is open:
|
||||||
|
virtual void
|
||||||
|
OnOpenMetadataForRead(const Metadata& aMetadata) = 0;
|
||||||
|
|
||||||
// Called by MainProcessRunnable on the main thread after the entry is open:
|
// Called by MainProcessRunnable on the main thread after the entry is open:
|
||||||
virtual void
|
virtual void
|
||||||
OnOpen() = 0;
|
OnOpenCacheFile() = 0;
|
||||||
|
|
||||||
// This method may be overridden, but it must be called from the overrider.
|
// This method may be overridden, but it must be called from the overrider.
|
||||||
// Called by MainProcessRunnable on the main thread after a call to Fail():
|
// Called by MainProcessRunnable on the main thread after a call to Fail():
|
||||||
@ -374,14 +476,37 @@ private:
|
|||||||
InitOnMainThread();
|
InitOnMainThread();
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
OpenFileOnIOThread();
|
ReadMetadata();
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
OpenCacheFileForWrite();
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
OpenCacheFileForRead();
|
||||||
|
|
||||||
void
|
void
|
||||||
FinishOnMainThread();
|
FinishOnMainThread();
|
||||||
|
|
||||||
|
void
|
||||||
|
DispatchToIOThread()
|
||||||
|
{
|
||||||
|
// If shutdown just started, the QuotaManager may have been deleted.
|
||||||
|
QuotaManager* qm = QuotaManager::Get();
|
||||||
|
if (!qm) {
|
||||||
|
Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult rv = qm->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nsIPrincipal* const mPrincipal;
|
nsIPrincipal* const mPrincipal;
|
||||||
const OpenMode mOpenMode;
|
const OpenMode mOpenMode;
|
||||||
const size_t mSizeToWrite;
|
const WriteParams mWriteParams;
|
||||||
|
|
||||||
// State initialized during eInitial:
|
// State initialized during eInitial:
|
||||||
bool mNeedAllowNextSynchronizedOp;
|
bool mNeedAllowNextSynchronizedOp;
|
||||||
@ -389,12 +514,23 @@ private:
|
|||||||
nsCString mOrigin;
|
nsCString mOrigin;
|
||||||
nsCString mStorageId;
|
nsCString mStorageId;
|
||||||
|
|
||||||
|
// State initialized during eReadyToReadMetadata
|
||||||
|
nsCOMPtr<nsIFile> mDirectory;
|
||||||
|
nsCOMPtr<nsIFile> mMetadataFile;
|
||||||
|
Metadata mMetadata;
|
||||||
|
|
||||||
|
// State initialized during eWaitingToOpenCacheFileForRead
|
||||||
|
unsigned mModuleIndex;
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
eInitial, // Just created, waiting to be dispatched to main thread
|
eInitial, // Just created, waiting to be dispatched to main thread
|
||||||
eWaitingToOpen, // Waiting to be called back from WaitForOpenAllowed
|
eWaitingToOpenMetadata, // Waiting to be called back from WaitForOpenAllowed
|
||||||
eReadyToOpen, // Waiting to be dispatched to the IO thread
|
eReadyToReadMetadata, // Waiting to read the metadata file on the IO thread
|
||||||
eNotifying, // Waiting to be dispatched to main thread to notify of success
|
eSendingMetadataForRead, // Waiting to send OnOpenMetadataForRead
|
||||||
eOpened, // Finished calling OnOpen from main thread, waiting to be closed
|
eWaitingToOpenCacheFileForRead, // Waiting to hear back from child
|
||||||
|
eReadyToOpenCacheFileForRead, // Waiting to open cache file for read
|
||||||
|
eSendingCacheFile, // Waiting to send OnOpenCacheFile on the main thread
|
||||||
|
eOpened, // Finished calling OnOpen, waiting to be closed
|
||||||
eClosing, // Waiting to be dispatched to main thread again
|
eClosing, // Waiting to be dispatched to main thread again
|
||||||
eFailing, // Just failed, waiting to be dispatched to the main thread
|
eFailing, // Just failed, waiting to be dispatched to the main thread
|
||||||
eFinished, // Terminal state
|
eFinished, // Terminal state
|
||||||
@ -417,70 +553,178 @@ MainProcessRunnable::InitOnMainThread()
|
|||||||
|
|
||||||
QuotaManager::GetStorageId(quota::PERSISTENCE_TYPE_TEMPORARY,
|
QuotaManager::GetStorageId(quota::PERSISTENCE_TYPE_TEMPORARY,
|
||||||
mOrigin, quota::Client::ASMJS,
|
mOrigin, quota::Client::ASMJS,
|
||||||
NS_LITERAL_STRING(ASMJSCACHE_FILE_NAME),
|
NS_LITERAL_STRING("asmjs"),
|
||||||
mStorageId);
|
mStorageId);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
MainProcessRunnable::OpenFileOnIOThread()
|
MainProcessRunnable::ReadMetadata()
|
||||||
{
|
{
|
||||||
AssertIsOnIOThread();
|
AssertIsOnIOThread();
|
||||||
MOZ_ASSERT(mState == eReadyToOpen);
|
MOZ_ASSERT(mState == eReadyToReadMetadata);
|
||||||
|
|
||||||
QuotaManager* qm = QuotaManager::Get();
|
QuotaManager* qm = QuotaManager::Get();
|
||||||
MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
|
MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
|
||||||
|
|
||||||
nsCOMPtr<nsIFile> path;
|
|
||||||
nsresult rv = qm->EnsureOriginIsInitialized(quota::PERSISTENCE_TYPE_TEMPORARY,
|
nsresult rv = qm->EnsureOriginIsInitialized(quota::PERSISTENCE_TYPE_TEMPORARY,
|
||||||
mGroup, mOrigin, true,
|
mGroup, mOrigin, true,
|
||||||
getter_AddRefs(path));
|
getter_AddRefs(mDirectory));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
rv = path->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME));
|
rv = mDirectory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
bool exists;
|
bool exists;
|
||||||
rv = path->Exists(&exists);
|
rv = mDirectory->Exists(&exists);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
rv = path->Create(nsIFile::DIRECTORY_TYPE, 0755);
|
rv = mDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
} else {
|
} else {
|
||||||
DebugOnly<bool> isDirectory;
|
DebugOnly<bool> isDirectory;
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(path->IsDirectory(&isDirectory)));
|
MOZ_ASSERT(NS_SUCCEEDED(mDirectory->IsDirectory(&isDirectory)));
|
||||||
MOZ_ASSERT(isDirectory, "Should have caught this earlier!");
|
MOZ_ASSERT(isDirectory, "Should have caught this earlier!");
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = path->Append(NS_LITERAL_STRING(ASMJSCACHE_FILE_NAME));
|
rv = mDirectory->Clone(getter_AddRefs(mMetadataFile));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
mQuotaObject = qm->GetQuotaObject(quota::PERSISTENCE_TYPE_TEMPORARY,
|
rv = mMetadataFile->Append(NS_LITERAL_STRING(ASMJSCACHE_METADATA_FILE_NAME));
|
||||||
mGroup, mOrigin, path);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
NS_ENSURE_STATE(mQuotaObject);
|
|
||||||
|
|
||||||
int32_t openFlags;
|
rv = mMetadataFile->Exists(&exists);
|
||||||
if (mOpenMode == eOpenForRead) {
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
rv = path->GetFileSize(&mFileSize);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
openFlags = PR_RDONLY | nsIFile::OS_READAHEAD;
|
if (exists && NS_FAILED(ReadMetadataFile(mMetadataFile, mMetadata))) {
|
||||||
} else {
|
exists = false;
|
||||||
if (!mQuotaObject->MaybeAllocateMoreSpace(0, mSizeToWrite)) {
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
mFileSize = mSizeToWrite;
|
|
||||||
|
|
||||||
MOZ_ASSERT(mOpenMode == eOpenForWrite);
|
|
||||||
openFlags = PR_RDWR | PR_TRUNCATE | PR_CREATE_FILE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = path->OpenNSPRFileDesc(openFlags, 0644, &mFileDesc);
|
if (!exists) {
|
||||||
|
// If we are reading, we can't possibly have a cache hit.
|
||||||
|
if (mOpenMode == eOpenForRead) {
|
||||||
|
return NS_ERROR_FILE_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Metadata with a valid empty state for the LRU cache.
|
||||||
|
for (unsigned i = 0; i < Metadata::kNumEntries; i++) {
|
||||||
|
Metadata::Entry& entry = mMetadata.mEntries[i];
|
||||||
|
entry.mFastHash = -1;
|
||||||
|
entry.mNumChars = -1;
|
||||||
|
entry.mFullHash = -1;
|
||||||
|
entry.mModuleIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
GetCacheFile(nsIFile* aDirectory, unsigned aModuleIndex, nsIFile** aCacheFile)
|
||||||
|
{
|
||||||
|
nsCOMPtr<nsIFile> cacheFile;
|
||||||
|
nsresult rv = aDirectory->Clone(getter_AddRefs(cacheFile));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsString cacheFileName = NS_LITERAL_STRING(ASMJSCACHE_ENTRY_FILE_NAME_BASE);
|
||||||
|
cacheFileName.AppendInt(aModuleIndex);
|
||||||
|
rv = cacheFile->Append(cacheFileName);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
cacheFile.forget(aCacheFile);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
MainProcessRunnable::OpenCacheFileForWrite()
|
||||||
|
{
|
||||||
|
AssertIsOnIOThread();
|
||||||
|
MOZ_ASSERT(mState == eReadyToReadMetadata);
|
||||||
|
MOZ_ASSERT(mOpenMode == eOpenForWrite);
|
||||||
|
|
||||||
|
mFileSize = mWriteParams.mSize;
|
||||||
|
|
||||||
|
// Kick out the oldest entry in the LRU queue in the metadata.
|
||||||
|
mModuleIndex = mMetadata.mEntries[Metadata::kLastEntry].mModuleIndex;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIFile> file;
|
||||||
|
nsresult rv = GetCacheFile(mDirectory, mModuleIndex, getter_AddRefs(file));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
QuotaManager* qm = QuotaManager::Get();
|
||||||
|
MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
|
||||||
|
|
||||||
|
// Create the QuotaObject before all file IO to get maximum assertion coverage
|
||||||
|
// in QuotaManager against concurrent removal, etc.
|
||||||
|
mQuotaObject = qm->GetQuotaObject(quota::PERSISTENCE_TYPE_TEMPORARY,
|
||||||
|
mGroup, mOrigin, file);
|
||||||
|
NS_ENSURE_STATE(mQuotaObject);
|
||||||
|
|
||||||
|
// Let the QuotaManager know we're about to consume more storage. The
|
||||||
|
// QuotaManager may veto this or schedule other storage to get evicted.
|
||||||
|
if (!mQuotaObject->MaybeAllocateMoreSpace(0, mWriteParams.mSize)) {
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t openFlags = PR_RDWR | PR_TRUNCATE | PR_CREATE_FILE;
|
||||||
|
rv = file->OpenNSPRFileDesc(openFlags, 0644, &mFileDesc);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// Move the mModuleIndex's LRU entry to the recent end of the queue.
|
||||||
|
PodMove(mMetadata.mEntries + 1, mMetadata.mEntries, Metadata::kLastEntry);
|
||||||
|
Metadata::Entry& entry = mMetadata.mEntries[0];
|
||||||
|
entry.mFastHash = mWriteParams.mFastHash;
|
||||||
|
entry.mNumChars = mWriteParams.mNumChars;
|
||||||
|
entry.mFullHash = mWriteParams.mFullHash;
|
||||||
|
entry.mModuleIndex = mModuleIndex;
|
||||||
|
|
||||||
|
rv = WriteMetadataFile(mMetadataFile, mMetadata);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
MainProcessRunnable::OpenCacheFileForRead()
|
||||||
|
{
|
||||||
|
AssertIsOnIOThread();
|
||||||
|
MOZ_ASSERT(mState == eReadyToOpenCacheFileForRead);
|
||||||
|
MOZ_ASSERT(mOpenMode == eOpenForRead);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIFile> file;
|
||||||
|
nsresult rv = GetCacheFile(mDirectory, mModuleIndex, getter_AddRefs(file));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
QuotaManager* qm = QuotaManager::Get();
|
||||||
|
MOZ_ASSERT(qm, "We are on the QuotaManager's IO thread");
|
||||||
|
|
||||||
|
// Create the QuotaObject before all file IO to get maximum assertion coverage
|
||||||
|
// in QuotaManager against concurrent removal, etc.
|
||||||
|
mQuotaObject = qm->GetQuotaObject(quota::PERSISTENCE_TYPE_TEMPORARY,
|
||||||
|
mGroup, mOrigin, file);
|
||||||
|
NS_ENSURE_STATE(mQuotaObject);
|
||||||
|
|
||||||
|
rv = file->GetFileSize(&mFileSize);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
int32_t openFlags = PR_RDONLY | nsIFile::OS_READAHEAD;
|
||||||
|
rv = file->OpenNSPRFileDesc(openFlags, 0644, &mFileDesc);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
// Move the mModuleIndex's LRU entry to the recent end of the queue.
|
||||||
|
unsigned lruIndex = 0;
|
||||||
|
while (mMetadata.mEntries[lruIndex].mModuleIndex != mModuleIndex) {
|
||||||
|
if (++lruIndex == Metadata::kNumEntries) {
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Metadata::Entry entry = mMetadata.mEntries[lruIndex];
|
||||||
|
PodMove(mMetadata.mEntries + 1, mMetadata.mEntries, lruIndex);
|
||||||
|
mMetadata.mEntries[0] = entry;
|
||||||
|
|
||||||
|
rv = WriteMetadataFile(mMetadataFile, mMetadata);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
@ -522,7 +766,7 @@ MainProcessRunnable::Run()
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
mState = eWaitingToOpen;
|
mState = eWaitingToOpenMetadata;
|
||||||
rv = QuotaManager::Get()->WaitForOpenAllowed(
|
rv = QuotaManager::Get()->WaitForOpenAllowed(
|
||||||
OriginOrPatternString::FromOrigin(mOrigin),
|
OriginOrPatternString::FromOrigin(mOrigin),
|
||||||
Nullable<PersistenceType>(), mStorageId,
|
Nullable<PersistenceType>(), mStorageId,
|
||||||
@ -536,45 +780,69 @@ MainProcessRunnable::Run()
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eWaitingToOpen: {
|
case eWaitingToOpenMetadata: {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
mState = eReadyToOpen;
|
mState = eReadyToReadMetadata;
|
||||||
|
DispatchToIOThread();
|
||||||
QuotaManager* qm = QuotaManager::Get();
|
|
||||||
if (!qm) {
|
|
||||||
Fail();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = qm->IOThread()->Dispatch(this, NS_DISPATCH_NORMAL);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
Fail();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eReadyToOpen: {
|
case eReadyToReadMetadata: {
|
||||||
AssertIsOnIOThread();
|
AssertIsOnIOThread();
|
||||||
|
|
||||||
rv = OpenFileOnIOThread();
|
rv = ReadMetadata();
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
Fail();
|
Fail();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
mState = eNotifying;
|
if (mOpenMode == eOpenForRead) {
|
||||||
|
mState = eSendingMetadataForRead;
|
||||||
|
NS_DispatchToMainThread(this);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = OpenCacheFileForWrite();
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
Fail();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
mState = eSendingCacheFile;
|
||||||
NS_DispatchToMainThread(this);
|
NS_DispatchToMainThread(this);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eNotifying: {
|
case eSendingMetadataForRead: {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(mOpenMode == eOpenForRead);
|
||||||
|
|
||||||
|
mState = eWaitingToOpenCacheFileForRead;
|
||||||
|
OnOpenMetadataForRead(mMetadata);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eReadyToOpenCacheFileForRead: {
|
||||||
|
AssertIsOnIOThread();
|
||||||
|
MOZ_ASSERT(mOpenMode == eOpenForRead);
|
||||||
|
|
||||||
|
rv = OpenCacheFileForRead();
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
Fail();
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
mState = eSendingCacheFile;
|
||||||
|
NS_DispatchToMainThread(this);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case eSendingCacheFile: {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
mState = eOpened;
|
mState = eOpened;
|
||||||
OnOpen();
|
OnOpenCacheFile();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,6 +862,7 @@ MainProcessRunnable::Run()
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case eWaitingToOpenCacheFileForRead:
|
||||||
case eOpened:
|
case eOpened:
|
||||||
case eFinished: {
|
case eFinished: {
|
||||||
MOZ_ASSUME_UNREACHABLE("Shouldn't Run() in this state");
|
MOZ_ASSUME_UNREACHABLE("Shouldn't Run() in this state");
|
||||||
@ -604,6 +873,50 @@ MainProcessRunnable::Run()
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
FindHashMatch(const Metadata& aMetadata, const ReadParams& aReadParams,
|
||||||
|
uint32_t* aModuleIndex)
|
||||||
|
{
|
||||||
|
// Perform a fast hash of the first sNumFastHashChars chars. Each cache entry
|
||||||
|
// also stores an mFastHash of its first sNumFastHashChars so this gives us a
|
||||||
|
// fast way to probabilistically determine whether we have a cache hit. We
|
||||||
|
// still do a full hash of all the chars before returning the cache file to
|
||||||
|
// the engine to avoid penalizing the case where there are multiple cached
|
||||||
|
// asm.js modules where the first sNumFastHashChars are the same. The
|
||||||
|
// mFullHash of each cache entry can have a different mNumChars so the fast
|
||||||
|
// hash allows us to avoid performing up to Metadata::kNumEntries separate
|
||||||
|
// full hashes.
|
||||||
|
uint32_t numChars = aReadParams.mLimit - aReadParams.mBegin;
|
||||||
|
MOZ_ASSERT(numChars > sNumFastHashChars);
|
||||||
|
uint32_t fastHash = HashString(aReadParams.mBegin, sNumFastHashChars);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < Metadata::kNumEntries ; i++) {
|
||||||
|
// Compare the "fast hash" first to see whether it is worthwhile to
|
||||||
|
// hash all the chars.
|
||||||
|
Metadata::Entry entry = aMetadata.mEntries[i];
|
||||||
|
if (entry.mFastHash != fastHash) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assuming we have enough characters, hash all the chars it would take
|
||||||
|
// to match this cache entry and compare to the cache entry. If we get a
|
||||||
|
// hit we'll still do a full source match later (in the JS engine), but
|
||||||
|
// the full hash match means this is probably the cache entry we want.
|
||||||
|
if (numChars < entry.mNumChars) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint32_t fullHash = HashString(aReadParams.mBegin, entry.mNumChars);
|
||||||
|
if (entry.mFullHash != fullHash) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aModuleIndex = entry.mModuleIndex;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// A runnable that executes for a cache access originating in the main process.
|
// A runnable that executes for a cache access originating in the main process.
|
||||||
class SingleProcessRunnable MOZ_FINAL : public File,
|
class SingleProcessRunnable MOZ_FINAL : public File,
|
||||||
private MainProcessRunnable
|
private MainProcessRunnable
|
||||||
@ -616,8 +929,10 @@ public:
|
|||||||
// the main thread.
|
// the main thread.
|
||||||
SingleProcessRunnable(nsIPrincipal* aPrincipal,
|
SingleProcessRunnable(nsIPrincipal* aPrincipal,
|
||||||
OpenMode aOpenMode,
|
OpenMode aOpenMode,
|
||||||
size_t aSizeToWrite)
|
WriteParams aWriteParams,
|
||||||
: MainProcessRunnable(aPrincipal, aOpenMode, aSizeToWrite)
|
ReadParams aReadParams)
|
||||||
|
: MainProcessRunnable(aPrincipal, aOpenMode, aWriteParams),
|
||||||
|
mReadParams(aReadParams)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(IsMainProcess());
|
MOZ_ASSERT(IsMainProcess());
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
@ -631,17 +946,29 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void
|
void
|
||||||
Close() MOZ_OVERRIDE MOZ_FINAL
|
OnOpenMetadataForRead(const Metadata& aMetadata) MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
MainProcessRunnable::Close();
|
uint32_t moduleIndex;
|
||||||
|
if (!FindHashMatch(aMetadata, mReadParams, &moduleIndex)) {
|
||||||
|
MainProcessRunnable::Fail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MainProcessRunnable::OpenForRead(moduleIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OnOpen() MOZ_OVERRIDE
|
OnOpenCacheFile() MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
File::OnOpen();
|
File::OnOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Close() MOZ_OVERRIDE MOZ_FINAL
|
||||||
|
{
|
||||||
|
MainProcessRunnable::Close();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OnFailure() MOZ_OVERRIDE
|
OnFailure() MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
@ -662,6 +989,8 @@ private:
|
|||||||
{
|
{
|
||||||
return MainProcessRunnable::Run();
|
return MainProcessRunnable::Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReadParams mReadParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A runnable that executes in a parent process for a cache access originating
|
// A runnable that executes in a parent process for a cache access originating
|
||||||
@ -676,8 +1005,8 @@ public:
|
|||||||
// are on the main thread (where PContent messages are delivered).
|
// are on the main thread (where PContent messages are delivered).
|
||||||
ParentProcessRunnable(nsIPrincipal* aPrincipal,
|
ParentProcessRunnable(nsIPrincipal* aPrincipal,
|
||||||
OpenMode aOpenMode,
|
OpenMode aOpenMode,
|
||||||
size_t aSizeToWrite)
|
WriteParams aWriteParams)
|
||||||
: MainProcessRunnable(aPrincipal, aOpenMode, aSizeToWrite),
|
: MainProcessRunnable(aPrincipal, aOpenMode, aWriteParams),
|
||||||
mPrincipalHolder(aPrincipal),
|
mPrincipalHolder(aPrincipal),
|
||||||
mActorDestroyed(false),
|
mActorDestroyed(false),
|
||||||
mOpened(false),
|
mOpened(false),
|
||||||
@ -732,7 +1061,24 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
OnOpen() MOZ_OVERRIDE
|
OnOpenMetadataForRead(const Metadata& aMetadata) MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (!SendOnOpenMetadataForRead(aMetadata)) {
|
||||||
|
unused << Send__delete__(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RecvSelectCacheFileToRead(const uint32_t& aModuleIndex) MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
MainProcessRunnable::OpenForRead(aModuleIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
OnOpenCacheFile() MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
@ -741,7 +1087,7 @@ private:
|
|||||||
|
|
||||||
FileDescriptor::PlatformHandleType handle =
|
FileDescriptor::PlatformHandleType handle =
|
||||||
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFileDesc));
|
FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(mFileDesc));
|
||||||
if (!SendOnOpen(mFileSize, handle)) {
|
if (!SendOnOpenCacheFile(mFileSize, handle)) {
|
||||||
unused << Send__delete__(this);
|
unused << Send__delete__(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -788,11 +1134,11 @@ private:
|
|||||||
|
|
||||||
PAsmJSCacheEntryParent*
|
PAsmJSCacheEntryParent*
|
||||||
AllocEntryParent(OpenMode aOpenMode,
|
AllocEntryParent(OpenMode aOpenMode,
|
||||||
uint32_t aSizeToWrite,
|
WriteParams aWriteParams,
|
||||||
nsIPrincipal* aPrincipal)
|
nsIPrincipal* aPrincipal)
|
||||||
{
|
{
|
||||||
ParentProcessRunnable* runnable =
|
ParentProcessRunnable* runnable =
|
||||||
new ParentProcessRunnable(aPrincipal, aOpenMode, aSizeToWrite);
|
new ParentProcessRunnable(aPrincipal, aOpenMode, aWriteParams);
|
||||||
|
|
||||||
// AddRef to keep the runnable alive until DeallocEntryParent.
|
// AddRef to keep the runnable alive until DeallocEntryParent.
|
||||||
runnable->AddRef();
|
runnable->AddRef();
|
||||||
@ -825,10 +1171,12 @@ public:
|
|||||||
// the main thread.
|
// the main thread.
|
||||||
ChildProcessRunnable(nsIPrincipal* aPrincipal,
|
ChildProcessRunnable(nsIPrincipal* aPrincipal,
|
||||||
OpenMode aOpenMode,
|
OpenMode aOpenMode,
|
||||||
size_t aSizeToWrite)
|
WriteParams aWriteParams,
|
||||||
|
ReadParams aReadParams)
|
||||||
: mPrincipal(aPrincipal),
|
: mPrincipal(aPrincipal),
|
||||||
mOpenMode(aOpenMode),
|
mOpenMode(aOpenMode),
|
||||||
mSizeToWrite(aSizeToWrite),
|
mWriteParams(aWriteParams),
|
||||||
|
mReadParams(aReadParams),
|
||||||
mActorDestroyed(false),
|
mActorDestroyed(false),
|
||||||
mState(eInitial)
|
mState(eInitial)
|
||||||
{
|
{
|
||||||
@ -846,7 +1194,24 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool
|
bool
|
||||||
RecvOnOpen(const int64_t& aFileSize, const FileDescriptor& aFileDesc)
|
RecvOnOpenMetadataForRead(const Metadata& aMetadata) MOZ_OVERRIDE
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(mState == eOpening);
|
||||||
|
|
||||||
|
uint32_t moduleIndex;
|
||||||
|
if (!FindHashMatch(aMetadata, mReadParams, &moduleIndex)) {
|
||||||
|
Fail();
|
||||||
|
Send__delete__(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SendSelectCacheFileToRead(moduleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
RecvOnOpenCacheFile(const int64_t& aFileSize,
|
||||||
|
const FileDescriptor& aFileDesc) MOZ_OVERRIDE
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(mState == eOpening);
|
MOZ_ASSERT(mState == eOpening);
|
||||||
@ -869,8 +1234,7 @@ private:
|
|||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
MOZ_ASSERT(mState == eOpening);
|
MOZ_ASSERT(mState == eOpening);
|
||||||
|
|
||||||
mState = eFinished;
|
Fail();
|
||||||
File::OnFailure();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -891,9 +1255,20 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void
|
||||||
|
Fail()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MOZ_ASSERT(mState == eInitial || mState == eOpening);
|
||||||
|
|
||||||
|
mState = eFinished;
|
||||||
|
File::OnFailure();
|
||||||
|
}
|
||||||
|
|
||||||
nsIPrincipal* const mPrincipal;
|
nsIPrincipal* const mPrincipal;
|
||||||
const OpenMode mOpenMode;
|
const OpenMode mOpenMode;
|
||||||
size_t mSizeToWrite;
|
WriteParams mWriteParams;
|
||||||
|
ReadParams mReadParams;
|
||||||
bool mActorDestroyed;
|
bool mActorDestroyed;
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
@ -918,7 +1293,7 @@ ChildProcessRunnable::Run()
|
|||||||
AddRef();
|
AddRef();
|
||||||
|
|
||||||
if (!ContentChild::GetSingleton()->SendPAsmJSCacheEntryConstructor(
|
if (!ContentChild::GetSingleton()->SendPAsmJSCacheEntryConstructor(
|
||||||
this, mOpenMode, mSizeToWrite, IPC::Principal(mPrincipal)))
|
this, mOpenMode, mWriteParams, IPC::Principal(mPrincipal)))
|
||||||
{
|
{
|
||||||
// On failure, undo the AddRef (since DeallocEntryChild will not be
|
// On failure, undo the AddRef (since DeallocEntryChild will not be
|
||||||
// called) and unblock the parsing thread with a failure. The main
|
// called) and unblock the parsing thread with a failure. The main
|
||||||
@ -926,8 +1301,7 @@ ChildProcessRunnable::Run()
|
|||||||
// 'this' alive until returning to the event loop.
|
// 'this' alive until returning to the event loop.
|
||||||
Release();
|
Release();
|
||||||
|
|
||||||
mState = eFinished;
|
Fail();
|
||||||
File::OnFailure();
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -976,10 +1350,12 @@ namespace {
|
|||||||
bool
|
bool
|
||||||
OpenFile(nsIPrincipal* aPrincipal,
|
OpenFile(nsIPrincipal* aPrincipal,
|
||||||
OpenMode aOpenMode,
|
OpenMode aOpenMode,
|
||||||
size_t aSizeToWrite,
|
WriteParams aWriteParams,
|
||||||
|
ReadParams aReadParams,
|
||||||
File::AutoClose* aFile)
|
File::AutoClose* aFile)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT_IF(aOpenMode == eOpenForRead, aSizeToWrite == 0);
|
MOZ_ASSERT_IF(aOpenMode == eOpenForRead, aWriteParams.mSize == 0);
|
||||||
|
MOZ_ASSERT_IF(aOpenMode == eOpenForWrite, aReadParams.mBegin == nullptr);
|
||||||
|
|
||||||
// There are three reasons we don't attempt caching from the main thread:
|
// There are three reasons we don't attempt caching from the main thread:
|
||||||
// 1. In the parent process: QuotaManager::WaitForOpenAllowed prevents
|
// 1. In the parent process: QuotaManager::WaitForOpenAllowed prevents
|
||||||
@ -1002,9 +1378,11 @@ OpenFile(nsIPrincipal* aPrincipal,
|
|||||||
// child can then map the file into its address space to perform I/O.
|
// child can then map the file into its address space to perform I/O.
|
||||||
nsRefPtr<File> file;
|
nsRefPtr<File> file;
|
||||||
if (IsMainProcess()) {
|
if (IsMainProcess()) {
|
||||||
file = new SingleProcessRunnable(aPrincipal, aOpenMode, aSizeToWrite);
|
file = new SingleProcessRunnable(aPrincipal, aOpenMode, aWriteParams,
|
||||||
|
aReadParams);
|
||||||
} else {
|
} else {
|
||||||
file = new ChildProcessRunnable(aPrincipal, aOpenMode, aSizeToWrite);
|
file = new ChildProcessRunnable(aPrincipal, aOpenMode, aWriteParams,
|
||||||
|
aReadParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file->BlockUntilOpen(aFile)) {
|
if (!file->BlockUntilOpen(aFile)) {
|
||||||
@ -1019,10 +1397,6 @@ OpenFile(nsIPrincipal* aPrincipal,
|
|||||||
typedef uint32_t AsmJSCookieType;
|
typedef uint32_t AsmJSCookieType;
|
||||||
static const uint32_t sAsmJSCookie = 0x600d600d;
|
static const uint32_t sAsmJSCookie = 0x600d600d;
|
||||||
|
|
||||||
// Anything smaller should compile fast enough that caching will just add
|
|
||||||
// overhead.
|
|
||||||
static const size_t sMinCachedModuleLength = 10000;
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OpenEntryForRead(nsIPrincipal* aPrincipal,
|
OpenEntryForRead(nsIPrincipal* aPrincipal,
|
||||||
const jschar* aBegin,
|
const jschar* aBegin,
|
||||||
@ -1035,8 +1409,13 @@ OpenEntryForRead(nsIPrincipal* aPrincipal,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReadParams readParams;
|
||||||
|
readParams.mBegin = aBegin;
|
||||||
|
readParams.mLimit = aLimit;
|
||||||
|
|
||||||
File::AutoClose file;
|
File::AutoClose file;
|
||||||
if (!OpenFile(aPrincipal, eOpenForRead, 0, &file)) {
|
WriteParams notAWrite;
|
||||||
|
if (!OpenFile(aPrincipal, eOpenForRead, notAWrite, readParams, &file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1092,8 +1471,17 @@ OpenEntryForWrite(nsIPrincipal* aPrincipal,
|
|||||||
// Add extra space for the AsmJSCookieType (see OpenEntryForRead).
|
// Add extra space for the AsmJSCookieType (see OpenEntryForRead).
|
||||||
aSize += sizeof(AsmJSCookieType);
|
aSize += sizeof(AsmJSCookieType);
|
||||||
|
|
||||||
|
static_assert(sNumFastHashChars < sMinCachedModuleLength, "HashString safe");
|
||||||
|
|
||||||
|
WriteParams writeParams;
|
||||||
|
writeParams.mSize = aSize;
|
||||||
|
writeParams.mFastHash = HashString(aBegin, sNumFastHashChars);
|
||||||
|
writeParams.mNumChars = aEnd - aBegin;
|
||||||
|
writeParams.mFullHash = HashString(aBegin, writeParams.mNumChars);
|
||||||
|
|
||||||
File::AutoClose file;
|
File::AutoClose file;
|
||||||
if (!OpenFile(aPrincipal, eOpenForWrite, aSize, &file)) {
|
ReadParams notARead;
|
||||||
|
if (!OpenFile(aPrincipal, eOpenForWrite, writeParams, notARead, &file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1128,7 +1516,7 @@ CloseEntryForWrite(JS::Handle<JSObject*> global,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GetBuildId(js::Vector<char>* aBuildID)
|
GetBuildId(JS::BuildIdCharVector* aBuildID)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIXULAppInfo> info = do_GetService("@mozilla.org/xre/app-info;1");
|
nsCOMPtr<nsIXULAppInfo> info = do_GetService("@mozilla.org/xre/app-info;1");
|
||||||
if (!info) {
|
if (!info) {
|
||||||
@ -1192,19 +1580,24 @@ public:
|
|||||||
rv = directory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME));
|
rv = directory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
bool exists;
|
DebugOnly<bool> exists;
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(directory->Exists(&exists)) && exists);
|
MOZ_ASSERT(NS_SUCCEEDED(directory->Exists(&exists)) && exists);
|
||||||
|
|
||||||
nsIFile* path = directory;
|
nsCOMPtr<nsISimpleEnumerator> entries;
|
||||||
rv = path->Append(NS_LITERAL_STRING(ASMJSCACHE_FILE_NAME));
|
rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
rv = path->Exists(&exists);
|
bool more;
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
while (NS_SUCCEEDED((rv = entries->HasMoreElements(&more))) && more) {
|
||||||
|
nsCOMPtr<nsISupports> entry;
|
||||||
|
rv = entries->GetNext(getter_AddRefs(entry));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIFile> file = do_QueryInterface(entry);
|
||||||
|
NS_ENSURE_TRUE(file, NS_NOINTERFACE);
|
||||||
|
|
||||||
if (exists) {
|
|
||||||
int64_t fileSize;
|
int64_t fileSize;
|
||||||
rv = path->GetFileSize(&fileSize);
|
rv = file->GetFileSize(&fileSize);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
MOZ_ASSERT(fileSize >= 0, "Negative size?!");
|
MOZ_ASSERT(fileSize >= 0, "Negative size?!");
|
||||||
@ -1279,3 +1672,79 @@ CreateClient()
|
|||||||
} // namespace asmjscache
|
} // namespace asmjscache
|
||||||
} // namespace dom
|
} // namespace dom
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
namespace IPC {
|
||||||
|
|
||||||
|
using mozilla::dom::asmjscache::Metadata;
|
||||||
|
using mozilla::dom::asmjscache::WriteParams;
|
||||||
|
|
||||||
|
void
|
||||||
|
ParamTraits<Metadata>::Write(Message* aMsg, const paramType& aParam)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < Metadata::kNumEntries; i++) {
|
||||||
|
const Metadata::Entry& entry = aParam.mEntries[i];
|
||||||
|
WriteParam(aMsg, entry.mFastHash);
|
||||||
|
WriteParam(aMsg, entry.mNumChars);
|
||||||
|
WriteParam(aMsg, entry.mFullHash);
|
||||||
|
WriteParam(aMsg, entry.mModuleIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ParamTraits<Metadata>::Read(const Message* aMsg, void** aIter,
|
||||||
|
paramType* aResult)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < Metadata::kNumEntries; i++) {
|
||||||
|
Metadata::Entry& entry = aResult->mEntries[i];
|
||||||
|
if (!ReadParam(aMsg, aIter, &entry.mFastHash) ||
|
||||||
|
!ReadParam(aMsg, aIter, &entry.mNumChars) ||
|
||||||
|
!ReadParam(aMsg, aIter, &entry.mFullHash) ||
|
||||||
|
!ReadParam(aMsg, aIter, &entry.mModuleIndex))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParamTraits<Metadata>::Log(const paramType& aParam, std::wstring* aLog)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < Metadata::kNumEntries; i++) {
|
||||||
|
const Metadata::Entry& entry = aParam.mEntries[i];
|
||||||
|
LogParam(entry.mFastHash, aLog);
|
||||||
|
LogParam(entry.mNumChars, aLog);
|
||||||
|
LogParam(entry.mFullHash, aLog);
|
||||||
|
LogParam(entry.mModuleIndex, aLog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParamTraits<WriteParams>::Write(Message* aMsg, const paramType& aParam)
|
||||||
|
{
|
||||||
|
WriteParam(aMsg, aParam.mSize);
|
||||||
|
WriteParam(aMsg, aParam.mFastHash);
|
||||||
|
WriteParam(aMsg, aParam.mNumChars);
|
||||||
|
WriteParam(aMsg, aParam.mFullHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ParamTraits<WriteParams>::Read(const Message* aMsg, void** aIter,
|
||||||
|
paramType* aResult)
|
||||||
|
{
|
||||||
|
return ReadParam(aMsg, aIter, &aResult->mSize) &&
|
||||||
|
ReadParam(aMsg, aIter, &aResult->mFastHash) &&
|
||||||
|
ReadParam(aMsg, aIter, &aResult->mNumChars) &&
|
||||||
|
ReadParam(aMsg, aIter, &aResult->mFullHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ParamTraits<WriteParams>::Log(const paramType& aParam, std::wstring* aLog)
|
||||||
|
{
|
||||||
|
LogParam(aParam.mSize, aLog);
|
||||||
|
LogParam(aParam.mFastHash, aLog);
|
||||||
|
LogParam(aParam.mNumChars, aLog);
|
||||||
|
LogParam(aParam.mFullHash, aLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace IPC
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "ipc/IPCMessageUtils.h"
|
#include "ipc/IPCMessageUtils.h"
|
||||||
#include "js/TypeDecls.h"
|
#include "js/TypeDecls.h"
|
||||||
#include "js/Vector.h"
|
#include "js/Vector.h"
|
||||||
|
#include "jsapi.h"
|
||||||
|
|
||||||
class nsIPrincipal;
|
class nsIPrincipal;
|
||||||
|
|
||||||
@ -32,6 +33,54 @@ enum OpenMode
|
|||||||
NUM_OPEN_MODES
|
NUM_OPEN_MODES
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Each origin stores a fixed size (kNumEntries) LRU cache of compiled asm.js
|
||||||
|
// modules. Each compiled asm.js module is stored in a separate file with one
|
||||||
|
// extra metadata file that stores the LRU cache and enough information for a
|
||||||
|
// client to pick which cached module's file to open.
|
||||||
|
struct Metadata
|
||||||
|
{
|
||||||
|
static const unsigned kNumEntries = 16;
|
||||||
|
static const unsigned kLastEntry = kNumEntries - 1;
|
||||||
|
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
uint32_t mFastHash;
|
||||||
|
uint32_t mNumChars;
|
||||||
|
uint32_t mFullHash;
|
||||||
|
uint32_t mModuleIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
Entry mEntries[kNumEntries];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parameters specific to opening a cache entry for writing
|
||||||
|
struct WriteParams
|
||||||
|
{
|
||||||
|
int64_t mSize;
|
||||||
|
int64_t mFastHash;
|
||||||
|
int64_t mNumChars;
|
||||||
|
int64_t mFullHash;
|
||||||
|
|
||||||
|
WriteParams()
|
||||||
|
: mSize(0),
|
||||||
|
mFastHash(0),
|
||||||
|
mNumChars(0),
|
||||||
|
mFullHash(0)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parameters specific to opening a cache entry for reading
|
||||||
|
struct ReadParams
|
||||||
|
{
|
||||||
|
const jschar* mBegin;
|
||||||
|
const jschar* mLimit;
|
||||||
|
|
||||||
|
ReadParams()
|
||||||
|
: mBegin(nullptr),
|
||||||
|
mLimit(nullptr)
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
// Implementation of AsmJSCacheOps, installed for the main JSRuntime by
|
// Implementation of AsmJSCacheOps, installed for the main JSRuntime by
|
||||||
// nsJSEnvironment.cpp and DOM Worker JSRuntimes in RuntimeService.cpp.
|
// nsJSEnvironment.cpp and DOM Worker JSRuntimes in RuntimeService.cpp.
|
||||||
//
|
//
|
||||||
@ -68,8 +117,9 @@ CloseEntryForWrite(JS::Handle<JSObject*> aGlobal,
|
|||||||
size_t aSize,
|
size_t aSize,
|
||||||
uint8_t* aMemory,
|
uint8_t* aMemory,
|
||||||
intptr_t aHandle);
|
intptr_t aHandle);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
GetBuildId(js::Vector<char>* aBuildId);
|
GetBuildId(JS::BuildIdCharVector* aBuildId);
|
||||||
|
|
||||||
// Called from QuotaManager.cpp:
|
// Called from QuotaManager.cpp:
|
||||||
|
|
||||||
@ -79,7 +129,7 @@ CreateClient();
|
|||||||
// Called from ipc/ContentParent.cpp:
|
// Called from ipc/ContentParent.cpp:
|
||||||
|
|
||||||
PAsmJSCacheEntryParent*
|
PAsmJSCacheEntryParent*
|
||||||
AllocEntryParent(OpenMode aOpenMode, uint32_t aSizeToWrite,
|
AllocEntryParent(OpenMode aOpenMode, WriteParams aWriteParams,
|
||||||
nsIPrincipal* aPrincipal);
|
nsIPrincipal* aPrincipal);
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -103,6 +153,24 @@ struct ParamTraits<mozilla::dom::asmjscache::OpenMode> :
|
|||||||
mozilla::dom::asmjscache::NUM_OPEN_MODES>
|
mozilla::dom::asmjscache::NUM_OPEN_MODES>
|
||||||
{ };
|
{ };
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ParamTraits<mozilla::dom::asmjscache::Metadata>
|
||||||
|
{
|
||||||
|
typedef mozilla::dom::asmjscache::Metadata paramType;
|
||||||
|
static void Write(Message* aMsg, const paramType& aParam);
|
||||||
|
static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
|
||||||
|
static void Log(const paramType& aParam, std::wstring* aLog);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ParamTraits<mozilla::dom::asmjscache::WriteParams>
|
||||||
|
{
|
||||||
|
typedef mozilla::dom::asmjscache::WriteParams paramType;
|
||||||
|
static void Write(Message* aMsg, const paramType& aParam);
|
||||||
|
static bool Read(const Message* aMsg, void** aIter, paramType* aResult);
|
||||||
|
static void Log(const paramType& aParam, std::wstring* aLog);
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace IPC
|
} // namespace IPC
|
||||||
|
|
||||||
#endif // mozilla_dom_asmjscache_asmjscache_h
|
#endif // mozilla_dom_asmjscache_asmjscache_h
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
include protocol PContent;
|
include protocol PContent;
|
||||||
|
|
||||||
|
using mozilla::dom::asmjscache::Metadata from "mozilla/dom/asmjscache/AsmJSCache.h";
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
namespace asmjscache {
|
namespace asmjscache {
|
||||||
@ -12,8 +14,18 @@ protocol PAsmJSCacheEntry
|
|||||||
{
|
{
|
||||||
manager PContent;
|
manager PContent;
|
||||||
|
|
||||||
|
// When the cache is opened to read, the parent process sends over the
|
||||||
|
// origin's Metadata so the child process can select the cache entry to open
|
||||||
|
// (based on hash) and notify the parent (via SelectCacheFileToRead).
|
||||||
child:
|
child:
|
||||||
OnOpen(int64_t fileSize, FileDescriptor fileDesc);
|
OnOpenMetadataForRead(Metadata metadata);
|
||||||
|
parent:
|
||||||
|
SelectCacheFileToRead(uint32_t moduleIndex);
|
||||||
|
|
||||||
|
child:
|
||||||
|
// Once the cache file has been opened, the child is notified and sent an
|
||||||
|
// open file descriptor.
|
||||||
|
OnOpenCacheFile(int64_t fileSize, FileDescriptor fileDesc);
|
||||||
|
|
||||||
both:
|
both:
|
||||||
__delete__();
|
__delete__();
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
TEST_DIRS += ['test']
|
||||||
|
|
||||||
EXPORTS.mozilla.dom.asmjscache += [
|
EXPORTS.mozilla.dom.asmjscache += [
|
||||||
'AsmJSCache.h'
|
'AsmJSCache.h'
|
||||||
]
|
]
|
||||||
|
10
dom/asmjscache/test/mochitest.ini
Normal file
10
dom/asmjscache/test/mochitest.ini
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
support-files =
|
||||||
|
file_slow.js
|
||||||
|
|
||||||
|
[test_cachingBasic.html]
|
||||||
|
[test_workers.html]
|
||||||
|
[test_cachingMulti.html]
|
||||||
|
[test_slow.html]
|
||||||
|
# bug 929498
|
||||||
|
skip-if = os == 'android'
|
8
dom/asmjscache/test/moz.build
Normal file
8
dom/asmjscache/test/moz.build
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||||
|
# vim: set filetype=python:
|
||||||
|
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||||
|
|
77
dom/asmjscache/test/test_cachingMulti.html
Normal file
77
dom/asmjscache/test/test_cachingMulti.html
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=944821
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>asm.js browser tests</title>
|
||||||
|
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=944821">asm.js browser tests</a>
|
||||||
|
<p id="display"></p>
|
||||||
|
<div id="content" style="display: none"></div>
|
||||||
|
<pre id="test"></pre>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var jsFuns = SpecialPowers.Cu.getJSTestingFunctions();
|
||||||
|
ok(jsFuns.isAsmJSCompilationAvailable(), "compilation is available");
|
||||||
|
|
||||||
|
// generate four slightly different big asm.js modules and compile them async
|
||||||
|
// so that we can hit the asm.js cache.
|
||||||
|
|
||||||
|
var code = "function f() { 'use asm';\n";
|
||||||
|
for (var i = 0; i < 1000; i++)
|
||||||
|
code += "function g" + i + "() { return " + i + "}\n";
|
||||||
|
ok(code.length > 10000, "code is long enough");
|
||||||
|
|
||||||
|
const N = 4;
|
||||||
|
|
||||||
|
var codes = [];
|
||||||
|
for (var i = 0; i < N; i++) {
|
||||||
|
var code2 = code;
|
||||||
|
code2 += "return g" + i + ";\n";
|
||||||
|
code2 += "}\n";
|
||||||
|
code2 += "ok(jsFuns.isAsmJSModule(f), 'f is an asm.js module')\n";
|
||||||
|
code2 += "if (assertCacheHit) ok(jsFuns.isAsmJSModuleLoadedFromCache(f), 'cache hit');\n";
|
||||||
|
code2 += "var gX = f();\n";
|
||||||
|
code2 += "ok(jsFuns.isAsmJSFunction(gX), 'gX is an asm.js function')\n";
|
||||||
|
code2 += "ok(gX() === " + i + ", 'gX returns the correct result')\n";
|
||||||
|
code2 += "finishedEvalAsync();\n";
|
||||||
|
codes.push(code2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function evalAsync(code) {
|
||||||
|
var blob = new Blob([code], {type:"application/javascript"});
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.src = URL.createObjectURL(blob);
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
evalAsync(codes[i]);
|
||||||
|
|
||||||
|
var finishedCount = 0;
|
||||||
|
var assertCacheHit = false;
|
||||||
|
function finishedEvalAsync() {
|
||||||
|
finishedCount++;
|
||||||
|
|
||||||
|
if (finishedCount < 1 || finishedCount > 2*N) {
|
||||||
|
throw "Huh?!";
|
||||||
|
} else if (finishedCount == N) {
|
||||||
|
assertCacheHit = true;
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
evalAsync(codes[i]);
|
||||||
|
} else if (finishedCount == 2*N) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -20,10 +20,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=854209
|
|||||||
ok(jsFuns.isAsmJSCompilationAvailable(), "asm.js compilation is available");
|
ok(jsFuns.isAsmJSCompilationAvailable(), "asm.js compilation is available");
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script src="http://mochi.test:8888/tests/js/xpconnect/tests/mochitest/file_asmjs.js"></script>
|
<script src="http://mochi.test:8888/tests/dom/asmjscache/test/file_slow.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var w = new Worker('http://mochi.test:8888/tests/js/xpconnect/tests/mochitest/file_asmjs.js');
|
var w = new Worker('http://mochi.test:8888/tests/dom/asmjscache/test/file_slow.js');
|
||||||
w.onmessage = function(e) {
|
w.onmessage = function(e) {
|
||||||
ok(e.data === "ok", "Worker asm.js tests");
|
ok(e.data === "ok", "Worker asm.js tests");
|
||||||
SimpleTest.finish();
|
SimpleTest.finish();
|
@ -15,6 +15,7 @@
|
|||||||
#include "nsIScriptContext.h"
|
#include "nsIScriptContext.h"
|
||||||
#include "nsContentUtils.h"
|
#include "nsContentUtils.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
|
#include "nsJSUtils.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace dom {
|
namespace dom {
|
||||||
@ -92,6 +93,25 @@ void DestroyScriptSettings()
|
|||||||
delete ptr;
|
delete ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This mostly gets the entry global, but doesn't entirely match the spec in
|
||||||
|
// certain edge cases. It's good enough for some purposes, but not others. If
|
||||||
|
// you want to call this function, ping bholley and describe your use-case.
|
||||||
|
nsIGlobalObject*
|
||||||
|
BrokenGetEntryGlobal()
|
||||||
|
{
|
||||||
|
// We need the current JSContext in order to check the JS for
|
||||||
|
// scripted frames that may have appeared since anyone last
|
||||||
|
// manipulated the stack. If it's null, that means that there
|
||||||
|
// must be no entry point on the stack.
|
||||||
|
JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
|
||||||
|
if (!cx) {
|
||||||
|
MOZ_ASSERT(ScriptSettingsStack::Ref().EntryPoint() == nullptr);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsJSUtils::GetDynamicScriptGlobal(cx);
|
||||||
|
}
|
||||||
|
|
||||||
// Note: When we're ready to expose it, GetEntryGlobal will look similar to
|
// Note: When we're ready to expose it, GetEntryGlobal will look similar to
|
||||||
// GetIncumbentGlobal below.
|
// GetIncumbentGlobal below.
|
||||||
|
|
||||||
|
@ -27,6 +27,11 @@ namespace dom {
|
|||||||
void InitScriptSettings();
|
void InitScriptSettings();
|
||||||
void DestroyScriptSettings();
|
void DestroyScriptSettings();
|
||||||
|
|
||||||
|
// This mostly gets the entry global, but doesn't entirely match the spec in
|
||||||
|
// certain edge cases. It's good enough for some purposes, but not others. If
|
||||||
|
// you want to call this function, ping bholley and describe your use-case.
|
||||||
|
nsIGlobalObject* BrokenGetEntryGlobal();
|
||||||
|
|
||||||
// Note: We don't yet expose GetEntryGlobal, because in order for it to be
|
// Note: We don't yet expose GetEntryGlobal, because in order for it to be
|
||||||
// correct, we first need to replace a bunch of explicit cx pushing in the
|
// correct, we first need to replace a bunch of explicit cx pushing in the
|
||||||
// browser with AutoEntryScript. But GetIncumbentGlobal is simpler, because it
|
// browser with AutoEntryScript. But GetIncumbentGlobal is simpler, because it
|
||||||
|
@ -84,6 +84,7 @@ UNIFIED_SOURCES += [
|
|||||||
'nsFocusManager.cpp',
|
'nsFocusManager.cpp',
|
||||||
'nsGlobalWindowCommands.cpp',
|
'nsGlobalWindowCommands.cpp',
|
||||||
'nsHistory.cpp',
|
'nsHistory.cpp',
|
||||||
|
'nsIGlobalObject.cpp',
|
||||||
'nsJSTimeoutHandler.cpp',
|
'nsJSTimeoutHandler.cpp',
|
||||||
'nsJSUtils.cpp',
|
'nsJSUtils.cpp',
|
||||||
'nsLocation.cpp',
|
'nsLocation.cpp',
|
||||||
|
@ -7493,14 +7493,14 @@ class PostMessageEvent : public nsRunnable
|
|||||||
PostMessageEvent(nsGlobalWindow* aSource,
|
PostMessageEvent(nsGlobalWindow* aSource,
|
||||||
const nsAString& aCallerOrigin,
|
const nsAString& aCallerOrigin,
|
||||||
nsGlobalWindow* aTargetWindow,
|
nsGlobalWindow* aTargetWindow,
|
||||||
nsIURI* aProvidedOrigin,
|
nsIPrincipal* aProvidedPrincipal,
|
||||||
bool aTrustedCaller)
|
bool aTrustedCaller)
|
||||||
: mSource(aSource),
|
: mSource(aSource),
|
||||||
mCallerOrigin(aCallerOrigin),
|
mCallerOrigin(aCallerOrigin),
|
||||||
mMessage(nullptr),
|
mMessage(nullptr),
|
||||||
mMessageLen(0),
|
mMessageLen(0),
|
||||||
mTargetWindow(aTargetWindow),
|
mTargetWindow(aTargetWindow),
|
||||||
mProvidedOrigin(aProvidedOrigin),
|
mProvidedPrincipal(aProvidedPrincipal),
|
||||||
mTrustedCaller(aTrustedCaller)
|
mTrustedCaller(aTrustedCaller)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(PostMessageEvent);
|
MOZ_COUNT_CTOR(PostMessageEvent);
|
||||||
@ -7530,7 +7530,7 @@ class PostMessageEvent : public nsRunnable
|
|||||||
uint64_t* mMessage;
|
uint64_t* mMessage;
|
||||||
size_t mMessageLen;
|
size_t mMessageLen;
|
||||||
nsRefPtr<nsGlobalWindow> mTargetWindow;
|
nsRefPtr<nsGlobalWindow> mTargetWindow;
|
||||||
nsCOMPtr<nsIURI> mProvidedOrigin;
|
nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
|
||||||
bool mTrustedCaller;
|
bool mTrustedCaller;
|
||||||
nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
|
nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
|
||||||
};
|
};
|
||||||
@ -7699,32 +7699,22 @@ PostMessageEvent::Run()
|
|||||||
// intercept messages intended for another site by carefully timing navigation
|
// intercept messages intended for another site by carefully timing navigation
|
||||||
// of the target window so it changed location after postMessage but before
|
// of the target window so it changed location after postMessage but before
|
||||||
// now.
|
// now.
|
||||||
if (mProvidedOrigin) {
|
if (mProvidedPrincipal) {
|
||||||
// Get the target's origin either from its principal or, in the case the
|
// Get the target's origin either from its principal or, in the case the
|
||||||
// principal doesn't carry a URI (e.g. the system principal), the target's
|
// principal doesn't carry a URI (e.g. the system principal), the target's
|
||||||
// document.
|
// document.
|
||||||
nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
|
nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
|
||||||
if (!targetPrin)
|
if (NS_WARN_IF(!targetPrin))
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
nsCOMPtr<nsIURI> targetURI;
|
|
||||||
if (NS_FAILED(targetPrin->GetURI(getter_AddRefs(targetURI))))
|
|
||||||
return NS_OK;
|
|
||||||
if (!targetURI) {
|
|
||||||
targetURI = targetWindow->mDoc->GetDocumentURI();
|
|
||||||
if (!targetURI)
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: This is contrary to the spec with respect to file: URLs, which
|
// Note: This is contrary to the spec with respect to file: URLs, which
|
||||||
// the spec groups into a single origin, but given we intentionally
|
// the spec groups into a single origin, but given we intentionally
|
||||||
// don't do that in other places it seems better to hold the line for
|
// don't do that in other places it seems better to hold the line for
|
||||||
// now. Long-term, we want HTML5 to address this so that we can
|
// now. Long-term, we want HTML5 to address this so that we can
|
||||||
// be compliant while being safer.
|
// be compliant while being safer.
|
||||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
if (!targetPrin->EqualsIgnoringDomain(mProvidedPrincipal)) {
|
||||||
nsresult rv =
|
|
||||||
ssm->CheckSameOriginURI(mProvidedOrigin, targetURI, true);
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deserialize the structured clone data
|
// Deserialize the structured clone data
|
||||||
@ -7857,15 +7847,47 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert the provided origin string into a URI for comparison purposes.
|
// Convert the provided origin string into a URI for comparison purposes.
|
||||||
|
nsCOMPtr<nsIPrincipal> providedPrincipal;
|
||||||
|
|
||||||
|
if (aTargetOrigin.EqualsASCII("/")) {
|
||||||
|
providedPrincipal = BrokenGetEntryGlobal()->PrincipalOrNull();
|
||||||
|
if (NS_WARN_IF(!providedPrincipal))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// "*" indicates no specific origin is required.
|
// "*" indicates no specific origin is required.
|
||||||
nsCOMPtr<nsIURI> providedOrigin;
|
else if (!aTargetOrigin.EqualsASCII("*")) {
|
||||||
if (!aTargetOrigin.EqualsASCII("*")) {
|
nsCOMPtr<nsIURI> originURI;
|
||||||
if (NS_FAILED(NS_NewURI(getter_AddRefs(providedOrigin), aTargetOrigin))) {
|
if (NS_FAILED(NS_NewURI(getter_AddRefs(originURI), aTargetOrigin))) {
|
||||||
aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (NS_FAILED(providedOrigin->SetUserPass(EmptyCString())) ||
|
|
||||||
NS_FAILED(providedOrigin->SetPath(EmptyCString()))) {
|
if (NS_FAILED(originURI->SetUserPass(EmptyCString())) ||
|
||||||
|
NS_FAILED(originURI->SetPath(EmptyCString()))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsCOMPtr<nsIScriptSecurityManager> ssm =
|
||||||
|
nsContentUtils::GetSecurityManager();
|
||||||
|
MOZ_ASSERT(ssm);
|
||||||
|
|
||||||
|
nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetSubjectPrincipal();
|
||||||
|
MOZ_ASSERT(principal);
|
||||||
|
|
||||||
|
uint32_t appId;
|
||||||
|
if (NS_WARN_IF(NS_FAILED(principal->GetAppId(&appId))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool isInBrowser;
|
||||||
|
if (NS_WARN_IF(NS_FAILED(principal->GetIsInBrowserElement(&isInBrowser))))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Create a nsIPrincipal inheriting the app/browser attributes from the
|
||||||
|
// caller.
|
||||||
|
nsresult rv = ssm->GetAppCodebasePrincipal(originURI, appId, isInBrowser,
|
||||||
|
getter_AddRefs(providedPrincipal));
|
||||||
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7878,7 +7900,7 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
|||||||
: callerInnerWin->GetOuterWindowInternal(),
|
: callerInnerWin->GetOuterWindowInternal(),
|
||||||
origin,
|
origin,
|
||||||
this,
|
this,
|
||||||
providedOrigin,
|
providedPrincipal,
|
||||||
nsContentUtils::IsCallerChrome());
|
nsContentUtils::IsCallerChrome());
|
||||||
|
|
||||||
// We *must* clone the data here, or the JS::Value could be modified
|
// We *must* clone the data here, or the JS::Value could be modified
|
||||||
|
18
dom/base/nsIGlobalObject.cpp
Normal file
18
dom/base/nsIGlobalObject.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include "nsIGlobalObject.h"
|
||||||
|
#include "nsContentUtils.h"
|
||||||
|
|
||||||
|
nsIPrincipal*
|
||||||
|
nsIGlobalObject::PrincipalOrNull()
|
||||||
|
{
|
||||||
|
JSObject *global = GetGlobalJSObject();
|
||||||
|
if (NS_WARN_IF(!global))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return nsContentUtils::GetObjectPrincipal(global);
|
||||||
|
}
|
@ -13,12 +13,17 @@
|
|||||||
{ 0xe2538ded, 0x13ef, 0x4f4d, \
|
{ 0xe2538ded, 0x13ef, 0x4f4d, \
|
||||||
{ 0x94, 0x6b, 0x65, 0xd3, 0x33, 0xb4, 0xf0, 0x3c } }
|
{ 0x94, 0x6b, 0x65, 0xd3, 0x33, 0xb4, 0xf0, 0x3c } }
|
||||||
|
|
||||||
|
class nsIPrincipal;
|
||||||
|
|
||||||
class nsIGlobalObject : public nsISupports
|
class nsIGlobalObject : public nsISupports
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IGLOBALOBJECT_IID)
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IGLOBALOBJECT_IID)
|
||||||
|
|
||||||
virtual JSObject* GetGlobalJSObject() = 0;
|
virtual JSObject* GetGlobalJSObject() = 0;
|
||||||
|
|
||||||
|
// This method is not meant to be overridden.
|
||||||
|
nsIPrincipal* PrincipalOrNull();
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIGlobalObject,
|
NS_DEFINE_STATIC_IID_ACCESSOR(nsIGlobalObject,
|
||||||
|
15
dom/base/test/iframe_postMessage_solidus.html
Normal file
15
dom/base/test/iframe_postMessage_solidus.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
window.addEventListener('message', receiveMessage, false);
|
||||||
|
function receiveMessage(evt) {
|
||||||
|
window.parent.postMessage(evt.data, '*');
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
@ -4,6 +4,7 @@ support-files =
|
|||||||
iframe_messageChannel_pingpong.html
|
iframe_messageChannel_pingpong.html
|
||||||
iframe_messageChannel_post.html
|
iframe_messageChannel_post.html
|
||||||
file_empty.html
|
file_empty.html
|
||||||
|
iframe_postMessage_solidus.html
|
||||||
|
|
||||||
[test_Image_constructor.html]
|
[test_Image_constructor.html]
|
||||||
[test_appname_override.html]
|
[test_appname_override.html]
|
||||||
@ -45,4 +46,5 @@ support-files =
|
|||||||
[test_openDialogChromeOnly.html]
|
[test_openDialogChromeOnly.html]
|
||||||
[test_messagemanager_targetchain.html]
|
[test_messagemanager_targetchain.html]
|
||||||
[test_url_empty_port.html]
|
[test_url_empty_port.html]
|
||||||
|
[test_postMessage_solidus.html]
|
||||||
[test_urlSearchParams.html]
|
[test_urlSearchParams.html]
|
||||||
|
93
dom/base/test/test_postMessage_solidus.html
Normal file
93
dom/base/test/test_postMessage_solidus.html
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<!--
|
||||||
|
https://bugzilla.mozilla.org/show_bug.cgi?id=949488
|
||||||
|
-->
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test for Bug 949488 - basic support</title>
|
||||||
|
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=949488">Mozilla Bug 949488</a>
|
||||||
|
<div id="content"></div>
|
||||||
|
<script type="application/javascript">
|
||||||
|
|
||||||
|
function selfMessage() {
|
||||||
|
addEventListener('message', receiveMessage);
|
||||||
|
function receiveMessage(evt) {
|
||||||
|
is(evt.data, 1, "Message received");
|
||||||
|
removeEventListener('message', receiveMessage);
|
||||||
|
runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
postMessage(1, '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function frameOk() {
|
||||||
|
var ifr = document.createElement("iframe");
|
||||||
|
ifr.addEventListener("load", iframeLoaded, false);
|
||||||
|
ifr.setAttribute('src', "iframe_postMessage_solidus.html");
|
||||||
|
|
||||||
|
var div = document.getElementById("content");
|
||||||
|
div.appendChild(ifr);
|
||||||
|
|
||||||
|
function iframeLoaded() {
|
||||||
|
addEventListener('message', receiveMessage);
|
||||||
|
function receiveMessage(evt) {
|
||||||
|
is(evt.data, 2, "Message received");
|
||||||
|
removeEventListener('message', receiveMessage);
|
||||||
|
runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
ifr.contentWindow.postMessage(2, '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function frameWrong() {
|
||||||
|
var ifr = document.createElement("iframe");
|
||||||
|
ifr.addEventListener("load", iframeLoaded, false);
|
||||||
|
ifr.setAttribute('src', "http://www.example.com/tests/dom/base/test/iframe_postMessage_solidus.html");
|
||||||
|
|
||||||
|
var div = document.getElementById("content");
|
||||||
|
div.appendChild(ifr);
|
||||||
|
|
||||||
|
function iframeLoaded() {
|
||||||
|
addEventListener('message', receiveMessage);
|
||||||
|
function receiveMessage(evt) {
|
||||||
|
ok(evt.data, 3, "Message received");
|
||||||
|
removeEventListener('message', receiveMessage);
|
||||||
|
runTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
ifr.contentWindow.postMessage(4, '/');
|
||||||
|
SimpleTest.executeSoon(function() {
|
||||||
|
ifr.contentWindow.postMessage(3, '*');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = [
|
||||||
|
selfMessage,
|
||||||
|
frameOk,
|
||||||
|
frameWrong
|
||||||
|
];
|
||||||
|
|
||||||
|
function runTest() {
|
||||||
|
if (!tests.length) {
|
||||||
|
SimpleTest.finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var test = tests.shift();
|
||||||
|
test();
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleTest.waitForExplicitFinish();
|
||||||
|
runTest();
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -70,60 +70,63 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
|||||||
JSContext* cx = nullptr;
|
JSContext* cx = nullptr;
|
||||||
nsIGlobalObject* globalObject = nullptr;
|
nsIGlobalObject* globalObject = nullptr;
|
||||||
|
|
||||||
if (mIsMainThread) {
|
{
|
||||||
// Now get the global and JSContext for this callback.
|
JS::AutoAssertNoGC nogc;
|
||||||
nsGlobalWindow* win = xpc::WindowGlobalOrNull(realCallback);
|
if (mIsMainThread) {
|
||||||
if (win) {
|
// Now get the global and JSContext for this callback.
|
||||||
// Make sure that if this is a window it's the current inner, since the
|
nsGlobalWindow* win = xpc::WindowGlobalOrNull(realCallback);
|
||||||
// nsIScriptContext and hence JSContext are associated with the outer
|
if (win) {
|
||||||
// window. Which means that if someone holds on to a function from a
|
// Make sure that if this is a window it's the current inner, since the
|
||||||
// now-unloaded document we'd have the new document as the script entry
|
// nsIScriptContext and hence JSContext are associated with the outer
|
||||||
// point...
|
// window. Which means that if someone holds on to a function from a
|
||||||
MOZ_ASSERT(win->IsInnerWindow());
|
// now-unloaded document we'd have the new document as the script entry
|
||||||
nsPIDOMWindow* outer = win->GetOuterWindow();
|
// point...
|
||||||
if (!outer || win != outer->GetCurrentInnerWindow()) {
|
MOZ_ASSERT(win->IsInnerWindow());
|
||||||
// Just bail out from here
|
nsPIDOMWindow* outer = win->GetOuterWindow();
|
||||||
return;
|
if (!outer || win != outer->GetCurrentInnerWindow()) {
|
||||||
|
// Just bail out from here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cx = win->GetContext() ? win->GetContext()->GetNativeContext()
|
||||||
|
// This happens - Removing it causes
|
||||||
|
// test_bug293235.xul to go orange.
|
||||||
|
: nsContentUtils::GetSafeJSContext();
|
||||||
|
globalObject = win;
|
||||||
|
} else {
|
||||||
|
// No DOM Window. Store the global and use the SafeJSContext.
|
||||||
|
JSObject* glob = js::GetGlobalForObjectCrossCompartment(realCallback);
|
||||||
|
globalObject = xpc::GetNativeForGlobal(glob);
|
||||||
|
MOZ_ASSERT(globalObject);
|
||||||
|
cx = nsContentUtils::GetSafeJSContext();
|
||||||
}
|
}
|
||||||
cx = win->GetContext() ? win->GetContext()->GetNativeContext()
|
|
||||||
// This happens - Removing it causes
|
|
||||||
// test_bug293235.xul to go orange.
|
|
||||||
: nsContentUtils::GetSafeJSContext();
|
|
||||||
globalObject = win;
|
|
||||||
} else {
|
} else {
|
||||||
// No DOM Window. Store the global and use the SafeJSContext.
|
cx = workers::GetCurrentThreadJSContext();
|
||||||
JSObject* glob = js::GetGlobalForObjectCrossCompartment(realCallback);
|
globalObject = workers::GetCurrentThreadWorkerPrivate()->GlobalScope();
|
||||||
globalObject = xpc::GetNativeForGlobal(glob);
|
|
||||||
MOZ_ASSERT(globalObject);
|
|
||||||
cx = nsContentUtils::GetSafeJSContext();
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
cx = workers::GetCurrentThreadJSContext();
|
|
||||||
globalObject = workers::GetCurrentThreadWorkerPrivate()->GlobalScope();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bail out if there's no useful global. This seems to happen intermittently
|
// Bail out if there's no useful global. This seems to happen intermittently
|
||||||
// on gaia-ui tests, probably because nsInProcessTabChildGlobal is returning
|
// on gaia-ui tests, probably because nsInProcessTabChildGlobal is returning
|
||||||
// null in some kind of teardown state.
|
// null in some kind of teardown state.
|
||||||
if (!globalObject->GetGlobalJSObject()) {
|
if (!globalObject->GetGlobalJSObject()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mAutoEntryScript.construct(globalObject, mIsMainThread, cx);
|
mAutoEntryScript.construct(globalObject, mIsMainThread, cx);
|
||||||
if (aCallback->IncumbentGlobalOrNull()) {
|
if (aCallback->IncumbentGlobalOrNull()) {
|
||||||
mAutoIncumbentScript.construct(aCallback->IncumbentGlobalOrNull());
|
mAutoIncumbentScript.construct(aCallback->IncumbentGlobalOrNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmark the callable (by invoking Callback() and not the CallbackPreserveColor()
|
// Unmark the callable (by invoking Callback() and not the CallbackPreserveColor()
|
||||||
// variant), and stick it in a Rooted before it can go gray again.
|
// variant), and stick it in a Rooted before it can go gray again.
|
||||||
// Nothing before us in this function can trigger a CC, so it's safe to wait
|
// Nothing before us in this function can trigger a CC, so it's safe to wait
|
||||||
// until here it do the unmark. This allows us to order the following two
|
// until here it do the unmark. This allows us to order the following two
|
||||||
// operations _after_ the Push() above, which lets us take advantage of the
|
// operations _after_ the Push() above, which lets us take advantage of the
|
||||||
// JSAutoRequest embedded in the pusher.
|
// JSAutoRequest embedded in the pusher.
|
||||||
//
|
//
|
||||||
// We can do this even though we're not in the right compartment yet, because
|
// We can do this even though we're not in the right compartment yet, because
|
||||||
// Rooted<> does not care about compartments.
|
// Rooted<> does not care about compartments.
|
||||||
mRootedCallable.construct(cx, aCallback->Callback());
|
mRootedCallable.construct(cx, aCallback->Callback());
|
||||||
|
}
|
||||||
|
|
||||||
if (mIsMainThread) {
|
if (mIsMainThread) {
|
||||||
// Check that it's ok to run this callback at all.
|
// Check that it's ok to run this callback at all.
|
||||||
|
@ -863,9 +863,10 @@ ContentChild::DeallocPIndexedDBChild(PIndexedDBChild* aActor)
|
|||||||
}
|
}
|
||||||
|
|
||||||
asmjscache::PAsmJSCacheEntryChild*
|
asmjscache::PAsmJSCacheEntryChild*
|
||||||
ContentChild::AllocPAsmJSCacheEntryChild(const asmjscache::OpenMode& aOpenMode,
|
ContentChild::AllocPAsmJSCacheEntryChild(
|
||||||
const int64_t& aSizeToWrite,
|
const asmjscache::OpenMode& aOpenMode,
|
||||||
const IPC::Principal& aPrincipal)
|
const asmjscache::WriteParams& aWriteParams,
|
||||||
|
const IPC::Principal& aPrincipal)
|
||||||
{
|
{
|
||||||
NS_NOTREACHED("Should never get here!");
|
NS_NOTREACHED("Should never get here!");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -167,7 +167,7 @@ public:
|
|||||||
|
|
||||||
virtual PAsmJSCacheEntryChild* AllocPAsmJSCacheEntryChild(
|
virtual PAsmJSCacheEntryChild* AllocPAsmJSCacheEntryChild(
|
||||||
const asmjscache::OpenMode& aOpenMode,
|
const asmjscache::OpenMode& aOpenMode,
|
||||||
const int64_t& aSizeToWrite,
|
const asmjscache::WriteParams& aWriteParams,
|
||||||
const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
|
const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
|
||||||
virtual bool DeallocPAsmJSCacheEntryChild(
|
virtual bool DeallocPAsmJSCacheEntryChild(
|
||||||
PAsmJSCacheEntryChild* aActor) MOZ_OVERRIDE;
|
PAsmJSCacheEntryChild* aActor) MOZ_OVERRIDE;
|
||||||
|
@ -2506,11 +2506,11 @@ ContentParent::DeallocPFMRadioParent(PFMRadioParent* aActor)
|
|||||||
|
|
||||||
asmjscache::PAsmJSCacheEntryParent*
|
asmjscache::PAsmJSCacheEntryParent*
|
||||||
ContentParent::AllocPAsmJSCacheEntryParent(
|
ContentParent::AllocPAsmJSCacheEntryParent(
|
||||||
const asmjscache::OpenMode& aOpenMode,
|
const asmjscache::OpenMode& aOpenMode,
|
||||||
const int64_t& aSizeToWrite,
|
const asmjscache::WriteParams& aWriteParams,
|
||||||
const IPC::Principal& aPrincipal)
|
const IPC::Principal& aPrincipal)
|
||||||
{
|
{
|
||||||
return asmjscache::AllocEntryParent(aOpenMode, aSizeToWrite, aPrincipal);
|
return asmjscache::AllocEntryParent(aOpenMode, aWriteParams, aPrincipal);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -384,7 +384,7 @@ private:
|
|||||||
|
|
||||||
virtual PAsmJSCacheEntryParent* AllocPAsmJSCacheEntryParent(
|
virtual PAsmJSCacheEntryParent* AllocPAsmJSCacheEntryParent(
|
||||||
const asmjscache::OpenMode& aOpenMode,
|
const asmjscache::OpenMode& aOpenMode,
|
||||||
const int64_t& aSizeToWrite,
|
const asmjscache::WriteParams& aWriteParams,
|
||||||
const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
|
const IPC::Principal& aPrincipal) MOZ_OVERRIDE;
|
||||||
virtual bool DeallocPAsmJSCacheEntryParent(
|
virtual bool DeallocPAsmJSCacheEntryParent(
|
||||||
PAsmJSCacheEntryParent* aActor) MOZ_OVERRIDE;
|
PAsmJSCacheEntryParent* aActor) MOZ_OVERRIDE;
|
||||||
|
@ -42,6 +42,7 @@ using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
|
|||||||
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
|
using struct mozilla::null_t from "ipc/IPCMessageUtils.h";
|
||||||
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
|
||||||
using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h";
|
using mozilla::dom::asmjscache::OpenMode from "mozilla/dom/asmjscache/AsmJSCache.h";
|
||||||
|
using mozilla::dom::asmjscache::WriteParams from "mozilla/dom/asmjscache/AsmJSCache.h";
|
||||||
using mozilla::dom::AudioChannelType from "AudioChannelCommon.h";
|
using mozilla::dom::AudioChannelType from "AudioChannelCommon.h";
|
||||||
using mozilla::dom::AudioChannelState from "AudioChannelCommon.h";
|
using mozilla::dom::AudioChannelState from "AudioChannelCommon.h";
|
||||||
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
|
using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
|
||||||
@ -372,8 +373,7 @@ parent:
|
|||||||
|
|
||||||
PFMRadio();
|
PFMRadio();
|
||||||
|
|
||||||
PAsmJSCacheEntry(OpenMode openMode, int64_t sizeToWrite,
|
PAsmJSCacheEntry(OpenMode openMode, WriteParams write, Principal principal);
|
||||||
Principal principal);
|
|
||||||
|
|
||||||
// Services remoting
|
// Services remoting
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ function browserLoadEvent() {
|
|||||||
setupStorage(gBrowserStorage.localStorage);
|
setupStorage(gBrowserStorage.localStorage);
|
||||||
setupStorage(gBrowserStorage.sessionStorage);
|
setupStorage(gBrowserStorage.sessionStorage);
|
||||||
|
|
||||||
frames[1].postMessage("clear", "http://www.example.com");
|
frames[1].postMessage("clear", "*");
|
||||||
|
|
||||||
waitForClearBrowserData();
|
waitForClearBrowserData();
|
||||||
};
|
};
|
||||||
|
@ -28,11 +28,11 @@ function onMessageReceived(event)
|
|||||||
// Indication of successfully finished step of a test
|
// Indication of successfully finished step of a test
|
||||||
case "perf":
|
case "perf":
|
||||||
if (callMasterFrame)
|
if (callMasterFrame)
|
||||||
masterFrame.postMessage("step", masterFrameOrigin);
|
masterFrame.postMessage("step", "*");
|
||||||
else if (slaveFrame)
|
else if (slaveFrame)
|
||||||
slaveFrame.postMessage("step", slaveFrameOrigin);
|
slaveFrame.postMessage("step", "*");
|
||||||
else if (SpecialPowers.wrap(masterFrame).slaveFrame)
|
else if (SpecialPowers.wrap(masterFrame).slaveFrame)
|
||||||
SpecialPowers.wrap(masterFrame).slaveFrame.postMessage("step", slaveFrameOrigin);
|
SpecialPowers.wrap(masterFrame).slaveFrame.postMessage("step", "*");
|
||||||
callMasterFrame = !callMasterFrame;
|
callMasterFrame = !callMasterFrame;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"expect-hazards": 1
|
"expect-hazards": 0
|
||||||
}
|
}
|
||||||
|
@ -751,11 +751,9 @@ GetCPUID(uint32_t *cpuId)
|
|||||||
class MachineId
|
class MachineId
|
||||||
{
|
{
|
||||||
uint32_t cpuId_;
|
uint32_t cpuId_;
|
||||||
js::Vector<char> buildId_;
|
JS::BuildIdCharVector buildId_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MachineId(ExclusiveContext *cx) : buildId_(cx) {}
|
|
||||||
|
|
||||||
bool extractCurrentState(ExclusiveContext *cx) {
|
bool extractCurrentState(ExclusiveContext *cx) {
|
||||||
if (!cx->asmJSCacheOps().buildId)
|
if (!cx->asmJSCacheOps().buildId)
|
||||||
return false;
|
return false;
|
||||||
@ -940,7 +938,7 @@ js::StoreAsmJSModuleInCache(AsmJSParser &parser,
|
|||||||
const AsmJSStaticLinkData &linkData,
|
const AsmJSStaticLinkData &linkData,
|
||||||
ExclusiveContext *cx)
|
ExclusiveContext *cx)
|
||||||
{
|
{
|
||||||
MachineId machineId(cx);
|
MachineId machineId;
|
||||||
if (!machineId.extractCurrentState(cx))
|
if (!machineId.extractCurrentState(cx))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -999,7 +997,7 @@ js::LookupAsmJSModuleInCache(ExclusiveContext *cx,
|
|||||||
{
|
{
|
||||||
int64_t usecBefore = PRMJ_Now();
|
int64_t usecBefore = PRMJ_Now();
|
||||||
|
|
||||||
MachineId machineId(cx);
|
MachineId machineId;
|
||||||
if (!machineId.extractCurrentState(cx))
|
if (!machineId.extractCurrentState(cx))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -1016,7 +1014,7 @@ js::LookupAsmJSModuleInCache(ExclusiveContext *cx,
|
|||||||
|
|
||||||
const uint8_t *cursor = entry.memory;
|
const uint8_t *cursor = entry.memory;
|
||||||
|
|
||||||
MachineId cachedMachineId(cx);
|
MachineId cachedMachineId;
|
||||||
cursor = cachedMachineId.deserialize(cx, cursor);
|
cursor = cachedMachineId.deserialize(cx, cursor);
|
||||||
if (!cursor)
|
if (!cursor)
|
||||||
return false;
|
return false;
|
||||||
|
@ -4683,13 +4683,16 @@ typedef void
|
|||||||
(* CloseAsmJSCacheEntryForWriteOp)(HandleObject global, size_t size, uint8_t *memory,
|
(* CloseAsmJSCacheEntryForWriteOp)(HandleObject global, size_t size, uint8_t *memory,
|
||||||
intptr_t handle);
|
intptr_t handle);
|
||||||
|
|
||||||
|
typedef js::Vector<char, 0, js::SystemAllocPolicy> BuildIdCharVector;
|
||||||
|
|
||||||
// Return the buildId (represented as a sequence of characters) associated with
|
// Return the buildId (represented as a sequence of characters) associated with
|
||||||
// the currently-executing build. If the JS engine is embedded such that a
|
// the currently-executing build. If the JS engine is embedded such that a
|
||||||
// single cache entry can be observed by different compiled versions of the JS
|
// single cache entry can be observed by different compiled versions of the JS
|
||||||
// engine, it is critical that the buildId shall change for each new build of
|
// engine, it is critical that the buildId shall change for each new build of
|
||||||
// the JS engine.
|
// the JS engine.
|
||||||
|
|
||||||
typedef bool
|
typedef bool
|
||||||
(* BuildIdOp)(js::Vector<char> *buildId);
|
(* BuildIdOp)(BuildIdCharVector *buildId);
|
||||||
|
|
||||||
struct AsmJSCacheOps
|
struct AsmJSCacheOps
|
||||||
{
|
{
|
||||||
|
@ -5236,7 +5236,7 @@ ShellCloseAsmJSCacheEntryForWrite(HandleObject global, size_t serializedSize, ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
ShellBuildId(js::Vector<char> *buildId)
|
ShellBuildId(JS::BuildIdCharVector *buildId)
|
||||||
{
|
{
|
||||||
// The browser embeds the date into the buildid and the buildid is embedded
|
// The browser embeds the date into the buildid and the buildid is embedded
|
||||||
// in the binary, so every 'make' necessarily builds a new firefox binary.
|
// in the binary, so every 'make' necessarily builds a new firefox binary.
|
||||||
|
@ -8,7 +8,6 @@ support-files =
|
|||||||
chrome_wrappers_helper.html
|
chrome_wrappers_helper.html
|
||||||
file1_bug629227.html
|
file1_bug629227.html
|
||||||
file2_bug629227.html
|
file2_bug629227.html
|
||||||
file_asmjs.js
|
|
||||||
file_bug505915.html
|
file_bug505915.html
|
||||||
file_bug650273.html
|
file_bug650273.html
|
||||||
file_bug658560.html
|
file_bug658560.html
|
||||||
@ -36,11 +35,6 @@ support-files =
|
|||||||
test1_bug629331.html
|
test1_bug629331.html
|
||||||
test2_bug629331.html
|
test2_bug629331.html
|
||||||
|
|
||||||
[test_asmjs.html]
|
|
||||||
# bug 929498
|
|
||||||
skip-if = os == 'android'
|
|
||||||
[test_asmjs2.html]
|
|
||||||
[test_asmjs3.html]
|
|
||||||
[test_bug384632.html]
|
[test_bug384632.html]
|
||||||
[test_bug390488.html]
|
[test_bug390488.html]
|
||||||
[test_bug393269.html]
|
[test_bug393269.html]
|
||||||
|
@ -1025,15 +1025,20 @@ nsDocumentViewer::LoadComplete(nsresult aStatus)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that the document has loaded, we can tell the presshell
|
if (!mStopped) {
|
||||||
// to unsuppress painting.
|
if (mDocument) {
|
||||||
if (mPresShell && !mStopped) {
|
mDocument->ScrollToRef();
|
||||||
nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell);
|
}
|
||||||
mPresShell->UnsuppressPainting();
|
|
||||||
// mPresShell could have been removed now, see bug 378682/421432
|
// Now that the document has loaded, we can tell the presshell
|
||||||
|
// to unsuppress painting.
|
||||||
if (mPresShell) {
|
if (mPresShell) {
|
||||||
mPresShell->ScrollToAnchor();
|
nsCOMPtr<nsIPresShell> shellDeathGrip(mPresShell);
|
||||||
mPresShell->LoadComplete();
|
mPresShell->UnsuppressPainting();
|
||||||
|
// mPresShell could have been removed now, see bug 378682/421432
|
||||||
|
if (mPresShell) {
|
||||||
|
mPresShell->LoadComplete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
layout/reftests/scrolling/deferred-anchor-ref.html
Normal file
14
layout/reftests/scrolling/deferred-anchor-ref.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0;">
|
||||||
|
<div>
|
||||||
|
<div style="height: 50px; width: 50px; background-color: red;"></div>
|
||||||
|
<div style="height: 1000px;"></div>
|
||||||
|
<div id="d" style="height: 50px; width: 50px; background-color: green;"></div>
|
||||||
|
<div style="height: 1000px;"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
17
layout/reftests/scrolling/deferred-anchor.html
Normal file
17
layout/reftests/scrolling/deferred-anchor.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<script>
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.onload = function() {
|
||||||
|
document.body.appendChild(document.importNode(this.responseXML.getElementsByTagName("div")[0], true));
|
||||||
|
};
|
||||||
|
xhr.open("get", "deferred-anchor-ref.html");
|
||||||
|
xhr.responseType = "document";
|
||||||
|
xhr.send();
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0;">
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,3 +1,4 @@
|
|||||||
|
== deferred-anchor.html#d deferred-anchor-ref.html#d
|
||||||
HTTP == fixed-1.html fixed-1.html?ref
|
HTTP == fixed-1.html fixed-1.html?ref
|
||||||
HTTP == fixed-opacity-1.html fixed-opacity-1.html?ref
|
HTTP == fixed-opacity-1.html fixed-opacity-1.html?ref
|
||||||
skip-if(B2G) HTTP == fixed-opacity-2.html fixed-opacity-2.html?ref
|
skip-if(B2G) HTTP == fixed-opacity-2.html fixed-opacity-2.html?ref
|
||||||
|
@ -16,8 +16,7 @@ using namespace mozilla::net;
|
|||||||
nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &host, int32_t port,
|
nsHttpConnectionInfo::nsHttpConnectionInfo(const nsACString &host, int32_t port,
|
||||||
nsProxyInfo* proxyInfo,
|
nsProxyInfo* proxyInfo,
|
||||||
bool usingSSL)
|
bool usingSSL)
|
||||||
: mRef(0)
|
: mProxyInfo(proxyInfo)
|
||||||
, mProxyInfo(proxyInfo)
|
|
||||||
, mUsingSSL(usingSSL)
|
, mUsingSSL(usingSSL)
|
||||||
, mUsingConnect(false)
|
, mUsingConnect(false)
|
||||||
{
|
{
|
||||||
|
@ -25,27 +25,11 @@ public:
|
|||||||
nsProxyInfo* proxyInfo,
|
nsProxyInfo* proxyInfo,
|
||||||
bool usingSSL=false);
|
bool usingSSL=false);
|
||||||
|
|
||||||
~nsHttpConnectionInfo()
|
virtual ~nsHttpConnectionInfo()
|
||||||
{
|
{
|
||||||
PR_LOG(gHttpLog, 4, ("Destroying nsHttpConnectionInfo @%x\n", this));
|
PR_LOG(gHttpLog, 4, ("Destroying nsHttpConnectionInfo @%x\n", this));
|
||||||
}
|
}
|
||||||
|
|
||||||
nsrefcnt AddRef()
|
|
||||||
{
|
|
||||||
nsrefcnt n = ++mRef;
|
|
||||||
NS_LOG_ADDREF(this, n, "nsHttpConnectionInfo", sizeof(*this));
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsrefcnt Release()
|
|
||||||
{
|
|
||||||
nsrefcnt n = --mRef;
|
|
||||||
NS_LOG_RELEASE(this, n, "nsHttpConnectionInfo");
|
|
||||||
if (n == 0)
|
|
||||||
delete this;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nsAFlatCString &HashKey() const { return mHashKey; }
|
const nsAFlatCString &HashKey() const { return mHashKey; }
|
||||||
|
|
||||||
void SetOriginServer(const nsACString &host, int32_t port);
|
void SetOriginServer(const nsACString &host, int32_t port);
|
||||||
@ -96,7 +80,6 @@ public:
|
|||||||
bool HostIsLocalIPLiteral() const;
|
bool HostIsLocalIPLiteral() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mozilla::ThreadSafeAutoRefCnt mRef;
|
|
||||||
nsCString mHashKey;
|
nsCString mHashKey;
|
||||||
nsCString mHost;
|
nsCString mHost;
|
||||||
int32_t mPort;
|
int32_t mPort;
|
||||||
@ -104,6 +87,9 @@ private:
|
|||||||
bool mUsingHttpProxy;
|
bool mUsingHttpProxy;
|
||||||
bool mUsingSSL;
|
bool mUsingSSL;
|
||||||
bool mUsingConnect; // if will use CONNECT with http proxy
|
bool mUsingConnect; // if will use CONNECT with http proxy
|
||||||
|
|
||||||
|
// for nsRefPtr
|
||||||
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHttpConnectionInfo)
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsHttpConnectionInfo_h__
|
#endif // nsHttpConnectionInfo_h__
|
||||||
|
Loading…
Reference in New Issue
Block a user