Merge m-c to b2g-inbound

This commit is contained in:
Wes Kocher 2014-01-07 18:29:03 -08:00
commit 6bd3a94ee1
44 changed files with 1102 additions and 246 deletions

View File

@ -1,4 +1,4 @@
{ {
"revision": "53a930e0a23a6d2b0b53baea9a609359683758ab", "revision": "9960daf91c384990c4bbe7c1221905db7536596b",
"repo_path": "/integration/gaia-central" "repo_path": "/integration/gaia-central"
} }

View File

@ -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");
}, },
/** /**

View File

@ -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

View File

@ -8821,6 +8821,10 @@ void
nsDocument::ScrollToRef() nsDocument::ScrollToRef()
{ {
if (mScrolledToRefAlready) { if (mScrolledToRefAlready) {
nsCOMPtr<nsIPresShell> shell = GetShell();
if (shell) {
shell->ScrollToAnchor();
}
return; return;
} }

View File

@ -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(&currentBuildId);
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

View File

@ -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

View File

@ -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__();

View File

@ -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'
] ]

View 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'

View 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']

View 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>

View File

@ -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();

View File

@ -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.

View File

@ -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

View File

@ -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',

View File

@ -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

View 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);
}

View File

@ -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,

View 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>

View File

@ -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]

View 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>

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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();
}; };

View File

@ -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;

View File

@ -1,3 +1,3 @@
{ {
"expect-hazards": 1 "expect-hazards": 0
} }

View File

@ -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;

View File

@ -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
{ {

View File

@ -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.

View File

@ -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]

View File

@ -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();
}
} }
} }

View 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>

View 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>

View File

@ -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

View File

@ -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)
{ {

View File

@ -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__