From c3c054cb1e4704e9289e522fa549b0e98fe37dae Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 10 Jun 2015 13:07:40 -0700 Subject: [PATCH 01/49] Bug 1172784 (part 1) - Remove unused argument from UnmarkGrayJSListenersInCCGenerationDocuments(). r=mccr8. This is possible because ListenerEnumerator() doesn't do anything with the |aArg| argument. --HG-- extra : rebase_source : f0f489c3adfc21e249fe7ece2b7dbdbaafae406e --- dom/base/nsCCUncollectableMarker.cpp | 2 +- dom/base/nsContentUtils.cpp | 4 ++-- dom/base/nsContentUtils.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dom/base/nsCCUncollectableMarker.cpp b/dom/base/nsCCUncollectableMarker.cpp index 37c42155395e..b8056779ac74 100644 --- a/dom/base/nsCCUncollectableMarker.cpp +++ b/dom/base/nsCCUncollectableMarker.cpp @@ -432,7 +432,7 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic, switch(sFSState) { case eUnmarkJSEventListeners: { - nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(sGeneration); + nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(); break; } case eUnmarkMessageManagers: { diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 67822c78c5af..9fa4f3e27b19 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -4002,11 +4002,11 @@ ListenerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aEntry, } void -nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments(uint32_t aGeneration) +nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments() { if (sEventListenerManagersHash) { PL_DHashTableEnumerate(sEventListenerManagersHash, ListenerEnumerator, - &aGeneration); + nullptr); } } diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 92b9bd963ca7..6ab02face49d 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -1124,7 +1124,7 @@ public: static mozilla::EventListenerManager* GetExistingListenerManagerForNode(const nsINode* aNode); - static void UnmarkGrayJSListenersInCCGenerationDocuments(uint32_t aGeneration); + static void UnmarkGrayJSListenersInCCGenerationDocuments(); /** * Remove the eventlistener manager for aNode. From 369266e5821fe1aee3532541580ce6b5607c060f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 10 Jun 2015 13:07:40 -0700 Subject: [PATCH 02/49] Bug 1172784 (part 2) - Remove PL_DHashTableEnumerate use from nsContentUtils. r=mccr8. --HG-- extra : rebase_source : cc59f7012458d80ed3c70e15c975ac0669471945 --- dom/base/nsContentUtils.cpp | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 9fa4f3e27b19..922866c59760 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -3985,29 +3985,22 @@ nsContentUtils::MaybeFireNodeRemoved(nsINode* aChild, nsINode* aParent, } } -PLDHashOperator -ListenerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aEntry, - uint32_t aNumber, void* aArg) +void +nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments() { - EventListenerManagerMapEntry* entry = - static_cast(aEntry); - if (entry) { + if (!sEventListenerManagersHash) { + return; + } + + PLDHashTable::Iterator iter(sEventListenerManagersHash); + while (iter.HasMoreEntries()) { + auto entry = static_cast(iter.NextEntry()); nsINode* n = static_cast(entry->mListenerManager->GetTarget()); if (n && n->IsInDoc() && nsCCUncollectableMarker::InGeneration(n->OwnerDoc()->GetMarkedCCGeneration())) { entry->mListenerManager->MarkForCC(); } } - return PL_DHASH_NEXT; -} - -void -nsContentUtils::UnmarkGrayJSListenersInCCGenerationDocuments() -{ - if (sEventListenerManagersHash) { - PL_DHashTableEnumerate(sEventListenerManagersHash, ListenerEnumerator, - nullptr); - } } /* static */ From f781334cb277ad5e9504e3abd0fd42bfcd3deb28 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Mon, 15 Jun 2015 10:22:54 +0800 Subject: [PATCH 03/49] Bug 1173248 - Remove the workaround introduced to MDSM by bug 951278. r=cpearce. --- dom/media/MediaDecoderStateMachine.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index a22400ec9d66..38fa3b34ca98 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -2970,11 +2970,7 @@ void MediaDecoderStateMachine::AdvanceFrame() int64_t delta = currentFrame->mTime - clock_time; TimeStamp presTime = nowTime + TimeDuration::FromMicroseconds(delta / mPlaybackRate); NS_ASSERTION(currentFrame->mTime >= mStartTime, "Should have positive frame time"); - // Filter out invalid frames by checking the frame time. FrameTime could be - // zero if it's a initial frame. - int64_t frameTime = currentFrame->mTime - mStartTime; - if (frameTime > 0 || (frameTime == 0 && mPlayDuration == 0) || - IsRealTime()) { + { ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor()); // If we have video, we want to increment the clock in steps of the frame // duration. From 0544e6bf2cf58eba6d06c9452fa6009ee875651b Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Sun, 14 Jun 2015 21:37:12 -0700 Subject: [PATCH 04/49] Bug 1164714 - Move netwerk/test/TestSTSParser.cpp into security/manager/ssl/tests/. r=keeler --HG-- rename : netwerk/test/TestSTSParser.cpp => security/manager/ssl/tests/compiled/TestSTSParser.cpp --- netwerk/test/moz.build | 1 - .../manager/ssl/tests/compiled}/TestSTSParser.cpp | 0 security/manager/ssl/tests/compiled/moz.build | 8 ++++++-- 3 files changed, 6 insertions(+), 3 deletions(-) rename {netwerk/test => security/manager/ssl/tests/compiled}/TestSTSParser.cpp (100%) diff --git a/netwerk/test/moz.build b/netwerk/test/moz.build index 372967315547..35813296f9a6 100644 --- a/netwerk/test/moz.build +++ b/netwerk/test/moz.build @@ -48,7 +48,6 @@ GeckoSimplePrograms([ CppUnitTests([ 'TestBind', 'TestCookie', - 'TestSTSParser', 'TestUDPSocket', ]) diff --git a/netwerk/test/TestSTSParser.cpp b/security/manager/ssl/tests/compiled/TestSTSParser.cpp similarity index 100% rename from netwerk/test/TestSTSParser.cpp rename to security/manager/ssl/tests/compiled/TestSTSParser.cpp diff --git a/security/manager/ssl/tests/compiled/moz.build b/security/manager/ssl/tests/compiled/moz.build index 26829651e102..4f33a156556d 100644 --- a/security/manager/ssl/tests/compiled/moz.build +++ b/security/manager/ssl/tests/compiled/moz.build @@ -4,6 +4,10 @@ # 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/. -GeckoCppUnitTests([ - 'TestCertDB', +CppUnitTests([ + 'TestSTSParser', +]) + +GeckoCppUnitTests([ + 'TestCertDB', ]) From 61b1dc8e699351738517e8b5a3d3351c8e898b55 Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Sun, 14 Jun 2015 21:37:13 -0700 Subject: [PATCH 05/49] Bug 1174220 - Part 1: Remove capacity constructor of MediaLargeByteBuffer. r=jya --- dom/media/MediaData.cpp | 5 +++-- dom/media/MediaData.h | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dom/media/MediaData.cpp b/dom/media/MediaData.cpp index 8b02108c19fe..260f869a2524 100644 --- a/dom/media/MediaData.cpp +++ b/dom/media/MediaData.cpp @@ -490,9 +490,10 @@ MediaRawData::MediaRawData() , mData(nullptr) , mSize(0) , mCrypto(mCryptoInternal) - , mBuffer(new MediaLargeByteBuffer(RAW_DATA_DEFAULT_SIZE)) + , mBuffer(new MediaByteBuffer()) , mPadding(0) { + unused << mBuffer->SetCapacity(RAW_DATA_DEFAULT_SIZE, fallible); } MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize) @@ -500,7 +501,7 @@ MediaRawData::MediaRawData(const uint8_t* aData, size_t aSize) , mData(nullptr) , mSize(0) , mCrypto(mCryptoInternal) - , mBuffer(new MediaLargeByteBuffer(RAW_DATA_DEFAULT_SIZE)) + , mBuffer(new MediaByteBuffer()) , mPadding(0) { if (!EnsureCapacity(aSize)) { diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index 21868fce44f9..743eba7e4e29 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -413,8 +413,6 @@ private: // It is designed to share potentially big byte arrays. class MediaLargeByteBuffer : public FallibleTArray { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaLargeByteBuffer); - MediaLargeByteBuffer() = default; - explicit MediaLargeByteBuffer(size_t aCapacity) : FallibleTArray(aCapacity) {} private: ~MediaLargeByteBuffer() {} From 2d96c72f584d26c705e7d5b384f4c8f596bf8f6f Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Sun, 14 Jun 2015 21:37:13 -0700 Subject: [PATCH 06/49] Bug 1174220 - Part 2: Use MediaByteBuffer instead of MediaLargeByteBuffer. r=jya All MediaLargeByteBuffer calls already include the `mozilla::fallible` parameter so we can safely replace MediaLargeByteBuffer with MediaByteBuffer. --- dom/media/MediaData.h | 5 ++-- dom/media/fmp4/MP4Demuxer.cpp | 2 +- dom/media/fmp4/MP4Demuxer.h | 2 +- dom/media/mediasource/ContainerParser.cpp | 24 +++++++++---------- dom/media/mediasource/ContainerParser.h | 12 +++++----- dom/media/mediasource/ResourceQueue.cpp | 6 ++--- dom/media/mediasource/ResourceQueue.h | 6 ++--- dom/media/mediasource/SourceBuffer.cpp | 6 ++--- dom/media/mediasource/SourceBuffer.h | 10 ++++---- .../mediasource/SourceBufferContentManager.h | 2 +- .../mediasource/SourceBufferResource.cpp | 2 +- dom/media/mediasource/SourceBufferResource.h | 4 ++-- dom/media/mediasource/TrackBuffer.cpp | 8 +++---- dom/media/mediasource/TrackBuffer.h | 8 +++---- dom/media/mediasource/TrackBuffersManager.cpp | 12 +++++----- dom/media/mediasource/TrackBuffersManager.h | 8 +++---- media/libstagefright/binding/BufferStream.cpp | 4 ++-- .../include/mp4_demuxer/BufferStream.h | 6 ++--- 18 files changed, 63 insertions(+), 64 deletions(-) diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index 743eba7e4e29..e0ace84b8a0e 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -22,7 +22,6 @@ class Image; class ImageContainer; } -class MediaLargeByteBuffer; class MediaByteBuffer; // Container that holds media samples. @@ -369,7 +368,7 @@ private: explicit MediaRawDataWriter(MediaRawData* aMediaRawData); bool EnsureSize(size_t aSize); MediaRawData* mTarget; - nsRefPtr mBuffer; + nsRefPtr mBuffer; }; class MediaRawData : public MediaData { @@ -403,7 +402,7 @@ private: // read as required by some data decoders. // Returns false if memory couldn't be allocated. bool EnsureCapacity(size_t aSize); - nsRefPtr mBuffer; + nsRefPtr mBuffer; CryptoSample mCryptoInternal; uint32_t mPadding; MediaRawData(const MediaRawData&); // Not implemented diff --git a/dom/media/fmp4/MP4Demuxer.cpp b/dom/media/fmp4/MP4Demuxer.cpp index 6328cfb460ed..24cc2daf12ff 100644 --- a/dom/media/fmp4/MP4Demuxer.cpp +++ b/dom/media/fmp4/MP4Demuxer.cpp @@ -20,7 +20,7 @@ namespace mozilla { MP4Demuxer::MP4Demuxer(MediaResource* aResource) : mResource(aResource) , mStream(new mp4_demuxer::ResourceStream(aResource)) - , mInitData(new MediaLargeByteBuffer) + , mInitData(new MediaByteBuffer) { } diff --git a/dom/media/fmp4/MP4Demuxer.h b/dom/media/fmp4/MP4Demuxer.h index 57bbd744444b..b0838a4d4de4 100644 --- a/dom/media/fmp4/MP4Demuxer.h +++ b/dom/media/fmp4/MP4Demuxer.h @@ -51,7 +51,7 @@ private: friend class MP4TrackDemuxer; nsRefPtr mResource; nsRefPtr mStream; - nsRefPtr mInitData; + nsRefPtr mInitData; UniquePtr mMetadata; nsTArray> mDemuxers; }; diff --git a/dom/media/mediasource/ContainerParser.cpp b/dom/media/mediasource/ContainerParser.cpp index 24b78db8da79..18152c0fae4b 100644 --- a/dom/media/mediasource/ContainerParser.cpp +++ b/dom/media/mediasource/ContainerParser.cpp @@ -37,7 +37,7 @@ ContainerParser::ContainerParser(const nsACString& aType) } bool -ContainerParser::IsInitSegmentPresent(MediaLargeByteBuffer* aData) +ContainerParser::IsInitSegmentPresent(MediaByteBuffer* aData) { MSE_DEBUG(ContainerParser, "aLength=%u [%x%x%x%x]", aData->Length(), @@ -49,7 +49,7 @@ return false; } bool -ContainerParser::IsMediaSegmentPresent(MediaLargeByteBuffer* aData) +ContainerParser::IsMediaSegmentPresent(MediaByteBuffer* aData) { MSE_DEBUG(ContainerParser, "aLength=%u [%x%x%x%x]", aData->Length(), @@ -61,7 +61,7 @@ ContainerParser::IsMediaSegmentPresent(MediaLargeByteBuffer* aData) } bool -ContainerParser::ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData, +ContainerParser::ParseStartAndEndTimestamps(MediaByteBuffer* aData, int64_t& aStart, int64_t& aEnd) { return false; @@ -86,7 +86,7 @@ ContainerParser::HasCompleteInitData() return mHasInitData && !!mInitData->Length(); } -MediaLargeByteBuffer* +MediaByteBuffer* ContainerParser::InitData() { return mInitData; @@ -121,7 +121,7 @@ public: static const unsigned NS_PER_USEC = 1000; static const unsigned USEC_PER_SEC = 1000000; - bool IsInitSegmentPresent(MediaLargeByteBuffer* aData) override + bool IsInitSegmentPresent(MediaByteBuffer* aData) override { ContainerParser::IsInitSegmentPresent(aData); // XXX: This is overly primitive, needs to collect data as it's appended @@ -144,7 +144,7 @@ public: return false; } - bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData) override + bool IsMediaSegmentPresent(MediaByteBuffer* aData) override { ContainerParser::IsMediaSegmentPresent(aData); // XXX: This is overly primitive, needs to collect data as it's appended @@ -165,7 +165,7 @@ public: return false; } - bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData, + bool ParseStartAndEndTimestamps(MediaByteBuffer* aData, int64_t& aStart, int64_t& aEnd) override { bool initSegment = IsInitSegmentPresent(aData); @@ -173,7 +173,7 @@ public: mOffset = 0; mParser = WebMBufferedParser(0); mOverlappedMapping.Clear(); - mInitData = new MediaLargeByteBuffer(); + mInitData = new MediaByteBuffer(); mResource = new SourceBufferResource(NS_LITERAL_CSTRING("video/webm")); } @@ -258,7 +258,7 @@ public: , mMonitor("MP4ContainerParser Index Monitor") {} - bool IsInitSegmentPresent(MediaLargeByteBuffer* aData) override + bool IsInitSegmentPresent(MediaByteBuffer* aData) override { ContainerParser::IsInitSegmentPresent(aData); // Each MP4 atom has a chunk size and chunk type. The root chunk in an MP4 @@ -278,7 +278,7 @@ public: (*aData)[7] == 'p'; } - bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData) override + bool IsMediaSegmentPresent(MediaByteBuffer* aData) override { ContainerParser::IsMediaSegmentPresent(aData); if (aData->Length() < 8) { @@ -298,7 +298,7 @@ public: (*aData)[7] == 'x'); } - bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData, + bool ParseStartAndEndTimestamps(MediaByteBuffer* aData, int64_t& aStart, int64_t& aEnd) override { MonitorAutoLock mon(mMonitor); // We're not actually racing against anything, @@ -312,7 +312,7 @@ public: // manually. This allows the ContainerParser to be shared across different // timestampOffsets. mParser = new mp4_demuxer::MoofParser(mStream, 0, /* aIsAudio = */ false, &mMonitor); - mInitData = new MediaLargeByteBuffer(); + mInitData = new MediaByteBuffer(); } else if (!mStream || !mParser) { return false; } diff --git a/dom/media/mediasource/ContainerParser.h b/dom/media/mediasource/ContainerParser.h index e567723845b7..4ef737e23697 100644 --- a/dom/media/mediasource/ContainerParser.h +++ b/dom/media/mediasource/ContainerParser.h @@ -13,7 +13,7 @@ namespace mozilla { -class MediaLargeByteBuffer; +class MediaByteBuffer; class SourceBufferResource; class ContainerParser { @@ -24,17 +24,17 @@ public: // Return true if aData starts with an initialization segment. // The base implementation exists only for debug logging and is expected // to be called first from the overriding implementation. - virtual bool IsInitSegmentPresent(MediaLargeByteBuffer* aData); + virtual bool IsInitSegmentPresent(MediaByteBuffer* aData); // Return true if aData starts with a media segment. // The base implementation exists only for debug logging and is expected // to be called first from the overriding implementation. - virtual bool IsMediaSegmentPresent(MediaLargeByteBuffer* aData); + virtual bool IsMediaSegmentPresent(MediaByteBuffer* aData); // Parse aData to extract the start and end frame times from the media // segment. aData may not start on a parser sync boundary. Return true // if aStart and aEnd have been updated. - virtual bool ParseStartAndEndTimestamps(MediaLargeByteBuffer* aData, + virtual bool ParseStartAndEndTimestamps(MediaByteBuffer* aData, int64_t& aStart, int64_t& aEnd); // Compare aLhs and rHs, considering any error that may exist in the @@ -44,7 +44,7 @@ public: virtual int64_t GetRoundingError(); - MediaLargeByteBuffer* InitData(); + MediaByteBuffer* InitData(); bool HasInitData() { @@ -65,7 +65,7 @@ public: static ContainerParser* CreateForMIMEType(const nsACString& aType); protected: - nsRefPtr mInitData; + nsRefPtr mInitData; nsRefPtr mResource; bool mHasInitData; MediaByteRange mCompleteInitSegmentRange; diff --git a/dom/media/mediasource/ResourceQueue.cpp b/dom/media/mediasource/ResourceQueue.cpp index 83f4ee07808b..6f670d5203fd 100644 --- a/dom/media/mediasource/ResourceQueue.cpp +++ b/dom/media/mediasource/ResourceQueue.cpp @@ -20,7 +20,7 @@ extern PRLogModuleInfo* GetSourceBufferResourceLog(); namespace mozilla { -ResourceItem::ResourceItem(MediaLargeByteBuffer* aData) +ResourceItem::ResourceItem(MediaByteBuffer* aData) : mData(aData) { } @@ -82,7 +82,7 @@ ResourceQueue::CopyData(uint64_t aOffset, uint32_t aCount, char* aDest) } void -ResourceQueue::AppendItem(MediaLargeByteBuffer* aData) +ResourceQueue::AppendItem(MediaByteBuffer* aData) { mLogicalLength += aData->Length(); Push(new ResourceItem(aData)); @@ -111,7 +111,7 @@ uint32_t ResourceQueue::EvictBefore(uint64_t aOffset, ErrorResult& aRv) uint32_t offset = aOffset - mOffset; mOffset += offset; evicted += offset; - nsRefPtr data = new MediaLargeByteBuffer; + nsRefPtr data = new MediaByteBuffer; if (!data->AppendElements(item->mData->Elements() + offset, item->mData->Length() - offset, fallible)) { diff --git a/dom/media/mediasource/ResourceQueue.h b/dom/media/mediasource/ResourceQueue.h index 1ff26d00c549..de49cdc8e493 100644 --- a/dom/media/mediasource/ResourceQueue.h +++ b/dom/media/mediasource/ResourceQueue.h @@ -26,9 +26,9 @@ class ErrorResult; // timepoint. struct ResourceItem { - explicit ResourceItem(MediaLargeByteBuffer* aData); + explicit ResourceItem(MediaByteBuffer* aData); size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; - nsRefPtr mData; + nsRefPtr mData; }; class ResourceQueue : private nsDeque { @@ -45,7 +45,7 @@ public: // Copies aCount bytes from aOffset in the queue into aDest. void CopyData(uint64_t aOffset, uint32_t aCount, char* aDest); - void AppendItem(MediaLargeByteBuffer* aData); + void AppendItem(MediaByteBuffer* aData); // Tries to evict at least aSizeToEvict from the queue up until // aOffset. Returns amount evicted. diff --git a/dom/media/mediasource/SourceBuffer.cpp b/dom/media/mediasource/SourceBuffer.cpp index 1b21c9d65f01..84af6d49eb02 100644 --- a/dom/media/mediasource/SourceBuffer.cpp +++ b/dom/media/mediasource/SourceBuffer.cpp @@ -433,7 +433,7 @@ SourceBuffer::AppendData(const uint8_t* aData, uint32_t aLength, ErrorResult& aR { MSE_DEBUG("AppendData(aLength=%u)", aLength); - nsRefPtr data = PrepareAppend(aData, aLength, aRv); + nsRefPtr data = PrepareAppend(aData, aLength, aRv); if (!data) { return; } @@ -536,7 +536,7 @@ SourceBuffer::AppendError(bool aDecoderError) } } -already_AddRefed +already_AddRefed SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult& aRv) { typedef SourceBufferContentManager::EvictDataResult Result; @@ -584,7 +584,7 @@ SourceBuffer::PrepareAppend(const uint8_t* aData, uint32_t aLength, ErrorResult& return nullptr; } - nsRefPtr data = new MediaLargeByteBuffer(); + nsRefPtr data = new MediaByteBuffer(); if (!data->AppendElements(aData, aLength, fallible)) { aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR); return nullptr; diff --git a/dom/media/mediasource/SourceBuffer.h b/dom/media/mediasource/SourceBuffer.h index 719c0ffda428..c3134915efe2 100644 --- a/dom/media/mediasource/SourceBuffer.h +++ b/dom/media/mediasource/SourceBuffer.h @@ -32,7 +32,7 @@ struct JSContext; namespace mozilla { class ErrorResult; -class MediaLargeByteBuffer; +class MediaByteBuffer; template class AsyncEventRunner; class TrackBuffersManager; @@ -157,11 +157,11 @@ private: // http://w3c.github.io/media-source/#sourcebuffer-append-error void AppendError(bool aDecoderError); - // Implements the "Prepare Append Algorithm". Returns MediaLargeByteBuffer object + // Implements the "Prepare Append Algorithm". Returns MediaByteBuffer object // on success or nullptr (with aRv set) on error. - already_AddRefed PrepareAppend(const uint8_t* aData, - uint32_t aLength, - ErrorResult& aRv); + already_AddRefed PrepareAppend(const uint8_t* aData, + uint32_t aLength, + ErrorResult& aRv); void AppendDataCompletedWithSuccess(bool aHasActiveTracks); void AppendDataErrored(nsresult aError); diff --git a/dom/media/mediasource/SourceBufferContentManager.h b/dom/media/mediasource/SourceBufferContentManager.h index 918d82aa87a3..8e6d6ecda169 100644 --- a/dom/media/mediasource/SourceBufferContentManager.h +++ b/dom/media/mediasource/SourceBufferContentManager.h @@ -33,7 +33,7 @@ public: // Add data to the end of the input buffer. // Returns false if the append failed. virtual bool - AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) = 0; + AppendData(MediaByteBuffer* aData, TimeUnit aTimestampOffset) = 0; // Run MSE Buffer Append Algorithm // 3.5.5 Buffer Append Algorithm. diff --git a/dom/media/mediasource/SourceBufferResource.cpp b/dom/media/mediasource/SourceBufferResource.cpp index 4946af56a285..4f91ed3afaa2 100644 --- a/dom/media/mediasource/SourceBufferResource.cpp +++ b/dom/media/mediasource/SourceBufferResource.cpp @@ -212,7 +212,7 @@ SourceBufferResource::EvictAll() } void -SourceBufferResource::AppendData(MediaLargeByteBuffer* aData) +SourceBufferResource::AppendData(MediaByteBuffer* aData) { SBR_DEBUG("AppendData(aData=%p, aLength=%u)", aData->Elements(), aData->Length()); diff --git a/dom/media/mediasource/SourceBufferResource.h b/dom/media/mediasource/SourceBufferResource.h index b2d922f53433..5eb82f9abfd4 100644 --- a/dom/media/mediasource/SourceBufferResource.h +++ b/dom/media/mediasource/SourceBufferResource.h @@ -27,7 +27,7 @@ class nsIStreamListener; namespace mozilla { class MediaDecoder; -class MediaLargeByteBuffer; +class MediaByteBuffer; namespace dom { @@ -103,7 +103,7 @@ public: } // Used by SourceBuffer. - void AppendData(MediaLargeByteBuffer* aData); + void AppendData(MediaByteBuffer* aData); void Ended(); bool IsEnded() { diff --git a/dom/media/mediasource/TrackBuffer.cpp b/dom/media/mediasource/TrackBuffer.cpp index 0f2d88add43f..4a1119506b35 100644 --- a/dom/media/mediasource/TrackBuffer.cpp +++ b/dom/media/mediasource/TrackBuffer.cpp @@ -139,7 +139,7 @@ TrackBuffer::ContinueShutdown() } bool -TrackBuffer::AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) +TrackBuffer::AppendData(MediaByteBuffer* aData, TimeUnit aTimestampOffset) { MOZ_ASSERT(NS_IsMainThread()); mInputBuffer = aData; @@ -162,7 +162,7 @@ TrackBuffer::BufferAppend() nsRefPtr p = mInitializationPromise.Ensure(__func__); bool hadInitData = mParser->HasInitData(); bool hadCompleteInitData = mParser->HasCompleteInitData(); - nsRefPtr oldInit = mParser->InitData(); + nsRefPtr oldInit = mParser->InitData(); bool newInitData = mParser->IsInitSegmentPresent(mInputBuffer); // TODO: Run more of the buffer append algorithm asynchronously. @@ -262,7 +262,7 @@ TrackBuffer::BufferAppend() } bool -TrackBuffer::AppendDataToCurrentResource(MediaLargeByteBuffer* aData, uint32_t aDuration) +TrackBuffer::AppendDataToCurrentResource(MediaByteBuffer* aData, uint32_t aDuration) { MOZ_ASSERT(NS_IsMainThread()); if (!mCurrentDecoder) { @@ -724,7 +724,7 @@ TrackBuffer::OnMetadataRead(MetadataHolder* aMetadata, // Adding an empty buffer will reopen the SourceBufferResource if (!aWasEnded) { - nsRefPtr emptyBuffer = new MediaLargeByteBuffer; + nsRefPtr emptyBuffer = new MediaByteBuffer; aDecoder->GetResource()->AppendData(emptyBuffer); } // HACK END. diff --git a/dom/media/mediasource/TrackBuffer.h b/dom/media/mediasource/TrackBuffer.h index 541d7dd230b8..90c00ec9c987 100644 --- a/dom/media/mediasource/TrackBuffer.h +++ b/dom/media/mediasource/TrackBuffer.h @@ -22,7 +22,7 @@ namespace mozilla { class ContainerParser; class MediaSourceDecoder; -class MediaLargeByteBuffer; +class MediaByteBuffer; class TrackBuffer final : public SourceBufferContentManager { public: @@ -30,7 +30,7 @@ public: nsRefPtr Shutdown(); - bool AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) override; + bool AppendData(MediaByteBuffer* aData, TimeUnit aTimestampOffset) override; // Append data to the current decoder. Also responsible for calling // NotifyDataArrived on the decoder to keep buffered range computation up @@ -119,7 +119,7 @@ private: // Helper for AppendData, ensures NotifyDataArrived is called whenever // data is appended to the current decoder's SourceBufferResource. - bool AppendDataToCurrentResource(MediaLargeByteBuffer* aData, + bool AppendDataToCurrentResource(MediaByteBuffer* aData, uint32_t aDuration /* microseconds */); // Queue on the parent's decoder task queue a call to NotifyTimeRangesChanged. void NotifyTimeRangesChanged(); @@ -163,7 +163,7 @@ private: SourceBufferDecoder* aDecoder); nsAutoPtr mParser; - nsRefPtr mInputBuffer; + nsRefPtr mInputBuffer; // A task queue using the shared media thread pool. Used exclusively to // initialize (i.e. call ReadMetadata on) decoders as they are created via diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index b948ca156bc4..d888030f1b9f 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -38,7 +38,7 @@ AppendStateToStr(TrackBuffersManager::AppendState aState) } TrackBuffersManager::TrackBuffersManager(dom::SourceBuffer* aParent, MediaSourceDecoder* aParentDecoder, const nsACString& aType) - : mInputBuffer(new MediaLargeByteBuffer) + : mInputBuffer(new MediaByteBuffer) , mAppendState(AppendState::WAITING_FOR_SEGMENT) , mBufferFull(false) , mFirstInitializationSegmentReceived(false) @@ -65,7 +65,7 @@ TrackBuffersManager::TrackBuffersManager(dom::SourceBuffer* aParent, MediaSource } bool -TrackBuffersManager::AppendData(MediaLargeByteBuffer* aData, +TrackBuffersManager::AppendData(MediaByteBuffer* aData, TimeUnit aTimestampOffset) { MOZ_ASSERT(NS_IsMainThread()); @@ -316,13 +316,13 @@ TrackBuffersManager::CompleteResetParserState() // during the next Segment Parser Loop and a new demuxer will be created and // initialized. if (mFirstInitializationSegmentReceived) { - nsRefPtr initData = mParser->InitData(); + nsRefPtr initData = mParser->InitData(); MOZ_ASSERT(initData->Length(), "we must have an init segment"); // The aim here is really to destroy our current demuxer. CreateDemuxerforMIMEType(); // Recreate our input buffer. We can't directly assign the initData buffer // to mInputBuffer as it will get modified in the Segment Parser Loop. - mInputBuffer = new MediaLargeByteBuffer; + mInputBuffer = new MediaByteBuffer; MOZ_ALWAYS_TRUE(mInputBuffer->AppendElements(*initData, fallible)); } RecreateParser(); @@ -927,7 +927,7 @@ TrackBuffersManager::CodedFrameProcessing() } else { // The mediaRange is offset by the init segment position previously added. length = mediaRange.mEnd - (mProcessedInput - mInputBuffer->Length()); - nsRefPtr segment = new MediaLargeByteBuffer; + nsRefPtr segment = new MediaByteBuffer; MOZ_ASSERT(mInputBuffer->Length() >= length); if (!segment->AppendElements(mInputBuffer->Elements(), length, fallible)) { return CodedFrameProcessingPromise::CreateAndReject(NS_ERROR_OUT_OF_MEMORY, __func__); @@ -1380,7 +1380,7 @@ TrackBuffersManager::RecreateParser() // as it has parsed the entire InputBuffer provided. // Once the old TrackBuffer/MediaSource implementation is removed // we can optimize this part. TODO - nsRefPtr initData = mParser->InitData(); + nsRefPtr initData = mParser->InitData(); mParser = ContainerParser::CreateForMIMEType(mType); if (initData) { int64_t start, end; diff --git a/dom/media/mediasource/TrackBuffersManager.h b/dom/media/mediasource/TrackBuffersManager.h index 0eb57a4a4117..fb79afde3121 100644 --- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -20,7 +20,7 @@ namespace mozilla { class ContainerParser; -class MediaLargeByteBuffer; +class MediaByteBuffer; class MediaRawData; class MediaSourceDemuxer; class SourceBuffer; @@ -40,7 +40,7 @@ public: TrackBuffersManager(dom::SourceBuffer* aParent, MediaSourceDecoder* aParentDecoder, const nsACString& aType); - bool AppendData(MediaLargeByteBuffer* aData, TimeUnit aTimestampOffset) override; + bool AppendData(MediaByteBuffer* aData, TimeUnit aTimestampOffset) override; nsRefPtr BufferAppend() override; @@ -116,12 +116,12 @@ private: return mAudioTracks.mNumTracks > 0; } - typedef Pair, TimeUnit> IncomingBuffer; + typedef Pair, TimeUnit> IncomingBuffer; void AppendIncomingBuffer(IncomingBuffer aData); nsTArray mIncomingBuffers; // The input buffer as per http://w3c.github.io/media-source/index.html#sourcebuffer-input-buffer - nsRefPtr mInputBuffer; + nsRefPtr mInputBuffer; // The current append state as per https://w3c.github.io/media-source/#sourcebuffer-append-state // Accessed on both the main thread and the task queue. Atomic mAppendState; diff --git a/media/libstagefright/binding/BufferStream.cpp b/media/libstagefright/binding/BufferStream.cpp index 01801c278d2c..5e30ebcc7e8b 100644 --- a/media/libstagefright/binding/BufferStream.cpp +++ b/media/libstagefright/binding/BufferStream.cpp @@ -13,11 +13,11 @@ namespace mp4_demuxer { BufferStream::BufferStream() : mStartOffset(0) - , mData(new mozilla::MediaLargeByteBuffer) + , mData(new mozilla::MediaByteBuffer) { } -BufferStream::BufferStream(mozilla::MediaLargeByteBuffer* aBuffer) +BufferStream::BufferStream(mozilla::MediaByteBuffer* aBuffer) : mStartOffset(0) , mData(aBuffer) { diff --git a/media/libstagefright/binding/include/mp4_demuxer/BufferStream.h b/media/libstagefright/binding/include/mp4_demuxer/BufferStream.h index 4544d5177d83..659027d22c72 100644 --- a/media/libstagefright/binding/include/mp4_demuxer/BufferStream.h +++ b/media/libstagefright/binding/include/mp4_demuxer/BufferStream.h @@ -10,7 +10,7 @@ #include "MediaResource.h" namespace mozilla { -class MediaLargeByteBuffer; +class MediaByteBuffer; } namespace mp4_demuxer { @@ -22,7 +22,7 @@ public: * Therefore BufferStream shouldn't get used after aData is destroyed. */ BufferStream(); - explicit BufferStream(mozilla::MediaLargeByteBuffer* aBuffer); + explicit BufferStream(mozilla::MediaByteBuffer* aBuffer); virtual bool ReadAt(int64_t aOffset, void* aData, size_t aLength, size_t* aBytesRead) override; @@ -39,7 +39,7 @@ public: private: ~BufferStream(); int64_t mStartOffset; - nsRefPtr mData; + nsRefPtr mData; }; } From 04a761af4ff399881734eb3d2d024c00e0f350ae Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Sun, 14 Jun 2015 21:37:13 -0700 Subject: [PATCH 07/49] Bug 1174220 - Part 3: Remove MediaLargeByteBuffer. r=jya --- dom/media/MediaData.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/dom/media/MediaData.h b/dom/media/MediaData.h index e0ace84b8a0e..93e0526fd084 100644 --- a/dom/media/MediaData.h +++ b/dom/media/MediaData.h @@ -408,15 +408,6 @@ private: MediaRawData(const MediaRawData&); // Not implemented }; - // MediaLargeByteBuffer is a ref counted fallible TArray. - // It is designed to share potentially big byte arrays. -class MediaLargeByteBuffer : public FallibleTArray { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaLargeByteBuffer); - -private: - ~MediaLargeByteBuffer() {} -}; - // MediaByteBuffer is a ref counted infallible TArray. class MediaByteBuffer : public nsTArray { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaByteBuffer); From da2704a55c7a4fa982525a0e905f21e1847b108f Mon Sep 17 00:00:00 2001 From: Kyle Fung Date: Fri, 12 Jun 2015 17:28:25 -0400 Subject: [PATCH 08/49] Bug 1160070 - Used BitmapBrush instead of ImageBrush when no sampling bounds. r=bas --- gfx/2d/DrawTargetD2D1.cpp | 47 ++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/gfx/2d/DrawTargetD2D1.cpp b/gfx/2d/DrawTargetD2D1.cpp index 4a402cc6c886..b543bb0f94f7 100644 --- a/gfx/2d/DrawTargetD2D1.cpp +++ b/gfx/2d/DrawTargetD2D1.cpp @@ -1453,29 +1453,46 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha) D2D1_RECT_F samplingBounds; Matrix mat = pat->mMatrix; - bool useSamplingRect = false; - if (!pat->mSamplingRect.IsEmpty() && - (pat->mSurface->GetType() == SurfaceType::D2D1_1_IMAGE)) { - samplingBounds = D2DRect(pat->mSamplingRect); - mat.PreTranslate(pat->mSamplingRect.x, pat->mSamplingRect.y); - } else if (!pat->mSamplingRect.IsEmpty()) { - // We will do a partial upload of the sampling restricted area from GetImageForSurface. - samplingBounds = D2D1::RectF(0, 0, pat->mSamplingRect.width, pat->mSamplingRect.height); - } else { - samplingBounds = D2D1::RectF(0, 0, - Float(pat->mSurface->GetSize().width), - Float(pat->mSurface->GetSize().height)); - } - MOZ_ASSERT(pat->mSurface->IsValid()); - RefPtr imageBrush; RefPtr image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode, !pat->mSamplingRect.IsEmpty() ? &pat->mSamplingRect : nullptr); if (!image) { return CreateTransparentBlackBrush(); } + bool useSamplingRect = false; + if (pat->mSamplingRect.IsEmpty()) { + RefPtr bitmap; + image->QueryInterface((ID2D1Bitmap**)byRef(bitmap)); + if (bitmap) { + RefPtr bitmapBrush; + mDC->CreateBitmapBrush(bitmap, + D2D1::BitmapBrushProperties(D2DExtend(pat->mExtendMode), + D2DExtend(pat->mExtendMode), + D2DFilter(pat->mFilter)), + D2D1::BrushProperties(aAlpha, D2DMatrix(mat)), + byRef(bitmapBrush)); + if (!bitmapBrush) { + gfxWarning() << "Couldn't create bitmap brush!"; + return CreateTransparentBlackBrush(); + } + return bitmapBrush.forget(); + } + } + + RefPtr imageBrush; + if (pat->mSamplingRect.IsEmpty()) { + samplingBounds = D2D1::RectF(0, 0, + Float(pat->mSurface->GetSize().width), + Float(pat->mSurface->GetSize().height)); + } else if (pat->mSurface->GetType() == SurfaceType::D2D1_1_IMAGE) { + samplingBounds = D2DRect(pat->mSamplingRect); + mat.PreTranslate(pat->mSamplingRect.x, pat->mSamplingRect.y); + } else { + // We will do a partial upload of the sampling restricted area from GetImageForSurface. + samplingBounds = D2D1::RectF(0, 0, pat->mSamplingRect.width, pat->mSamplingRect.height); + } mDC->CreateImageBrush(image, D2D1::ImageBrushProperties(samplingBounds, D2DExtend(pat->mExtendMode), From 7a032efd9ba456cbce5ca296315e8addaecd0b56 Mon Sep 17 00:00:00 2001 From: Tim Chien Date: Thu, 21 May 2015 20:13:00 +0200 Subject: [PATCH 09/49] Bug 1162360 - Dispatches focus and blur message synchronously, r=yxl --- dom/inputmethod/forms.js | 39 +-------- .../mochitest/file_test_contenteditable.html | 17 ---- dom/inputmethod/mochitest/mochitest.ini | 1 - .../mochitest/test_bug1059163.html | 40 +++++---- dom/inputmethod/mochitest/test_sync_edit.html | 36 +++++--- .../mochitest/test_two_inputs.html | 76 +++++++++-------- .../mochitest/test_two_selects.html | 85 +++++++++++++------ 7 files changed, 151 insertions(+), 143 deletions(-) delete mode 100644 dom/inputmethod/mochitest/file_test_contenteditable.html diff --git a/dom/inputmethod/forms.js b/dom/inputmethod/forms.js index a5e3b125a02a..bf5ebd7346e9 100644 --- a/dom/inputmethod/forms.js +++ b/dom/inputmethod/forms.js @@ -18,10 +18,6 @@ XPCOMUtils.defineLazyServiceGetter(Services, "fm", "@mozilla.org/focus-manager;1", "nsIFocusManager"); -XPCOMUtils.defineLazyServiceGetter(Services, "threadManager", - "@mozilla.org/thread-manager;1", - "nsIThreadManager"); - XPCOMUtils.defineLazyGetter(this, "domWindowUtils", function () { return content.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindowUtils); @@ -461,13 +457,6 @@ let FormAssistant = { } }, - waitForNextTick: function(callback) { - var tm = Services.threadManager; - tm.mainThread.dispatch({ - run: callback, - }, Components.interfaces.nsIThread.DISPATCH_NORMAL); - }, - receiveMessage: function fa_receiveMessage(msg) { let target = this.focusedElement; let json = msg.json; @@ -682,35 +671,13 @@ let FormAssistant = { target = target.parentNode; this.setFocusedElement(target); - - let count = this._focusCounter; - this.waitForNextTick(function fa_handleFocusSync() { - if (count !== this._focusCounter) { - return; - } - - let isHandlingFocus = this.sendInputState(target); - this.isHandlingFocus = isHandlingFocus; - }.bind(this)); + this.isHandlingFocus = this.sendInputState(target); }, unhandleFocus: function fa_unhandleFocus() { this.setFocusedElement(null); - - let count = this._focusCounter; - - // Wait for the next tick before unset the focused element and etc. - // If the user move from one input from another, - // the remote process should get one Forms:Input message instead of two. - this.waitForNextTick(function fa_unhandleFocusSync() { - if (count !== this._focusCounter || - !this.isHandlingFocus) { - return; - } - - this.isHandlingFocus = false; - sendAsyncMessage("Forms:Input", { "type": "blur" }); - }.bind(this)); + this.isHandlingFocus = false; + sendAsyncMessage("Forms:Input", { "type": "blur" }); }, isFocusableElement: function fa_isFocusableElement(element) { diff --git a/dom/inputmethod/mochitest/file_test_contenteditable.html b/dom/inputmethod/mochitest/file_test_contenteditable.html deleted file mode 100644 index c7492e513565..000000000000 --- a/dom/inputmethod/mochitest/file_test_contenteditable.html +++ /dev/null @@ -1,17 +0,0 @@ - - - -
Jan Jongboom
- - - diff --git a/dom/inputmethod/mochitest/mochitest.ini b/dom/inputmethod/mochitest/mochitest.ini index 9d39987cc1f8..b3e3d0d0066d 100644 --- a/dom/inputmethod/mochitest/mochitest.ini +++ b/dom/inputmethod/mochitest/mochitest.ini @@ -6,7 +6,6 @@ support-files = file_inputmethod.html file_inputmethod_1043828.html file_test_app.html - file_test_contenteditable.html file_test_sendkey_cancel.html file_test_sms_app.html file_test_sms_app_1066515.html diff --git a/dom/inputmethod/mochitest/test_bug1059163.html b/dom/inputmethod/mochitest/test_bug1059163.html index 77c0a575c543..79da5d973e9d 100644 --- a/dom/inputmethod/mochitest/test_bug1059163.html +++ b/dom/inputmethod/mochitest/test_bug1059163.html @@ -20,8 +20,20 @@ inputmethod_setup(function() { // The frame script running in the file function appFrameScript() { + let document = content.document; + let window = content.document.defaultView; + + let t = document.getElementById('text'); + t.focus(); + + let range = document.createRange(); + range.selectNodeContents(t); + range.collapse(false); + let selection = window.getSelection(); + selection.removeAllRanges(); + selection.addRange(range); + addMessageListener('test:InputMethod:clear', function() { - var t = content.document.getElementById('text'); t.innerHTML = ''; }); } @@ -34,18 +46,26 @@ function runTest() { // Create an app frame to recieve keyboard inputs. let app = document.createElement('iframe'); - app.src = 'file_test_contenteditable.html'; + app.src = 'data:text/html,
Jan Jongboom
'; app.setAttribute('mozbrowser', true); document.body.appendChild(app); app.addEventListener('mozbrowserloadend', function() { let mm = SpecialPowers.getBrowserFrameMessageManager(app); + mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false); + + im.oninputcontextchange = function() { + if (im.inputcontext) { + im.oninputcontextchange = null; + register(); + } + }; function register() { im.inputcontext.onselectionchange = function() { im.inputcontext.onselectionchange = null; is(im.inputcontext.textBeforeCursor, '', 'textBeforeCursor'); - is(im.inputcontext.textBeforeCursor, '', 'textAfterCursor'); + is(im.inputcontext.textAfterCursor, '', 'textAfterCursor'); is(im.inputcontext.selectionStart, 0, 'selectionStart'); is(im.inputcontext.selectionEnd, 0, 'selectionEnd'); @@ -54,20 +74,6 @@ function runTest() { mm.sendAsyncMessage('test:InputMethod:clear'); } - - if (im.inputcontext) { - register(); - } - else { - im.oninputcontextchange = function() { - if (im.inputcontext) { - im.oninputcontextchange = null; - register(); - } - }; - } - - mm.loadFrameScript('data:,(' + appFrameScript.toString() + ')();', false); }); } diff --git a/dom/inputmethod/mochitest/test_sync_edit.html b/dom/inputmethod/mochitest/test_sync_edit.html index ac24b7d23f7e..f17d62e84952 100644 --- a/dom/inputmethod/mochitest/test_sync_edit.html +++ b/dom/inputmethod/mochitest/test_sync_edit.html @@ -25,10 +25,6 @@ let appFrameScript = function appFrameScript() { input.focus(); input.value = 'First1'; input.blur(); - - content.setTimeout(function() { - sendAsyncMessage('test:next', {}); - }); }; function runTest() { @@ -36,7 +32,32 @@ function runTest() { let i = 0; im.oninputcontextchange = function() { - ok(false, 'Should not receive any inputcontextchange events.'); + let inputcontext = im.inputcontext; + i++; + switch (i) { + case 1: + ok(!!inputcontext, 'Should receive inputcontext from focus().'); + is(inputcontext.textAfterCursor, 'First'); + + break; + + case 2: + ok(!!inputcontext, 'Should receive inputcontext from value change.'); + is(inputcontext.textBeforeCursor, 'First1'); + + break; + + case 3: + ok(!inputcontext, 'Should lost inputcontext from blur().'); + + inputmethod_cleanup(); + break; + + default: + ok(false, 'Unknown event count.'); + + inputmethod_cleanup(); + } }; // Set current page as an input method. @@ -48,11 +69,6 @@ function runTest() { document.body.appendChild(iframe); let mm = SpecialPowers.getBrowserFrameMessageManager(iframe); - mm.addMessageListener('test:next', function() { - ok(true, '\\o/'); - inputmethod_cleanup(); - }); - iframe.addEventListener('mozbrowserloadend', function() { mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false); }); diff --git a/dom/inputmethod/mochitest/test_two_inputs.html b/dom/inputmethod/mochitest/test_two_inputs.html index 8667ffbc05d2..343ae5802cdb 100644 --- a/dom/inputmethod/mochitest/test_two_inputs.html +++ b/dom/inputmethod/mochitest/test_two_inputs.html @@ -34,12 +34,7 @@ let appFrameScript = function appFrameScript() { switch (i) { case 2: input2.focus(); - - break; - - case 3: - input2.blur(); - input2.focus(); + i++; // keep the same count with the parent frame. break; @@ -50,23 +45,26 @@ let appFrameScript = function appFrameScript() { case 5: input2.focus(); - input2.blur(); - - input1.focus(); break; case 6: - content.document.body.removeChild(input1); - - break; - - case 7: - input2.focus(); + input1.focus(); + i++; // keep the same count with the parent frame. break; case 8: + content.document.body.removeChild(input1); + + break; + + case 9: + input2.focus(); + + break; + + case 10: content.document.body.removeChild(input2); break; @@ -85,26 +83,21 @@ function runTest() { switch (i) { // focus on the first input receives the first input context. case 1: - ok(!!inputcontext, 'Receving the first input context'); + ok(!!inputcontext, '1) Receving the first input context'); is(inputcontext.textAfterCursor, 'First'); mm.sendAsyncMessage('test:next'); break; - // focus on the second input (implicitly blur the first input) - // results the second input context. + // focus on the second input should implicitly blur the first input case 2: - ok(!!inputcontext, 'Receving the second input context'); - is(inputcontext.textAfterCursor, 'Second'); + is(inputcontext, null, '2) Receving null inputcontext'); - - mm.sendAsyncMessage('test:next'); break; - // blur and re-focus on the second input results updated - // input context for the second input. + // ... and results the second input context. case 3: - ok(!!inputcontext, 'Receving the second input context'); + ok(!!inputcontext, '3) Receving the second input context'); is(inputcontext.textAfterCursor, 'Second'); mm.sendAsyncMessage('test:next'); @@ -112,38 +105,51 @@ function runTest() { // blur on the second input results null input context case 4: - is(inputcontext, null, 'Receving null inputcontext'); + is(inputcontext, null, '4) Receving null inputcontext'); mm.sendAsyncMessage('test:next'); break; - // focus and blur on the second input sends no message; - // focus on the first input receives the first input context. + // focus on the second input receives the second input context. case 5: - ok(!!inputcontext, 'Receving the first input context'); + ok(!!inputcontext, '5) Receving the second input context'); + is(inputcontext.textAfterCursor, 'Second'); + + mm.sendAsyncMessage('test:next'); + break; + + // focus on the second input should implicitly blur the first input + case 6: + is(inputcontext, null, '6) Receving null inputcontext'); + + break; + + // ... and results the second input context. + case 7: + ok(!!inputcontext, '7) Receving the first input context'); is(inputcontext.textAfterCursor, 'First'); mm.sendAsyncMessage('test:next'); break; // remove on the first focused input results null input context - case 6: - is(inputcontext, null, 'Receving null inputcontext'); + case 8: + is(inputcontext, null, '8) Receving null inputcontext'); mm.sendAsyncMessage('test:next'); break; // input context for the second input. - case 7: - ok(!!inputcontext, 'Receving the second input context'); + case 9: + ok(!!inputcontext, '9) Receving the second input context'); is(inputcontext.textAfterCursor, 'Second'); mm.sendAsyncMessage('test:next'); break; // remove on the second focused input results null input context - case 8: - is(inputcontext, null, 'Receving null inputcontext'); + case 10: + is(inputcontext, null, '10) Receving null inputcontext'); inputmethod_cleanup(); break; diff --git a/dom/inputmethod/mochitest/test_two_selects.html b/dom/inputmethod/mochitest/test_two_selects.html index d3495e88a402..b6cc9aff8027 100644 --- a/dom/inputmethod/mochitest/test_two_selects.html +++ b/dom/inputmethod/mochitest/test_two_selects.html @@ -32,12 +32,7 @@ let appFrameScript = function appFrameScript() { switch (i) { case 2: select2.focus(); - - break; - - case 3: - select2.blur(); - select2.focus(); + i++; // keep the same count with the parent frame. break; @@ -48,14 +43,27 @@ let appFrameScript = function appFrameScript() { case 5: select2.focus(); - select2.blur(); - - select1.focus(); break; case 6: - select1.blur(); + select1.focus(); + i++; // keep the same count with the parent frame. + + break; + + case 8: + content.document.body.removeChild(select1); + + break; + + case 9: + select2.focus(); + + break; + + case 10: + content.document.body.removeChild(select2); break; } @@ -73,26 +81,21 @@ function runTest() { switch (i) { // focus on the first input receives the first input context. case 1: - ok(!!inputcontext, 'Receving the first input context'); + ok(!!inputcontext, '1) Receving the first input context'); is(inputcontext.textAfterCursor, 'First'); mm.sendAsyncMessage('test:next'); break; - // focus on the second input (implicitly blur the first input) - // results the second input context. + // focus on the second input should implicitly blur the first input case 2: - ok(!!inputcontext, 'Receving the second input context'); - is(inputcontext.textAfterCursor, 'Second'); + is(inputcontext, null, '2) Receving null inputcontext'); - - mm.sendAsyncMessage('test:next'); break; - // blur and re-focus on the second input results updated - // input context for the second input. + // ... and results the second input context. case 3: - ok(!!inputcontext, 'Receving the second input context'); + ok(!!inputcontext, '3) Receving the second input context'); is(inputcontext.textAfterCursor, 'Second'); mm.sendAsyncMessage('test:next'); @@ -100,23 +103,51 @@ function runTest() { // blur on the second input results null input context case 4: - is(inputcontext, null, 'Receving null inputcontext'); + is(inputcontext, null, '4) Receving null inputcontext'); mm.sendAsyncMessage('test:next'); break; - // focus and blur on the second input sends no message; - // focus on the first input receives the first input context. + // focus on the second input receives the second input context. case 5: - ok(!!inputcontext, 'Receving the first input context'); + ok(!!inputcontext, '5) Receving the second input context'); + is(inputcontext.textAfterCursor, 'Second'); + + mm.sendAsyncMessage('test:next'); + break; + + // focus on the second input should implicitly blur the first input + case 6: + is(inputcontext, null, '6) Receving null inputcontext'); + + break; + + // ... and results the second input context. + case 7: + ok(!!inputcontext, '7) Receving the first input context'); is(inputcontext.textAfterCursor, 'First'); mm.sendAsyncMessage('test:next'); break; - // blur on the first input results null input context - case 6: - is(inputcontext, null, 'Receving null inputcontext'); + // remove on the first focused input results null input context + case 8: + is(inputcontext, null, '8) Receving null inputcontext'); + + mm.sendAsyncMessage('test:next'); + break; + + // input context for the second input. + case 9: + ok(!!inputcontext, '9) Receving the second input context'); + is(inputcontext.textAfterCursor, 'Second'); + + mm.sendAsyncMessage('test:next'); + break; + + // remove on the second focused input results null input context + case 10: + is(inputcontext, null, '10) Receving null inputcontext'); inputmethod_cleanup(); break; From cfd306a839048380b5386982853cc4bc0bbf3dec Mon Sep 17 00:00:00 2001 From: Cykesiopka Date: Sat, 13 Jun 2015 00:51:00 +0200 Subject: [PATCH 10/49] Bug 1171820 - Convert test_bug483440.html mochitest to an xpcshell test. r=keeler --HG-- rename : security/manager/ssl/tests/mochitest/bugs/test_bug483440.html => security/manager/ssl/tests/unit/test_certviewer_invalid_oids.js rename : build/pgo/certs/bug483440-attack2b.ca => security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack2b.pem rename : build/pgo/certs/bug483440-attack7.ca => security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack7.pem rename : build/pgo/certs/bug483440-pk10oflo.ca => security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-pk10oflo.pem --- .../ssl/tests/mochitest/bugs/mochitest.ini | 2 - .../tests/mochitest/bugs/test_bug483440.html | 62 ------------------- .../unit/test_certviewer_invalid_oids.js | 62 +++++++++++++++++++ .../bug483440-attack2b.pem | 0 .../bug483440-attack7.pem | 0 .../bug483440-pk10oflo.pem | 0 security/manager/ssl/tests/unit/xpcshell.ini | 3 + 7 files changed, 65 insertions(+), 64 deletions(-) delete mode 100644 security/manager/ssl/tests/mochitest/bugs/test_bug483440.html create mode 100644 security/manager/ssl/tests/unit/test_certviewer_invalid_oids.js rename build/pgo/certs/bug483440-attack2b.ca => security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack2b.pem (100%) rename build/pgo/certs/bug483440-attack7.ca => security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack7.pem (100%) rename build/pgo/certs/bug483440-pk10oflo.ca => security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-pk10oflo.pem (100%) diff --git a/security/manager/ssl/tests/mochitest/bugs/mochitest.ini b/security/manager/ssl/tests/mochitest/bugs/mochitest.ini index bfe32ea79da7..e18e6979c8d6 100644 --- a/security/manager/ssl/tests/mochitest/bugs/mochitest.ini +++ b/security/manager/ssl/tests/mochitest/bugs/mochitest.ini @@ -4,5 +4,3 @@ skip-if = buildapp == 'b2g' || e10s [test_bug480509.html] skip-if = toolkit == 'android' -[test_bug483440.html] -skip-if = toolkit == 'android' diff --git a/security/manager/ssl/tests/mochitest/bugs/test_bug483440.html b/security/manager/ssl/tests/mochitest/bugs/test_bug483440.html deleted file mode 100644 index 657aa9826658..000000000000 --- a/security/manager/ssl/tests/mochitest/bugs/test_bug483440.html +++ /dev/null @@ -1,62 +0,0 @@ - - - Test bug 483437 and bug 480509 - - - - - - - - - diff --git a/security/manager/ssl/tests/unit/test_certviewer_invalid_oids.js b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids.js new file mode 100644 index 000000000000..2c244aad7fb8 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids.js @@ -0,0 +1,62 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +// 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/. +"use strict"; + +// Checks that invalid OID encodings are detected in the Cert Viewer Details tab. + +do_get_profile(); // Must be called before getting nsIX509CertDB +const certDB = Cc["@mozilla.org/security/x509certdb;1"] + .getService(Ci.nsIX509CertDB); + +function certFromFile(filename) { + return constructCertFromFile(`test_certviewer_invalid_oids/${filename}.pem`); +} + +function test(certFilename, expectedOIDText) { + let cert = certFromFile(certFilename); + let certDumpTree = Cc["@mozilla.org/security/nsASN1Tree;1"] + .createInstance(Ci.nsIASN1Tree); + certDumpTree.loadASN1Structure(cert.ASN1Structure); + let actualOIDText = certDumpTree.getDisplayData(9); + + equal(actualOIDText, expectedOIDText, + "Actual and expected OID text should match"); +} + +function run_test() { + test("bug483440-attack2b", + "Object Identifier (2 5 4 Unknown) = www.bank.com\n" + + "OU = Hacking Division\n" + + "CN = www.badguy.com\nO = Badguy Inc\n"); + + test("bug483440-pk10oflo", + "Object Identifier (2 5 4 Unknown) = www.bank.com\n" + + "OU = Hacking Division\n" + + "CN = www.badguy.com\nO = Badguy Inc\n"); + + test("bug483440-attack7", + + // Check 88 80 80 80 01, not leading, have to pass + "Object Identifier (2 5 4 2147483649) = attack1\n" + + + // Check 90 80 80 80 01, not leading, have to fail + "Object Identifier (2 5 4 Unknown) = attack2\n" + + + // Check 80 80 80 80 80, not leading, have to fail + "Object Identifier (2 5 4 Unknown) = attack3\n" + + + // Check 81 81, trailing, have to fail + "Object Identifier (2 5 4 3 Unknown) = attack4\n" + + + // Check FF FF FF 7F, not leading, have to pass + "Object Identifier (2 5 4 268435455) = attack5\n" + + + // Check 80 leading, have to fail + "Object Identifier (Unknown 3) = attack6\n" + + + // Check 14757 = 2*40 + 14677 leading single byte encoded as F325, + // have to pass + "Object Identifier (2 14677 4 3) = attack7\n"); +} diff --git a/build/pgo/certs/bug483440-attack2b.ca b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack2b.pem similarity index 100% rename from build/pgo/certs/bug483440-attack2b.ca rename to security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack2b.pem diff --git a/build/pgo/certs/bug483440-attack7.ca b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack7.pem similarity index 100% rename from build/pgo/certs/bug483440-attack7.ca rename to security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-attack7.pem diff --git a/build/pgo/certs/bug483440-pk10oflo.ca b/security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-pk10oflo.pem similarity index 100% rename from build/pgo/certs/bug483440-pk10oflo.ca rename to security/manager/ssl/tests/unit/test_certviewer_invalid_oids/bug483440-pk10oflo.pem diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini index f8b0790876b3..cc3740541c2d 100644 --- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -7,6 +7,7 @@ support-files = test_signed_apps/** tlsserver/** test_cert_signatures/** + test_certviewer_invalid_oids/** test_client_cert/** test_ev_certs/** test_getchain/** @@ -129,3 +130,5 @@ run-sequentially = hardcoded ports run-sequentially = hardcoded ports [test_nsIX509Cert_utf8.js] [test_constructX509FromBase64.js] +[test_certviewer_invalid_oids.js] +skip-if = toolkit == 'android' || buildapp == 'b2g' From 10c812cd9d0488af62d945febaaf025122586857 Mon Sep 17 00:00:00 2001 From: Blake Wu Date: Fri, 12 Jun 2015 22:23:33 +0800 Subject: [PATCH 11/49] Bug 1174166 - Support H.263 in Gonk PDM. r=sotaro --- dom/media/platforms/gonk/GonkDecoderModule.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dom/media/platforms/gonk/GonkDecoderModule.cpp b/dom/media/platforms/gonk/GonkDecoderModule.cpp index b95010778e4d..7b8aad1b2c7d 100644 --- a/dom/media/platforms/gonk/GonkDecoderModule.cpp +++ b/dom/media/platforms/gonk/GonkDecoderModule.cpp @@ -68,6 +68,7 @@ GonkDecoderModule::SupportsMimeType(const nsACString& aMimeType) aMimeType.EqualsLiteral("audio/amr-wb") || aMimeType.EqualsLiteral("video/mp4") || aMimeType.EqualsLiteral("video/mp4v-es") || - aMimeType.EqualsLiteral("video/avc"); + aMimeType.EqualsLiteral("video/avc") || + aMimeType.EqualsLiteral("video/3gpp"); } } // namespace mozilla From 930111242884ee29b4ba6ecdf076e4fcf10377d0 Mon Sep 17 00:00:00 2001 From: Amod Narvekar Date: Thu, 11 Jun 2015 10:15:00 +0200 Subject: [PATCH 12/49] Bug 1061813 - Added a check to test whether this.currentTest.scope.test is a function. r=jmaher --- testing/mochitest/browser-test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testing/mochitest/browser-test.js b/testing/mochitest/browser-test.js index 7258f21c4990..48dd88f1db69 100644 --- a/testing/mochitest/browser-test.js +++ b/testing/mochitest/browser-test.js @@ -766,8 +766,10 @@ Tester.prototype = { var result = this.currentTest.scope.generatorTest(); this.currentTest.scope.__generator = result; result.next(); - } else { + } else if (typeof this.currentTest.scope.test == "function") { this.currentTest.scope.test(); + } else { + throw "This test didn't call add_task, nor did it define a generatorTest() function, nor did it define a test() function, so we don't know how to run it."; } } catch (ex) { let isExpected = !!this.SimpleTest.isExpectingUncaughtException(); From 630008d522cd1e07297b994510fad5bcdd7c972c Mon Sep 17 00:00:00 2001 From: chunminchang Date: Fri, 12 Jun 2015 18:01:00 +0200 Subject: [PATCH 13/49] Bug 1141415 - add expire setting of permission to SpecialPowers. r=jmaher --- .../tests/Harness_sanity/mochitest.ini | 2 + .../specialPowers_framescript.js | 13 ++++ .../test_SpecialPowersPushPermissions.html | 74 ++++++++++++++++++- .../content/SpecialPowersObserverAPI.js | 2 +- .../specialpowers/content/specialpowersAPI.js | 22 +++++- 5 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 testing/mochitest/tests/Harness_sanity/specialPowers_framescript.js diff --git a/testing/mochitest/tests/Harness_sanity/mochitest.ini b/testing/mochitest/tests/Harness_sanity/mochitest.ini index 44ef14efc7f8..6d55c20121c1 100644 --- a/testing/mochitest/tests/Harness_sanity/mochitest.ini +++ b/testing/mochitest/tests/Harness_sanity/mochitest.ini @@ -12,6 +12,8 @@ skip-if = (toolkit == 'android' && processor == 'x86') #x86 only [test_SpecialPowersExtension2.html] support-files = file_SpecialPowersFrame1.html [test_SpecialPowersPushPermissions.html] +support-files = + specialPowers_framescript.js [test_SpecialPowersPushAppPermissions.html] support-files = file_app.sjs diff --git a/testing/mochitest/tests/Harness_sanity/specialPowers_framescript.js b/testing/mochitest/tests/Harness_sanity/specialPowers_framescript.js new file mode 100644 index 000000000000..da1b87782a49 --- /dev/null +++ b/testing/mochitest/tests/Harness_sanity/specialPowers_framescript.js @@ -0,0 +1,13 @@ +Components.utils.import("resource://gre/modules/Services.jsm"); + +var permChangedObs = { + observe: function(subject, topic, data) { + if (topic == 'perm-changed') { + var permission = subject.QueryInterface(Components.interfaces.nsIPermission); + var msg = { op: data, type: permission.type }; + sendAsyncMessage('perm-changed', msg); + } + } +}; + +Services.obs.addObserver(permChangedObs, 'perm-changed', false); diff --git a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html index 9f48359abe8f..194ee4b3052d 100644 --- a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html +++ b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushPermissions.html @@ -17,6 +17,17 @@ const ACCESS_SESSION = SpecialPowers.Ci.nsICookiePermission.ACCESS_SESSION; const ACCESS_ALLOW_FIRST_PARTY_ONLY = SpecialPowers.Ci.nsICookiePermission.ACCESS_ALLOW_FIRST_PARTY_ONLY; const ACCESS_LIMIT_THIRD_PARTY = SpecialPowers.Ci.nsICookiePermission.ACCESS_LIMIT_THIRD_PARTY; +const EXPIRE_TIME = SpecialPowers.Ci.nsIPermissionManager.EXPIRE_TIME; +var start; +const DELAY = 500; +// PR_Now() that called in nsPermissionManager to get the system time and +// Date.now() are out of sync on win32 platform(XP/win7). The PR_Now() is +// 15~20ms less than Date.now(). Unfortunately, this time skew can't be +// avoided, so it needs to add a time buffer to compensate. +const TIME_SKEW = 100; +var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('specialPowers_framescript.js')); +SimpleTest.requestFlakyTimeout("untriaged"); + function starttest(){ SpecialPowers.addPermission("pPROMPT", PROMPT_ACTION, document); SpecialPowers.addPermission("pALLOW", ALLOW_ACTION, document); @@ -136,9 +147,70 @@ function test6() { dump('/**** pTHIRDPARTY still set ****/\n'); setTimeout(test6, 0); } else { - SimpleTest.finish(); + test7(); } } + +function test7() { + afterPermissionChanged('pEXPIRE', 'deleted', test8); + afterPermissionChanged('pEXPIRE', 'added', permissionPollingCheck); + start = Number(Date.now()); + SpecialPowers.addPermission('pEXPIRE', true, document, EXPIRE_TIME, start + DELAY); +} + +function test8() { + afterPermissionChanged('pEXPIRE', 'deleted', SimpleTest.finish); + afterPermissionChanged('pEXPIRE', 'added', permissionPollingCheck); + start = Number(Date.now()); + SpecialPowers.pushPermissions([ + { 'type': 'pEXPIRE', + 'allow': true, + 'expireType': EXPIRE_TIME, + 'expireTime': start + DELAY, + 'context': document + }], function() { + info("Wait permission changed signal!"); + } + ); +} + +function afterPermissionChanged(type, op, callback) { + // handle the message from specialPowers_framescript.js + gScript.addMessageListener('perm-changed', function onChange(msg) { + if (msg.type == type && msg.op == op) { + gScript.removeMessageListener('perm-changed', onChange); + callback(); + } + }); +} + +function permissionPollingCheck() { + var now = Number(Date.now()); + if (now < start + DELAY) { + ok(SpecialPowers.testPermission('pEXPIRE', ALLOW_ACTION, document), + 'unexpired permission is still there!'); + setTimeout(permissionPollingCheck, DELAY); + return; + } + + if (SpecialPowers.testPermission('pEXPIRE', ALLOW_ACTION, document) && + (now < start + DELAY + TIME_SKEW) && + isWin32()) { + setTimeout(permissionPollingCheck, DELAY); + return; + } + + // The permission is already expired! + ok(!SpecialPowers.testPermission('pEXPIRE', ALLOW_ACTION, document), + 'expired permission should be removed!'); +} + +function isWin32() { + var version = SpecialPowers.Services.sysinfo.getProperty('version'); + version = parseFloat(version); + // version 5.1 is win XP, 6.1 is win7 + return (navigator.platform.indexOf('Win') == 0) && (version <= 6.1); +} diff --git a/testing/specialpowers/content/SpecialPowersObserverAPI.js b/testing/specialpowers/content/SpecialPowersObserverAPI.js index 42f4d0daa4c7..2baa5a5bd21e 100644 --- a/testing/specialpowers/content/SpecialPowersObserverAPI.js +++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js @@ -318,7 +318,7 @@ SpecialPowersObserverAPI.prototype = { switch (msg.op) { case "add": - Services.perms.addFromPrincipal(principal, msg.type, msg.permission); + Services.perms.addFromPrincipal(principal, msg.type, msg.permission, msg.expireType, msg.expireTime); break; case "remove": Services.perms.removeFromPrincipal(principal, msg.type); diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js index d1442c6955e7..59cd60b415ee 100644 --- a/testing/specialpowers/content/specialpowersAPI.js +++ b/testing/specialpowers/content/specialpowersAPI.js @@ -806,14 +806,26 @@ SpecialPowersAPI.prototype = { continue; } - var todo = {'op': 'add', 'type': permission.type, 'permission': perm, 'value': perm, 'url': url, 'appId': appId, 'isInBrowserElement': isInBrowserElement}; + var todo = {'op': 'add', + 'type': permission.type, + 'permission': perm, + 'value': perm, + 'url': url, + 'appId': appId, + 'isInBrowserElement': isInBrowserElement, + 'expireType': (typeof permission.expireType === "number") ? + permission.expireType : 0, // default: EXPIRE_NEVER + 'expireTime': (typeof permission.expireTime === "number") ? + permission.expireTime : 0}; + + var cleanupTodo = Object.assign({}, todo); + if (permission.remove == true) todo.op = 'remove'; pendingPermissions.push(todo); /* Push original permissions value or clear into cleanup array */ - var cleanupTodo = {'op': 'add', 'type': permission.type, 'permission': perm, 'value': perm, 'url': url, 'appId': appId, 'isInBrowserElement': isInBrowserElement}; if (originalValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) { cleanupTodo.op = 'remove'; } else { @@ -1866,7 +1878,7 @@ SpecialPowersAPI.prototype = { return [ url, appId, isInBrowserElement, isSystem ]; }, - addPermission: function(type, allow, arg) { + addPermission: function(type, allow, arg, expireType, expireTime) { let [url, appId, isInBrowserElement, isSystem] = this._getInfoFromPermissionArg(arg); if (isSystem) { return; // nothing to do @@ -1886,7 +1898,9 @@ SpecialPowersAPI.prototype = { 'permission': permission, 'url': url, 'appId': appId, - 'isInBrowserElement': isInBrowserElement + 'isInBrowserElement': isInBrowserElement, + 'expireType': (typeof expireType === "number") ? expireType : 0, + 'expireTime': (typeof expireTime === "number") ? expireTime : 0 }; this._sendSyncMessage('SPPermissionManager', msg); From 0597055c597ff6a5b3555ea1fc2b54c24a0ca773 Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Mon, 15 Jun 2015 16:01:39 +0900 Subject: [PATCH 14/49] Bug 1120851 - Set candidate window position for prediction even if no composition. r=masayuki --- widget/gtk/nsGtkIMModule.cpp | 54 +++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/widget/gtk/nsGtkIMModule.cpp b/widget/gtk/nsGtkIMModule.cpp index b80d273ef25e..dde1836a1274 100644 --- a/widget/gtk/nsGtkIMModule.cpp +++ b/widget/gtk/nsGtkIMModule.cpp @@ -547,6 +547,14 @@ nsGtkIMModule::OnUpdateComposition() return; } + if (!IsComposing()) { + // Composition has been committed. So we need update selection for + // caret + mSelection.Clear(); + EnsureToCacheSelection(); + mLayoutChanged = false; + } + // If we've already set candidate window position, we don't need to update // the position with update composition notification. if (!mLayoutChanged) { @@ -776,6 +784,12 @@ nsGtkIMModule::OnSelectionChange(nsWindow* aCaller, return; } + if (!IsComposing()) { + // Now we have no composition (mostly situation on calling this method) + // If we have it, it will set by NOTIFY_IME_OF_COMPOSITION_UPDATE. + SetCursorPosition(GetActiveContext()); + } + // The focused editor might have placeholder text with normal text node. // In such case, the text node must be removed from a compositionstart // event handler. So, we're dispatching NS_COMPOSITION_START, @@ -1417,15 +1431,21 @@ nsGtkIMModule::SetCursorPosition(GtkIMContext* aContext) MOZ_LOG(gGtkIMLog, LogLevel::Info, ("GtkIMModule(%p): SetCursorPosition, aContext=%p, " "mCompositionTargetRange={ mOffset=%u, mLength=%u }" - "mSelection.mWritingMode=%s", + "mSelection={ mOffset=%u, mLength=%u, mWritingMode=%s }", this, aContext, mCompositionTargetRange.mOffset, mCompositionTargetRange.mLength, + mSelection.mOffset, mSelection.mLength, GetWritingModeName(mSelection.mWritingMode).get())); + bool useCaret = false; if (!mCompositionTargetRange.IsValid()) { - MOZ_LOG(gGtkIMLog, LogLevel::Info, - (" FAILED, mCompositionTargetRange is invalid")); - return; + if (!mSelection.IsValid()) { + MOZ_LOG(gGtkIMLog, LogLevel::Info, + (" FAILED, mCompositionTargetRange and mSelection are " + "invalid")); + return; + } + useCaret = true; } if (!mLastFocusedWindow) { @@ -1440,23 +1460,31 @@ nsGtkIMModule::SetCursorPosition(GtkIMContext* aContext) return; } - WidgetQueryContentEvent charRect(true, NS_QUERY_TEXT_RECT, + WidgetQueryContentEvent charRect(true, + useCaret ? NS_QUERY_CARET_RECT : + NS_QUERY_TEXT_RECT, mLastFocusedWindow); - if (mSelection.mWritingMode.IsVertical()) { - // For preventing the candidate window to overlap the target clause, - // we should set fake (typically, very tall) caret rect. - uint32_t length = mCompositionTargetRange.mLength ? - mCompositionTargetRange.mLength : 1; - charRect.InitForQueryTextRect(mCompositionTargetRange.mOffset, length); + if (useCaret) { + charRect.InitForQueryCaretRect(mSelection.mOffset); } else { - charRect.InitForQueryTextRect(mCompositionTargetRange.mOffset, 1); + if (mSelection.mWritingMode.IsVertical()) { + // For preventing the candidate window to overlap the target + // clause, we should set fake (typically, very tall) caret rect. + uint32_t length = mCompositionTargetRange.mLength ? + mCompositionTargetRange.mLength : 1; + charRect.InitForQueryTextRect(mCompositionTargetRange.mOffset, + length); + } else { + charRect.InitForQueryTextRect(mCompositionTargetRange.mOffset, 1); + } } InitEvent(charRect); nsEventStatus status; mLastFocusedWindow->DispatchEvent(&charRect, status); if (!charRect.mSucceeded) { MOZ_LOG(gGtkIMLog, LogLevel::Info, - (" FAILED, NS_QUERY_TEXT_RECT was failed")); + (" FAILED, %s was failed", + useCaret ? "NS_QUERY_CARET_RECT" : "NS_QUERY_TEXT_RECT")); return; } From 80880ed6821b10df399efeba40097781cc96a6d4 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Mon, 15 Jun 2015 11:48:15 +0200 Subject: [PATCH 15/49] Bug 1172076 - Switch compartment before computing recover instruction results. r=jandem --- js/src/jit/JitFrames.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index fedfb51b8a5f..b96be72e4ec4 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -2183,6 +2183,8 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback& fallback) JitFrameLayout* fp = fallback.frame->jsFrame(); RInstructionResults* results = fallback.activation->maybeIonFrameRecovery(fp); if (!results) { + AutoCompartment ac(cx, fallback.frame->script()->compartment()); + // We do not have the result yet, which means that an observable stack // slot is requested. As we do not want to bailout every time for the // same reason, we need to recompile without optimizing away the From 40a12f200587c94d4c6e8f438b2ca776cc5a4859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hubert=20Figui=C3=A8re?= Date: Fri, 12 Jun 2015 22:38:20 -0400 Subject: [PATCH 16/49] Bug 1174374 - gdk_cursor_new() is deprecated in 3.16. Use gdk_cursor_new_for_display(). r=karlt --HG-- extra : transplant_source : %DF%15%81%18%1A%93D%ADQ%BDO%3EN4%F7%3E%F9%8B%3C%0D --- widget/gtk/mozgtk/mozgtk.c | 2 +- widget/gtk/nsWindow.cpp | 53 ++++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/widget/gtk/mozgtk/mozgtk.c b/widget/gtk/mozgtk/mozgtk.c index c64c61fe1c92..4022ec95ed0c 100644 --- a/widget/gtk/mozgtk/mozgtk.c +++ b/widget/gtk/mozgtk/mozgtk.c @@ -8,7 +8,7 @@ STUB(gdk_atom_intern) STUB(gdk_atom_name) STUB(gdk_beep) STUB(gdk_color_free) -STUB(gdk_cursor_new) +STUB(gdk_cursor_new_for_display) STUB(gdk_cursor_new_from_name) STUB(gdk_cursor_new_from_pixbuf) STUB(gdk_display_close) diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 149bd4d0558f..4056bf287f8f 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -4937,49 +4937,54 @@ get_gtk_cursor(nsCursor aCursor) // Spec is here: http://www.freedesktop.org/wiki/Specifications/cursor-spec/ switch (aCursor) { case eCursor_standard: - gdkcursor = gdk_cursor_new(GDK_LEFT_PTR); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR); break; case eCursor_wait: - gdkcursor = gdk_cursor_new(GDK_WATCH); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_WATCH); break; case eCursor_select: - gdkcursor = gdk_cursor_new(GDK_XTERM); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_XTERM); break; case eCursor_hyperlink: - gdkcursor = gdk_cursor_new(GDK_HAND2); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_HAND2); break; case eCursor_n_resize: - gdkcursor = gdk_cursor_new(GDK_TOP_SIDE); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_SIDE); break; case eCursor_s_resize: - gdkcursor = gdk_cursor_new(GDK_BOTTOM_SIDE); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_SIDE); break; case eCursor_w_resize: - gdkcursor = gdk_cursor_new(GDK_LEFT_SIDE); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_SIDE); break; case eCursor_e_resize: - gdkcursor = gdk_cursor_new(GDK_RIGHT_SIDE); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_RIGHT_SIDE); break; case eCursor_nw_resize: - gdkcursor = gdk_cursor_new(GDK_TOP_LEFT_CORNER); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, + GDK_TOP_LEFT_CORNER); break; case eCursor_se_resize: - gdkcursor = gdk_cursor_new(GDK_BOTTOM_RIGHT_CORNER); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, + GDK_BOTTOM_RIGHT_CORNER); break; case eCursor_ne_resize: - gdkcursor = gdk_cursor_new(GDK_TOP_RIGHT_CORNER); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, + GDK_TOP_RIGHT_CORNER); break; case eCursor_sw_resize: - gdkcursor = gdk_cursor_new(GDK_BOTTOM_LEFT_CORNER); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, + GDK_BOTTOM_LEFT_CORNER); break; case eCursor_crosshair: - gdkcursor = gdk_cursor_new(GDK_CROSSHAIR); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_CROSSHAIR); break; case eCursor_move: - gdkcursor = gdk_cursor_new(GDK_FLEUR); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR); break; case eCursor_help: - gdkcursor = gdk_cursor_new(GDK_QUESTION_ARROW); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, + GDK_QUESTION_ARROW); break; case eCursor_copy: // CSS3 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy"); @@ -4997,7 +5002,7 @@ get_gtk_cursor(nsCursor aCursor) newType = MOZ_CURSOR_CONTEXT_MENU; break; case eCursor_cell: - gdkcursor = gdk_cursor_new(GDK_PLUS); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_PLUS); break; // Those two aren’t standardized. Trying both KDE’s and GNOME’s names case eCursor_grab: @@ -5043,7 +5048,7 @@ get_gtk_cursor(nsCursor aCursor) newType = MOZ_CURSOR_VERTICAL_TEXT; break; case eCursor_all_scroll: - gdkcursor = gdk_cursor_new(GDK_FLEUR); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR); break; case eCursor_nesw_resize: gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_bdiag"); @@ -5056,28 +5061,32 @@ get_gtk_cursor(nsCursor aCursor) newType = MOZ_CURSOR_NWSE_RESIZE; break; case eCursor_ns_resize: - gdkcursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, + GDK_SB_V_DOUBLE_ARROW); break; case eCursor_ew_resize: - gdkcursor = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, + GDK_SB_H_DOUBLE_ARROW); break; // Here, two better fitting cursors exist in some cursor themes. Try those first case eCursor_row_resize: gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_v"); if (!gdkcursor) - gdkcursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, + GDK_SB_V_DOUBLE_ARROW); break; case eCursor_col_resize: gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_h"); if (!gdkcursor) - gdkcursor = gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, + GDK_SB_H_DOUBLE_ARROW); break; case eCursor_none: newType = MOZ_CURSOR_NONE; break; default: NS_ASSERTION(aCursor, "Invalid cursor type"); - gdkcursor = gdk_cursor_new(GDK_LEFT_PTR); + gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR); break; } From 6179c7e55bc9704d3b51dcd66f65769813ea859f Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Fri, 12 Jun 2015 15:51:47 -0400 Subject: [PATCH 17/49] bug 977805 - add missing #include. r=jandem --HG-- extra : commitid : 7O5wByzxfit extra : rebase_source : 9f296d9adfe15f7631f601c5b65581b8306267d8 extra : source : 9fa312e065e1e9da9b5cb3514c3b40dcc7f65539 --- js/src/jit/ExecutableAllocator.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/js/src/jit/ExecutableAllocator.cpp b/js/src/jit/ExecutableAllocator.cpp index 08e550d38f7f..3de8e6b4a6c0 100644 --- a/js/src/jit/ExecutableAllocator.cpp +++ b/js/src/jit/ExecutableAllocator.cpp @@ -29,6 +29,10 @@ #include "js/MemoryMetrics.h" +#ifdef __APPLE__ +#include +#endif + using namespace js::jit; size_t ExecutableAllocator::pageSize = 0; @@ -62,7 +66,7 @@ ExecutableAllocator::addSizeOfCode(JS::CodeSizes* sizes) const } } -#ifdef TARGET_OS_IPHONE +#if TARGET_OS_IPHONE bool ExecutableAllocator::nonWritableJitCode = true; #else bool ExecutableAllocator::nonWritableJitCode = false; From 3a8036a7a7286b9949af86a506bad72578ee3fec Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Mon, 15 Jun 2015 14:59:49 +0200 Subject: [PATCH 18/49] Bug 1100498 - Report function names for addon exceptions. r=billm --- js/src/jsexn.cpp | 93 +++++++++++++++++++++++++++++++------------- js/src/jsfriendapi.h | 3 ++ 2 files changed, 70 insertions(+), 26 deletions(-) diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 1b57d6ed2d16..31b0ce509942 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -681,42 +681,83 @@ ErrorReport::~ErrorReport() js_free(const_cast(ownedReport.ucmessage)); } +void +ErrorReport::ReportAddonExceptionToTelementry(JSContext* cx) +{ + MOZ_ASSERT(exnObject); + RootedObject unwrapped(cx, UncheckedUnwrap(exnObject)); + MOZ_ASSERT(unwrapped, "UncheckedUnwrap failed?"); + + // There is not much we can report if the exception is not an ErrorObject, let's ignore those. + if (!unwrapped->is()) + return; + + Rooted errObj(cx, &unwrapped->as()); + RootedObject stack(cx, errObj->stack()); + + // Let's ignore TOP level exceptions. For regular add-ons those will not be reported anyway, + // for SDK based once it should not be a valid case either. + // At this point the frame stack is unwound but the exception object stored the stack so let's + // use that for getting the function name. + if (!stack) + return; + + JSCompartment* comp = stack->compartment(); + JSAddonId* addonId = comp->addonId; + + // We only want to send the report if the scope that just have thrown belongs to an add-on. + // Let's check the compartment of the youngest function on the stack, to determine that. + if (!addonId) + return; + + RootedString funnameString(cx); + JS::SavedFrameResult result = GetSavedFrameFunctionDisplayName(cx, stack, &funnameString); + // AccessDenied should never be the case here for add-ons but let's not risk it. + JSAutoByteString bytes; + const char* funname = nullptr; + funname = result == JS::SavedFrameResult::AccessDenied ? "unknown" + : AtomToPrintableString(cx, + &funnameString->asAtom(), + &bytes); + + UniqueChars addonIdChars(JS_EncodeString(cx, addonId)); + + const char* filename = nullptr; + if (reportp && reportp->filename) { + filename = strrchr(reportp->filename, '/'); + if (filename) + filename++; + } + if (!filename) { + filename = "FILE_NOT_FOUND"; + } + char histogramKey[64]; + JS_snprintf(histogramKey, sizeof(histogramKey), + "%s %s %s %u", + addonIdChars.get(), + funname, + filename, + (reportp ? reportp->lineno : 0) ); + cx->runtime()->addTelemetry(JS_TELEMETRY_ADDON_EXCEPTIONS, 1, histogramKey); +} + bool ErrorReport::init(JSContext* cx, HandleValue exn) { MOZ_ASSERT(!cx->isExceptionPending()); - /* - * Because ToString below could error and an exception object could become - * unrooted, we must root our exception object, if any. - */ if (exn.isObject()) { + // Because ToString below could error and an exception object could become + // unrooted, we must root our exception object, if any. exnObject = &exn.toObject(); reportp = ErrorFromException(cx, exnObject); - JSCompartment* comp = exnObject->compartment(); - JSAddonId* addonId = comp->addonId; - if (addonId) { - UniqueChars addonIdChars(JS_EncodeString(cx, addonId)); - - const char* filename = nullptr; - if (reportp && reportp->filename) { - filename = strrchr(reportp->filename, '/'); - if (filename) - filename++; - } - if (!filename) { - filename = "FILE_NOT_FOUND"; - } - char histogramKey[64]; - JS_snprintf(histogramKey, sizeof(histogramKey), - "%s %s %u", - addonIdChars.get(), - filename, - (reportp ? reportp->lineno : 0) ); - cx->runtime()->addTelemetry(JS_TELEMETRY_ADDON_EXCEPTIONS, 1, histogramKey); - } + // Let's see if the exception is from add-on code, if so, it should be reported + // to telementry. + ReportAddonExceptionToTelementry(cx); } + + // Be careful not to invoke ToString if we've already successfully extracted // an error report, since the exception might be wrapped in a security // wrapper, and ToString-ing it might throw. diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index bfe26161f93c..4014e8e8055c 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1396,6 +1396,9 @@ struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport) bool populateUncaughtExceptionReport(JSContext* cx, ...); bool populateUncaughtExceptionReportVA(JSContext* cx, va_list ap); + // Reports exceptions from add-on scopes to telementry. + void ReportAddonExceptionToTelementry(JSContext* cx); + // We may have a provided JSErrorReport, so need a way to represent that. JSErrorReport* reportp; From 9b1ac68ebb86e6c47ec6d81ec9f5903600e61282 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 15 Jun 2015 14:08:25 +0100 Subject: [PATCH 19/49] Bug 911972 - MessagePort and MessageChannel in workers, r=smaug, r=bent --HG-- rename : dom/base/MessageChannel.cpp => dom/messagechannel/MessageChannel.cpp rename : dom/base/MessageChannel.h => dom/messagechannel/MessageChannel.h rename : dom/base/MessagePort.cpp => dom/messagechannel/MessagePort.cpp rename : dom/base/MessagePort.h => dom/messagechannel/MessagePort.h rename : dom/base/MessagePortList.cpp => dom/messagechannel/MessagePortList.cpp rename : dom/base/MessagePortList.h => dom/messagechannel/MessagePortList.h rename : dom/base/test/iframe_messageChannel_chrome.html => dom/messagechannel/tests/iframe_messageChannel_chrome.html rename : dom/base/test/iframe_messageChannel_cloning.html => dom/messagechannel/tests/iframe_messageChannel_cloning.html rename : dom/base/test/iframe_messageChannel_pingpong.html => dom/messagechannel/tests/iframe_messageChannel_pingpong.html rename : dom/base/test/iframe_messageChannel_post.html => dom/messagechannel/tests/iframe_messageChannel_post.html rename : dom/base/test/test_messageChannel.html => dom/messagechannel/tests/test_messageChannel.html rename : dom/base/test/test_messageChannel.xul => dom/messagechannel/tests/test_messageChannel.xul rename : dom/base/test/test_messageChannel_cloning.html => dom/messagechannel/tests/test_messageChannel_cloning.html rename : dom/base/test/test_messageChannel_pingpong.html => dom/messagechannel/tests/test_messageChannel_pingpong.html rename : dom/base/test/test_messageChannel_post.html => dom/messagechannel/tests/test_messageChannel_post.html rename : dom/base/test/test_messageChannel_pref.html => dom/messagechannel/tests/test_messageChannel_pref.html rename : dom/base/test/test_messageChannel_start.html => dom/messagechannel/tests/test_messageChannel_start.html rename : dom/base/test/test_messageChannel_transferable.html => dom/messagechannel/tests/test_messageChannel_transferable.html rename : dom/base/test/test_messageChannel_unshipped.html => dom/messagechannel/tests/test_messageChannel_unshipped.html --- dom/base/MessageChannel.cpp | 104 --- dom/base/MessagePort.cpp | 564 ------------ dom/base/MessagePort.h | 115 --- dom/base/NodeInfo.cpp | 6 +- dom/base/PostMessageEvent.cpp | 389 ++++++++ dom/base/PostMessageEvent.h | 108 +++ dom/base/ProcessGlobal.cpp | 1 + dom/base/moz.build | 8 +- dom/base/nsContentUtils.cpp | 22 + dom/base/nsContentUtils.h | 7 + dom/base/nsCopySupport.cpp | 1 + dom/base/nsFrameMessageManager.cpp | 15 +- dom/base/nsGlobalWindow.cpp | 382 +------- dom/base/nsGlobalWindow.h | 3 +- dom/base/test/chrome.ini | 1 - dom/base/test/mochitest.ini | 12 - dom/bindings/Bindings.conf | 3 - dom/broadcastchannel/BroadcastChannel.cpp | 17 +- .../BroadcastChannelChild.cpp | 7 +- dom/ipc/StructuredCloneUtils.cpp | 12 +- dom/ipc/StructuredCloneUtils.h | 2 +- dom/messagechannel/MessageChannel.cpp | 228 +++++ dom/{base => messagechannel}/MessageChannel.h | 3 +- dom/messagechannel/MessagePort.cpp | 867 ++++++++++++++++++ dom/messagechannel/MessagePort.h | 210 +++++ dom/messagechannel/MessagePortChild.cpp | 49 + dom/messagechannel/MessagePortChild.h | 52 ++ .../MessagePortList.cpp | 0 .../MessagePortList.h | 0 dom/messagechannel/MessagePortParent.cpp | 163 ++++ dom/messagechannel/MessagePortParent.h | 61 ++ dom/messagechannel/MessagePortService.cpp | 328 +++++++ dom/messagechannel/MessagePortService.h | 61 ++ dom/messagechannel/MessagePortUtils.cpp | 277 ++++++ dom/messagechannel/MessagePortUtils.h | 55 ++ dom/messagechannel/PMessagePort.ipdl | 62 ++ .../SharedMessagePortMessage.cpp | 180 ++++ dom/messagechannel/SharedMessagePortMessage.h | 58 ++ dom/messagechannel/moz.build | 41 + dom/messagechannel/tests/chrome.ini | 5 + .../tests}/iframe_messageChannel_chrome.html | 0 .../tests}/iframe_messageChannel_cloning.html | 0 .../iframe_messageChannel_pingpong.html | 0 .../tests}/iframe_messageChannel_post.html | 0 .../iframe_messageChannel_sharedWorker2.html | 14 + .../iframe_messageChannel_transferable.html | 26 + dom/messagechannel/tests/mochitest.ini | 25 + dom/messagechannel/tests/moz.build | 8 + .../tests/sharedWorker2_messageChannel.js | 7 + .../tests/sharedWorker_messageChannel.js | 8 + .../tests}/test_messageChannel.html | 0 .../tests}/test_messageChannel.xul | 2 +- .../tests/test_messageChannel_any.html | 115 +++ .../tests}/test_messageChannel_cloning.html | 0 .../tests}/test_messageChannel_pingpong.html | 0 .../tests}/test_messageChannel_post.html | 0 .../tests}/test_messageChannel_pref.html | 0 .../test_messageChannel_selfTransferring.html | 38 + .../test_messageChannel_sharedWorker.html | 39 + .../test_messageChannel_sharedWorker2.html | 37 + .../tests}/test_messageChannel_start.html | 0 .../test_messageChannel_transferable.html | 58 +- .../tests}/test_messageChannel_unshipped.html | 0 .../tests/test_messageChannel_worker.html | 60 ++ .../tests/worker_messageChannel.js | 119 +++ .../tests/worker_messageChannel_any.js | 7 + dom/moz.build | 1 + dom/webidl/MessageChannel.webidl | 3 +- dom/workers/MessagePort.cpp | 13 +- dom/workers/MessagePort.h | 10 +- dom/workers/ServiceWorkerClient.cpp | 22 +- dom/workers/WorkerPrivate.cpp | 226 +++-- dom/workers/WorkerPrivate.h | 3 +- dom/workers/WorkerStructuredClone.h | 53 ++ dom/workers/XMLHttpRequest.cpp | 62 +- dom/workers/XMLHttpRequest.h | 3 +- dom/workers/test/sharedWorker_sharedWorker.js | 4 +- ipc/glue/BackgroundChild.h | 5 + ipc/glue/BackgroundChildImpl.cpp | 23 + ipc/glue/BackgroundChildImpl.h | 7 + ipc/glue/BackgroundImpl.cpp | 20 +- ipc/glue/BackgroundParentImpl.cpp | 38 + ipc/glue/BackgroundParentImpl.h | 14 + ipc/glue/PBackground.ipdl | 4 + js/public/StructuredClone.h | 2 +- js/src/vm/StructuredClone.cpp | 6 +- .../event-ports-dedicated.html.ini | 5 - 87 files changed, 4217 insertions(+), 1349 deletions(-) delete mode 100644 dom/base/MessageChannel.cpp delete mode 100644 dom/base/MessagePort.cpp delete mode 100644 dom/base/MessagePort.h create mode 100644 dom/base/PostMessageEvent.cpp create mode 100644 dom/base/PostMessageEvent.h create mode 100644 dom/messagechannel/MessageChannel.cpp rename dom/{base => messagechannel}/MessageChannel.h (99%) create mode 100644 dom/messagechannel/MessagePort.cpp create mode 100644 dom/messagechannel/MessagePort.h create mode 100644 dom/messagechannel/MessagePortChild.cpp create mode 100644 dom/messagechannel/MessagePortChild.h rename dom/{base => messagechannel}/MessagePortList.cpp (100%) rename dom/{base => messagechannel}/MessagePortList.h (100%) create mode 100644 dom/messagechannel/MessagePortParent.cpp create mode 100644 dom/messagechannel/MessagePortParent.h create mode 100644 dom/messagechannel/MessagePortService.cpp create mode 100644 dom/messagechannel/MessagePortService.h create mode 100644 dom/messagechannel/MessagePortUtils.cpp create mode 100644 dom/messagechannel/MessagePortUtils.h create mode 100644 dom/messagechannel/PMessagePort.ipdl create mode 100644 dom/messagechannel/SharedMessagePortMessage.cpp create mode 100644 dom/messagechannel/SharedMessagePortMessage.h create mode 100644 dom/messagechannel/moz.build create mode 100644 dom/messagechannel/tests/chrome.ini rename dom/{base/test => messagechannel/tests}/iframe_messageChannel_chrome.html (100%) rename dom/{base/test => messagechannel/tests}/iframe_messageChannel_cloning.html (100%) rename dom/{base/test => messagechannel/tests}/iframe_messageChannel_pingpong.html (100%) rename dom/{base/test => messagechannel/tests}/iframe_messageChannel_post.html (100%) create mode 100644 dom/messagechannel/tests/iframe_messageChannel_sharedWorker2.html create mode 100644 dom/messagechannel/tests/iframe_messageChannel_transferable.html create mode 100644 dom/messagechannel/tests/mochitest.ini create mode 100644 dom/messagechannel/tests/moz.build create mode 100644 dom/messagechannel/tests/sharedWorker2_messageChannel.js create mode 100644 dom/messagechannel/tests/sharedWorker_messageChannel.js rename dom/{base/test => messagechannel/tests}/test_messageChannel.html (100%) rename dom/{base/test => messagechannel/tests}/test_messageChannel.xul (91%) create mode 100644 dom/messagechannel/tests/test_messageChannel_any.html rename dom/{base/test => messagechannel/tests}/test_messageChannel_cloning.html (100%) rename dom/{base/test => messagechannel/tests}/test_messageChannel_pingpong.html (100%) rename dom/{base/test => messagechannel/tests}/test_messageChannel_post.html (100%) rename dom/{base/test => messagechannel/tests}/test_messageChannel_pref.html (100%) create mode 100644 dom/messagechannel/tests/test_messageChannel_selfTransferring.html create mode 100644 dom/messagechannel/tests/test_messageChannel_sharedWorker.html create mode 100644 dom/messagechannel/tests/test_messageChannel_sharedWorker2.html rename dom/{base/test => messagechannel/tests}/test_messageChannel_start.html (100%) rename dom/{base/test => messagechannel/tests}/test_messageChannel_transferable.html (57%) rename dom/{base/test => messagechannel/tests}/test_messageChannel_unshipped.html (100%) create mode 100644 dom/messagechannel/tests/test_messageChannel_worker.html create mode 100644 dom/messagechannel/tests/worker_messageChannel.js create mode 100644 dom/messagechannel/tests/worker_messageChannel_any.js create mode 100644 dom/workers/WorkerStructuredClone.h delete mode 100644 testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html.ini diff --git a/dom/base/MessageChannel.cpp b/dom/base/MessageChannel.cpp deleted file mode 100644 index e04ca2fc72d3..000000000000 --- a/dom/base/MessageChannel.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; 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 "MessageChannel.h" - -#include "mozilla/Preferences.h" -#include "mozilla/dom/MessageChannelBinding.h" -#include "mozilla/dom/MessagePort.h" -#include "nsContentUtils.h" -#include "nsPIDOMWindow.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mWindow, mPort1, mPort2) -NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel) -NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -namespace { - bool gPrefInitialized = false; - bool gPrefEnabled = false; - -} - -/* static */ bool -MessageChannel::Enabled(JSContext* aCx, JSObject* aObj) -{ - if (!gPrefInitialized) { - Preferences::AddBoolVarCache(&gPrefEnabled, "dom.messageChannel.enabled"); - gPrefInitialized = true; - } - - // Enabled by pref - if (gPrefEnabled) { - return true; - } - - // Chrome callers are allowed. - if (nsContentUtils::ThreadsafeIsCallerChrome()) { - return true; - } - - nsCOMPtr principal = nsContentUtils::SubjectPrincipal(); - MOZ_ASSERT(principal); - - nsCOMPtr uri; - if (NS_FAILED(principal->GetURI(getter_AddRefs(uri))) || !uri) { - return false; - } - - bool isResource = false; - if (NS_FAILED(uri->SchemeIs("resource", &isResource))) { - return false; - } - - return isResource; -} - -MessageChannel::MessageChannel(nsPIDOMWindow* aWindow) - : mWindow(aWindow) -{ - MOZ_COUNT_CTOR(MessageChannel); - - mPort1 = new MessagePort(mWindow); - mPort2 = new MessagePort(mWindow); - - mPort1->Entangle(mPort2); - mPort2->Entangle(mPort1); -} - -MessageChannel::~MessageChannel() -{ - MOZ_COUNT_DTOR(MessageChannel); -} - -JSObject* -MessageChannel::WrapObject(JSContext* aCx, JS::Handle aGivenProto) -{ - return MessageChannelBinding::Wrap(aCx, this, aGivenProto); -} - -/* static */ already_AddRefed -MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) -{ - nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); - if (!window) { - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - - nsRefPtr channel = new MessageChannel(window); - return channel.forget(); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/base/MessagePort.cpp b/dom/base/MessagePort.cpp deleted file mode 100644 index fbbafbdbf464..000000000000 --- a/dom/base/MessagePort.cpp +++ /dev/null @@ -1,564 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; 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 "MessagePort.h" -#include "MessageEvent.h" -#include "mozilla/dom/BlobBinding.h" -#include "mozilla/dom/Event.h" -#include "mozilla/dom/File.h" -#include "mozilla/dom/MessageChannel.h" -#include "mozilla/dom/MessagePortBinding.h" -#include "mozilla/dom/MessagePortList.h" -#include "mozilla/dom/StructuredCloneTags.h" -#include "nsContentUtils.h" -#include "nsGlobalWindow.h" -#include "nsPresContext.h" -#include "ScriptSettings.h" - -#include "nsIDocument.h" -#include "nsIDOMFileList.h" -#include "nsIPresShell.h" - -namespace mozilla { -namespace dom { - -class DispatchEventRunnable : public nsRunnable -{ - friend class MessagePort; - - public: - explicit DispatchEventRunnable(MessagePort* aPort) - : mPort(aPort) - { - } - - NS_IMETHOD - Run() - { - nsRefPtr mKungFuDeathGrip(this); - - mPort->mDispatchRunnable = nullptr; - mPort->Dispatch(); - - return NS_OK; - } - - private: - nsRefPtr mPort; -}; - -class PostMessageRunnable : public nsRunnable -{ - friend class MessagePort; - - public: - NS_DECL_NSIRUNNABLE - - PostMessageRunnable() - { - } - - ~PostMessageRunnable() - { - } - - JSAutoStructuredCloneBuffer& Buffer() - { - return mBuffer; - } - - bool StoreISupports(nsISupports* aSupports) - { - mSupportsArray.AppendElement(aSupports); - return true; - } - - void Dispatch(MessagePort* aPort) - { - mPort = aPort; - NS_DispatchToCurrentThread(this); - } - - private: - nsRefPtr mPort; - JSAutoStructuredCloneBuffer mBuffer; - - nsTArray > mSupportsArray; -}; - -namespace { - -struct StructuredCloneInfo -{ - PostMessageRunnable* mEvent; - MessagePort* mPort; - nsRefPtrHashtable, MessagePortBase> mPorts; -}; - -static JSObject* -PostMessageReadStructuredClone(JSContext* cx, - JSStructuredCloneReader* reader, - uint32_t tag, - uint32_t data, - void* closure) -{ - StructuredCloneInfo* scInfo = static_cast(closure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (tag == SCTAG_DOM_BLOB) { - NS_ASSERTION(!data, "Data should be empty"); - - // What we get back from the reader is a BlobImpl. - // From that we create a new File. - BlobImpl* blobImpl; - if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) { - MOZ_ASSERT(blobImpl); - - // nsRefPtr needs to go out of scope before toObjectOrNull() is - // called because the static analysis thinks dereferencing XPCOM objects - // can GC (because in some cases it can!), and a return statement with a - // JSObject* type means that JSObject* is on the stack as a raw pointer - // while destructors are running. - JS::Rooted val(cx); - { - nsRefPtr blob = Blob::Create(scInfo->mPort->GetParentObject(), - blobImpl); - if (!ToJSValue(cx, blob, &val)) { - return nullptr; - } - } - - return &val.toObject(); - } - } - - if (tag == SCTAG_DOM_FILELIST) { - NS_ASSERTION(!data, "Data should be empty"); - - nsISupports* supports; - if (JS_ReadBytes(reader, &supports, sizeof(supports))) { - JS::Rooted val(cx); - if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) { - return val.toObjectOrNull(); - } - } - } - - const JSStructuredCloneCallbacks* runtimeCallbacks = - js::GetContextStructuredCloneCallbacks(cx); - - if (runtimeCallbacks) { - return runtimeCallbacks->read(cx, reader, tag, data, nullptr); - } - - return nullptr; -} - -static bool -PostMessageWriteStructuredClone(JSContext* cx, - JSStructuredCloneWriter* writer, - JS::Handle obj, - void *closure) -{ - StructuredCloneInfo* scInfo = static_cast(closure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - // See if this is a File/Blob object. - { - Blob* blob = nullptr; - if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) { - BlobImpl* blobImpl = blob->Impl(); - if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) && - JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) { - scInfo->mEvent->StoreISupports(blobImpl); - return true; - } - } - } - - nsCOMPtr wrappedNative; - nsContentUtils::XPConnect()-> - GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative)); - if (wrappedNative) { - uint32_t scTag = 0; - nsISupports* supports = wrappedNative->Native(); - - nsCOMPtr list = do_QueryInterface(supports); - if (list) { - scTag = SCTAG_DOM_FILELIST; - } - - if (scTag) { - return JS_WriteUint32Pair(writer, scTag, 0) && - JS_WriteBytes(writer, &supports, sizeof(supports)) && - scInfo->mEvent->StoreISupports(supports); - } - } - - const JSStructuredCloneCallbacks* runtimeCallbacks = - js::GetContextStructuredCloneCallbacks(cx); - - if (runtimeCallbacks) { - return runtimeCallbacks->write(cx, writer, obj, nullptr); - } - - return false; -} - -static bool -PostMessageReadTransferStructuredClone(JSContext* aCx, - JSStructuredCloneReader* reader, - uint32_t tag, void* data, - uint64_t unused, - void* aClosure, - JS::MutableHandle returnObject) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (tag == SCTAG_DOM_MAP_MESSAGEPORT) { - MessagePort* port = static_cast(data); - port->BindToOwner(scInfo->mPort->GetOwner()); - scInfo->mPorts.Put(port, nullptr); - - JS::Rooted obj(aCx, port->WrapObject(aCx, nullptr)); - if (!obj || !JS_WrapObject(aCx, &obj)) { - return false; - } - - MOZ_ASSERT(port->GetOwner() == scInfo->mPort->GetOwner()); - returnObject.set(obj); - return true; - } - - return false; -} - -static bool -PostMessageTransferStructuredClone(JSContext* aCx, - JS::Handle aObj, - void* aClosure, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t *aExtraData) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - MessagePortBase *port = nullptr; - nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); - if (NS_SUCCEEDED(rv)) { - nsRefPtr newPort; - if (scInfo->mPorts.Get(port, getter_AddRefs(newPort))) { - // No duplicate. - return false; - } - - newPort = port->Clone(); - scInfo->mPorts.Put(port, newPort); - - *aTag = SCTAG_DOM_MAP_MESSAGEPORT; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = newPort; - *aExtraData = 0; - - return true; - } - - return false; -} - -static void -PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership, - void* aData, - uint64_t aExtraData, - void* aClosure) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { - MOZ_ASSERT(aOwnership == JS::SCTAG_TMO_CUSTOM); - nsRefPtr port(static_cast(aData)); - scInfo->mPorts.Remove(port); - } -} - -const JSStructuredCloneCallbacks kPostMessageCallbacks = { - PostMessageReadStructuredClone, - PostMessageWriteStructuredClone, - nullptr, - PostMessageReadTransferStructuredClone, - PostMessageTransferStructuredClone, - PostMessageFreeTransferStructuredClone -}; - -} // anonymous namespace - -static PLDHashOperator -PopulateMessagePortList(MessagePortBase* aKey, MessagePortBase* aValue, void* aClosure) -{ - nsTArray > *array = - static_cast > *>(aClosure); - - array->AppendElement(aKey); - return PL_DHASH_NEXT; -} - -NS_IMETHODIMP -PostMessageRunnable::Run() -{ - MOZ_ASSERT(mPort); - - AutoJSAPI jsapi; - if (NS_WARN_IF(!jsapi.Init(mPort->GetParentObject()))) { - return NS_ERROR_UNEXPECTED; - } - JSContext* cx = jsapi.cx(); - - // Deserialize the structured clone data - JS::Rooted messageData(cx); - StructuredCloneInfo scInfo; - scInfo.mEvent = this; - scInfo.mPort = mPort; - - if (!mBuffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo)) { - return NS_ERROR_DOM_DATA_CLONE_ERR; - } - - // Create the event - nsCOMPtr eventTarget = - do_QueryInterface(mPort->GetOwner()); - nsRefPtr event = - new MessageEvent(eventTarget, nullptr, nullptr); - - event->InitMessageEvent(NS_LITERAL_STRING("message"), false /* non-bubbling */, - false /* cancelable */, messageData, EmptyString(), - EmptyString(), nullptr); - event->SetTrusted(true); - event->SetSource(mPort); - - nsTArray > ports; - scInfo.mPorts.EnumerateRead(PopulateMessagePortList, &ports); - event->SetPorts(new MessagePortList(static_cast(event.get()), ports)); - - bool status; - mPort->DispatchEvent(static_cast(event.get()), &status); - return status ? NS_OK : NS_ERROR_FAILURE; -} - -MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow) - : DOMEventTargetHelper(aWindow) -{ -} - -MessagePortBase::MessagePortBase() -{ -} - -NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort, - DOMEventTargetHelper) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mEntangledPort) - - // Custom unlink loop because this array contains nsRunnable objects - // which are not cycle colleactable. - while (!tmp->mMessageQueue.IsEmpty()) { - NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mPort); - NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mSupportsArray); - tmp->mMessageQueue.RemoveElementAt(0); - } - - if (tmp->mDispatchRunnable) { - NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort); - } - -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort, - DOMEventTargetHelper) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEntangledPort) - - // Custom unlink loop because this array contains nsRunnable objects - // which are not cycle colleactable. - for (uint32_t i = 0, len = tmp->mMessageQueue.Length(); i < len; ++i) { - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mPort); - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mSupportsArray); - } - - if (tmp->mDispatchRunnable) { - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort); - } - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort) -NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) - -NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper) -NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper) - -MessagePort::MessagePort(nsPIDOMWindow* aWindow) - : MessagePortBase(aWindow) - , mMessageQueueEnabled(false) -{ -} - -MessagePort::~MessagePort() -{ - Close(); -} - -JSObject* -MessagePort::WrapObject(JSContext* aCx, JS::Handle aGivenProto) -{ - return MessagePortBinding::Wrap(aCx, this, aGivenProto); -} - -void -MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) -{ - nsRefPtr event = new PostMessageRunnable(); - - // We *must* clone the data here, or the JS::Value could be modified - // by script - StructuredCloneInfo scInfo; - scInfo.mEvent = event; - scInfo.mPort = this; - - JS::Rooted transferable(aCx, JS::UndefinedValue()); - if (aTransferable.WasPassed()) { - const Sequence& realTransferable = aTransferable.Value(); - - // The input sequence only comes from the generated bindings code, which - // ensures it is rooted. - JS::HandleValueArray elements = - JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), - realTransferable.Elements()); - - JSObject* array = - JS_NewArrayObject(aCx, elements); - if (!array) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - transferable.setObject(*array); - } - - if (!event->Buffer().write(aCx, aMessage, transferable, - &kPostMessageCallbacks, &scInfo)) { - aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); - return; - } - - if (!mEntangledPort) { - return; - } - - mEntangledPort->mMessageQueue.AppendElement(event); - mEntangledPort->Dispatch(); -} - -void -MessagePort::Start() -{ - if (mMessageQueueEnabled) { - return; - } - - mMessageQueueEnabled = true; - Dispatch(); -} - -void -MessagePort::Dispatch() -{ - if (!mMessageQueueEnabled || mMessageQueue.IsEmpty() || mDispatchRunnable) { - return; - } - - nsRefPtr event = mMessageQueue.ElementAt(0); - mMessageQueue.RemoveElementAt(0); - - event->Dispatch(this); - - mDispatchRunnable = new DispatchEventRunnable(this); - NS_DispatchToCurrentThread(mDispatchRunnable); -} - -void -MessagePort::Close() -{ - if (!mEntangledPort) { - return; - } - - // This avoids loops. - nsRefPtr port = mEntangledPort; - mEntangledPort = nullptr; - - // Let's disentangle the 2 ports symmetrically. - port->Close(); -} - -EventHandlerNonNull* -MessagePort::GetOnmessage() -{ - if (NS_IsMainThread()) { - return GetEventHandler(nsGkAtoms::onmessage, EmptyString()); - } - return GetEventHandler(nullptr, NS_LITERAL_STRING("message")); -} - -void -MessagePort::SetOnmessage(EventHandlerNonNull* aCallback) -{ - if (NS_IsMainThread()) { - SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback); - } else { - SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback); - } - - // When using onmessage, the call to start() is implied. - Start(); -} - -void -MessagePort::Entangle(MessagePort* aMessagePort) -{ - MOZ_ASSERT(aMessagePort); - MOZ_ASSERT(aMessagePort != this); - - Close(); - - mEntangledPort = aMessagePort; -} - -already_AddRefed -MessagePort::Clone() -{ - nsRefPtr newPort = new MessagePort(nullptr); - - // Move all the events in the port message queue of original port. - newPort->mMessageQueue.SwapElements(mMessageQueue); - - if (mEntangledPort) { - nsRefPtr port = mEntangledPort; - mEntangledPort = nullptr; - - newPort->Entangle(port); - port->Entangle(newPort); - } - - return newPort.forget(); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/base/MessagePort.h b/dom/base/MessagePort.h deleted file mode 100644 index fe51bc295fd0..000000000000 --- a/dom/base/MessagePort.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; 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/. */ - -#ifndef mozilla_dom_MessagePort_h -#define mozilla_dom_MessagePort_h - -#include "mozilla/Attributes.h" -#include "mozilla/DOMEventTargetHelper.h" - -class nsPIDOMWindow; - -namespace mozilla { -namespace dom { - -class DispatchEventRunnable; -class PostMessageRunnable; - -class MessagePortBase : public DOMEventTargetHelper -{ -protected: - explicit MessagePortBase(nsPIDOMWindow* aWindow); - MessagePortBase(); - -public: - - virtual void - PostMessageMoz(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) = 0; - - virtual void - Start() = 0; - - virtual void - Close() = 0; - - // The 'message' event handler has to call |Start()| method, so we - // cannot use IMPL_EVENT_HANDLER macro here. - virtual EventHandlerNonNull* - GetOnmessage() = 0; - - virtual void - SetOnmessage(EventHandlerNonNull* aCallback) = 0; - - // Duplicate this message port. This method is used by the Structured Clone - // Algorithm and makes the new MessagePort active with the entangled - // MessagePort of this object. - virtual already_AddRefed - Clone() = 0; -}; - -class MessagePort final : public MessagePortBase -{ - friend class DispatchEventRunnable; - friend class PostMessageRunnable; - -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, - DOMEventTargetHelper) - - explicit MessagePort(nsPIDOMWindow* aWindow); - - virtual JSObject* - WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - - virtual void - PostMessageMoz(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) override; - - virtual void - Start() override; - - virtual void - Close() override; - - virtual EventHandlerNonNull* - GetOnmessage() override; - - virtual void - SetOnmessage(EventHandlerNonNull* aCallback) override; - - // Non WebIDL methods - - // This method entangles this MessagePort with another one. - // If it is already entangled, it's disentangled first and enatangle to the - // new one. - void - Entangle(MessagePort* aMessagePort); - - virtual already_AddRefed - Clone() override; - -private: - ~MessagePort(); - - // Dispatch events from the Message Queue using a nsRunnable. - void Dispatch(); - - nsRefPtr mDispatchRunnable; - - nsRefPtr mEntangledPort; - - nsTArray > mMessageQueue; - bool mMessageQueueEnabled; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_MessagePort_h diff --git a/dom/base/NodeInfo.cpp b/dom/base/NodeInfo.cpp index 8c60eee4f455..00166783758f 100644 --- a/dom/base/NodeInfo.cpp +++ b/dom/base/NodeInfo.cpp @@ -111,7 +111,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(NodeInfo) NS_IMPL_CYCLE_COLLECTION_UNLINK_0(NodeInfo) -static const char* kNSURIs[] = { +static const char* kNodeInfoNSURIs[] = { " ([none])", " (xmlns)", " (xml)", @@ -129,8 +129,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(NodeInfo) char name[72]; uint32_t nsid = tmp->NamespaceID(); nsAtomCString localName(tmp->NameAtom()); - if (nsid < ArrayLength(kNSURIs)) { - PR_snprintf(name, sizeof(name), "NodeInfo%s %s", kNSURIs[nsid], + if (nsid < ArrayLength(kNodeInfoNSURIs)) { + PR_snprintf(name, sizeof(name), "NodeInfo%s %s", kNodeInfoNSURIs[nsid], localName.get()); } else { diff --git a/dom/base/PostMessageEvent.cpp b/dom/base/PostMessageEvent.cpp new file mode 100644 index 000000000000..6070015a8322 --- /dev/null +++ b/dom/base/PostMessageEvent.cpp @@ -0,0 +1,389 @@ +/* -*- Mode: C++; tab-width: 8; 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 "PostMessageEvent.h" + +#include "MessageEvent.h" +#include "mozilla/dom/BlobBinding.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/MessagePortBinding.h" +#include "mozilla/dom/PMessagePort.h" +#include "mozilla/dom/StructuredCloneTags.h" +#include "mozilla/EventDispatcher.h" +#include "nsGlobalWindow.h" +#include "nsIPresShell.h" +#include "nsIPrincipal.h" + +namespace mozilla { +namespace dom { + +namespace { + +struct StructuredCloneInfo +{ + PostMessageEvent* event; + bool subsumes; + nsPIDOMWindow* window; + + // This hashtable contains the transferred ports - used to avoid duplicates. + nsTArray> transferredPorts; + + // This array is populated when the ports are cloned. + nsTArray> clonedPorts; +}; + +} // anonymous namespace + +const JSStructuredCloneCallbacks PostMessageEvent::sPostMessageCallbacks = { + PostMessageEvent::ReadStructuredClone, + PostMessageEvent::WriteStructuredClone, + nullptr, + PostMessageEvent::ReadTransferStructuredClone, + PostMessageEvent::TransferStructuredClone, + PostMessageEvent::FreeTransferStructuredClone +}; + +/* static */ JSObject* +PostMessageEvent::ReadStructuredClone(JSContext* cx, + JSStructuredCloneReader* reader, + uint32_t tag, + uint32_t data, + void* closure) +{ + StructuredCloneInfo* scInfo = static_cast(closure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (tag == SCTAG_DOM_BLOB) { + NS_ASSERTION(!data, "Data should be empty"); + + // What we get back from the reader is a BlobImpl. + // From that we create a new File. + BlobImpl* blobImpl; + if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) { + MOZ_ASSERT(blobImpl); + + // nsRefPtr needs to go out of scope before toObjectOrNull() is + // called because the static analysis thinks dereferencing XPCOM objects + // can GC (because in some cases it can!), and a return statement with a + // JSObject* type means that JSObject* is on the stack as a raw pointer + // while destructors are running. + JS::Rooted val(cx); + { + nsRefPtr blob = Blob::Create(scInfo->window, blobImpl); + if (!ToJSValue(cx, blob, &val)) { + return nullptr; + } + } + + return &val.toObject(); + } + } + + if (tag == SCTAG_DOM_FILELIST) { + NS_ASSERTION(!data, "Data should be empty"); + + nsISupports* supports; + if (JS_ReadBytes(reader, &supports, sizeof(supports))) { + JS::Rooted val(cx); + if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) { + return val.toObjectOrNull(); + } + } + } + + const JSStructuredCloneCallbacks* runtimeCallbacks = + js::GetContextStructuredCloneCallbacks(cx); + + if (runtimeCallbacks) { + return runtimeCallbacks->read(cx, reader, tag, data, nullptr); + } + + return nullptr; +} + +/* static */ bool +PostMessageEvent::WriteStructuredClone(JSContext* cx, + JSStructuredCloneWriter* writer, + JS::Handle obj, + void *closure) +{ + StructuredCloneInfo* scInfo = static_cast(closure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + // See if this is a File/Blob object. + { + Blob* blob = nullptr; + if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) { + BlobImpl* blobImpl = blob->Impl(); + if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) && + JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) { + scInfo->event->StoreISupports(blobImpl); + return true; + } + } + } + + nsCOMPtr wrappedNative; + nsContentUtils::XPConnect()-> + GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative)); + if (wrappedNative) { + uint32_t scTag = 0; + nsISupports* supports = wrappedNative->Native(); + + nsCOMPtr list = do_QueryInterface(supports); + if (list && scInfo->subsumes) + scTag = SCTAG_DOM_FILELIST; + + if (scTag) + return JS_WriteUint32Pair(writer, scTag, 0) && + JS_WriteBytes(writer, &supports, sizeof(supports)) && + scInfo->event->StoreISupports(supports); + } + + const JSStructuredCloneCallbacks* runtimeCallbacks = + js::GetContextStructuredCloneCallbacks(cx); + + if (runtimeCallbacks) { + return runtimeCallbacks->write(cx, writer, obj, nullptr); + } + + return false; +} + +/* static */ bool +PostMessageEvent::ReadTransferStructuredClone(JSContext* aCx, + JSStructuredCloneReader* reader, + uint32_t tag, void* aData, + uint64_t aExtraData, + void* aClosure, + JS::MutableHandle returnObject) +{ + StructuredCloneInfo* scInfo = static_cast(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (tag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(!aData); + // aExtraData is the index of this port identifier. + ErrorResult rv; + nsRefPtr port = + MessagePort::Create(scInfo->window, + scInfo->event->GetPortIdentifier(aExtraData), + rv); + if (NS_WARN_IF(rv.Failed())) { + return false; + } + + scInfo->clonedPorts.AppendElement(port); + + JS::Rooted value(aCx); + if (!GetOrCreateDOMReflector(aCx, port, &value)) { + JS_ClearPendingException(aCx); + return false; + } + + returnObject.set(&value.toObject()); + return true; + } + + return false; +} + +/* static */ bool +PostMessageEvent::TransferStructuredClone(JSContext* aCx, + JS::Handle aObj, + void* aClosure, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t* aExtraData) +{ + StructuredCloneInfo* scInfo = static_cast(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + MessagePortBase* port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); + if (NS_SUCCEEDED(rv)) { + if (scInfo->transferredPorts.Contains(port)) { + // No duplicates. + return false; + } + + // We use aExtraData to store the index of this new port identifier. + MessagePortIdentifier* identifier = + scInfo->event->NewPortIdentifier(aExtraData); + + if (!port->CloneAndDisentangle(*identifier)) { + return false; + } + + scInfo->transferredPorts.AppendElement(port); + + *aTag = SCTAG_DOM_MAP_MESSAGEPORT; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = nullptr; + + return true; + } + + return false; +} + +/* static */ void +PostMessageEvent::FreeTransferStructuredClone(uint32_t aTag, + JS::TransferableOwnership aOwnership, + void *aContent, + uint64_t aExtraData, + void* aClosure) +{ + // Nothing to do. +} + +PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource, + const nsAString& aCallerOrigin, + nsGlobalWindow* aTargetWindow, + nsIPrincipal* aProvidedPrincipal, + bool aTrustedCaller) +: mSource(aSource), + mCallerOrigin(aCallerOrigin), + mTargetWindow(aTargetWindow), + mProvidedPrincipal(aProvidedPrincipal), + mTrustedCaller(aTrustedCaller) +{ + MOZ_COUNT_CTOR(PostMessageEvent); +} + +PostMessageEvent::~PostMessageEvent() +{ + MOZ_COUNT_DTOR(PostMessageEvent); +} + +const MessagePortIdentifier& +PostMessageEvent::GetPortIdentifier(uint64_t aId) +{ + MOZ_ASSERT(aId < mPortIdentifiers.Length()); + return mPortIdentifiers[aId]; +} + +MessagePortIdentifier* +PostMessageEvent::NewPortIdentifier(uint64_t* aPosition) +{ + *aPosition = mPortIdentifiers.Length(); + return mPortIdentifiers.AppendElement(); +} + +NS_IMETHODIMP +PostMessageEvent::Run() +{ + MOZ_ASSERT(mTargetWindow->IsOuterWindow(), + "should have been passed an outer window!"); + MOZ_ASSERT(!mSource || mSource->IsOuterWindow(), + "should have been passed an outer window!"); + + AutoJSAPI jsapi; + jsapi.Init(); + JSContext* cx = jsapi.cx(); + + // If we bailed before this point we're going to leak mMessage, but + // that's probably better than crashing. + + nsRefPtr targetWindow; + if (mTargetWindow->IsClosedOrClosing() || + !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) || + targetWindow->IsClosedOrClosing()) + return NS_OK; + + MOZ_ASSERT(targetWindow->IsInnerWindow(), + "we ordered an inner window!"); + JSAutoCompartment ac(cx, targetWindow->GetWrapperPreserveColor()); + + // Ensure that any origin which might have been provided is the origin of this + // window's document. Note that we do this *now* instead of when postMessage + // is called because the target window might have been navigated to a + // different location between then and now. If this check happened when + // postMessage was called, it would be fairly easy for a malicious webpage to + // intercept messages intended for another site by carefully timing navigation + // of the target window so it changed location after postMessage but before + // now. + if (mProvidedPrincipal) { + // 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 + // document. + nsIPrincipal* targetPrin = targetWindow->GetPrincipal(); + if (NS_WARN_IF(!targetPrin)) + return NS_OK; + + // Note: This is contrary to the spec with respect to file: URLs, which + // 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 + // now. Long-term, we want HTML5 to address this so that we can + // be compliant while being safer. + if (!targetPrin->Equals(mProvidedPrincipal)) { + return NS_OK; + } + } + + // Deserialize the structured clone data + JS::Rooted messageData(cx); + StructuredCloneInfo scInfo; + scInfo.event = this; + scInfo.window = targetWindow; + + if (!mBuffer.read(cx, &messageData, &sPostMessageCallbacks, &scInfo)) { + return NS_ERROR_DOM_DATA_CLONE_ERR; + } + + // Create the event + nsCOMPtr eventTarget = + do_QueryInterface(static_cast(targetWindow.get())); + nsRefPtr event = + new MessageEvent(eventTarget, nullptr, nullptr); + + event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */, + false /*cancelable */, messageData, mCallerOrigin, + EmptyString(), mSource); + + event->SetPorts(new MessagePortList(static_cast(event.get()), + scInfo.clonedPorts)); + + // We can't simply call dispatchEvent on the window because doing so ends + // up flipping the trusted bit on the event, and we don't want that to + // happen because then untrusted content can call postMessage on a chrome + // window if it can get a reference to it. + + nsIPresShell *shell = targetWindow->GetExtantDoc()->GetShell(); + nsRefPtr presContext; + if (shell) + presContext = shell->GetPresContext(); + + event->SetTrusted(mTrustedCaller); + WidgetEvent* internalEvent = event->GetInternalNSEvent(); + + nsEventStatus status = nsEventStatus_eIgnore; + EventDispatcher::Dispatch(static_cast(mTargetWindow), + presContext, + internalEvent, + static_cast(event.get()), + &status); + return NS_OK; +} + +bool +PostMessageEvent::Write(JSContext* aCx, JS::Handle aMessage, + JS::Handle aTransfer, bool aSubsumes, + nsPIDOMWindow* aWindow) +{ + // We *must* clone the data here, or the JS::Value could be modified + // by script + StructuredCloneInfo scInfo; + scInfo.event = this; + scInfo.window = aWindow; + + return mBuffer.write(aCx, aMessage, aTransfer, &sPostMessageCallbacks, + &scInfo); +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/base/PostMessageEvent.h b/dom/base/PostMessageEvent.h new file mode 100644 index 000000000000..917d4da05558 --- /dev/null +++ b/dom/base/PostMessageEvent.h @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 8; 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/. */ + +#ifndef mozilla_dom_PostMessageEvent_h +#define mozilla_dom_PostMessageEvent_h + +#include "js/StructuredClone.h" +#include "nsCOMPtr.h" +#include "nsRefPtr.h" +#include "nsTArray.h" + +class nsGlobalWindow; +class nsIPrincipal; + +namespace mozilla { +namespace dom { + +class MessagePortBase; +class MessagePortIdentifier; + +/** + * Class used to represent events generated by calls to Window.postMessage, + * which asynchronously creates and dispatches events. + */ +class PostMessageEvent final : public nsRunnable +{ +public: + NS_DECL_NSIRUNNABLE + + PostMessageEvent(nsGlobalWindow* aSource, + const nsAString& aCallerOrigin, + nsGlobalWindow* aTargetWindow, + nsIPrincipal* aProvidedPrincipal, + bool aTrustedCaller); + + bool Write(JSContext* aCx, JS::Handle aMessage, + JS::Handle aTransfer, bool aSubsumes, + nsPIDOMWindow* aWindow); + +private: + ~PostMessageEvent(); + + const MessagePortIdentifier& GetPortIdentifier(uint64_t aId); + + MessagePortIdentifier* NewPortIdentifier(uint64_t* aPosition); + + bool StoreISupports(nsISupports* aSupports) + { + mSupportsArray.AppendElement(aSupports); + return true; + } + + static JSObject* + ReadStructuredClone(JSContext* cx, + JSStructuredCloneReader* reader, + uint32_t tag, + uint32_t data, + void* closure); + + static bool + WriteStructuredClone(JSContext* cx, + JSStructuredCloneWriter* writer, + JS::Handle obj, + void *closure); + + static bool + ReadTransferStructuredClone(JSContext* aCx, + JSStructuredCloneReader* reader, + uint32_t tag, void* aData, + uint64_t aExtraData, + void* aClosure, + JS::MutableHandle returnObject); + + static bool + TransferStructuredClone(JSContext* aCx, + JS::Handle aObj, + void* aClosure, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t* aExtraData); + + static void + FreeTransferStructuredClone(uint32_t aTag, + JS::TransferableOwnership aOwnership, + void *aContent, + uint64_t aExtraData, + void* aClosure); + + static const JSStructuredCloneCallbacks sPostMessageCallbacks; + + JSAutoStructuredCloneBuffer mBuffer; + nsRefPtr mSource; + nsString mCallerOrigin; + nsRefPtr mTargetWindow; + nsCOMPtr mProvidedPrincipal; + bool mTrustedCaller; + nsTArray> mSupportsArray; + nsTArray mPortIdentifiers; +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_PostMessageEvent_h diff --git a/dom/base/ProcessGlobal.cpp b/dom/base/ProcessGlobal.cpp index 21d89565de92..dbd2e6700e50 100644 --- a/dom/base/ProcessGlobal.cpp +++ b/dom/base/ProcessGlobal.cpp @@ -7,6 +7,7 @@ #include "ProcessGlobal.h" #include "nsContentCID.h" +#include "nsDOMClassInfoID.h" using namespace mozilla; using namespace mozilla::dom; diff --git a/dom/base/moz.build b/dom/base/moz.build index da333ad85598..d2a15365bcc9 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -179,9 +179,6 @@ EXPORTS.mozilla.dom += [ 'ImageEncoder.h', 'ImportManager.h', 'Link.h', - 'MessageChannel.h', - 'MessagePort.h', - 'MessagePortList.h', 'NameSpaceConstants.h', 'Navigator.h', 'NodeInfo.h', @@ -237,8 +234,6 @@ UNIFIED_SOURCES += [ 'ImageEncoder.cpp', 'ImportManager.cpp', 'Link.cpp', - 'MessageChannel.cpp', - 'MessagePortList.cpp', 'MultipartBlobImpl.cpp', 'Navigator.cpp', 'NodeInfo.cpp', @@ -329,6 +324,7 @@ UNIFIED_SOURCES += [ 'PerformanceMark.cpp', 'PerformanceMeasure.cpp', 'PerformanceResourceTiming.cpp', + 'PostMessageEvent.cpp', 'ProcessGlobal.cpp', 'ResponsiveImageSelector.cpp', 'SameProcessMessageQueue.cpp', @@ -353,8 +349,6 @@ if CONFIG['MOZ_WEBRTC']: # these files couldn't be in UNIFIED_SOURCES for now for reasons given below: SOURCES += [ - # this file doesn't like windows.h - 'MessagePort.cpp', # Because of OS X headers. 'nsContentUtils.cpp', # this file doesn't like windows.h diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 922866c59760..3349e65b57d8 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -218,6 +218,7 @@ nsIPrincipal *nsContentUtils::sNullSubjectPrincipal; nsIParserService *nsContentUtils::sParserService = nullptr; nsNameSpaceManager *nsContentUtils::sNameSpaceManager; nsIIOService *nsContentUtils::sIOService; +nsIUUIDGenerator *nsContentUtils::sUUIDGenerator; nsIConsoleService *nsContentUtils::sConsoleService; nsDataHashtable* nsContentUtils::sAtomEventTable = nullptr; nsDataHashtable* nsContentUtils::sStringEventTable = nullptr; @@ -551,6 +552,13 @@ nsContentUtils::Init() Element::InitCCCallbacks(); + nsCOMPtr uuidGenerator = + do_GetService("@mozilla.org/uuid-generator;1", &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + uuidGenerator.forget(&sUUIDGenerator); + sInitialized = true; return NS_OK; @@ -1803,6 +1811,7 @@ nsContentUtils::Shutdown() NS_IF_RELEASE(sNullSubjectPrincipal); NS_IF_RELEASE(sParserService); NS_IF_RELEASE(sIOService); + NS_IF_RELEASE(sUUIDGenerator); NS_IF_RELEASE(sLineBreaker); NS_IF_RELEASE(sWordBreaker); NS_IF_RELEASE(sBidiKeyboard); @@ -7151,6 +7160,19 @@ nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType) return false; } +nsresult +nsContentUtils::GenerateUUIDInPlace(nsID& aUUID) +{ + MOZ_ASSERT(sUUIDGenerator); + + nsresult rv = sUUIDGenerator->GenerateUUIDInPlace(&aUUID); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + uint64_t nsContentUtils::GetInnerWindowID(nsIRequest* aRequest) { diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 6ab02face49d..479cb67482e6 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -85,6 +85,7 @@ class nsIStringBundleService; class nsISupportsArray; class nsISupportsHashKey; class nsIURI; +class nsIUUIDGenerator; class nsIWidget; class nsIWordBreaker; class nsIXPConnect; @@ -853,6 +854,11 @@ public: */ static uint32_t ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr); + /** + * Helper function that generates a UUID. + */ + static nsresult GenerateUUIDInPlace(nsID& aUUID); + /** * Fill (with the parameters given) the localized string named |aKey| in @@ -2438,6 +2444,7 @@ private: static nsNameSpaceManager *sNameSpaceManager; static nsIIOService *sIOService; + static nsIUUIDGenerator *sUUIDGenerator; static bool sImgLoaderInitialized; static void InitImgLoader(); diff --git a/dom/base/nsCopySupport.cpp b/dom/base/nsCopySupport.cpp index bde0e70b9172..0885f275c203 100644 --- a/dom/base/nsCopySupport.cpp +++ b/dom/base/nsCopySupport.cpp @@ -11,6 +11,7 @@ #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsIClipboard.h" +#include "nsIFormControl.h" #include "nsISelection.h" #include "nsWidgetsCID.h" #include "nsXPCOM.h" diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index e385c7997230..7c6e3d20dfc1 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -277,15 +277,15 @@ BuildClonedMessageData(typename BlobTraits::ConcreteContentManagerType* SerializedStructuredCloneBuffer& buffer = aClonedData.data(); buffer.data = aData.mData; buffer.dataLength = aData.mDataLength; - const nsTArray>& blobs = aData.mClosure.mBlobs; - if (!blobs.IsEmpty()) { + const nsTArray>& blobImpls = aData.mClosure.mBlobImpls; + if (!blobImpls.IsEmpty()) { typedef typename BlobTraits::ProtocolType ProtocolType; InfallibleTArray& blobList = DataBlobs::Blobs(aClonedData); - uint32_t length = blobs.Length(); + uint32_t length = blobImpls.Length(); blobList.SetCapacity(length); for (uint32_t i = 0; i < length; ++i) { typename BlobTraits::BlobType* protocolActor = - aManager->GetOrCreateActorForBlob(blobs[i]); + aManager->GetOrCreateActorForBlobImpl(blobImpls[i]); if (!protocolActor) { return false; } @@ -323,7 +323,7 @@ UnpackClonedMessageData(const ClonedMessageData& aData) cloneData.mDataLength = buffer.dataLength; if (!blobs.IsEmpty()) { uint32_t length = blobs.Length(); - cloneData.mClosure.mBlobs.SetCapacity(length); + cloneData.mClosure.mBlobImpls.SetCapacity(length); for (uint32_t i = 0; i < length; ++i) { auto* blob = static_cast::BlobType*>(blobs[i]); @@ -332,10 +332,7 @@ UnpackClonedMessageData(const ClonedMessageData& aData) nsRefPtr blobImpl = blob->GetBlobImpl(); MOZ_ASSERT(blobImpl); - // This object will be duplicated with a correct parent before being - // exposed to JS. - nsRefPtr domBlob = Blob::Create(nullptr, blobImpl); - cloneData.mClosure.mBlobs.AppendElement(domBlob); + cloneData.mClosure.mBlobImpls.AppendElement(blobImpl); } } return cloneData; diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 7252824b72f0..a48f08e661ee 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -59,7 +59,6 @@ #include "nsLayoutStatics.h" #include "nsCCUncollectableMarker.h" #include "mozilla/dom/workers/Workers.h" -#include "mozilla/dom/MessagePortList.h" #include "mozilla/dom/ToJSValue.h" #include "nsJSPrincipals.h" #include "mozilla/Attributes.h" @@ -69,9 +68,9 @@ #include "mozilla/MouseEvents.h" #include "mozilla/ProcessHangMonitor.h" #include "AudioChannelService.h" -#include "MessageEvent.h" #include "nsAboutProtocolUtils.h" #include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE +#include "PostMessageEvent.h" // Interfaces Needed #include "nsIFrame.h" @@ -179,13 +178,9 @@ #include "prprf.h" #include "mozilla/dom/MessageChannel.h" -#include "mozilla/dom/MessagePort.h" -#include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/indexedDB/IDBFactory.h" #include "mozilla/dom/Promise.h" -#include "mozilla/dom/StructuredCloneTags.h" - #ifdef MOZ_GAMEPAD #include "mozilla/dom/Gamepad.h" #include "mozilla/dom/GamepadService.h" @@ -207,7 +202,6 @@ #include "TimeChangeObserver.h" #include "TouchCaret.h" #include "mozilla/dom/AudioContext.h" -#include "mozilla/dom/BlobBinding.h" #include "mozilla/dom/BrowserElementDictionariesBinding.h" #include "mozilla/dom/cache/CacheStorage.h" #include "mozilla/dom/Console.h" @@ -8038,367 +8032,6 @@ nsGlobalWindow::CallerInnerWindow() return static_cast(win.get()); } -/** - * Class used to represent events generated by calls to Window.postMessage, - * which asynchronously creates and dispatches events. - */ -class PostMessageEvent : public nsRunnable -{ - public: - NS_DECL_NSIRUNNABLE - - PostMessageEvent(nsGlobalWindow* aSource, - const nsAString& aCallerOrigin, - nsGlobalWindow* aTargetWindow, - nsIPrincipal* aProvidedPrincipal, - bool aTrustedCaller) - : mSource(aSource), - mCallerOrigin(aCallerOrigin), - mTargetWindow(aTargetWindow), - mProvidedPrincipal(aProvidedPrincipal), - mTrustedCaller(aTrustedCaller) - { - MOZ_COUNT_CTOR(PostMessageEvent); - } - -protected: - ~PostMessageEvent() - { - MOZ_COUNT_DTOR(PostMessageEvent); - } - -public: - JSAutoStructuredCloneBuffer& Buffer() - { - return mBuffer; - } - - bool StoreISupports(nsISupports* aSupports) - { - mSupportsArray.AppendElement(aSupports); - return true; - } - - private: - JSAutoStructuredCloneBuffer mBuffer; - nsRefPtr mSource; - nsString mCallerOrigin; - nsRefPtr mTargetWindow; - nsCOMPtr mProvidedPrincipal; - bool mTrustedCaller; - nsTArray > mSupportsArray; -}; - -namespace { - -struct StructuredCloneInfo { - PostMessageEvent* event; - bool subsumes; - nsPIDOMWindow* window; - nsRefPtrHashtable, MessagePortBase> ports; -}; - -static JSObject* -PostMessageReadStructuredClone(JSContext* cx, - JSStructuredCloneReader* reader, - uint32_t tag, - uint32_t data, - void* closure) -{ - StructuredCloneInfo* scInfo = static_cast(closure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (tag == SCTAG_DOM_BLOB) { - NS_ASSERTION(!data, "Data should be empty"); - - // What we get back from the reader is a BlobImpl. - // From that we create a new File. - BlobImpl* blobImpl; - if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) { - MOZ_ASSERT(blobImpl); - - // nsRefPtr needs to go out of scope before toObjectOrNull() is - // called because the static analysis thinks dereferencing XPCOM objects - // can GC (because in some cases it can!), and a return statement with a - // JSObject* type means that JSObject* is on the stack as a raw pointer - // while destructors are running. - JS::Rooted val(cx); - { - nsRefPtr blob = Blob::Create(scInfo->window, blobImpl); - if (!ToJSValue(cx, blob, &val)) { - return nullptr; - } - } - - return &val.toObject(); - } - } - - if (tag == SCTAG_DOM_FILELIST) { - NS_ASSERTION(!data, "Data should be empty"); - - nsISupports* supports; - if (JS_ReadBytes(reader, &supports, sizeof(supports))) { - JS::Rooted val(cx); - if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) { - return val.toObjectOrNull(); - } - } - } - - const JSStructuredCloneCallbacks* runtimeCallbacks = - js::GetContextStructuredCloneCallbacks(cx); - - if (runtimeCallbacks) { - return runtimeCallbacks->read(cx, reader, tag, data, nullptr); - } - - return nullptr; -} - -static bool -PostMessageWriteStructuredClone(JSContext* cx, - JSStructuredCloneWriter* writer, - JS::Handle obj, - void *closure) -{ - StructuredCloneInfo* scInfo = static_cast(closure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - // See if this is a File/Blob object. - { - Blob* blob = nullptr; - if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) { - BlobImpl* blobImpl = blob->Impl(); - if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) && - JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) { - scInfo->event->StoreISupports(blobImpl); - return true; - } - } - } - - nsCOMPtr wrappedNative; - nsContentUtils::XPConnect()-> - GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative)); - if (wrappedNative) { - uint32_t scTag = 0; - nsISupports* supports = wrappedNative->Native(); - - nsCOMPtr list = do_QueryInterface(supports); - if (list && scInfo->subsumes) - scTag = SCTAG_DOM_FILELIST; - - if (scTag) - return JS_WriteUint32Pair(writer, scTag, 0) && - JS_WriteBytes(writer, &supports, sizeof(supports)) && - scInfo->event->StoreISupports(supports); - } - - const JSStructuredCloneCallbacks* runtimeCallbacks = - js::GetContextStructuredCloneCallbacks(cx); - - if (runtimeCallbacks) { - return runtimeCallbacks->write(cx, writer, obj, nullptr); - } - - return false; -} - -static bool -PostMessageReadTransferStructuredClone(JSContext* aCx, - JSStructuredCloneReader* reader, - uint32_t tag, void* aData, - uint64_t aExtraData, - void* aClosure, - JS::MutableHandle returnObject) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (tag == SCTAG_DOM_MAP_MESSAGEPORT) { - MessagePort* port = static_cast(aData); - port->BindToOwner(scInfo->window); - scInfo->ports.Put(port, nullptr); - - JS::Rooted obj(aCx, port->WrapObject(aCx, nullptr)); - if (JS_WrapObject(aCx, &obj)) { - MOZ_ASSERT(port->GetOwner() == scInfo->window); - returnObject.set(obj); - } - - return true; - } - - return false; -} - -static bool -PostMessageTransferStructuredClone(JSContext* aCx, - JS::Handle aObj, - void* aClosure, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t* aExtraData) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - MessagePortBase* port = nullptr; - nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); - if (NS_SUCCEEDED(rv)) { - nsRefPtr newPort; - if (scInfo->ports.Get(port, getter_AddRefs(newPort))) { - // No duplicate. - return false; - } - - newPort = port->Clone(); - scInfo->ports.Put(port, newPort); - - *aTag = SCTAG_DOM_MAP_MESSAGEPORT; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = newPort; - *aExtraData = 0; - - return true; - } - - return false; -} - -void -PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership, - void *aContent, uint64_t aExtraData, void* aClosure) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { - nsRefPtr port(static_cast(aContent)); - scInfo->ports.Remove(port); - } -} - -const JSStructuredCloneCallbacks kPostMessageCallbacks = { - PostMessageReadStructuredClone, - PostMessageWriteStructuredClone, - nullptr, - PostMessageReadTransferStructuredClone, - PostMessageTransferStructuredClone, - PostMessageFreeTransferStructuredClone -}; - -} // anonymous namespace - -static PLDHashOperator -PopulateMessagePortList(MessagePortBase* aKey, MessagePortBase* aValue, void* aClosure) -{ - nsTArray > *array = - static_cast > *>(aClosure); - - array->AppendElement(aKey); - return PL_DHASH_NEXT; -} - -NS_IMETHODIMP -PostMessageEvent::Run() -{ - MOZ_ASSERT(mTargetWindow->IsOuterWindow(), - "should have been passed an outer window!"); - MOZ_ASSERT(!mSource || mSource->IsOuterWindow(), - "should have been passed an outer window!"); - - AutoJSAPI jsapi; - jsapi.Init(); - JSContext* cx = jsapi.cx(); - - // If we bailed before this point we're going to leak mMessage, but - // that's probably better than crashing. - - nsRefPtr targetWindow; - if (mTargetWindow->IsClosedOrClosing() || - !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) || - targetWindow->IsClosedOrClosing()) - return NS_OK; - - MOZ_ASSERT(targetWindow->IsInnerWindow(), - "we ordered an inner window!"); - JSAutoCompartment ac(cx, targetWindow->GetWrapperPreserveColor()); - - // Ensure that any origin which might have been provided is the origin of this - // window's document. Note that we do this *now* instead of when postMessage - // is called because the target window might have been navigated to a - // different location between then and now. If this check happened when - // postMessage was called, it would be fairly easy for a malicious webpage to - // intercept messages intended for another site by carefully timing navigation - // of the target window so it changed location after postMessage but before - // now. - if (mProvidedPrincipal) { - // 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 - // document. - nsIPrincipal* targetPrin = targetWindow->GetPrincipal(); - if (NS_WARN_IF(!targetPrin)) - return NS_OK; - - // Note: This is contrary to the spec with respect to file: URLs, which - // 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 - // now. Long-term, we want HTML5 to address this so that we can - // be compliant while being safer. - if (!targetPrin->Equals(mProvidedPrincipal)) { - return NS_OK; - } - } - - // Deserialize the structured clone data - JS::Rooted messageData(cx); - StructuredCloneInfo scInfo; - scInfo.event = this; - scInfo.window = targetWindow; - - if (!mBuffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo)) { - return NS_ERROR_DOM_DATA_CLONE_ERR; - } - - // Create the event - nsCOMPtr eventTarget = - do_QueryInterface(static_cast(targetWindow.get())); - nsRefPtr event = - new MessageEvent(eventTarget, nullptr, nullptr); - - event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */, - false /*cancelable */, messageData, mCallerOrigin, - EmptyString(), mSource); - - nsTArray > ports; - scInfo.ports.EnumerateRead(PopulateMessagePortList, &ports); - event->SetPorts(new MessagePortList(static_cast(event.get()), ports)); - - // We can't simply call dispatchEvent on the window because doing so ends - // up flipping the trusted bit on the event, and we don't want that to - // happen because then untrusted content can call postMessage on a chrome - // window if it can get a reference to it. - - nsIPresShell *shell = targetWindow->mDoc->GetShell(); - nsRefPtr presContext; - if (shell) - presContext = shell->GetPresContext(); - - event->SetTrusted(mTrustedCaller); - WidgetEvent* internalEvent = event->GetInternalNSEvent(); - - nsEventStatus status = nsEventStatus_eIgnore; - EventDispatcher::Dispatch(static_cast(mTargetWindow), - presContext, - internalEvent, - static_cast(event.get()), - &status); - return NS_OK; -} - void nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, const nsAString& aTargetOrigin, @@ -8522,18 +8155,13 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, providedPrincipal, nsContentUtils::IsCallerChrome()); - // We *must* clone the data here, or the JS::Value could be modified - // by script - StructuredCloneInfo scInfo; - scInfo.event = event; - scInfo.window = this; - nsIPrincipal* principal = GetPrincipal(); JS::Rooted message(aCx, aMessage); JS::Rooted transfer(aCx, aTransfer); - if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)) || - !event->Buffer().write(aCx, message, transfer, &kPostMessageCallbacks, - &scInfo)) { + bool subsumes; + + if (NS_FAILED(callerPrin->Subsumes(principal, &subsumes)) || + !event->Write(aCx, message, transfer, subsumes, this)) { aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 15871c2c8ff1..b38ab2e77d3a 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -111,6 +111,7 @@ class MozSelfSupport; class Navigator; class OwningExternalOrWindowProxy; class Promise; +class PostMessageEvent; struct RequestInit; class RequestOrUSVString; class Selection; @@ -1752,7 +1753,7 @@ protected: friend class nsDOMScriptableHelper; friend class nsDOMWindowUtils; - friend class PostMessageEvent; + friend class mozilla::dom::PostMessageEvent; friend class DesktopNotification; static WindowByIdTable* sWindowsById; diff --git a/dom/base/test/chrome.ini b/dom/base/test/chrome.ini index 34f81ead9d99..9684ee8dba5a 100644 --- a/dom/base/test/chrome.ini +++ b/dom/base/test/chrome.ini @@ -13,7 +13,6 @@ support-files = [test_domrequesthelper.xul] [test_url.xul] [test_console.xul] -[test_messageChannel.xul] [test_navigator_resolve_identity_xrays.xul] [test_sendQueryContentAndSelectionSetEvent.html] [test_bug1016960.html] diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index cb92be425c36..c6479fdbc53a 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -4,10 +4,6 @@ support-files = iframe_bug976673.html iframe_main_bug1022229.html iframe_sandbox_bug1022229.html - iframe_messageChannel_cloning.html - iframe_messageChannel_chrome.html - iframe_messageChannel_pingpong.html - iframe_messageChannel_post.html file_empty.html iframe_postMessage_solidus.html file_setname.html @@ -286,15 +282,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1 [test_history_state_null.html] [test_Image_constructor.html] [test_innersize_scrollport.html] -[test_messageChannel.html] -[test_messageChannel_cloning.html] -[test_messageChannel_pingpong.html] -[test_messageChannel_post.html] -[test_messageChannel_pref.html] -[test_messageChannel_start.html] [test_messagemanager_targetchain.html] -[test_messageChannel_transferable.html] -[test_messageChannel_unshipped.html] [test_named_frames.html] [test_navigator_resolve_identity.html] [test_navigator_language.html] diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 2b0181dd8a95..110bb45572a8 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -729,9 +729,6 @@ DOMInterfaces = { 'MessagePort': { 'nativeType': 'mozilla::dom::MessagePortBase', 'headerFile': 'mozilla/dom/MessagePort.h', - 'binaryNames': { - 'postMessage': 'postMessageMoz', - }, }, 'MimeType': { diff --git a/dom/broadcastchannel/BroadcastChannel.cpp b/dom/broadcastchannel/BroadcastChannel.cpp index 325722cfcaab..ae00470858a6 100644 --- a/dom/broadcastchannel/BroadcastChannel.cpp +++ b/dom/broadcastchannel/BroadcastChannel.cpp @@ -212,14 +212,15 @@ public: PBackgroundChild* backgroundManager = mActor->Manager(); MOZ_ASSERT(backgroundManager); - const nsTArray>& blobs = mData->mClosure.mBlobs; + const nsTArray>& blobImpls = mData->mClosure.mBlobImpls; - if (!blobs.IsEmpty()) { - message.blobsChild().SetCapacity(blobs.Length()); + if (!blobImpls.IsEmpty()) { + message.blobsChild().SetCapacity(blobImpls.Length()); - for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) { + for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { PBlobChild* blobChild = - BackgroundChild::GetOrCreateActorForBlob(backgroundManager, blobs[i]); + BackgroundChild::GetOrCreateActorForBlobImpl(backgroundManager, + blobImpls[i]); MOZ_ASSERT(blobChild); message.blobsChild().AppendElement(blobChild); @@ -541,9 +542,9 @@ BroadcastChannel::PostMessageInternal(JSContext* aCx, return; } - const nsTArray>& blobs = data->mClosure.mBlobs; - for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) { - if (!blobs[i]->Impl()->MayBeClonedToOtherThreads()) { + const nsTArray>& blobImpls = data->mClosure.mBlobImpls; + for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { + if (!blobImpls[i]->MayBeClonedToOtherThreads()) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } diff --git a/dom/broadcastchannel/BroadcastChannelChild.cpp b/dom/broadcastchannel/BroadcastChannelChild.cpp index 40c394e68729..6b8647064581 100644 --- a/dom/broadcastchannel/BroadcastChannelChild.cpp +++ b/dom/broadcastchannel/BroadcastChannelChild.cpp @@ -42,7 +42,7 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData) { // Make sure to retrieve all blobs from the message before returning to avoid // leaking their actors. - nsTArray> blobs; + nsTArray> blobs; if (!aData.blobsChild().IsEmpty()) { blobs.SetCapacity(aData.blobsChild().Length()); @@ -50,8 +50,7 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData) nsRefPtr impl = static_cast(aData.blobsChild()[i])->GetBlobImpl(); - nsRefPtr blob = Blob::Create(mBC ? mBC->GetOwner() : nullptr, impl); - blobs.AppendElement(blob); + blobs.AppendElement(impl); } } @@ -92,7 +91,7 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData) StructuredCloneData cloneData; cloneData.mData = buffer.data; cloneData.mDataLength = buffer.dataLength; - cloneData.mClosure.mBlobs.SwapElements(blobs); + cloneData.mClosure.mBlobImpls.SwapElements(blobs); JS::Rooted value(cx, JS::NullValue()); if (cloneData.mDataLength && !ReadStructuredClone(cx, cloneData, &value)) { diff --git a/dom/ipc/StructuredCloneUtils.cpp b/dom/ipc/StructuredCloneUtils.cpp index cba261c1f7a0..f7ced0cdb034 100644 --- a/dom/ipc/StructuredCloneUtils.cpp +++ b/dom/ipc/StructuredCloneUtils.cpp @@ -50,14 +50,14 @@ Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, // while destructors are running. JS::Rooted val(aCx); { - MOZ_ASSERT(aData < closure->mBlobs.Length()); - nsRefPtr blob = closure->mBlobs[aData]; + MOZ_ASSERT(aData < closure->mBlobImpls.Length()); + nsRefPtr blobImpl = closure->mBlobImpls[aData]; #ifdef DEBUG { // Blob should not be mutable. bool isMutable; - MOZ_ASSERT(NS_SUCCEEDED(blob->GetMutable(&isMutable))); + MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable))); MOZ_ASSERT(!isMutable); } #endif @@ -66,7 +66,7 @@ Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)); MOZ_ASSERT(global); - nsRefPtr newBlob = Blob::Create(global, blob->Impl()); + nsRefPtr newBlob = Blob::Create(global, blobImpl); if (!ToJSValue(aCx, newBlob, &val)) { return nullptr; } @@ -93,8 +93,8 @@ Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) && NS_SUCCEEDED(blob->SetMutable(false)) && JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, - closure->mBlobs.Length())) { - closure->mBlobs.AppendElement(blob); + closure->mBlobImpls.Length())) { + closure->mBlobImpls.AppendElement(blob->Impl()); return true; } } diff --git a/dom/ipc/StructuredCloneUtils.h b/dom/ipc/StructuredCloneUtils.h index b103d54a4122..f8d1c37d7dbe 100644 --- a/dom/ipc/StructuredCloneUtils.h +++ b/dom/ipc/StructuredCloneUtils.h @@ -19,7 +19,7 @@ namespace dom { struct StructuredCloneClosure { - nsTArray> mBlobs; + nsTArray> mBlobImpls; }; struct diff --git a/dom/messagechannel/MessageChannel.cpp b/dom/messagechannel/MessageChannel.cpp new file mode 100644 index 000000000000..a2635d10c2e5 --- /dev/null +++ b/dom/messagechannel/MessageChannel.cpp @@ -0,0 +1,228 @@ +/* -*- Mode: C++; tab-width: 8; 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 "MessageChannel.h" + +#include "mozilla/Preferences.h" +#include "mozilla/dom/MessageChannelBinding.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/Navigator.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerRunnable.h" +#include "nsContentUtils.h" +#include "nsIDocument.h" +#include "nsIPrincipal.h" +#include "nsPIDOMWindow.h" +#include "nsServiceManagerUtils.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mWindow, mPort1, mPort2) +NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel) +NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +namespace { +bool gPrefInitialized = false; +bool gPrefEnabled = false; + +bool +CheckPermission(nsIPrincipal* aPrincipal, bool aCallerChrome) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (!gPrefInitialized) { + Preferences::AddBoolVarCache(&gPrefEnabled, "dom.messageChannel.enabled"); + gPrefInitialized = true; + } + + // Enabled by pref + if (gPrefEnabled) { + return true; + } + + // Chrome callers are allowed. + if (aCallerChrome) { + return true; + } + + nsCOMPtr uri; + if (NS_FAILED(aPrincipal->GetURI(getter_AddRefs(uri))) || !uri) { + return false; + } + + bool isResource = false; + if (NS_FAILED(uri->SchemeIs("resource", &isResource))) { + return false; + } + + return isResource; +} + +nsIPrincipal* +GetPrincipalFromWorkerPrivate(workers::WorkerPrivate* aWorkerPrivate) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsIPrincipal* principal = aWorkerPrivate->GetPrincipal(); + if (principal) { + return principal; + } + + // Walk up to our containing page + workers::WorkerPrivate* wp = aWorkerPrivate; + while (wp->GetParent()) { + wp = wp->GetParent(); + } + + nsPIDOMWindow* window = wp->GetWindow(); + if (!window) { + return nullptr; + } + + nsIDocument* doc = window->GetExtantDoc(); + if (!doc) { + return nullptr; + } + + return doc->NodePrincipal(); +} + +// A WorkerMainThreadRunnable to synchronously dispatch the call of +// CheckPermission() from the worker thread to the main thread. +class CheckPermissionRunnable final : public workers::WorkerMainThreadRunnable +{ +public: + bool mResult; + bool mCallerChrome; + + explicit CheckPermissionRunnable(workers::WorkerPrivate* aWorkerPrivate) + : workers::WorkerMainThreadRunnable(aWorkerPrivate) + , mResult(false) + , mCallerChrome(false) + { + MOZ_ASSERT(aWorkerPrivate); + aWorkerPrivate->AssertIsOnWorkerThread(); + mCallerChrome = aWorkerPrivate->UsesSystemPrincipal(); + } + +protected: + virtual bool + MainThreadRun() override + { + MOZ_ASSERT(NS_IsMainThread()); + + nsIPrincipal* principal = GetPrincipalFromWorkerPrivate(mWorkerPrivate); + if (!principal) { + return true; + } + + bool isNullPrincipal; + nsresult rv = principal->GetIsNullPrincipal(&isNullPrincipal); + if (NS_WARN_IF(NS_FAILED(rv))) { + return true; + } + + if (NS_WARN_IF(isNullPrincipal)) { + return true; + } + + mResult = CheckPermission(principal, mCallerChrome); + return true; + } +}; + +} // anonymous namespace + +/* static */ bool +MessageChannel::Enabled(JSContext* aCx, JSObject* aGlobal) +{ + if (NS_IsMainThread()) { + JS::Rooted global(aCx, aGlobal); + + nsCOMPtr win = Navigator::GetWindowFromGlobal(global); + if (!win) { + return false; + } + + nsIDocument* doc = win->GetExtantDoc(); + if (!doc) { + return false; + } + + return CheckPermission(doc->NodePrincipal(), + nsContentUtils::IsCallerChrome()); + } + + workers::WorkerPrivate* workerPrivate = + workers::GetWorkerPrivateFromContext(aCx); + workerPrivate->AssertIsOnWorkerThread(); + + nsRefPtr runnable = + new CheckPermissionRunnable(workerPrivate); + runnable->Dispatch(aCx); + + return runnable->mResult; +} + +MessageChannel::MessageChannel(nsPIDOMWindow* aWindow) + : mWindow(aWindow) +{ +} + +MessageChannel::~MessageChannel() +{ +} + +JSObject* +MessageChannel::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return MessageChannelBinding::Wrap(aCx, this, aGivenProto); +} + +/* static */ already_AddRefed +MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) +{ + // window can be null in workers. + nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); + + nsID portUUID1; + aRv = nsContentUtils::GenerateUUIDInPlace(portUUID1); + if (aRv.Failed()) { + return nullptr; + } + + nsID portUUID2; + aRv = nsContentUtils::GenerateUUIDInPlace(portUUID2); + if (aRv.Failed()) { + return nullptr; + } + + nsRefPtr channel = new MessageChannel(window); + + channel->mPort1 = MessagePort::Create(window, portUUID1, portUUID2, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + channel->mPort2 = MessagePort::Create(window, portUUID2, portUUID1, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + + channel->mPort1->UnshippedEntangle(channel->mPort2); + channel->mPort2->UnshippedEntangle(channel->mPort1); + + return channel.forget(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/MessageChannel.h b/dom/messagechannel/MessageChannel.h similarity index 99% rename from dom/base/MessageChannel.h rename to dom/messagechannel/MessageChannel.h index 14a14b5c5d6c..a20921dfa8e8 100644 --- a/dom/base/MessageChannel.h +++ b/dom/messagechannel/MessageChannel.h @@ -31,8 +31,6 @@ public: static bool Enabled(JSContext* aCx, JSObject* aGlobal); public: - explicit MessageChannel(nsPIDOMWindow* aWindow); - nsPIDOMWindow* GetParentObject() const { @@ -58,6 +56,7 @@ public: } private: + explicit MessageChannel(nsPIDOMWindow* aWindow); ~MessageChannel(); nsCOMPtr mWindow; diff --git a/dom/messagechannel/MessagePort.cpp b/dom/messagechannel/MessagePort.cpp new file mode 100644 index 000000000000..6a328bb969ee --- /dev/null +++ b/dom/messagechannel/MessagePort.cpp @@ -0,0 +1,867 @@ +/* -*- Mode: C++; tab-width: 8; 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 "MessagePort.h" + +#include "MessageEvent.h" +#include "MessagePortChild.h" +#include "mozilla/dom/BlobBinding.h" +#include "mozilla/dom/Event.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/MessageChannel.h" +#include "mozilla/dom/MessagePortBinding.h" +#include "mozilla/dom/MessagePortChild.h" +#include "mozilla/dom/MessagePortList.h" +#include "mozilla/dom/PMessagePort.h" +#include "mozilla/dom/StructuredCloneTags.h" +#include "mozilla/dom/WorkerPrivate.h" +#include "mozilla/dom/WorkerScope.h" +#include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/ipc/PBackgroundChild.h" +#include "nsContentUtils.h" +#include "nsGlobalWindow.h" +#include "nsPresContext.h" +#include "ScriptSettings.h" +#include "SharedMessagePortMessage.h" + +#include "nsIBFCacheEntry.h" +#include "nsIDocument.h" +#include "nsIDOMFileList.h" +#include "nsIPresShell.h" +#include "nsISupportsPrimitives.h" +#include "nsServiceManagerUtils.h" + +#ifdef XP_WIN +#undef PostMessage +#endif + +using namespace mozilla::dom::workers; + +namespace mozilla { +namespace dom { + +class DispatchEventRunnable final : public nsICancelableRunnable +{ + friend class MessagePort; + +public: + NS_DECL_ISUPPORTS + + explicit DispatchEventRunnable(MessagePort* aPort) + : mPort(aPort) + { } + + NS_IMETHOD + Run() override + { + MOZ_ASSERT(mPort); + MOZ_ASSERT(mPort->mDispatchRunnable == this); + mPort->mDispatchRunnable = nullptr; + mPort->Dispatch(); + + return NS_OK; + } + + NS_IMETHOD + Cancel() override + { + mPort = nullptr; + return NS_OK; + } + +private: + ~DispatchEventRunnable() + {} + + nsRefPtr mPort; +}; + +NS_IMPL_ISUPPORTS(DispatchEventRunnable, nsICancelableRunnable, nsIRunnable) + +class PostMessageRunnable final : public nsICancelableRunnable +{ +public: + NS_DECL_ISUPPORTS + + PostMessageRunnable(MessagePort* aPort, SharedMessagePortMessage* aData) + : mPort(aPort) + , mData(aData) + { + MOZ_ASSERT(aPort); + MOZ_ASSERT(aData); + } + + NS_IMETHOD + Run() override + { + nsCOMPtr globalObject; + + if (NS_IsMainThread()) { + globalObject = do_QueryInterface(mPort->GetParentObject()); + } else { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + globalObject = workerPrivate->GlobalScope(); + } + + AutoJSAPI jsapi; + if (!globalObject || !jsapi.Init(globalObject)) { + NS_WARNING("Failed to initialize AutoJSAPI object."); + return NS_ERROR_FAILURE; + } + + JSContext* cx = jsapi.cx(); + + nsTArray> ports; + nsCOMPtr window = + do_QueryInterface(mPort->GetParentObject()); + + JS::Rooted value(cx); + if (!mData->mData.IsEmpty()) { + bool ok = ReadStructuredCloneWithTransfer(cx, mData->mData, + mData->mClosure, + &value, window, ports); + FreeStructuredClone(mData->mData, mData->mClosure); + + if (!ok) { + return NS_ERROR_FAILURE; + } + } + + // The data should be already be cleaned. + MOZ_ASSERT(!mData->mData.Length()); + + // Create the event + nsCOMPtr eventTarget = + do_QueryInterface(mPort->GetOwner()); + nsRefPtr event = + new MessageEvent(eventTarget, nullptr, nullptr); + + event->InitMessageEvent(NS_LITERAL_STRING("message"), + false /* non-bubbling */, + false /* cancelable */, value, EmptyString(), + EmptyString(), nullptr); + event->SetTrusted(true); + event->SetSource(mPort); + + nsTArray> array; + array.SetCapacity(ports.Length()); + for (uint32_t i = 0; i < ports.Length(); ++i) { + array.AppendElement(ports[i]); + } + + nsRefPtr portList = + new MessagePortList(static_cast(event.get()), array); + event->SetPorts(portList); + + bool dummy; + mPort->DispatchEvent(static_cast(event.get()), &dummy); + return NS_OK; + } + + NS_IMETHOD + Cancel() override + { + mPort = nullptr; + mData = nullptr; + return NS_OK; + } + +private: + ~PostMessageRunnable() + {} + + nsRefPtr mPort; + nsRefPtr mData; +}; + +NS_IMPL_ISUPPORTS(PostMessageRunnable, nsICancelableRunnable, nsIRunnable) + +MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow) + : DOMEventTargetHelper(aWindow) +{ +} + +MessagePortBase::MessagePortBase() +{ +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort, + MessagePortBase) + if (tmp->mDispatchRunnable) { + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort); + } + + NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessages); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagesForTheOtherPort); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mUnshippedEntangledPort); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort, + MessagePortBase) + if (tmp->mDispatchRunnable) { + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort); + } + + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnshippedEntangledPort); +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort) + NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback) + NS_INTERFACE_MAP_ENTRY(nsIObserver) +NS_INTERFACE_MAP_END_INHERITING(MessagePortBase) + +NS_IMPL_ADDREF_INHERITED(MessagePort, MessagePortBase) +NS_IMPL_RELEASE_INHERITED(MessagePort, MessagePortBase) + +namespace { + +class MessagePortFeature final : public workers::WorkerFeature +{ + MessagePort* mPort; + +public: + explicit MessagePortFeature(MessagePort* aPort) + : mPort(aPort) + { + MOZ_ASSERT(aPort); + MOZ_COUNT_CTOR(MessagePortFeature); + } + + virtual bool Notify(JSContext* aCx, workers::Status aStatus) override + { + if (mPort && aStatus > Running) { + mPort->Close(); + } + + return true; + } + +private: + ~MessagePortFeature() + { + MOZ_COUNT_DTOR(MessagePortFeature); + } +}; + +} // anonymous namespace + +MessagePort::MessagePort(nsPIDOMWindow* aWindow) + : MessagePortBase(aWindow) + , mInnerID(0) + , mMessageQueueEnabled(false) + , mIsKeptAlive(false) +{ + mIdentifier = new MessagePortIdentifier(); + mIdentifier->neutered() = true; + mIdentifier->sequenceId() = 0; +} + +MessagePort::~MessagePort() +{ + Close(); + MOZ_ASSERT(!mWorkerFeature); +} + +/* static */ already_AddRefed +MessagePort::Create(nsPIDOMWindow* aWindow, const nsID& aUUID, + const nsID& aDestinationUUID, ErrorResult& aRv) +{ + nsRefPtr mp = new MessagePort(aWindow); + mp->Initialize(aUUID, aDestinationUUID, 1 /* 0 is an invalid sequence ID */, + false /* Neutered */, eStateUnshippedEntangled, aRv); + return mp.forget(); +} + +/* static */ already_AddRefed +MessagePort::Create(nsPIDOMWindow* aWindow, + const MessagePortIdentifier& aIdentifier, + ErrorResult& aRv) +{ + nsRefPtr mp = new MessagePort(aWindow); + mp->Initialize(aIdentifier.uuid(), aIdentifier.destinationUuid(), + aIdentifier.sequenceId(), aIdentifier.neutered(), + eStateEntangling, aRv); + return mp.forget(); +} + +void +MessagePort::UnshippedEntangle(MessagePort* aEntangledPort) +{ + MOZ_ASSERT(aEntangledPort); + MOZ_ASSERT(!mUnshippedEntangledPort); + + mUnshippedEntangledPort = aEntangledPort; +} + +void +MessagePort::Initialize(const nsID& aUUID, + const nsID& aDestinationUUID, + uint32_t aSequenceID, bool mNeutered, + State aState, ErrorResult& aRv) +{ + MOZ_ASSERT(mIdentifier); + mIdentifier->uuid() = aUUID; + mIdentifier->destinationUuid() = aDestinationUUID; + mIdentifier->sequenceId() = aSequenceID; + + mState = aState; + mNextStep = eNextStepNone; + + if (mNeutered) { + mState = eStateDisentangled; + } else if (mState == eStateEntangling) { + ConnectToPBackground(); + } else { + MOZ_ASSERT(mState == eStateUnshippedEntangled); + } + + // The port has to keep itself alive until it's entangled. + UpdateMustKeepAlive(); + + if (NS_IsMainThread()) { + MOZ_ASSERT(GetOwner()); + MOZ_ASSERT(GetOwner()->IsInnerWindow()); + mInnerID = GetOwner()->WindowID(); + + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(this, "inner-window-destroyed", false); + } + } else { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + MOZ_ASSERT(!mWorkerFeature); + + nsAutoPtr feature(new MessagePortFeature(this)); + JSContext* cx = workerPrivate->GetJSContext(); + if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + mWorkerFeature = Move(feature); + } +} + +JSObject* +MessagePort::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return MessagePortBinding::Wrap(aCx, this, aGivenProto); +} + +void +MessagePort::PostMessage(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) +{ + // We *must* clone the data here, or the JS::Value could be modified + // by script + + JS::Rooted transferable(aCx, JS::UndefinedValue()); + if (aTransferable.WasPassed()) { + const Sequence& realTransferable = aTransferable.Value(); + + // Here we want to check if the transerable object list contains + // this port. No other checks are done. + for (const JS::Value& value : realTransferable) { + if (!value.isObject()) { + continue; + } + + MessagePortBase* port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, &value.toObject(), port); + if (NS_FAILED(rv)) { + continue; + } + + if (port == this) { + aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); + return; + } + } + + // The input sequence only comes from the generated bindings code, which + // ensures it is rooted. + JS::HandleValueArray elements = + JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), + realTransferable.Elements()); + + JSObject* array = + JS_NewArrayObject(aCx, elements); + if (!array) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + + transferable.setObject(*array); + } + + nsRefPtr data = new SharedMessagePortMessage(); + + if (!WriteStructuredCloneWithTransfer(aCx, aMessage, transferable, + data->mData, data->mClosure)) { + aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); + return; + } + + // This message has to be ignored. + if (mState > eStateEntangled) { + return; + } + + // If we are unshipped we are connected to the other port on the same thread. + if (mState == eStateUnshippedEntangled) { + MOZ_ASSERT(mUnshippedEntangledPort); + mUnshippedEntangledPort->mMessages.AppendElement(data); + mUnshippedEntangledPort->Dispatch(); + return; + } + + // Not entangled yet, but already closed. + if (mNextStep != eNextStepNone) { + return; + } + + RemoveDocFromBFCache(); + + // Not entangled yet. + if (mState == eStateEntangling) { + mMessagesForTheOtherPort.AppendElement(data); + return; + } + + MOZ_ASSERT(mActor); + MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty()); + + nsAutoTArray, 1> array; + array.AppendElement(data); + + nsAutoTArray messages; + SharedMessagePortMessage::FromSharedToMessagesChild(mActor, array, messages); + mActor->SendPostMessages(messages); +} + +void +MessagePort::Start() +{ + if (mMessageQueueEnabled) { + return; + } + + mMessageQueueEnabled = true; + Dispatch(); +} + +void +MessagePort::Dispatch() +{ + if (!mMessageQueueEnabled || mMessages.IsEmpty() || mDispatchRunnable || + mState > eStateEntangled || mNextStep != eNextStepNone) { + return; + } + + nsRefPtr data = mMessages.ElementAt(0); + mMessages.RemoveElementAt(0); + + nsRefPtr runnable = new PostMessageRunnable(this, data); + + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable))); + + mDispatchRunnable = new DispatchEventRunnable(this); + + MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(mDispatchRunnable))); +} + +void +MessagePort::Close() +{ + // Not entangled yet, but already closed. + if (mNextStep != eNextStepNone) { + return; + } + + if (mState == eStateUnshippedEntangled) { + MOZ_ASSERT(mUnshippedEntangledPort); + + // This avoids loops. + nsRefPtr port = Move(mUnshippedEntangledPort); + MOZ_ASSERT(mUnshippedEntangledPort == nullptr); + + mState = eStateDisentangled; + port->Close(); + + UpdateMustKeepAlive(); + return; + } + + // Not entangled yet, we have to wait. + if (mState < eStateEntangling) { + mNextStep = eNextStepClose; + return; + } + + if (mState > eStateEntangled) { + return; + } + + // We don't care about stopping the sending of messages because from now all + // the incoming messages will be ignored. + mState = eStateDisentangled; + + MOZ_ASSERT(mActor); + + mActor->SendClose(); + mActor->SetPort(nullptr); + mActor = nullptr; + + UpdateMustKeepAlive(); +} + +EventHandlerNonNull* +MessagePort::GetOnmessage() +{ + if (NS_IsMainThread()) { + return GetEventHandler(nsGkAtoms::onmessage, EmptyString()); + } + return GetEventHandler(nullptr, NS_LITERAL_STRING("message")); +} + +void +MessagePort::SetOnmessage(EventHandlerNonNull* aCallback) +{ + if (NS_IsMainThread()) { + SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback); + } else { + SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback); + } + + // When using onmessage, the call to start() is implied. + Start(); +} + +// This method is called when the PMessagePortChild actor is entangled to +// another actor. It receives a list of messages to be dispatch. It can be that +// we were waiting for this entangling step in order to disentangle the port or +// to close it. +void +MessagePort::Entangled(nsTArray& aMessages) +{ + MOZ_ASSERT(mState == eStateEntangling); + + mState = eStateEntangled; + + // If we have pending messages, these have to be sent. + if (!mMessagesForTheOtherPort.IsEmpty()) { + nsTArray messages; + SharedMessagePortMessage::FromSharedToMessagesChild(mActor, + mMessagesForTheOtherPort, + messages); + mMessagesForTheOtherPort.Clear(); + mActor->SendPostMessages(messages); + } + + // We must convert the messages into SharedMessagePortMessages to avoid leaks. + FallibleTArray> data; + if (NS_WARN_IF(!SharedMessagePortMessage::FromMessagesToSharedChild(aMessages, + data))) { + // OOM, we cannot continue. + return; + } + + if (mNextStep == eNextStepClose) { + Close(); + return; + } + + mMessages.AppendElements(data); + + // We were waiting for the entangling callback in order to disentangle this + // port immediately after. + if (mNextStep == eNextStepDisentangle) { + StartDisentangling(); + return; + } + + MOZ_ASSERT(mNextStep == eNextStepNone); + Dispatch(); +} + +void +MessagePort::StartDisentangling() +{ + MOZ_ASSERT(mActor); + MOZ_ASSERT(mState == eStateEntangled); + + mState = eStateDisentangling; + mNextStep = eNextStepNone; + + // Sending this message we communicate to the parent actor that we don't want + // to receive any new messages. It is possible that a message has been + // already sent but not received yet. So we have to collect all of them and + // we send them in the SendDispatch() request. + mActor->SendStopSendingData(); +} + +void +MessagePort::MessagesReceived(nsTArray& aMessages) +{ + MOZ_ASSERT(mState == eStateEntangled || mState == eStateDisentangling); + MOZ_ASSERT(mNextStep == eNextStepNone); + MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty()); + + RemoveDocFromBFCache(); + + FallibleTArray> data; + if (!NS_WARN_IF(SharedMessagePortMessage::FromMessagesToSharedChild(aMessages, + data))) { + // OOM, We cannot continue. + return; + } + + mMessages.AppendElements(data); + + if (mState == eStateEntangled) { + Dispatch(); + } +} + +void +MessagePort::StopSendingDataConfirmed() +{ + MOZ_ASSERT(mState == eStateDisentangling); + MOZ_ASSERT(mActor); + + Disentangle(); +} + +void +MessagePort::Disentangle() +{ + MOZ_ASSERT(mState == eStateDisentangling); + MOZ_ASSERT(mActor); + + mState = eStateDisentangled; + + nsTArray messages; + SharedMessagePortMessage::FromSharedToMessagesChild(mActor, mMessages, + messages); + mMessages.Clear(); + mActor->SendDisentangle(messages); + + mActor->SetPort(nullptr); + mActor = nullptr; + + UpdateMustKeepAlive(); +} + +bool +MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier) +{ + MOZ_ASSERT(mIdentifier); + + // We can clone a port that has already been transfered. In this case, on the + // otherside will have a neutered port. Here we set neutered to true so that + // we are safe in case a early return. + aIdentifier.neutered() = true; + + if (mState > eStateEntangled) { + return true; + } + + // We already have a 'next step'. We have to consider this port as already + // cloned/closed/disentangled. + if (mNextStep != eNextStepNone) { + return true; + } + + aIdentifier.uuid() = mIdentifier->uuid(); + aIdentifier.destinationUuid() = mIdentifier->destinationUuid(); + aIdentifier.sequenceId() = mIdentifier->sequenceId() + 1; + aIdentifier.neutered() = false; + + // We have to entangle first. + if (mState == eStateUnshippedEntangled) { + MOZ_ASSERT(mUnshippedEntangledPort); + MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty()); + + // Disconnect the entangled port and connect it to PBackground. + mUnshippedEntangledPort->ConnectToPBackground(); + mUnshippedEntangledPort = nullptr; + + // In this case, we don't need to be connected to the PBackground service. + if (mMessages.IsEmpty()) { + aIdentifier.sequenceId() = mIdentifier->sequenceId(); + + mState = eStateDisentangled; + UpdateMustKeepAlive(); + return true; + } + + // Register this component to PBackground. + ConnectToPBackground(); + + mNextStep = eNextStepDisentangle; + return true; + } + + // Not entangled yet, we have to wait. + if (mState < eStateEntangled) { + mNextStep = eNextStepDisentangle; + return true; + } + + StartDisentangling(); + return true; +} + +void +MessagePort::Closed() +{ + if (mState == eStateDisentangled) { + return; + } + + mState = eStateDisentangled; + + if (mActor) { + mActor->SetPort(nullptr); + mActor = nullptr; + } + + UpdateMustKeepAlive(); +} + +void +MessagePort::ConnectToPBackground() +{ + mState = eStateEntangling; + + PBackgroundChild* actor = + mozilla::ipc::BackgroundChild::GetForCurrentThread(); + if (actor) { + ActorCreated(actor); + } else { + if (NS_WARN_IF( + !mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(this))) { + MOZ_CRASH(); + } + } +} + +void +MessagePort::ActorFailed() +{ + MOZ_CRASH("Failed to create a PBackgroundChild actor!"); +} + +void +MessagePort::ActorCreated(mozilla::ipc::PBackgroundChild* aActor) +{ + MOZ_ASSERT(aActor); + MOZ_ASSERT(!mActor); + MOZ_ASSERT(mIdentifier); + MOZ_ASSERT(mState == eStateEntangling); + + PMessagePortChild* actor = + aActor->SendPMessagePortConstructor(mIdentifier->uuid(), + mIdentifier->destinationUuid(), + mIdentifier->sequenceId()); + + mActor = static_cast(actor); + MOZ_ASSERT(mActor); + + mActor->SetPort(this); +} + +void +MessagePort::UpdateMustKeepAlive() +{ + if (mState == eStateDisentangled && mIsKeptAlive) { + mIsKeptAlive = false; + + if (mWorkerFeature) { + WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); + MOZ_ASSERT(workerPrivate); + + workerPrivate->RemoveFeature(workerPrivate->GetJSContext(), + mWorkerFeature); + mWorkerFeature = nullptr; + } + + Release(); + return; + } + + if (mState < eStateDisentangled && !mIsKeptAlive) { + mIsKeptAlive = true; + AddRef(); + } +} + +NS_IMETHODIMP +MessagePort::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) +{ + MOZ_ASSERT(NS_IsMainThread()); + + if (strcmp(aTopic, "inner-window-destroyed")) { + return NS_OK; + } + + // If the window id destroyed we have to release the reference that we are + // keeping. + if (!mIsKeptAlive) { + return NS_OK; + } + + nsCOMPtr wrapper = do_QueryInterface(aSubject); + NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE); + + uint64_t innerID; + nsresult rv = wrapper->GetData(&innerID); + NS_ENSURE_SUCCESS(rv, rv); + + if (innerID == mInnerID) { + nsCOMPtr obs = + do_GetService("@mozilla.org/observer-service;1"); + if (obs) { + obs->RemoveObserver(this, "inner-window-destroyed"); + } + + Close(); + } + + return NS_OK; +} + +void +MessagePort::RemoveDocFromBFCache() +{ + if (!NS_IsMainThread()) { + return; + } + + nsPIDOMWindow* window = GetOwner(); + MOZ_ASSERT(window); + + nsIDocument* doc = window->GetExtantDoc(); + if (!doc) { + return; + } + + nsCOMPtr bfCacheEntry = doc->GetBFCacheEntry(); + if (!bfCacheEntry) { + return; + } + + bfCacheEntry->RemoveFromBFCacheSync(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/messagechannel/MessagePort.h b/dom/messagechannel/MessagePort.h new file mode 100644 index 000000000000..63081a083323 --- /dev/null +++ b/dom/messagechannel/MessagePort.h @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 8; 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/. */ + +#ifndef mozilla_dom_MessagePort_h +#define mozilla_dom_MessagePort_h + +#include "mozilla/Attributes.h" +#include "mozilla/DOMEventTargetHelper.h" +#include "nsIIPCBackgroundChildCreateCallback.h" +#include "nsTArray.h" + +#ifdef XP_WIN +#undef PostMessage +#endif + +class nsPIDOMWindow; + +namespace mozilla { +namespace dom { + +class DispatchEventRunnable; +class MessagePortChild; +class MessagePortIdentifier; +class MessagePortMessage; +class SharedMessagePortMessage; + +namespace workers { +class WorkerFeature; +} + +class MessagePortBase : public DOMEventTargetHelper +{ +protected: + explicit MessagePortBase(nsPIDOMWindow* aWindow); + MessagePortBase(); + +public: + + virtual void + PostMessage(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) = 0; + + virtual void + Start() = 0; + + virtual void + Close() = 0; + + // The 'message' event handler has to call |Start()| method, so we + // cannot use IMPL_EVENT_HANDLER macro here. + virtual EventHandlerNonNull* + GetOnmessage() = 0; + + virtual void + SetOnmessage(EventHandlerNonNull* aCallback) = 0; + + // Duplicate this message port. This method is used by the Structured Clone + // Algorithm and populates a MessagePortIdentifier object with the information + // useful to create new MessagePort. + virtual bool + CloneAndDisentangle(MessagePortIdentifier& aIdentifier) = 0; +}; + +class MessagePort final : public MessagePortBase + , public nsIIPCBackgroundChildCreateCallback + , public nsIObserver +{ + friend class DispatchEventRunnable; + +public: + NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK + NS_DECL_NSIOBSERVER + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, + DOMEventTargetHelper) + + static already_AddRefed + Create(nsPIDOMWindow* aWindow, const nsID& aUUID, + const nsID& aDestinationUUID, ErrorResult& aRv); + + static already_AddRefed + Create(nsPIDOMWindow* aWindow, const MessagePortIdentifier& aIdentifier, + ErrorResult& aRv); + + virtual JSObject* + WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + virtual void + PostMessage(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) override; + + virtual void Start() override; + + virtual void Close() override; + + virtual EventHandlerNonNull* GetOnmessage() override; + + virtual void SetOnmessage(EventHandlerNonNull* aCallback) override; + + // Non WebIDL methods + + void UnshippedEntangle(MessagePort* aEntangledPort); + + virtual bool CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override; + + // These methods are useful for MessagePortChild + + void Entangled(nsTArray& aMessages); + void MessagesReceived(nsTArray& aMessages); + void StopSendingDataConfirmed(); + void Closed(); + +private: + explicit MessagePort(nsPIDOMWindow* aWindow); + ~MessagePort(); + + enum State { + // When a port is created by a MessageChannel it is entangled with the + // other. They both run on the same thread, same event loop and the + // messages are added to the queues without using PBackground actors. + // When one of the port is shipped, the state is changed to + // StateEntangling. + eStateUnshippedEntangled, + + // If the port is closed or cloned when we are in this state, we set the + // mNextStep. This 'next' operation will be done when entangled() message + // is received. + eStateEntangling, + + // When entangled() is received we send all the messages in the + // mMessagesForTheOtherPort to the actor and we change the state to + // StateEntangled. At this point the port is entangled with the other. We + // send and receive messages. + // If the port queue is not enabled, the received messages are stored in + // the mMessages. + eStateEntangled, + + // When the port is cloned or disentangled we want to stop receiving + // messages. We call 'SendStopSendingData' to the actor and we wait for an + // answer. All the messages received between now and the + // 'StopSendingDataComfirmed are queued in the mMessages but not + // dispatched. + eStateDisentangling, + + // When 'StopSendingDataConfirmed' is received, we can disentangle the port + // calling SendDisentangle in the actor because we are 100% sure that we + // don't receive any other message, so nothing will be lost. + // Disentangling the port we send all the messages from the mMessages + // though the actor. + eStateDisentangled + }; + + void Initialize(const nsID& aUUID, const nsID& aDestinationUUID, + uint32_t aSequenceID, bool mNeutered, State aState, + ErrorResult& aRv); + + void ConnectToPBackground(); + + // Dispatch events from the Message Queue using a nsRunnable. + void Dispatch(); + + void StartDisentangling(); + void Disentangle(); + + void RemoveDocFromBFCache(); + + // This method is meant to keep alive the MessagePort when this object is + // creating the actor and until the actor is entangled. + // We release the object when the port is closed or disentangled. + void UpdateMustKeepAlive(); + + nsAutoPtr mWorkerFeature; + + nsRefPtr mDispatchRunnable; + + nsRefPtr mActor; + + nsRefPtr mUnshippedEntangledPort; + + nsTArray> mMessages; + nsTArray> mMessagesForTheOtherPort; + + nsAutoPtr mIdentifier; + + uint64_t mInnerID; + + State mState; + + // This 'nextStep' is used when we are waiting to be entangled but the + // content has called Clone() or Close(). + enum { + eNextStepNone, + eNextStepDisentangle, + eNextStepClose + } mNextStep; + + bool mMessageQueueEnabled; + + bool mIsKeptAlive; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_MessagePort_h diff --git a/dom/messagechannel/MessagePortChild.cpp b/dom/messagechannel/MessagePortChild.cpp new file mode 100644 index 000000000000..baa1b3771316 --- /dev/null +++ b/dom/messagechannel/MessagePortChild.cpp @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "MessagePortChild.h" +#include "MessagePort.h" +#include "mozilla/dom/MessageEvent.h" +#include "mozilla/ipc/PBackgroundChild.h" + +namespace mozilla { +namespace dom { + +bool +MessagePortChild::RecvStopSendingDataConfirmed() +{ + MOZ_ASSERT(mPort); + mPort->StopSendingDataConfirmed(); + MOZ_ASSERT(!mPort); + return true; +} + +bool +MessagePortChild::RecvEntangled(nsTArray&& aMessages) +{ + MOZ_ASSERT(mPort); + mPort->Entangled(aMessages); + return true; +} + +bool +MessagePortChild::RecvReceiveData(nsTArray&& aMessages) +{ + MOZ_ASSERT(mPort); + mPort->MessagesReceived(aMessages); + return true; +} + +void +MessagePortChild::ActorDestroy(ActorDestroyReason aWhy) +{ + if (mPort) { + mPort->Closed(); + MOZ_ASSERT(!mPort); + } +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/messagechannel/MessagePortChild.h b/dom/messagechannel/MessagePortChild.h new file mode 100644 index 000000000000..7ab954ad0687 --- /dev/null +++ b/dom/messagechannel/MessagePortChild.h @@ -0,0 +1,52 @@ +/* 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/. */ + +#ifndef mozilla_dom_MessagePortChild_h +#define mozilla_dom_MessagePortChild_h + +#include "mozilla/Assertions.h" +#include "mozilla/dom/PMessagePortChild.h" +#include "nsISupportsImpl.h" + +namespace mozilla { +namespace dom { + +class MessagePort; + +class MessagePortChild final : public PMessagePortChild +{ +public: + NS_INLINE_DECL_REFCOUNTING(MessagePortChild) + + MessagePortChild() {} + + void SetPort(MessagePort* aPort) + { + mPort = aPort; + } + +private: + ~MessagePortChild() + { + MOZ_ASSERT(!mPort); + } + + virtual bool + RecvEntangled(nsTArray&& aMessages) override; + + virtual bool + RecvReceiveData(nsTArray&& aMessages) override; + + virtual bool RecvStopSendingDataConfirmed() override; + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + // This is a raw pointer because this child is owned by this MessagePort. + MessagePort* mPort; +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_MessagePortChild_h diff --git a/dom/base/MessagePortList.cpp b/dom/messagechannel/MessagePortList.cpp similarity index 100% rename from dom/base/MessagePortList.cpp rename to dom/messagechannel/MessagePortList.cpp diff --git a/dom/base/MessagePortList.h b/dom/messagechannel/MessagePortList.h similarity index 100% rename from dom/base/MessagePortList.h rename to dom/messagechannel/MessagePortList.h diff --git a/dom/messagechannel/MessagePortParent.cpp b/dom/messagechannel/MessagePortParent.cpp new file mode 100644 index 000000000000..25dadafdab3b --- /dev/null +++ b/dom/messagechannel/MessagePortParent.cpp @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "MessagePortParent.h" +#include "MessagePortService.h" +#include "SharedMessagePortMessage.h" +#include "mozilla/unused.h" + +namespace mozilla { +namespace dom { + +MessagePortParent::MessagePortParent(const nsID& aUUID) + : mService(MessagePortService::GetOrCreate()) + , mUUID(aUUID) + , mEntangled(false) + , mCanSendData(true) +{ + MOZ_ASSERT(mService); +} + +MessagePortParent::~MessagePortParent() +{ + MOZ_ASSERT(!mService); + MOZ_ASSERT(!mEntangled); +} + +bool +MessagePortParent::Entangle(const nsID& aDestinationUUID, + const uint32_t& aSequenceID) +{ + if (!mService) { + NS_WARNING("Entangle is called after a shutdown!"); + return false; + } + + MOZ_ASSERT(!mEntangled); + + return mService->RequestEntangling(this, aDestinationUUID, aSequenceID); +} + +bool +MessagePortParent::RecvPostMessages(nsTArray&& aMessages) +{ + // This converts the object in a data struct where we have BlobImpls. + FallibleTArray> messages; + if (NS_WARN_IF( + !SharedMessagePortMessage::FromMessagesToSharedParent(aMessages, + messages))) { + return false; + } + + if (!mEntangled) { + return false; + } + + if (!mService) { + NS_WARNING("Entangle is called after a shutdown!"); + return false; + } + + if (messages.IsEmpty()) { + return false; + } + + return mService->PostMessages(this, messages); +} + +bool +MessagePortParent::RecvDisentangle(nsTArray&& aMessages) +{ + // This converts the object in a data struct where we have BlobImpls. + FallibleTArray> messages; + if (NS_WARN_IF( + !SharedMessagePortMessage::FromMessagesToSharedParent(aMessages, + messages))) { + return false; + } + + if (!mEntangled) { + return false; + } + + if (!mService) { + NS_WARNING("Entangle is called after a shutdown!"); + return false; + } + + if (!mService->DisentanglePort(this, messages)) { + return false; + } + + CloseAndDelete(); + return true; +} + +bool +MessagePortParent::RecvStopSendingData() +{ + if (!mEntangled) { + return true; + } + + mCanSendData = false; + unused << SendStopSendingDataConfirmed(); + return true; +} + +bool +MessagePortParent::RecvClose() +{ + if (mService) { + MOZ_ASSERT(mEntangled); + + if (!mService->ClosePort(this)) { + return false; + } + + Close(); + } + + MOZ_ASSERT(!mEntangled); + + unused << Send__delete__(this); + return true; +} + +void +MessagePortParent::ActorDestroy(ActorDestroyReason aWhy) +{ + if (mService && mEntangled) { + // When the last parent is deleted, this service is freed but this cannot + // be done when the hashtables are written by CloseAll. + nsRefPtr kungFuDeathGrip = mService; + mService->ParentDestroy(this); + } +} + +bool +MessagePortParent::Entangled(const nsTArray& aMessages) +{ + MOZ_ASSERT(!mEntangled); + mEntangled = true; + return SendEntangled(aMessages); +} + +void +MessagePortParent::CloseAndDelete() +{ + Close(); + unused << Send__delete__(this); +} + +void +MessagePortParent::Close() +{ + mService = nullptr; + mEntangled = false; +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/messagechannel/MessagePortParent.h b/dom/messagechannel/MessagePortParent.h new file mode 100644 index 000000000000..46dbb19ff0cc --- /dev/null +++ b/dom/messagechannel/MessagePortParent.h @@ -0,0 +1,61 @@ +/* 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/. */ + +#ifndef mozilla_dom_MessagePortParent_h +#define mozilla_dom_MessagePortParent_h + +#include "mozilla/dom/PMessagePortParent.h" + +namespace mozilla { +namespace dom { + +class MessagePortService; + +class MessagePortParent final : public PMessagePortParent +{ +public: + explicit MessagePortParent(const nsID& aUUID); + ~MessagePortParent(); + + bool Entangle(const nsID& aDestinationUUID, + const uint32_t& aSequenceID); + + bool Entangled(const nsTArray& aMessages); + + void Close(); + void CloseAndDelete(); + + bool CanSendData() const + { + return mCanSendData; + } + + const nsID& ID() const + { + return mUUID; + } + +private: + virtual bool RecvPostMessages(nsTArray&& aMessages) + override; + + virtual bool RecvDisentangle(nsTArray&& aMessages) + override; + + virtual bool RecvStopSendingData() override; + + virtual bool RecvClose() override; + + virtual void ActorDestroy(ActorDestroyReason aWhy) override; + + nsRefPtr mService; + const nsID mUUID; + bool mEntangled; + bool mCanSendData; +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_MessagePortParent_h diff --git a/dom/messagechannel/MessagePortService.cpp b/dom/messagechannel/MessagePortService.cpp new file mode 100644 index 000000000000..0d75e6ba1951 --- /dev/null +++ b/dom/messagechannel/MessagePortService.cpp @@ -0,0 +1,328 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "MessagePortService.h" +#include "MessagePortParent.h" +#include "SharedMessagePortMessage.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/unused.h" +#include "nsDataHashtable.h" +#include "nsTArray.h" + +namespace mozilla { +namespace dom { + +namespace { +StaticRefPtr gInstance; +} // anonymous namespace + +class MessagePortService::MessagePortServiceData final +{ +public: + explicit MessagePortServiceData(const nsID& aDestinationUUID) + : mDestinationUUID(aDestinationUUID) + , mSequenceID(1) + , mParent(nullptr) + { + MOZ_COUNT_CTOR(MessagePortServiceData); + } + + MessagePortServiceData(const MessagePortServiceData& aOther) = delete; + MessagePortServiceData& operator=(const MessagePortServiceData&) = delete; + + ~MessagePortServiceData() + { + MOZ_COUNT_DTOR(MessagePortServiceData); + } + + nsID mDestinationUUID; + + uint32_t mSequenceID; + MessagePortParent* mParent; + + struct NextParent + { + uint32_t mSequenceID; + // MessagePortParent keeps the service alive, and we don't want a cycle. + MessagePortParent* mParent; + }; + + FallibleTArray mNextParents; + FallibleTArray> mMessages; +}; + +/* static */ MessagePortService* +MessagePortService::GetOrCreate() +{ + if (!gInstance) { + gInstance = new MessagePortService(); + } + + return gInstance; +} + +bool +MessagePortService::RequestEntangling(MessagePortParent* aParent, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) +{ + MOZ_ASSERT(aParent); + MessagePortServiceData* data; + + // If we don't have a MessagePortServiceData, we must create 2 of them for + // both ports. + if (!mPorts.Get(aParent->ID(), &data)) { + // Create the MessagePortServiceData for the destination. + if (mPorts.Get(aDestinationUUID, nullptr)) { + MOZ_ASSERT(false, "The creation of the 2 ports should be in sync."); + return false; + } + + data = new MessagePortServiceData(aParent->ID()); + mPorts.Put(aDestinationUUID, data); + + data = new MessagePortServiceData(aDestinationUUID); + mPorts.Put(aParent->ID(), data); + } + + // This is a security check. + if (!data->mDestinationUUID.Equals(aDestinationUUID)) { + MOZ_ASSERT(false, "DestinationUUIDs do not match!"); + return false; + } + + if (aSequenceID < data->mSequenceID) { + MOZ_ASSERT(false, "Invalid sequence ID!"); + return false; + } + + if (aSequenceID == data->mSequenceID) { + if (data->mParent) { + MOZ_ASSERT(false, "Two ports cannot have the same sequenceID."); + return false; + } + + // We activate this port, sending all the messages. + data->mParent = aParent; + FallibleTArray array; + if (!SharedMessagePortMessage::FromSharedToMessagesParent(aParent, + data->mMessages, + array)) { + return false; + } + + data->mMessages.Clear(); + return aParent->Entangled(array); + } + + // This new parent will be the next one when a Disentangle request is + // received from the current parent. + MessagePortServiceData::NextParent* nextParent = + data->mNextParents.AppendElement(mozilla::fallible); + if (!nextParent) { + return false; + } + + nextParent->mSequenceID = aSequenceID; + nextParent->mParent = aParent; + + return true; +} + +bool +MessagePortService::DisentanglePort( + MessagePortParent* aParent, + FallibleTArray>& aMessages) +{ + MessagePortServiceData* data; + if (!mPorts.Get(aParent->ID(), &data)) { + MOZ_ASSERT(false, "Unknown MessagePortParent should not happen."); + return false; + } + + if (data->mParent != aParent) { + MOZ_ASSERT(false, "DisentanglePort() should be called just from the correct parent."); + return false; + } + + // Let's put the messages in the correct order. |aMessages| contains the + // unsent messages so they have to go first. + if (!aMessages.AppendElements(data->mMessages, mozilla::fallible)) { + return false; + } + + data->mMessages.Clear(); + + ++data->mSequenceID; + + // If we don't have a parent, we have to store the pending messages and wait. + uint32_t index = 0; + MessagePortParent* nextParent = nullptr; + for (; index < data->mNextParents.Length(); ++index) { + if (data->mNextParents[index].mSequenceID == data->mSequenceID) { + nextParent = data->mNextParents[index].mParent; + break; + } + } + + // We didn't find the parent. + if (!nextParent) { + data->mMessages.SwapElements(aMessages); + data->mParent = nullptr; + return true; + } + + data->mParent = nextParent; + data->mNextParents.RemoveElementAt(index); + + FallibleTArray array; + if (!SharedMessagePortMessage::FromSharedToMessagesParent(data->mParent, + aMessages, + array)) { + return false; + } + + unused << data->mParent->Entangled(array); + return true; +} + +bool +MessagePortService::ClosePort(MessagePortParent* aParent) +{ + MessagePortServiceData* data; + if (!mPorts.Get(aParent->ID(), &data)) { + MOZ_ASSERT(false, "Unknown MessagePortParent should not happend."); + return false; + } + + if (data->mParent != aParent) { + MOZ_ASSERT(false, "ClosePort() should be called just from the correct parent."); + return false; + } + + if (!data->mNextParents.IsEmpty()) { + MOZ_ASSERT(false, "ClosePort() should be called when there are not next parents."); + return false; + } + + // We don't want to send a message to this parent. + data->mParent = nullptr; + + CloseAll(aParent->ID()); + return true; +} + +#ifdef DEBUG +PLDHashOperator +MessagePortService::CloseAllDebugCheck(const nsID& aID, + MessagePortServiceData* aData, + void* aPtr) +{ + nsID* id = static_cast(aPtr); + MOZ_ASSERT(!id->Equals(aID)); + return PL_DHASH_NEXT; +} +#endif + +void +MessagePortService::CloseAll(const nsID& aUUID) +{ + MessagePortServiceData* data; + if (!mPorts.Get(aUUID, &data)) { + MaybeShutdown(); + return; + } + + if (data->mParent) { + data->mParent->Close(); + } + + for (const MessagePortServiceData::NextParent& parent : data->mNextParents) { + parent.mParent->CloseAndDelete(); + } + + nsID destinationUUID = data->mDestinationUUID; + mPorts.Remove(aUUID); + + CloseAll(destinationUUID); + +#ifdef DEBUG + mPorts.EnumerateRead(CloseAllDebugCheck, const_cast(&aUUID)); +#endif + + MaybeShutdown(); +} + +// This service can be dismissed when there are not active ports. +void +MessagePortService::MaybeShutdown() +{ + if (mPorts.Count() == 0) { + gInstance = nullptr; + } +} + +bool +MessagePortService::PostMessages( + MessagePortParent* aParent, + FallibleTArray>& aMessages) +{ + MessagePortServiceData* data; + if (!mPorts.Get(aParent->ID(), &data)) { + MOZ_ASSERT(false, "Unknown MessagePortParent should not happend."); + return false; + } + + if (data->mParent != aParent) { + MOZ_ASSERT(false, "PostMessages() should be called just from the correct parent."); + return false; + } + + MOZ_ALWAYS_TRUE(mPorts.Get(data->mDestinationUUID, &data)); + + if (!data->mMessages.AppendElements(aMessages, mozilla::fallible)) { + return false; + } + + // If the parent can send data to the child, let's proceed. + if (data->mParent && data->mParent->CanSendData()) { + FallibleTArray messages; + if (!SharedMessagePortMessage::FromSharedToMessagesParent(data->mParent, + data->mMessages, + messages)) { + return false; + } + + data->mMessages.Clear(); + unused << data->mParent->SendReceiveData(messages); + } + + return true; +} + +void +MessagePortService::ParentDestroy(MessagePortParent* aParent) +{ + // This port has already been destroyed. + MessagePortServiceData* data; + if (!mPorts.Get(aParent->ID(), &data)) { + return; + } + + if (data->mParent != aParent) { + // We don't want to send a message to this parent. + for (uint32_t i = 0; i < data->mNextParents.Length(); ++i) { + if (aParent == data->mNextParents[i].mParent) { + data->mNextParents.RemoveElementAt(i); + break; + } + } + } + + CloseAll(aParent->ID()); +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/messagechannel/MessagePortService.h b/dom/messagechannel/MessagePortService.h new file mode 100644 index 000000000000..437cf2393c11 --- /dev/null +++ b/dom/messagechannel/MessagePortService.h @@ -0,0 +1,61 @@ +/* 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/. */ + +#ifndef mozilla_dom_MessagePortService_h +#define mozilla_dom_MessagePortService_h + +#include "nsClassHashtable.h" +#include "nsHashKeys.h" +#include "nsISupportsImpl.h" + +namespace mozilla { +namespace dom { + +class MessagePortParent; +class SharedMessagePortMessage; + +class MessagePortService final +{ +public: + NS_INLINE_DECL_REFCOUNTING(MessagePortService) + + static MessagePortService* GetOrCreate(); + + bool RequestEntangling(MessagePortParent* aParent, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID); + + bool DisentanglePort( + MessagePortParent* aParent, + FallibleTArray>& aMessages); + + bool ClosePort(MessagePortParent* aParent); + + bool PostMessages( + MessagePortParent* aParent, + FallibleTArray>& aMessages); + + void ParentDestroy(MessagePortParent* aParent); + +private: + ~MessagePortService() {} + + void CloseAll(const nsID& aUUID); + void MaybeShutdown(); + + class MessagePortServiceData; + +#ifdef DEBUG + static PLDHashOperator + CloseAllDebugCheck(const nsID& aID, MessagePortServiceData* aData, + void* aPtr); +#endif + + nsClassHashtable mPorts; +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_MessagePortService_h diff --git a/dom/messagechannel/MessagePortUtils.cpp b/dom/messagechannel/MessagePortUtils.cpp new file mode 100644 index 000000000000..06b330b7f426 --- /dev/null +++ b/dom/messagechannel/MessagePortUtils.cpp @@ -0,0 +1,277 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "MessagePortUtils.h" +#include "MessagePort.h" +#include "mozilla/dom/BlobBinding.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/MessagePortBinding.h" +#include "mozilla/dom/StructuredCloneTags.h" + +namespace mozilla { +namespace dom { +namespace messageport { + +namespace { + +struct MOZ_STACK_CLASS StructuredCloneClosureInternal +{ + StructuredCloneClosureInternal( + StructuredCloneClosure& aClosure, nsPIDOMWindow* aWindow) + : mClosure(aClosure) + , mWindow(aWindow) + { } + + StructuredCloneClosure& mClosure; + nsPIDOMWindow* mWindow; + nsTArray> mMessagePorts; + nsTArray> mTransferredPorts; +}; + +struct MOZ_STACK_CLASS StructuredCloneClosureInternalReadOnly +{ + StructuredCloneClosureInternalReadOnly( + const StructuredCloneClosure& aClosure, nsPIDOMWindow* aWindow) + : mClosure(aClosure) + , mWindow(aWindow) + { } + + const StructuredCloneClosure& mClosure; + nsPIDOMWindow* mWindow; + nsTArray> mMessagePorts; + nsTArray> mTransferredPorts; +}; + +void +Error(JSContext* aCx, uint32_t aErrorId) +{ + if (NS_IsMainThread()) { + NS_DOMStructuredCloneError(aCx, aErrorId); + } else { + Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); + } +} + +JSObject* +Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, + uint32_t aData, void* aClosure) +{ + MOZ_ASSERT(aClosure); + + auto* closure = static_cast(aClosure); + + if (aTag == SCTAG_DOM_BLOB) { + // nsRefPtr needs to go out of scope before toObjectOrNull() is + // called because the static analysis thinks dereferencing XPCOM objects + // can GC (because in some cases it can!), and a return statement with a + // JSObject* type means that JSObject* is on the stack as a raw pointer + // while destructors are running. + JS::Rooted val(aCx); + { + MOZ_ASSERT(aData < closure->mClosure.mBlobImpls.Length()); + nsRefPtr blobImpl = closure->mClosure.mBlobImpls[aData]; + +#ifdef DEBUG + { + // Blob should not be mutable. + bool isMutable; + MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable))); + MOZ_ASSERT(!isMutable); + } +#endif + + // Let's create a new blob with the correct parent. + nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)); + MOZ_ASSERT(global); + + nsRefPtr newBlob = Blob::Create(global, blobImpl); + if (!ToJSValue(aCx, newBlob, &val)) { + return nullptr; + } + } + + return &val.toObject(); + } + + return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr); +} + +bool +Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, + JS::Handle aObj, void* aClosure) +{ + MOZ_ASSERT(aClosure); + + auto* closure = static_cast(aClosure); + + // See if the wrapped native is a File/Blob. + { + Blob* blob = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) && + NS_SUCCEEDED(blob->SetMutable(false)) && + JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, + closure->mClosure.mBlobImpls.Length())) { + closure->mClosure.mBlobImpls.AppendElement(blob->Impl()); + return true; + } + } + + return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); +} + +bool +ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader, + uint32_t aTag, void* aContent, uint64_t aExtraData, + void* aClosure, JS::MutableHandle aReturnObject) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aClosure); + + auto* closure = static_cast(aClosure); + + if (aTag != SCTAG_DOM_MAP_MESSAGEPORT) { + return false; + } + + MOZ_ASSERT(aContent == 0); + MOZ_ASSERT(aExtraData < closure->mClosure.mMessagePortIdentifiers.Length()); + + ErrorResult rv; + nsRefPtr port = + MessagePort::Create(closure->mWindow, + closure->mClosure.mMessagePortIdentifiers[(uint32_t)aExtraData], + rv); + if (NS_WARN_IF(rv.Failed())) { + return false; + } + + closure->mMessagePorts.AppendElement(port); + + JS::Rooted value(aCx); + if (!GetOrCreateDOMReflector(aCx, port, &value)) { + JS_ClearPendingException(aCx); + return false; + } + + aReturnObject.set(&value.toObject()); + return true; +} + +bool +WriteTransfer(JSContext* aCx, JS::Handle aObj, void* aClosure, + uint32_t* aTag, JS::TransferableOwnership* aOwnership, + void** aContent, uint64_t* aExtraData) +{ + MOZ_ASSERT(aClosure); + + auto* closure = static_cast(aClosure); + + MessagePortBase* port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); + if (NS_FAILED(rv)) { + return false; + } + + if (closure->mTransferredPorts.Contains(port)) { + // No duplicates. + return false; + } + + MessagePortIdentifier identifier; + if (!port->CloneAndDisentangle(identifier)) { + return false; + } + + closure->mClosure.mMessagePortIdentifiers.AppendElement(identifier); + closure->mTransferredPorts.AppendElement(port); + + *aTag = SCTAG_DOM_MAP_MESSAGEPORT; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = nullptr; + *aExtraData = closure->mClosure.mMessagePortIdentifiers.Length() - 1; + + return true; +} + +const JSStructuredCloneCallbacks gCallbacks = { + Read, + Write, + Error, + ReadTransfer, + WriteTransfer, + nullptr +}; + +} // anonymous namespace + +bool +ReadStructuredCloneWithTransfer(JSContext* aCx, nsTArray& aData, + const StructuredCloneClosure& aClosure, + JS::MutableHandle aClone, + nsPIDOMWindow* aParentWindow, + nsTArray>& aMessagePorts) +{ + auto* data = reinterpret_cast(aData.Elements()); + size_t dataLen = aData.Length(); + MOZ_ASSERT(!(dataLen % sizeof(*data))); + + StructuredCloneClosureInternalReadOnly internalClosure(aClosure, + aParentWindow); + + bool rv = JS_ReadStructuredClone(aCx, data, dataLen, + JS_STRUCTURED_CLONE_VERSION, aClone, + &gCallbacks, &internalClosure); + if (rv) { + aMessagePorts.SwapElements(internalClosure.mMessagePorts); + } + + return rv; +} + +bool +WriteStructuredCloneWithTransfer(JSContext* aCx, JS::Handle aSource, + JS::Handle aTransferable, + nsTArray& aData, + StructuredCloneClosure& aClosure) +{ + StructuredCloneClosureInternal internalClosure(aClosure, nullptr); + JSAutoStructuredCloneBuffer buffer(&gCallbacks, &internalClosure); + + if (!buffer.write(aCx, aSource, aTransferable, &gCallbacks, + &internalClosure)) { + return false; + } + + FallibleTArray cloneData; + if (NS_WARN_IF(!cloneData.SetLength(buffer.nbytes(), mozilla::fallible))) { + return false; + } + + uint64_t* data; + size_t size; + buffer.steal(&data, &size); + + memcpy(cloneData.Elements(), data, size); + js_free(data); + + MOZ_ASSERT(aData.IsEmpty()); + aData.SwapElements(cloneData); + return true; +} + +void +FreeStructuredClone(nsTArray& aData, StructuredCloneClosure& aClosure) +{ + auto* data = reinterpret_cast(aData.Elements()); + size_t dataLen = aData.Length(); + MOZ_ASSERT(!(dataLen % sizeof(*data))); + + JS_ClearStructuredClone(data, dataLen, &gCallbacks, &aClosure, false); + aData.Clear(); +} + +} // messageport namespace +} // dom namespace +} // mozilla namespace diff --git a/dom/messagechannel/MessagePortUtils.h b/dom/messagechannel/MessagePortUtils.h new file mode 100644 index 000000000000..9c9442700e73 --- /dev/null +++ b/dom/messagechannel/MessagePortUtils.h @@ -0,0 +1,55 @@ +/* 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/. */ + +#ifndef mozilla_dom_MessagePortUtils_h +#define mozilla_dom_MessagePortUtils_h + +#include "MessagePort.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/PMessagePort.h" + +class nsPIDOMWindow; + +namespace mozilla { +namespace dom { +namespace messageport { + +struct +StructuredCloneClosure +{ + nsTArray> mBlobImpls; + nsTArray mMessagePortIdentifiers; +}; + +struct +StructuredCloneData +{ + StructuredCloneData() : mData(nullptr), mDataLength(0) {} + uint64_t* mData; + size_t mDataLength; + StructuredCloneClosure mClosure; +}; + +bool +ReadStructuredCloneWithTransfer(JSContext* aCx, nsTArray& aData, + const StructuredCloneClosure& aClosure, + JS::MutableHandle aClone, + nsPIDOMWindow* aParentWindow, + nsTArray>& aMessagePorts); + +bool +WriteStructuredCloneWithTransfer(JSContext* aCx, JS::Handle aSource, + JS::Handle aTransferable, + nsTArray& aData, + StructuredCloneClosure& aClosure); + +void +FreeStructuredClone(nsTArray& aData, + StructuredCloneClosure& aClosure); + +} // messageport namespace +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_MessagePortUtils_h diff --git a/dom/messagechannel/PMessagePort.ipdl b/dom/messagechannel/PMessagePort.ipdl new file mode 100644 index 000000000000..299b00fedf14 --- /dev/null +++ b/dom/messagechannel/PMessagePort.ipdl @@ -0,0 +1,62 @@ +/* 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 protocol PBackground; +include protocol PBlob; + +using struct nsID from "nsID.h"; + +namespace mozilla { +namespace dom { + +struct MessagePortIdentifier +{ + nsID uuid; + nsID destinationUuid; + uint32_t sequenceId; + bool neutered; +}; + +struct MessagePortMessage +{ + MessagePortIdentifier[] transferredPorts; + uint8_t[] data; + PBlob[] blobs; +}; + +// This protocol is used for the MessageChannel/MessagePort API +protocol PMessagePort +{ + manager PBackground; + + /* Many of these methods are used just for the shutdown sequence. The + correct sequence for the child actor is: + 1. SendStopSendingData(); + 2. RecvStopSendingDataConfirmed(); + 3. SendClose(); + 4. Recv__delete__(); */ + + /* When the port is transferred the sequence is: + 1. SendStopSendingData(); + 2. RecvStopSendingDataConfirmed(); + 3. SendDisentangle(); + 4. Recv__delete__(); */ + +parent: + PostMessages(MessagePortMessage[] messages); + Disentangle(MessagePortMessage[] messages); + StopSendingData(); + Close(); + +child: + Entangled(MessagePortMessage[] messages); + ReceiveData(MessagePortMessage[] messages); + StopSendingDataConfirmed(); + + __delete__(); +}; + +} // namespace dom +} // namespace mozilla + diff --git a/dom/messagechannel/SharedMessagePortMessage.cpp b/dom/messagechannel/SharedMessagePortMessage.cpp new file mode 100644 index 000000000000..bbd8fbdbdd5d --- /dev/null +++ b/dom/messagechannel/SharedMessagePortMessage.cpp @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "SharedMessagePortMessage.h" +#include "MessagePort.h" +#include "MessagePortChild.h" +#include "MessagePortParent.h" +#include "mozilla/dom/ipc/BlobChild.h" +#include "mozilla/dom/ipc/BlobParent.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/PMessagePort.h" +#include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/ipc/BackgroundParent.h" + +namespace mozilla { + +using namespace ipc; + +namespace dom { + +SharedMessagePortMessage::~SharedMessagePortMessage() +{ + if (!mData.IsEmpty()) { + FreeStructuredClone(mData, mClosure); + } +} + +/* static */ void +SharedMessagePortMessage::FromSharedToMessagesChild( + MessagePortChild* aActor, + const nsTArray>& aData, + nsTArray& aArray) +{ + MOZ_ASSERT(aActor); + MOZ_ASSERT(aArray.IsEmpty()); + aArray.SetCapacity(aData.Length()); + + PBackgroundChild* backgroundManager = aActor->Manager(); + MOZ_ASSERT(backgroundManager); + + for (auto& data : aData) { + MessagePortMessage* message = aArray.AppendElement(); + message->data().SwapElements(data->mData); + + const nsTArray>& blobImpls = + data->mClosure.mBlobImpls; + if (!blobImpls.IsEmpty()) { + message->blobsChild().SetCapacity(blobImpls.Length()); + + for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { + PBlobChild* blobChild = + BackgroundChild::GetOrCreateActorForBlobImpl(backgroundManager, + blobImpls[i]); + message->blobsChild().AppendElement(blobChild); + } + } + + message->transferredPorts().AppendElements( + data->mClosure.mMessagePortIdentifiers); + } +} + +/* static */ bool +SharedMessagePortMessage::FromMessagesToSharedChild( + nsTArray& aArray, + FallibleTArray>& aData) +{ + MOZ_ASSERT(aData.IsEmpty()); + + if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) { + return false; + } + + for (auto& message : aArray) { + nsRefPtr data = new SharedMessagePortMessage(); + + data->mData.SwapElements(message.data()); + + const nsTArray& blobs = message.blobsChild(); + if (!blobs.IsEmpty()) { + data->mClosure.mBlobImpls.SetCapacity(blobs.Length()); + + for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) { + nsRefPtr impl = + static_cast(blobs[i])->GetBlobImpl(); + data->mClosure.mBlobImpls.AppendElement(impl); + } + } + + data->mClosure.mMessagePortIdentifiers.AppendElements( + message.transferredPorts()); + + if (!aData.AppendElement(data, mozilla::fallible)) { + return false; + } + } + + return true; +} + +/* static */ bool +SharedMessagePortMessage::FromSharedToMessagesParent( + MessagePortParent* aActor, + const nsTArray>& aData, + FallibleTArray& aArray) +{ + MOZ_ASSERT(aArray.IsEmpty()); + + if (NS_WARN_IF(!aArray.SetCapacity(aData.Length(), mozilla::fallible))) { + return false; + } + + PBackgroundParent* backgroundManager = aActor->Manager(); + MOZ_ASSERT(backgroundManager); + + for (auto& data : aData) { + MessagePortMessage* message = aArray.AppendElement(mozilla::fallible); + message->data().SwapElements(data->mData); + + const nsTArray>& blobImpls = data->mClosure.mBlobImpls; + if (!blobImpls.IsEmpty()) { + message->blobsParent().SetCapacity(blobImpls.Length()); + + for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { + PBlobParent* blobParent = + BackgroundParent::GetOrCreateActorForBlobImpl(backgroundManager, + blobImpls[i]); + message->blobsParent().AppendElement(blobParent); + } + } + + message->transferredPorts().AppendElements( + data->mClosure.mMessagePortIdentifiers); + } + + return true; +} + +/* static */ bool +SharedMessagePortMessage::FromMessagesToSharedParent( + nsTArray& aArray, + FallibleTArray>& aData) +{ + MOZ_ASSERT(aData.IsEmpty()); + + if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) { + return false; + } + + for (auto& message : aArray) { + nsRefPtr data = new SharedMessagePortMessage(); + + data->mData.SwapElements(message.data()); + + const nsTArray& blobs = message.blobsParent(); + if (!blobs.IsEmpty()) { + data->mClosure.mBlobImpls.SetCapacity(blobs.Length()); + + for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) { + nsRefPtr impl = + static_cast(blobs[i])->GetBlobImpl(); + data->mClosure.mBlobImpls.AppendElement(impl); + } + } + + data->mClosure.mMessagePortIdentifiers.AppendElements( + message.transferredPorts()); + + if (!aData.AppendElement(data, mozilla::fallible)) { + return false; + } + } + + return true; +} + +} // dom namespace +} // mozilla namespace diff --git a/dom/messagechannel/SharedMessagePortMessage.h b/dom/messagechannel/SharedMessagePortMessage.h new file mode 100644 index 000000000000..c2516874edf5 --- /dev/null +++ b/dom/messagechannel/SharedMessagePortMessage.h @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. */ + +#ifndef mozilla_dom_SharedMessagePortMessage_h +#define mozilla_dom_SharedMessagePortMessage_h + +#include "MessagePortUtils.h" + +namespace mozilla { +namespace dom { + +class MessagePortChild; +class MessagePortMessage; +class MessagePortParent; + +class SharedMessagePortMessage final +{ +public: + NS_INLINE_DECL_REFCOUNTING(SharedMessagePortMessage) + + nsTArray mData; + messageport::StructuredCloneClosure mClosure; + + SharedMessagePortMessage() + {} + + static void + FromSharedToMessagesChild( + MessagePortChild* aActor, + const nsTArray>& aData, + nsTArray& aArray); + + static bool + FromMessagesToSharedChild( + nsTArray& aArray, + FallibleTArray>& aData); + + static bool + FromSharedToMessagesParent( + MessagePortParent* aActor, + const nsTArray>& aData, + FallibleTArray& aArray); + + static bool + FromMessagesToSharedParent( + nsTArray& aArray, + FallibleTArray>& aData); + +private: + ~SharedMessagePortMessage(); +}; + +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_SharedMessagePortMessage_h diff --git a/dom/messagechannel/moz.build b/dom/messagechannel/moz.build new file mode 100644 index 000000000000..c5850dbe0bce --- /dev/null +++ b/dom/messagechannel/moz.build @@ -0,0 +1,41 @@ +# -*- 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/. + +TEST_DIRS += ['tests'] + +EXPORTS.mozilla.dom += [ + 'MessageChannel.h', + 'MessagePort.h', + 'MessagePortChild.h', + 'MessagePortList.h', + 'MessagePortParent.h', +] + +UNIFIED_SOURCES += [ + 'MessageChannel.cpp', + 'MessagePort.cpp', + 'MessagePortChild.cpp', + 'MessagePortList.cpp', + 'MessagePortParent.cpp', + 'MessagePortService.cpp', + 'MessagePortUtils.cpp', + 'SharedMessagePortMessage.cpp', +] + +IPDL_SOURCES += [ + 'PMessagePort.ipdl', +] + +LOCAL_INCLUDES += [ + '../base', + '../events', + '../workers', +] + +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' +FAIL_ON_WARNINGS = True diff --git a/dom/messagechannel/tests/chrome.ini b/dom/messagechannel/tests/chrome.ini new file mode 100644 index 000000000000..8d7140d76f29 --- /dev/null +++ b/dom/messagechannel/tests/chrome.ini @@ -0,0 +1,5 @@ +[DEFAULT] +support-files = + iframe_messageChannel_chrome.html + +[test_messageChannel.xul] diff --git a/dom/base/test/iframe_messageChannel_chrome.html b/dom/messagechannel/tests/iframe_messageChannel_chrome.html similarity index 100% rename from dom/base/test/iframe_messageChannel_chrome.html rename to dom/messagechannel/tests/iframe_messageChannel_chrome.html diff --git a/dom/base/test/iframe_messageChannel_cloning.html b/dom/messagechannel/tests/iframe_messageChannel_cloning.html similarity index 100% rename from dom/base/test/iframe_messageChannel_cloning.html rename to dom/messagechannel/tests/iframe_messageChannel_cloning.html diff --git a/dom/base/test/iframe_messageChannel_pingpong.html b/dom/messagechannel/tests/iframe_messageChannel_pingpong.html similarity index 100% rename from dom/base/test/iframe_messageChannel_pingpong.html rename to dom/messagechannel/tests/iframe_messageChannel_pingpong.html diff --git a/dom/base/test/iframe_messageChannel_post.html b/dom/messagechannel/tests/iframe_messageChannel_post.html similarity index 100% rename from dom/base/test/iframe_messageChannel_post.html rename to dom/messagechannel/tests/iframe_messageChannel_post.html diff --git a/dom/messagechannel/tests/iframe_messageChannel_sharedWorker2.html b/dom/messagechannel/tests/iframe_messageChannel_sharedWorker2.html new file mode 100644 index 000000000000..a693cba22c2e --- /dev/null +++ b/dom/messagechannel/tests/iframe_messageChannel_sharedWorker2.html @@ -0,0 +1,14 @@ + + + + + + + diff --git a/dom/messagechannel/tests/iframe_messageChannel_transferable.html b/dom/messagechannel/tests/iframe_messageChannel_transferable.html new file mode 100644 index 000000000000..108edeb7e6ae --- /dev/null +++ b/dom/messagechannel/tests/iframe_messageChannel_transferable.html @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/dom/messagechannel/tests/mochitest.ini b/dom/messagechannel/tests/mochitest.ini new file mode 100644 index 000000000000..fc5cecd1304a --- /dev/null +++ b/dom/messagechannel/tests/mochitest.ini @@ -0,0 +1,25 @@ +[DEFAULT] +support-files = + iframe_messageChannel_cloning.html + iframe_messageChannel_pingpong.html + iframe_messageChannel_post.html + iframe_messageChannel_transferable.html + worker_messageChannel.js + worker_messageChannel_any.js + sharedWorker_messageChannel.js + sharedWorker2_messageChannel.js + iframe_messageChannel_sharedWorker2.html + +[test_messageChannel.html] +[test_messageChannel_cloning.html] +[test_messageChannel_pingpong.html] +[test_messageChannel_post.html] +[test_messageChannel_pref.html] +[test_messageChannel_start.html] +[test_messageChannel_transferable.html] +[test_messageChannel_unshipped.html] +[test_messageChannel_worker.html] +[test_messageChannel_selfTransferring.html] +[test_messageChannel_sharedWorker.html] +[test_messageChannel_sharedWorker2.html] +[test_messageChannel_any.html] diff --git a/dom/messagechannel/tests/moz.build b/dom/messagechannel/tests/moz.build new file mode 100644 index 000000000000..846268289f1d --- /dev/null +++ b/dom/messagechannel/tests/moz.build @@ -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'] +MOCHITEST_CHROME_MANIFESTS += ['chrome.ini'] diff --git a/dom/messagechannel/tests/sharedWorker2_messageChannel.js b/dom/messagechannel/tests/sharedWorker2_messageChannel.js new file mode 100644 index 000000000000..8cc98aa209b8 --- /dev/null +++ b/dom/messagechannel/tests/sharedWorker2_messageChannel.js @@ -0,0 +1,7 @@ +var mc = new MessageChannel(); +var i = 0; + +onconnect = function(evt) { + dump("CONNECTING: "+ i +"\n"); + evt.ports[0].postMessage(42, [mc['port' + ++i]]); +} diff --git a/dom/messagechannel/tests/sharedWorker_messageChannel.js b/dom/messagechannel/tests/sharedWorker_messageChannel.js new file mode 100644 index 000000000000..4b24642f9d26 --- /dev/null +++ b/dom/messagechannel/tests/sharedWorker_messageChannel.js @@ -0,0 +1,8 @@ +onconnect = function(evt) { + var mc = new MessageChannel(); + + evt.ports[0].postMessage(42, [mc.port2]); + mc.port1.onmessage = function(e) { + mc.port1.postMessage(e.data); + } +} diff --git a/dom/base/test/test_messageChannel.html b/dom/messagechannel/tests/test_messageChannel.html similarity index 100% rename from dom/base/test/test_messageChannel.html rename to dom/messagechannel/tests/test_messageChannel.html diff --git a/dom/base/test/test_messageChannel.xul b/dom/messagechannel/tests/test_messageChannel.xul similarity index 91% rename from dom/base/test/test_messageChannel.xul rename to dom/messagechannel/tests/test_messageChannel.xul index ab2fae4d93f7..3d8e3485c6be 100644 --- a/dom/base/test/test_messageChannel.xul +++ b/dom/messagechannel/tests/test_messageChannel.xul @@ -23,7 +23,7 @@ } var ifr = document.createElement('browser'); - ifr.setAttribute("src", "http://mochi.test:8888/tests/dom/base/test/iframe_messageChannel_chrome.html"); + ifr.setAttribute("src", "iframe_messageChannel_chrome.html"); ifr.setAttribute("flex", "1"); ifr.addEventListener('load', function() { ifr.contentWindow.postMessage(channel.port2, '*', [channel.port2]); diff --git a/dom/messagechannel/tests/test_messageChannel_any.html b/dom/messagechannel/tests/test_messageChannel_any.html new file mode 100644 index 000000000000..2cc34443ddb4 --- /dev/null +++ b/dom/messagechannel/tests/test_messageChannel_any.html @@ -0,0 +1,115 @@ + + + + + + MessagePort/Channel any content + + + + +Mozilla Bug 677638 +
+
+
+ + + diff --git a/dom/base/test/test_messageChannel_cloning.html b/dom/messagechannel/tests/test_messageChannel_cloning.html similarity index 100% rename from dom/base/test/test_messageChannel_cloning.html rename to dom/messagechannel/tests/test_messageChannel_cloning.html diff --git a/dom/base/test/test_messageChannel_pingpong.html b/dom/messagechannel/tests/test_messageChannel_pingpong.html similarity index 100% rename from dom/base/test/test_messageChannel_pingpong.html rename to dom/messagechannel/tests/test_messageChannel_pingpong.html diff --git a/dom/base/test/test_messageChannel_post.html b/dom/messagechannel/tests/test_messageChannel_post.html similarity index 100% rename from dom/base/test/test_messageChannel_post.html rename to dom/messagechannel/tests/test_messageChannel_post.html diff --git a/dom/base/test/test_messageChannel_pref.html b/dom/messagechannel/tests/test_messageChannel_pref.html similarity index 100% rename from dom/base/test/test_messageChannel_pref.html rename to dom/messagechannel/tests/test_messageChannel_pref.html diff --git a/dom/messagechannel/tests/test_messageChannel_selfTransferring.html b/dom/messagechannel/tests/test_messageChannel_selfTransferring.html new file mode 100644 index 000000000000..d84a616e4255 --- /dev/null +++ b/dom/messagechannel/tests/test_messageChannel_selfTransferring.html @@ -0,0 +1,38 @@ + + + + + + MessagePort/Channel no self tranferring + + + + +Mozilla Bug 677638 +
+
+
+ + + + diff --git a/dom/messagechannel/tests/test_messageChannel_sharedWorker.html b/dom/messagechannel/tests/test_messageChannel_sharedWorker.html new file mode 100644 index 000000000000..9bb330a851fb --- /dev/null +++ b/dom/messagechannel/tests/test_messageChannel_sharedWorker.html @@ -0,0 +1,39 @@ + + + + + + Test for Bug 677638 - sharedWorker + + + + +Mozilla Bug 677638 +

+ +
+
+ + + diff --git a/dom/messagechannel/tests/test_messageChannel_sharedWorker2.html b/dom/messagechannel/tests/test_messageChannel_sharedWorker2.html new file mode 100644 index 000000000000..d8a4c624b1ab --- /dev/null +++ b/dom/messagechannel/tests/test_messageChannel_sharedWorker2.html @@ -0,0 +1,37 @@ + + + + + + Test for Bug 677638 - sharedWorker + + + + + Mozilla Bug 677638 +
+ + + + diff --git a/dom/base/test/test_messageChannel_start.html b/dom/messagechannel/tests/test_messageChannel_start.html similarity index 100% rename from dom/base/test/test_messageChannel_start.html rename to dom/messagechannel/tests/test_messageChannel_start.html diff --git a/dom/base/test/test_messageChannel_transferable.html b/dom/messagechannel/tests/test_messageChannel_transferable.html similarity index 57% rename from dom/base/test/test_messageChannel_transferable.html rename to dom/messagechannel/tests/test_messageChannel_transferable.html index c1e661ead89e..82b575bac666 100644 --- a/dom/base/test/test_messageChannel_transferable.html +++ b/dom/messagechannel/tests/test_messageChannel_transferable.html @@ -16,14 +16,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=677638 diff --git a/dom/base/test/test_messageChannel_unshipped.html b/dom/messagechannel/tests/test_messageChannel_unshipped.html similarity index 100% rename from dom/base/test/test_messageChannel_unshipped.html rename to dom/messagechannel/tests/test_messageChannel_unshipped.html diff --git a/dom/messagechannel/tests/test_messageChannel_worker.html b/dom/messagechannel/tests/test_messageChannel_worker.html new file mode 100644 index 000000000000..0eb8489f5170 --- /dev/null +++ b/dom/messagechannel/tests/test_messageChannel_worker.html @@ -0,0 +1,60 @@ + + + + + + + Test for Bug 677638 - basic support + + + + +Mozilla Bug 677638 +

+ +
+
+ + + diff --git a/dom/messagechannel/tests/worker_messageChannel.js b/dom/messagechannel/tests/worker_messageChannel.js new file mode 100644 index 000000000000..87b0b8eb0c27 --- /dev/null +++ b/dom/messagechannel/tests/worker_messageChannel.js @@ -0,0 +1,119 @@ +function ok(a, msg) { + postMessage({ type: 'check', check: !!a, message: msg }); +} + +function is(a, b, msg) { + ok (a === b, msg); +} + +function info(msg) { + postMessage({ type: 'info', message: msg }); +} + +function finish() { + postMessage({ type: 'finish' }); +} + +function basic() +{ + var a = new MessageChannel(); + ok(a, "MessageChannel created"); + + var port1 = a.port1; + ok(port1, "MessageChannel.port1 exists"); + is(port1, a.port1, "MessageChannel.port1 is port1"); + + var port2 = a.port2; + ok(port2, "MessageChannel.port1 exists"); + is(port2, a.port2, "MessageChannel.port2 is port2"); + + [ 'postMessage', 'start', 'close' ].forEach(function(e) { + ok(e in port1, "MessagePort1." + e + " exists"); + ok(e in port2, "MessagePort2." + e + " exists"); + }); + + runTests(); +} + +function sendMessages() +{ + var a = new MessageChannel(); + ok(a, "MessageChannel created"); + + a.port1.postMessage("Hello world!"); + a.port1.onmessage = function(e) { + is(e.data, "Hello world!", "The message is back!"); + runTests(); + } + + a.port2.onmessage = function(e) { + a.port2.postMessage(e.data); + } +} + +function transferPort() +{ + var a = new MessageChannel(); + ok(a, "MessageChannel created"); + + a.port1.postMessage("Hello world!"); + a.port1.onmessage = function(e) { + is(e.data, "Hello world!", "The message is back!"); + runTests(); + } + + postMessage({ type: 'port' }, [a.port2]); +} + +function transferPort2() +{ + onmessage = function(evt) { + is(evt.ports.length, 1, "A port has been received by the worker"); + evt.ports[0].onmessage = function(e) { + is(e.data, 42, "Data is 42!"); + runTests(); + } + } + + postMessage({ type: 'newport' }); +} + +var tests = [ + basic, + sendMessages, + transferPort, + transferPort2, +]; + +function runTests() { + if (!tests.length) { + finish(); + return; + } + + var t = tests.shift(); + t(); +} + +var subworker; +onmessage = function(evt) { + if (evt.data == 0) { + runTests(); + return; + } + + if (!subworker) { + info("Create a subworkers. ID: " + evt.data); + subworker = new Worker('worker_messageChannel.js'); + subworker.onmessage = function(e) { + info("Proxy a message to the parent."); + postMessage(e.data, e.ports); + } + + subworker.postMessage(evt.data - 1); + return; + } + + info("Dispatch a message to the subworker."); + subworker.postMessage(evt.data, evt.ports); +} diff --git a/dom/messagechannel/tests/worker_messageChannel_any.js b/dom/messagechannel/tests/worker_messageChannel_any.js new file mode 100644 index 000000000000..bbb1d50f974e --- /dev/null +++ b/dom/messagechannel/tests/worker_messageChannel_any.js @@ -0,0 +1,7 @@ +onmessage = function(evt) { + evt.data.onmessage = function(event) { + evt.data.postMessage(event.data); + } +} + +postMessage("READY"); diff --git a/dom/moz.build b/dom/moz.build index 41b1d209db7b..236e9d352f7b 100644 --- a/dom/moz.build +++ b/dom/moz.build @@ -96,6 +96,7 @@ DIRS += [ 'camera', 'audiochannel', 'broadcastchannel', + 'messagechannel', 'promise', 'smil', 'telephony', diff --git a/dom/webidl/MessageChannel.webidl b/dom/webidl/MessageChannel.webidl index 34de4b46e207..64b1262e3611 100644 --- a/dom/webidl/MessageChannel.webidl +++ b/dom/webidl/MessageChannel.webidl @@ -7,7 +7,8 @@ * http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging */ -[Constructor, Func="MessageChannel::Enabled"] +[Constructor, Func="MessageChannel::Enabled", + Exposed=(Window,Worker)] interface MessageChannel { readonly attribute MessagePort port1; readonly attribute MessagePort port2; diff --git a/dom/workers/MessagePort.cpp b/dom/workers/MessagePort.cpp index 136787777615..19aa73559e31 100644 --- a/dom/workers/MessagePort.cpp +++ b/dom/workers/MessagePort.cpp @@ -17,6 +17,7 @@ using mozilla::dom::EventHandlerNonNull; using mozilla::dom::MessagePortBase; +using mozilla::dom::MessagePortIdentifier; using mozilla::dom::Optional; using mozilla::dom::Sequence; using mozilla::dom::AutoNoJSAPI; @@ -96,9 +97,9 @@ MessagePort::~MessagePort() } void -MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) +MessagePort::PostMessage(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) { AssertCorrectThread(); @@ -198,11 +199,11 @@ MessagePort::SetOnmessage(EventHandlerNonNull* aCallback) Start(); } -already_AddRefed -MessagePort::Clone() +bool +MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier) { NS_WARNING("Haven't implemented structured clone for these ports yet!"); - return nullptr; + return false; } void diff --git a/dom/workers/MessagePort.h b/dom/workers/MessagePort.h index 51b1d6c9c018..30dcc3a2e13c 100644 --- a/dom/workers/MessagePort.h +++ b/dom/workers/MessagePort.h @@ -43,9 +43,9 @@ public: PrefEnabled(); virtual void - PostMessageMoz(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) override; + PostMessage(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) override; virtual void Start() override; @@ -71,8 +71,8 @@ public: virtual void SetOnmessage(EventHandlerNonNull* aCallback) override; - virtual already_AddRefed - Clone() override; + virtual bool + CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override; bool IsClosed() const diff --git a/dom/workers/ServiceWorkerClient.cpp b/dom/workers/ServiceWorkerClient.cpp index 41d992ac74f8..1bfe6457a8af 100644 --- a/dom/workers/ServiceWorkerClient.cpp +++ b/dom/workers/ServiceWorkerClient.cpp @@ -12,6 +12,7 @@ #include "nsGlobalWindow.h" #include "nsIDocument.h" #include "WorkerPrivate.h" +#include "WorkerStructuredClone.h" using namespace mozilla; using namespace mozilla::dom; @@ -75,16 +76,18 @@ class ServiceWorkerClientPostMessageRunnable final : public nsRunnable { uint64_t mWindowId; JSAutoStructuredCloneBuffer mBuffer; - nsTArray> mClonedObjects; + WorkerStructuredCloneClosure mClosure; public: ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId, JSAutoStructuredCloneBuffer&& aData, - nsTArray>& aClonedObjects) + WorkerStructuredCloneClosure& aClosure) : mWindowId(aWindowId), mBuffer(Move(aData)) { - mClonedObjects.SwapElements(aClonedObjects); + mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects); + MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty()); + mClosure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers); } NS_IMETHOD @@ -118,8 +121,10 @@ private: // Release reference to objects that were AddRef'd for // cloning into worker when array goes out of scope. - nsTArray> clonedObjects; - clonedObjects.SwapElements(mClonedObjects); + WorkerStructuredCloneClosure closure; + closure.mClonedObjects.SwapElements(mClosure.mClonedObjects); + MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty()); + closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers); JS::Rooted messageData(aCx); if (!mBuffer.read(aCx, &messageData, @@ -185,16 +190,17 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle aMessage, const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks(false); - nsTArray> clonedObjects; + WorkerStructuredCloneClosure closure; JSAutoStructuredCloneBuffer buffer; - if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) { + if (!buffer.write(aCx, aMessage, transferable, callbacks, &closure)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } nsRefPtr runnable = - new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer), clonedObjects); + new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer), + closure); nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { aRv.Throw(NS_ERROR_FAILURE); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index ac29fc04989c..a917d6eccc52 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -52,6 +52,8 @@ #include "mozilla/dom/ImageDataBinding.h" #include "mozilla/dom/MessageEvent.h" #include "mozilla/dom/MessageEventBinding.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/MessagePortList.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseDebugging.h" @@ -105,6 +107,7 @@ #include "WorkerFeature.h" #include "WorkerRunnable.h" #include "WorkerScope.h" +#include "WorkerStructuredClone.h" #include "WorkerThread.h" #ifdef XP_WIN @@ -511,7 +514,7 @@ bool WriteBlobOrFile(JSContext* aCx, JSStructuredCloneWriter* aWriter, BlobImpl* aBlobOrBlobImpl, - nsTArray>& aClonedObjects) + WorkerStructuredCloneClosure& aClosure) { MOZ_ASSERT(aCx); MOZ_ASSERT(aWriter); @@ -529,7 +532,7 @@ WriteBlobOrFile(JSContext* aCx, return false; } - aClonedObjects.AppendElement(aBlobOrBlobImpl); + aClosure.mClonedObjects.AppendElement(aBlobOrBlobImpl); return true; } @@ -547,7 +550,7 @@ bool WriteFormData(JSContext* aCx, JSStructuredCloneWriter* aWriter, nsFormData* aFormData, - nsTArray>& aClonedObjects) + WorkerStructuredCloneClosure& aClosure) { MOZ_ASSERT(aCx); MOZ_ASSERT(aWriter); @@ -560,11 +563,11 @@ WriteFormData(JSContext* aCx, class MOZ_STACK_CLASS Closure { JSContext* mCx; JSStructuredCloneWriter* mWriter; - nsTArray>& mClones; + WorkerStructuredCloneClosure& mClones; public: Closure(JSContext* aCx, JSStructuredCloneWriter* aWriter, - nsTArray>& aClones) + WorkerStructuredCloneClosure& aClones) : mCx(aCx), mWriter(aWriter), mClones(aClones) { } @@ -595,7 +598,7 @@ WriteFormData(JSContext* aCx, } }; - Closure closure(aCx, aWriter, aClonedObjects); + Closure closure(aCx, aWriter, aClosure); return aFormData->ForEach(Closure::Write, &closure); } @@ -639,9 +642,7 @@ struct WorkerStructuredCloneCallbacks { NS_ASSERTION(aClosure, "Null pointer!"); - // We'll stash any nsISupports pointers that need to be AddRef'd here. - auto* clonedObjects = - static_cast>*>(aClosure); + auto* closure = static_cast(aClosure); // See if this is a Blob/File object. { @@ -650,7 +651,7 @@ struct WorkerStructuredCloneCallbacks BlobImpl* blobImpl = blob->Impl(); MOZ_ASSERT(blobImpl); - if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) { + if (WriteBlobOrFile(aCx, aWriter, blobImpl, *closure)) { return true; } } @@ -668,7 +669,7 @@ struct WorkerStructuredCloneCallbacks { nsFormData* formData = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) { - if (WriteFormData(aCx, aWriter, formData, *clonedObjects)) { + if (WriteFormData(aCx, aWriter, formData, *closure)) { return true; } } @@ -683,15 +684,96 @@ struct WorkerStructuredCloneCallbacks { Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); } + + static bool + ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader, + uint32_t aTag, void* aContent, uint64_t aExtraData, + void* aClosure, JS::MutableHandle aReturnObject) + { + MOZ_ASSERT(aClosure); + + auto* closure = static_cast(aClosure); + + if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(!aContent); + MOZ_ASSERT(aExtraData < closure->mMessagePortIdentifiers.Length()); + + ErrorResult rv; + nsRefPtr port = + dom::MessagePort::Create(closure->mParentWindow, + closure->mMessagePortIdentifiers[aExtraData], + rv); + + if (NS_WARN_IF(rv.Failed())) { + return false; + } + + closure->mMessagePorts.AppendElement(port); + + JS::Rooted value(aCx); + if (!GetOrCreateDOMReflector(aCx, port, &value)) { + JS_ClearPendingException(aCx); + return false; + } + + aReturnObject.set(&value.toObject()); + return true; + } + + return false; + } + + static bool + Transfer(JSContext* aCx, JS::Handle aObj, void* aClosure, + uint32_t* aTag, JS::TransferableOwnership* aOwnership, + void** aContent, uint64_t *aExtraData) + { + MOZ_ASSERT(aClosure); + + auto* closure = static_cast(aClosure); + + MessagePortBase* port; + nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); + if (NS_SUCCEEDED(rv)) { + if (NS_WARN_IF(closure->mTransferredPorts.Contains(port))) { + // No duplicates. + return false; + } + + MessagePortIdentifier identifier; + if (!port->CloneAndDisentangle(identifier)) { + return false; + } + + closure->mMessagePortIdentifiers.AppendElement(identifier); + closure->mTransferredPorts.AppendElement(port); + + *aTag = SCTAG_DOM_MAP_MESSAGEPORT; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = nullptr; + *aExtraData = closure->mMessagePortIdentifiers.Length() - 1; + + return true; + } + + return false; + } + + static void + FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership, + void *aContent, uint64_t aExtraData, void* aClosure) + { + // Nothing to do. + } }; const JSStructuredCloneCallbacks gWorkerStructuredCloneCallbacks = { WorkerStructuredCloneCallbacks::Read, WorkerStructuredCloneCallbacks::Write, WorkerStructuredCloneCallbacks::Error, - nullptr, - nullptr, - nullptr + WorkerStructuredCloneCallbacks::ReadTransfer, + WorkerStructuredCloneCallbacks::Transfer, + WorkerStructuredCloneCallbacks::FreeTransfer }; struct MainThreadWorkerStructuredCloneCallbacks @@ -731,9 +813,7 @@ struct MainThreadWorkerStructuredCloneCallbacks NS_ASSERTION(aClosure, "Null pointer!"); - // We'll stash any nsISupports pointers that need to be AddRef'd here. - auto* clonedObjects = - static_cast>*>(aClosure); + auto* closure = static_cast(aClosure); // See if this is a Blob/File object. { @@ -744,7 +824,7 @@ struct MainThreadWorkerStructuredCloneCallbacks if (!blobImpl->MayBeClonedToOtherThreads()) { NS_WARNING("Not all the blob implementations can be sent between threads."); - } else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) { + } else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *closure)) { return true; } } @@ -767,9 +847,9 @@ const JSStructuredCloneCallbacks gMainThreadWorkerStructuredCloneCallbacks = { MainThreadWorkerStructuredCloneCallbacks::Read, MainThreadWorkerStructuredCloneCallbacks::Write, MainThreadWorkerStructuredCloneCallbacks::Error, - nullptr, - nullptr, - nullptr + WorkerStructuredCloneCallbacks::ReadTransfer, + WorkerStructuredCloneCallbacks::Transfer, + WorkerStructuredCloneCallbacks::FreeTransfer }; struct ChromeWorkerStructuredCloneCallbacks @@ -800,9 +880,9 @@ const JSStructuredCloneCallbacks gChromeWorkerStructuredCloneCallbacks = { ChromeWorkerStructuredCloneCallbacks::Read, ChromeWorkerStructuredCloneCallbacks::Write, ChromeWorkerStructuredCloneCallbacks::Error, - nullptr, - nullptr, - nullptr + WorkerStructuredCloneCallbacks::ReadTransfer, + WorkerStructuredCloneCallbacks::Transfer, + WorkerStructuredCloneCallbacks::FreeTransfer }; struct MainThreadChromeWorkerStructuredCloneCallbacks @@ -1153,7 +1233,7 @@ private: class MessageEventRunnable final : public WorkerRunnable { JSAutoStructuredCloneBuffer mBuffer; - nsTArray > mClonedObjects; + WorkerStructuredCloneClosure mClosure; uint64_t mMessagePortSerial; bool mToMessagePort; @@ -1163,15 +1243,24 @@ class MessageEventRunnable final : public WorkerRunnable public: MessageEventRunnable(WorkerPrivate* aWorkerPrivate, TargetAndBusyBehavior aBehavior, - JSAutoStructuredCloneBuffer&& aData, - nsTArray >& aClonedObjects, bool aToMessagePort, uint64_t aMessagePortSerial) : WorkerRunnable(aWorkerPrivate, aBehavior) - , mBuffer(Move(aData)) , mMessagePortSerial(aMessagePortSerial) , mToMessagePort(aToMessagePort) { - mClonedObjects.SwapElements(aClonedObjects); + } + + bool + Write(JSContext* aCx, JS::Handle aValue, + JS::Handle aTransferredValue, + const JSStructuredCloneCallbacks *aCallbacks) + { + bool ok = mBuffer.write(aCx, aValue, aTransferredValue, aCallbacks, + &mClosure); + // This hashtable has to be empty because it could contain MessagePort + // objects that cannot be freed on a different thread. + mClosure.mTransferredPorts.Clear(); + return ok; } void @@ -1186,12 +1275,19 @@ public: { // Release reference to objects that were AddRef'd for // cloning into worker when array goes out of scope. - nsTArray> clonedObjects; - clonedObjects.SwapElements(mClonedObjects); + WorkerStructuredCloneClosure closure; + closure.mClonedObjects.SwapElements(mClosure.mClonedObjects); + MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty()); + closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers); + + if (aIsMainThread) { + closure.mParentWindow = do_QueryInterface(aTarget->GetParentObject()); + } JS::Rooted messageData(aCx); if (!mBuffer.read(aCx, &messageData, - workers::WorkerStructuredCloneCallbacks(aIsMainThread))) { + workers::WorkerStructuredCloneCallbacks(aIsMainThread), + &closure)) { xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); return false; } @@ -1217,7 +1313,8 @@ public: } event->SetTrusted(true); - + event->SetPorts(new MessagePortList(static_cast(event.get()), + closure.mMessagePorts)); nsCOMPtr domEvent = do_QueryObject(event); nsEventStatus dummy = nsEventStatus_eIgnore; @@ -1243,7 +1340,7 @@ private: aWorkerPrivate->DispatchMessageEventToMessagePort(aCx, mMessagePortSerial, Move(mBuffer), - mClonedObjects); + mClosure); } if (aWorkerPrivate->IsFrozen()) { @@ -3379,19 +3476,16 @@ WorkerPrivateParent::PostMessageInternal( transferable.setObject(*array); } - nsTArray> clonedObjects; + nsRefPtr runnable = + new MessageEventRunnable(ParentAsWorkerPrivate(), + WorkerRunnable::WorkerThreadModifyBusyCount, + aToMessagePort, aMessagePortSerial); - JSAutoStructuredCloneBuffer buffer; - if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) { + if (!runnable->Write(aCx, aMessage, transferable, callbacks)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } - nsRefPtr runnable = - new MessageEventRunnable(ParentAsWorkerPrivate(), - WorkerRunnable::WorkerThreadModifyBusyCount, - Move(buffer), clonedObjects, aToMessagePort, - aMessagePortSerial); runnable->SetMessageSource(aClientInfo); if (!runnable->Dispatch(aCx)) { @@ -3432,14 +3526,16 @@ bool WorkerPrivateParent::DispatchMessageEventToMessagePort( JSContext* aCx, uint64_t aMessagePortSerial, JSAutoStructuredCloneBuffer&& aBuffer, - nsTArray>& aClonedObjects) + WorkerStructuredCloneClosure& aClosure) { AssertIsOnMainThread(); JSAutoStructuredCloneBuffer buffer(Move(aBuffer)); - nsTArray> clonedObjects; - clonedObjects.SwapElements(aClonedObjects); + WorkerStructuredCloneClosure closure; + closure.mClonedObjects.SwapElements(aClosure.mClonedObjects); + MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty()); + closure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers); SharedWorker* sharedWorker; if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) { @@ -3454,6 +3550,8 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( return true; } + closure.mParentWindow = do_QueryInterface(port->GetParentObject()); + AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) { return false; @@ -3461,7 +3559,8 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( JSContext* cx = jsapi.cx(); JS::Rooted data(cx); - if (!buffer.read(cx, &data, WorkerStructuredCloneCallbacks(true))) { + if (!buffer.read(cx, &data, WorkerStructuredCloneCallbacks(true), + &closure)) { return false; } @@ -3478,11 +3577,7 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( event->SetTrusted(true); - nsTArray> ports; - ports.AppendElement(port); - - nsRefPtr portList = new MessagePortList(port, ports); - event->SetPorts(portList); + event->SetPorts(new MessagePortList(port, closure.mMessagePorts)); nsCOMPtr domEvent; CallQueryInterface(event.get(), getter_AddRefs(domEvent)); @@ -6182,19 +6277,16 @@ WorkerPrivate::PostMessageToParentInternal( &gChromeWorkerStructuredCloneCallbacks : &gWorkerStructuredCloneCallbacks; - nsTArray> clonedObjects; + nsRefPtr runnable = + new MessageEventRunnable(this, + WorkerRunnable::ParentThreadUnchangedBusyCount, + aToMessagePort, aMessagePortSerial); - JSAutoStructuredCloneBuffer buffer; - if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) { + if (!runnable->Write(aCx, aMessage, transferable, callbacks)) { aRv = NS_ERROR_DOM_DATA_CLONE_ERR; return; } - nsRefPtr runnable = - new MessageEventRunnable(this, - WorkerRunnable::ParentThreadUnchangedBusyCount, - Move(buffer), clonedObjects, aToMessagePort, - aMessagePortSerial); if (!runnable->Dispatch(aCx)) { aRv = NS_ERROR_FAILURE; } @@ -7348,4 +7440,20 @@ ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime) // Force instantiation. template class WorkerPrivateParent; +WorkerStructuredCloneClosure::WorkerStructuredCloneClosure() +{} + +WorkerStructuredCloneClosure::~WorkerStructuredCloneClosure() +{} + +void +WorkerStructuredCloneClosure::Clear() +{ + mParentWindow = nullptr; + mClonedObjects.Clear(); + mMessagePorts.Clear(); + mMessagePortIdentifiers.Clear(); + mTransferredPorts.Clear(); +} + END_WORKERS_NAMESPACE diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index ef04c31ba4e1..976c05813918 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -73,6 +73,7 @@ class WorkerDebuggerGlobalScope; class WorkerGlobalScope; class WorkerPrivate; class WorkerRunnable; +class WorkerStructuredCloneClosure; class WorkerThread; // SharedMutex is a small wrapper around an (internal) reference-counted Mutex @@ -349,7 +350,7 @@ public: JSContext* aCx, uint64_t aMessagePortSerial, JSAutoStructuredCloneBuffer&& aBuffer, - nsTArray>& aClonedObjects); + WorkerStructuredCloneClosure& aClosure); void UpdateRuntimeOptions(JSContext* aCx, diff --git a/dom/workers/WorkerStructuredClone.h b/dom/workers/WorkerStructuredClone.h new file mode 100644 index 000000000000..85b7ab3f7f5f --- /dev/null +++ b/dom/workers/WorkerStructuredClone.h @@ -0,0 +1,53 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* 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/. */ + +#ifndef mozilla_dom_workers_WorkerStructuredClone_h +#define mozilla_dom_workers_WorkerStructuredClone_h + +#include "Workers.h" +#include "mozilla/dom/PMessagePort.h" + +class nsPIDOMWindow; + +namespace mozilla { +namespace dom { + +class MessagePortBase; + +namespace workers { + +// This class is implemented in WorkerPrivate.cpp +class WorkerStructuredCloneClosure final +{ +private: + WorkerStructuredCloneClosure(const WorkerStructuredCloneClosure&) = delete; + WorkerStructuredCloneClosure & operator=(const WorkerStructuredCloneClosure&) = delete; + +public: + WorkerStructuredCloneClosure(); + ~WorkerStructuredCloneClosure(); + + void Clear(); + + // This can be null if the MessagePort is created in a worker. + nsCOMPtr mParentWindow; + + nsTArray> mClonedObjects; + + // The transferred ports. + nsTArray> mMessagePorts; + + // Information for the transferring. + nsTArray mMessagePortIdentifiers; + + // To avoid duplicates in the transferred ports. + nsTArray> mTransferredPorts; +}; + +} // workers namespace +} // dom namespace +} // mozilla namespace + +#endif // mozilla_dom_workers_WorkerStructuredClone_h diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 03479c0c51d6..6b61e824fe99 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -27,6 +27,7 @@ #include "RuntimeService.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" +#include "WorkerStructuredClone.h" #include "XMLHttpRequestUpload.h" using namespace mozilla; @@ -413,7 +414,7 @@ class EventRunnable final : public MainThreadProxyRunnable nsString mType; nsString mResponseType; JSAutoStructuredCloneBuffer mResponseBuffer; - nsTArray > mClonedObjects; + WorkerStructuredCloneClosure mResponseClosure; JS::Heap mResponse; nsString mResponseText; nsString mResponseURL; @@ -794,14 +795,14 @@ class SendRunnable final : public WorkerThreadProxySyncRunnable { nsString mStringBody; JSAutoStructuredCloneBuffer mBody; - nsTArray > mClonedObjects; + WorkerStructuredCloneClosure mClosure; nsCOMPtr mSyncLoopTarget; bool mHasUploadListeners; public: SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody, - nsTArray>& aClonedObjects, + WorkerStructuredCloneClosure& aClosure, nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners) : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) , mStringBody(aStringBody) @@ -809,7 +810,9 @@ public: , mSyncLoopTarget(aSyncLoopTarget) , mHasUploadListeners(aHasUploadListeners) { - mClonedObjects.SwapElements(aClonedObjects); + mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects); + MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty()); + MOZ_ASSERT(aClosure.mMessagePortIdentifiers.IsEmpty()); } private: @@ -1229,11 +1232,13 @@ EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) workers::ChromeWorkerStructuredCloneCallbacks(true) : workers::WorkerStructuredCloneCallbacks(true); - nsTArray > clonedObjects; + WorkerStructuredCloneClosure closure; if (mResponseBuffer.write(aCx, response, transferable, callbacks, - &clonedObjects)) { - mClonedObjects.SwapElements(clonedObjects); + &closure)) { + mResponseClosure.mClonedObjects.SwapElements(closure.mClonedObjects); + MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty()); + MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty()); } else { NS_WARNING("Failed to clone response!"); mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR; @@ -1341,11 +1346,13 @@ EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) workers::ChromeWorkerStructuredCloneCallbacks(false) : workers::WorkerStructuredCloneCallbacks(false); - nsTArray > clonedObjects; - clonedObjects.SwapElements(mClonedObjects); + WorkerStructuredCloneClosure closure; + closure.mClonedObjects.SwapElements(mResponseClosure.mClonedObjects); + MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty()); + MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty()); JS::Rooted response(aCx); - if (!responseBuffer.read(aCx, &response, callbacks, &clonedObjects)) { + if (!responseBuffer.read(aCx, &response, callbacks, &closure)) { return false; } @@ -1526,7 +1533,7 @@ SendRunnable::MainThreadRun() workers::WorkerStructuredCloneCallbacks(true); JS::Rooted body(cx); - if (mBody.read(cx, &body, callbacks, &mClonedObjects)) { + if (mBody.read(cx, &body, callbacks, &mClosure)) { if (NS_FAILED(xpc->JSValToVariant(cx, body, getter_AddRefs(variant)))) { rv = NS_ERROR_DOM_INVALID_STATE_ERR; } @@ -1536,7 +1543,7 @@ SendRunnable::MainThreadRun() } mBody.clear(); - mClonedObjects.Clear(); + mClosure.Clear(); NS_ENSURE_SUCCESS(rv, rv); } @@ -1846,7 +1853,7 @@ XMLHttpRequest::Unpin() void XMLHttpRequest::SendInternal(const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody, - nsTArray >& aClonedObjects, + WorkerStructuredCloneClosure& aClosure, ErrorResult& aRv) { mWorkerPrivate->AssertIsOnWorkerThread(); @@ -1880,7 +1887,7 @@ XMLHttpRequest::SendInternal(const nsAString& aStringBody, nsRefPtr runnable = new SendRunnable(mWorkerPrivate, mProxy, aStringBody, Move(aBody), - aClonedObjects, syncLoopTarget, hasUploadListeners); + aClosure, syncLoopTarget, hasUploadListeners); if (!runnable->Dispatch(cx)) { // Dispatch() may have spun the event loop and we may have already unrooted. // If so we don't want autoUnpin to try again. @@ -2102,9 +2109,9 @@ XMLHttpRequest::Send(ErrorResult& aRv) // Nothing to clone. JSAutoStructuredCloneBuffer buffer; - nsTArray > clonedObjects; + WorkerStructuredCloneClosure closure; - SendInternal(NullString(), Move(buffer), clonedObjects, aRv); + SendInternal(NullString(), Move(buffer), closure, aRv); } void @@ -2124,9 +2131,9 @@ XMLHttpRequest::Send(const nsAString& aBody, ErrorResult& aRv) // Nothing to clone. JSAutoStructuredCloneBuffer buffer; - nsTArray > clonedObjects; + WorkerStructuredCloneClosure closure; - SendInternal(aBody, Move(buffer), clonedObjects, aRv); + SendInternal(aBody, Move(buffer), closure, aRv); } void @@ -2167,15 +2174,15 @@ XMLHttpRequest::Send(JS::Handle aBody, ErrorResult& aRv) ChromeWorkerStructuredCloneCallbacks(false) : WorkerStructuredCloneCallbacks(false); - nsTArray > clonedObjects; + WorkerStructuredCloneClosure closure; JSAutoStructuredCloneBuffer buffer; - if (!buffer.write(cx, valToClone, callbacks, &clonedObjects)) { + if (!buffer.write(cx, valToClone, callbacks, &closure)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } - SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv); + SendInternal(EmptyString(), Move(buffer), closure, aRv); } void @@ -2213,15 +2220,15 @@ XMLHttpRequest::Send(Blob& aBody, ErrorResult& aRv) ChromeWorkerStructuredCloneCallbacks(false) : WorkerStructuredCloneCallbacks(false); - nsTArray > clonedObjects; + WorkerStructuredCloneClosure closure; JSAutoStructuredCloneBuffer buffer; - if (!buffer.write(cx, value, callbacks, &clonedObjects)) { + if (!buffer.write(cx, value, callbacks, &closure)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } - SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv); + SendInternal(EmptyString(), Move(buffer), closure, aRv); } void @@ -2251,15 +2258,14 @@ XMLHttpRequest::Send(nsFormData& aBody, ErrorResult& aRv) ChromeWorkerStructuredCloneCallbacks(false) : WorkerStructuredCloneCallbacks(false); - nsTArray> clonedObjects; - JSAutoStructuredCloneBuffer buffer; - if (!buffer.write(cx, value, callbacks, &clonedObjects)) { + WorkerStructuredCloneClosure closure; + if (!buffer.write(cx, value, callbacks, &closure)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } - SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv); + SendInternal(EmptyString(), Move(buffer), closure, aRv); } void diff --git a/dom/workers/XMLHttpRequest.h b/dom/workers/XMLHttpRequest.h index 9475d9ad3308..a3c4d14b0d68 100644 --- a/dom/workers/XMLHttpRequest.h +++ b/dom/workers/XMLHttpRequest.h @@ -28,6 +28,7 @@ BEGIN_WORKERS_NAMESPACE class Proxy; class XMLHttpRequestUpload; class WorkerPrivate; +class WorkerStructuredCloneClosure; class XMLHttpRequest final: public nsXHREventTarget, public WorkerFeature @@ -292,7 +293,7 @@ private: void SendInternal(const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody, - nsTArray >& aClonedObjects, + WorkerStructuredCloneClosure& aClosure, ErrorResult& aRv); }; diff --git a/dom/workers/test/sharedWorker_sharedWorker.js b/dom/workers/test/sharedWorker_sharedWorker.js index 4df59861658d..6c917036b392 100644 --- a/dom/workers/test/sharedWorker_sharedWorker.js +++ b/dom/workers/test/sharedWorker_sharedWorker.js @@ -79,8 +79,8 @@ onconnect = function(event) { if (!("ports" in event)) { throw new Error("'message' event doesn't have a 'ports' property!"); } - if (!(event.ports === null)) { - throw new Error("'message' event has a non-null 'ports' property!"); + if (event.ports === null) { + throw new Error("'message' event has a null 'ports' property!"); } event.target.postMessage(event.data); throw new Error(event.data); diff --git a/ipc/glue/BackgroundChild.h b/ipc/glue/BackgroundChild.h index 5f3c3274b619..2b572266246d 100644 --- a/ipc/glue/BackgroundChild.h +++ b/ipc/glue/BackgroundChild.h @@ -15,6 +15,7 @@ class nsIIPCBackgroundChildCreateCallback; namespace mozilla { namespace dom { +class BlobImpl; class ContentChild; class ContentParent; class PBlobChild; @@ -67,6 +68,10 @@ public: GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor, nsIDOMBlob* aBlob); + static mozilla::dom::PBlobChild* + GetOrCreateActorForBlobImpl(PBackgroundChild* aBackgroundActor, + mozilla::dom::BlobImpl* aBlobImpl); + // See above. static void CloseForCurrentThread(); diff --git a/ipc/glue/BackgroundChildImpl.cpp b/ipc/glue/BackgroundChildImpl.cpp index 68411a91612b..a806692a27fe 100644 --- a/ipc/glue/BackgroundChildImpl.cpp +++ b/ipc/glue/BackgroundChildImpl.cpp @@ -14,6 +14,7 @@ #include "mozilla/dom/cache/ActorUtils.h" #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h" #include "mozilla/dom/ipc/BlobChild.h" +#include "mozilla/dom/MessagePortChild.h" #include "mozilla/ipc/PBackgroundTestChild.h" #include "mozilla/layout/VsyncChild.h" #include "mozilla/net/PUDPSocketChild.h" @@ -340,6 +341,28 @@ BackgroundChildImpl::DeallocPMediaChild(media::PMediaChild *aActor) return media::DeallocPMediaChild(aActor); } +// ----------------------------------------------------------------------------- +// MessageChannel/MessagePort API +// ----------------------------------------------------------------------------- + +dom::PMessagePortChild* +BackgroundChildImpl::AllocPMessagePortChild(const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) +{ + nsRefPtr agent = new dom::MessagePortChild(); + return agent.forget().take(); +} + +bool +BackgroundChildImpl::DeallocPMessagePortChild(PMessagePortChild* aActor) +{ + nsRefPtr child = + dont_AddRef(static_cast(aActor)); + MOZ_ASSERT(child); + return true; +} + } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/BackgroundChildImpl.h b/ipc/glue/BackgroundChildImpl.h index 9c2e011ed55e..c40db905a7c5 100644 --- a/ipc/glue/BackgroundChildImpl.h +++ b/ipc/glue/BackgroundChildImpl.h @@ -121,6 +121,13 @@ protected: virtual bool DeallocPCacheStreamControlChild(dom::cache::PCacheStreamControlChild* aActor) override; + + virtual PMessagePortChild* + AllocPMessagePortChild(const nsID& aUUID, const nsID& aDestinationUUID, + const uint32_t& aSequenceID) override; + + virtual bool + DeallocPMessagePortChild(PMessagePortChild* aActor) override; }; class BackgroundChildImpl::ThreadLocal final diff --git a/ipc/glue/BackgroundImpl.cpp b/ipc/glue/BackgroundImpl.cpp index bbe6b8d3968e..10db43258268 100644 --- a/ipc/glue/BackgroundImpl.cpp +++ b/ipc/glue/BackgroundImpl.cpp @@ -914,17 +914,27 @@ PBlobChild* BackgroundChild::GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor, nsIDOMBlob* aBlob) { - MOZ_ASSERT(aBackgroundActor); MOZ_ASSERT(aBlob); + + nsRefPtr blobImpl = static_cast(aBlob)->Impl(); + MOZ_ASSERT(blobImpl); + + return GetOrCreateActorForBlobImpl(aBackgroundActor, blobImpl); +} + +// static +PBlobChild* +BackgroundChild::GetOrCreateActorForBlobImpl(PBackgroundChild* aBackgroundActor, + BlobImpl* aBlobImpl) +{ + MOZ_ASSERT(aBackgroundActor); + MOZ_ASSERT(aBlobImpl); MOZ_ASSERT(GetForCurrentThread(), "BackgroundChild not created on this thread yet!"); MOZ_ASSERT(aBackgroundActor == GetForCurrentThread(), "BackgroundChild is bound to a different thread!"); - nsRefPtr blobImpl = static_cast(aBlob)->Impl(); - MOZ_ASSERT(blobImpl); - - BlobChild* actor = BlobChild::GetOrCreate(aBackgroundActor, blobImpl); + BlobChild* actor = BlobChild::GetOrCreate(aBackgroundActor, aBlobImpl); if (NS_WARN_IF(!actor)) { return nullptr; } diff --git a/ipc/glue/BackgroundParentImpl.cpp b/ipc/glue/BackgroundParentImpl.cpp index b5da95cc0931..e1b6849d9439 100644 --- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -11,6 +11,7 @@ #include "mozilla/Assertions.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/PBlobParent.h" +#include "mozilla/dom/MessagePortParent.h" #include "mozilla/dom/ServiceWorkerRegistrar.h" #include "mozilla/dom/cache/ActorUtils.h" #include "mozilla/dom/indexedDB/ActorsParent.h" @@ -39,6 +40,8 @@ using mozilla::ipc::AssertIsOnBackgroundThread; using mozilla::dom::cache::PCacheParent; using mozilla::dom::cache::PCacheStorageParent; using mozilla::dom::cache::PCacheStreamControlParent; +using mozilla::dom::MessagePortParent; +using mozilla::dom::PMessagePortParent; using mozilla::dom::UDPSocketParent; namespace { @@ -563,6 +566,41 @@ BackgroundParentImpl::DeallocPCacheStreamControlParent(PCacheStreamControlParent return true; } +PMessagePortParent* +BackgroundParentImpl::AllocPMessagePortParent(const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) +{ + AssertIsInMainProcess(); + AssertIsOnBackgroundThread(); + + return new MessagePortParent(aUUID); +} + +bool +BackgroundParentImpl::RecvPMessagePortConstructor(PMessagePortParent* aActor, + const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) +{ + AssertIsInMainProcess(); + AssertIsOnBackgroundThread(); + + MessagePortParent* mp = static_cast(aActor); + return mp->Entangle(aDestinationUUID, aSequenceID); +} + +bool +BackgroundParentImpl::DeallocPMessagePortParent(PMessagePortParent* aActor) +{ + AssertIsInMainProcess(); + AssertIsOnBackgroundThread(); + MOZ_ASSERT(aActor); + + delete static_cast(aActor); + return true; +} + } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/BackgroundParentImpl.h b/ipc/glue/BackgroundParentImpl.h index 5c27512f25d8..b2ad232076ae 100644 --- a/ipc/glue/BackgroundParentImpl.h +++ b/ipc/glue/BackgroundParentImpl.h @@ -129,6 +129,20 @@ protected: const nsCString& aFilter) override; virtual bool DeallocPUDPSocketParent(PUDPSocketParent*) override; + + virtual PMessagePortParent* + AllocPMessagePortParent(const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) override; + + virtual bool + RecvPMessagePortConstructor(PMessagePortParent* aActor, + const nsID& aUUID, + const nsID& aDestinationUUID, + const uint32_t& aSequenceID) override; + + virtual bool + DeallocPMessagePortParent(PMessagePortParent* aActor) override; }; } // namespace ipc diff --git a/ipc/glue/PBackground.ipdl b/ipc/glue/PBackground.ipdl index 084fe99878ac..cd3e8f2b2de4 100644 --- a/ipc/glue/PBackground.ipdl +++ b/ipc/glue/PBackground.ipdl @@ -10,6 +10,7 @@ include protocol PCache; include protocol PCacheStorage; include protocol PCacheStreamControl; include protocol PFileDescriptorSet; +include protocol PMessagePort; include protocol PMedia; include protocol PServiceWorkerManager; include protocol PUDPSocket; @@ -35,6 +36,7 @@ sync protocol PBackground manages PCacheStorage; manages PCacheStreamControl; manages PFileDescriptorSet; + manages PMessagePort; manages PMedia; manages PServiceWorkerManager; manages PUDPSocket; @@ -59,6 +61,8 @@ parent: PCacheStorage(Namespace aNamespace, PrincipalInfo aPrincipalInfo); + PMessagePort(nsID uuid, nsID destinationUuid, uint32_t sequenceId); + child: PCache(); PCacheStreamControl(); diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index 50a7913d5ec4..967eefdaf5af 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -148,7 +148,7 @@ JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, uint64_t** datap, size JS_PUBLIC_API(bool) JS_ClearStructuredClone(uint64_t* data, size_t nbytes, const JSStructuredCloneCallbacks* optionalCallbacks, - void* closure); + void *closure, bool freeData = true); JS_PUBLIC_API(bool) JS_StructuredCloneHasTransferables(const uint64_t* data, size_t nbytes, bool* hasTransferable); diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index ab17cfe40309..fd12bf266106 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -1908,10 +1908,12 @@ JS_WriteStructuredClone(JSContext* cx, HandleValue value, uint64_t** bufp, size_ JS_PUBLIC_API(bool) JS_ClearStructuredClone(uint64_t* data, size_t nbytes, const JSStructuredCloneCallbacks* optionalCallbacks, - void* closure) + void* closure, bool freeData) { DiscardTransferables(data, nbytes, optionalCallbacks, closure); - js_free(data); + if (freeData) { + js_free(data); + } return true; } diff --git a/testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html.ini b/testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html.ini deleted file mode 100644 index 6dfbdc124e0e..000000000000 --- a/testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[event-ports-dedicated.html] - type: testharness - [e.ports in dedicated worker] - expected: FAIL - From 14bc4ccfab906f1a3c788b4072cbb5addeeaf15e Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Mon, 15 Jun 2015 15:47:43 +0200 Subject: [PATCH 20/49] Bug 1165833 - LUL testing: import gtest/gmock based Dwarf CFI tests from toolkit/crashreporter/google-breakpad. r=jimb. --- tools/profiler/LulDwarfExt.h | 2 +- tools/profiler/tests/gtest/LulTest.cpp | 6 +- tools/profiler/tests/gtest/LulTestDwarf.cpp | 2293 +++++++++++++++++ .../tests/gtest/LulTestInfrastructure.cpp | 491 ++++ .../tests/gtest/LulTestInfrastructure.h | 666 +++++ tools/profiler/tests/gtest/moz.build | 2 + 6 files changed, 3456 insertions(+), 4 deletions(-) create mode 100644 tools/profiler/tests/gtest/LulTestDwarf.cpp create mode 100644 tools/profiler/tests/gtest/LulTestInfrastructure.cpp create mode 100644 tools/profiler/tests/gtest/LulTestInfrastructure.h diff --git a/tools/profiler/LulDwarfExt.h b/tools/profiler/LulDwarfExt.h index 30a5d5156f8b..0b0af326569a 100644 --- a/tools/profiler/LulDwarfExt.h +++ b/tools/profiler/LulDwarfExt.h @@ -1062,7 +1062,7 @@ class CallFrameInfo::Handler { // report errors or warn about problems in the data it is parsing. // These messages are sent to the message sink |aLog| provided to the // constructor. -class CallFrameInfo::Reporter final { +class CallFrameInfo::Reporter { public: // Create an error reporter which attributes troubles to the section // named SECTION in FILENAME. diff --git a/tools/profiler/tests/gtest/LulTest.cpp b/tools/profiler/tests/gtest/LulTest.cpp index 8fbcd9675d9c..8a165ab340cb 100644 --- a/tools/profiler/tests/gtest/LulTest.cpp +++ b/tools/profiler/tests/gtest/LulTest.cpp @@ -16,7 +16,7 @@ // LUL needs a callback for its logging sink. static void -gtest_logging_sink_for_LUL(const char* str) { +gtest_logging_sink_for_LulIntegration(const char* str) { if (DEBUG_LUL_TEST == 0) { return; } @@ -32,11 +32,11 @@ gtest_logging_sink_for_LUL(const char* str) { } } -TEST(LUL, unwind_consistency) { +TEST(LulIntegration, unwind_consistency) { // Set up LUL and get it to read unwind info for libxul.so, which is // all we care about here, plus (incidentally) practically every // other object in the process too. - lul::LUL* lul = new lul::LUL(gtest_logging_sink_for_LUL); + lul::LUL* lul = new lul::LUL(gtest_logging_sink_for_LulIntegration); read_procmaps(lul); // Run unwind tests and receive information about how many there diff --git a/tools/profiler/tests/gtest/LulTestDwarf.cpp b/tools/profiler/tests/gtest/LulTestDwarf.cpp new file mode 100644 index 000000000000..6337b882bb1f --- /dev/null +++ b/tools/profiler/tests/gtest/LulTestDwarf.cpp @@ -0,0 +1,2293 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "gtest/gtest.h" +#include "gmock/gmock.h" +#include "LulCommonExt.h" +#include "LulDwarfExt.h" +#include "LulDwarfInt.h" +#include "LulTestInfrastructure.h" + +using testing::Test; +using testing::Return; +using testing::Sequence; +using testing::InSequence; +using testing::_; +using lul_test::CFISection; +using lul_test::test_assembler::kBigEndian; +using lul_test::test_assembler::kLittleEndian; +using lul_test::test_assembler::Label; + +#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) /**/ +#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) /**/ + +// Set this to 0 to make LUL be completely silent during tests. +// Set it to 1 to get logging output from LUL, presumably for +// the purpose of debugging it. +#define DEBUG_LUL_TEST_DWARF 0 + +// LUL needs a callback for its logging sink. +static void +gtest_logging_sink_for_LulTestDwarf(const char* str) { + if (DEBUG_LUL_TEST_DWARF == 0) { + return; + } + // Ignore any trailing \n, since LOG will add one anyway. + size_t n = strlen(str); + if (n > 0 && str[n-1] == '\n') { + char* tmp = strdup(str); + tmp[n-1] = 0; + fprintf(stderr, "LUL-in-gtest: %s\n", tmp); + free(tmp); + } else { + fprintf(stderr, "LUL-in-gtest: %s\n", str); + } +} + +namespace lul { + +class MockCallFrameInfoHandler : public CallFrameInfo::Handler { + public: + MOCK_METHOD6(Entry, bool(size_t offset, uint64 address, uint64 length, + uint8 version, const std::string &augmentation, + unsigned return_address)); + MOCK_METHOD2(UndefinedRule, bool(uint64 address, int reg)); + MOCK_METHOD2(SameValueRule, bool(uint64 address, int reg)); + MOCK_METHOD4(OffsetRule, bool(uint64 address, int reg, int base_register, + long offset)); + MOCK_METHOD4(ValOffsetRule, bool(uint64 address, int reg, int base_register, + long offset)); + MOCK_METHOD3(RegisterRule, bool(uint64 address, int reg, int base_register)); + MOCK_METHOD3(ExpressionRule, bool(uint64 address, int reg, + const std::string &expression)); + MOCK_METHOD3(ValExpressionRule, bool(uint64 address, int reg, + const std::string &expression)); + MOCK_METHOD0(End, bool()); + MOCK_METHOD2(PersonalityRoutine, bool(uint64 address, bool indirect)); + MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64 address, bool indirect)); + MOCK_METHOD0(SignalHandler, bool()); +}; + +class MockCallFrameErrorReporter : public CallFrameInfo::Reporter { + public: + MockCallFrameErrorReporter() + : Reporter(gtest_logging_sink_for_LulTestDwarf, + "mock filename", "mock section") + { } + MOCK_METHOD2(Incomplete, void(uint64, CallFrameInfo::EntryKind)); + MOCK_METHOD1(EarlyEHTerminator, void(uint64)); + MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64)); + MOCK_METHOD2(BadCIEId, void(uint64, uint64)); + MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version)); + MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &)); + MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8)); + MOCK_METHOD2(UnusablePointerEncoding, void(uint64, uint8)); + MOCK_METHOD2(RestoreInCIE, void(uint64, uint64)); + MOCK_METHOD3(BadInstruction, void(uint64, CallFrameInfo::EntryKind, uint64)); + MOCK_METHOD3(NoCFARule, void(uint64, CallFrameInfo::EntryKind, uint64)); + MOCK_METHOD3(EmptyStateStack, void(uint64, CallFrameInfo::EntryKind, uint64)); + MOCK_METHOD3(ClearingCFARule, void(uint64, CallFrameInfo::EntryKind, uint64)); +}; + +struct CFIFixture { + + enum { kCFARegister = CallFrameInfo::Handler::kCFARegister }; + + CFIFixture() { + // Default expectations for the data handler. + // + // - Leave Entry and End without expectations, as it's probably a + // good idea to set those explicitly in each test. + // + // - Expect the *Rule functions to not be called, + // so that each test can simply list the calls they expect. + // + // I gather I could use StrictMock for this, but the manual seems + // to suggest using that only as a last resort, and this isn't so + // bad. + EXPECT_CALL(handler, UndefinedRule(_, _)).Times(0); + EXPECT_CALL(handler, SameValueRule(_, _)).Times(0); + EXPECT_CALL(handler, OffsetRule(_, _, _, _)).Times(0); + EXPECT_CALL(handler, ValOffsetRule(_, _, _, _)).Times(0); + EXPECT_CALL(handler, RegisterRule(_, _, _)).Times(0); + EXPECT_CALL(handler, ExpressionRule(_, _, _)).Times(0); + EXPECT_CALL(handler, ValExpressionRule(_, _, _)).Times(0); + EXPECT_CALL(handler, PersonalityRoutine(_, _)).Times(0); + EXPECT_CALL(handler, LanguageSpecificDataArea(_, _)).Times(0); + EXPECT_CALL(handler, SignalHandler()).Times(0); + + // Default expectations for the error/warning reporer. + EXPECT_CALL(reporter, Incomplete(_, _)).Times(0); + EXPECT_CALL(reporter, EarlyEHTerminator(_)).Times(0); + EXPECT_CALL(reporter, CIEPointerOutOfRange(_, _)).Times(0); + EXPECT_CALL(reporter, BadCIEId(_, _)).Times(0); + EXPECT_CALL(reporter, UnrecognizedVersion(_, _)).Times(0); + EXPECT_CALL(reporter, UnrecognizedAugmentation(_, _)).Times(0); + EXPECT_CALL(reporter, InvalidPointerEncoding(_, _)).Times(0); + EXPECT_CALL(reporter, UnusablePointerEncoding(_, _)).Times(0); + EXPECT_CALL(reporter, RestoreInCIE(_, _)).Times(0); + EXPECT_CALL(reporter, BadInstruction(_, _, _)).Times(0); + EXPECT_CALL(reporter, NoCFARule(_, _, _)).Times(0); + EXPECT_CALL(reporter, EmptyStateStack(_, _, _)).Times(0); + EXPECT_CALL(reporter, ClearingCFARule(_, _, _)).Times(0); + } + + MockCallFrameInfoHandler handler; + MockCallFrameErrorReporter reporter; +}; + +class LulDwarfCFI: public CFIFixture, public Test { }; + +TEST_F(LulDwarfCFI, EmptyRegion) { + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + static const char data[1] = { 42 }; + + ByteReader reader(ENDIANNESS_BIG); + CallFrameInfo parser(data, 0, &reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +TEST_F(LulDwarfCFI, IncompleteLength32) { + CFISection section(kBigEndian, 8); + section + // Not even long enough for an initial length. + .D16(0xa0f) + // Padding to keep valgrind happy. We subtract these off when we + // construct the parser. + .D16(0); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) + .WillOnce(Return()); + + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(8); + CallFrameInfo parser(contents.data(), contents.size() - 2, + &reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +TEST_F(LulDwarfCFI, IncompleteLength64) { + CFISection section(kLittleEndian, 4); + section + // An incomplete 64-bit DWARF initial length. + .D32(0xffffffff).D32(0x71fbaec2) + // Padding to keep valgrind happy. We subtract these off when we + // construct the parser. + .D32(0); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) + .WillOnce(Return()); + + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(4); + CallFrameInfo parser(contents.data(), contents.size() - 4, + &reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +TEST_F(LulDwarfCFI, IncompleteId32) { + CFISection section(kBigEndian, 8); + section + .D32(3) // Initial length, not long enough for id + .D8(0xd7).D8(0xe5).D8(0xf1) // incomplete id + .CIEHeader(8727, 3983, 8889, 3, "") + .FinishEntry(); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) + .WillOnce(Return()); + + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(8); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +TEST_F(LulDwarfCFI, BadId32) { + CFISection section(kBigEndian, 8); + section + .D32(0x100) // Initial length + .D32(0xe802fade) // bogus ID + .Append(0x100 - 4, 0x42); // make the length true + section + .CIEHeader(1672, 9872, 8529, 3, "") + .FinishEntry(); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + EXPECT_CALL(reporter, CIEPointerOutOfRange(_, 0xe802fade)) + .WillOnce(Return()); + + string contents; + ASSERT_TRUE(section.GetContents(&contents)); + + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(8); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +// A lone CIE shouldn't cause any handler calls. +TEST_F(LulDwarfCFI, SingleCIE) { + CFISection section(kLittleEndian, 4); + section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, ""); + section.Append(10, lul::DW_CFA_nop); + section.FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section); + + EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); + EXPECT_CALL(handler, End()).Times(0); + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(4); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// One FDE, one CIE. +TEST_F(LulDwarfCFI, OneFDE) { + CFISection section(kBigEndian, 4); + Label cie; + section + .Mark(&cie) + .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "") + .FinishEntry() + .FDEHeader(cie, 0x7714740d, 0x3d5a10cd) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("OneFDE", section); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0x7714740d, 0x3d5a10cd, 3, "", 0x6b6efb87)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// Two FDEs share a CIE. +TEST_F(LulDwarfCFI, TwoFDEsOneCIE) { + CFISection section(kBigEndian, 4); + Label cie; + section + // First FDE. readelf complains about this one because it makes + // a forward reference to its CIE. + .FDEHeader(cie, 0xa42744df, 0xa3b42121) + .FinishEntry() + // CIE. + .Mark(&cie) + .CIEHeader(0x04f7dc7b, 0x3d00c05f, 0xbd43cb59, 3, "") + .FinishEntry() + // Second FDE. + .FDEHeader(cie, 0x6057d391, 0x700f608d) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsOneCIE", section); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0xa42744df, 0xa3b42121, 3, "", 0xbd43cb59)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0x6057d391, 0x700f608d, 3, "", 0xbd43cb59)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// Two FDEs, two CIEs. +TEST_F(LulDwarfCFI, TwoFDEsTwoCIEs) { + CFISection section(kLittleEndian, 8); + Label cie1, cie2; + section + // First CIE. + .Mark(&cie1) + .CIEHeader(0x694d5d45, 0x4233221b, 0xbf45e65a, 3, "") + .FinishEntry() + // First FDE which cites second CIE. readelf complains about + // this one because it makes a forward reference to its CIE. + .FDEHeader(cie2, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL) + .FinishEntry() + // Second FDE, which cites first CIE. + .FDEHeader(cie1, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL) + .FinishEntry() + // Second CIE. + .Mark(&cie2) + .CIEHeader(0xfba3fad7, 0x6287e1fd, 0x61d2c581, 2, "") + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsTwoCIEs", section); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL, 2, + "", 0x61d2c581)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL, 3, + "", 0xbf45e65a)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader reader(ENDIANNESS_LITTLE); + reader.SetAddressSize(8); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// An FDE whose CIE specifies a version we don't recognize. +TEST_F(LulDwarfCFI, BadVersion) { + CFISection section(kBigEndian, 4); + Label cie1, cie2; + section + .Mark(&cie1) + .CIEHeader(0xca878cf0, 0x7698ec04, 0x7b616f54, 0x52, "") + .FinishEntry() + // We should skip this entry, as its CIE specifies a version we + // don't recognize. + .FDEHeader(cie1, 0x08852292, 0x2204004a) + .FinishEntry() + // Despite the above, we should visit this entry. + .Mark(&cie2) + .CIEHeader(0x7c3ae7c9, 0xb9b9a512, 0x96cb3264, 3, "") + .FinishEntry() + .FDEHeader(cie2, 0x2094735a, 0x6e875501) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("BadVersion", section); + + EXPECT_CALL(reporter, UnrecognizedVersion(_, 0x52)) + .WillOnce(Return()); + + { + InSequence s; + // We should see no mention of the first FDE, but we should get + // a call to Entry for the second. + EXPECT_CALL(handler, Entry(_, 0x2094735a, 0x6e875501, 3, "", + 0x96cb3264)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +// An FDE whose CIE specifies an augmentation we don't recognize. +TEST_F(LulDwarfCFI, BadAugmentation) { + CFISection section(kBigEndian, 4); + Label cie1, cie2; + section + .Mark(&cie1) + .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "spaniels!") + .FinishEntry() + // We should skip this entry, as its CIE specifies an + // augmentation we don't recognize. + .FDEHeader(cie1, 0x7714740d, 0x3d5a10cd) + .FinishEntry() + // Despite the above, we should visit this entry. + .Mark(&cie2) + .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 3, "") + .FinishEntry() + .FDEHeader(cie2, 0x7bf0fda0, 0xcbcd28d8) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("BadAugmentation", section); + + EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "spaniels!")) + .WillOnce(Return()); + + { + InSequence s; + // We should see no mention of the first FDE, but we should get + // a call to Entry for the second. + EXPECT_CALL(handler, Entry(_, 0x7bf0fda0, 0xcbcd28d8, 3, "", + 0xf2f519b2)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_FALSE(parser.Start()); +} + +// The return address column field is a byte in CFI version 1 +// (DWARF2), but a ULEB128 value in version 3 (DWARF3). +TEST_F(LulDwarfCFI, CIEVersion1ReturnColumn) { + CFISection section(kBigEndian, 4); + Label cie; + section + // CIE, using the version 1 format: return column is a ubyte. + .Mark(&cie) + // Use a value for the return column that is parsed differently + // as a ubyte and as a ULEB128. + .CIEHeader(0xbcdea24f, 0x5be28286, 0x9f, 1, "") + .FinishEntry() + // FDE, citing that CIE. + .FDEHeader(cie, 0xb8d347b5, 0x825e55dc) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion1ReturnColumn", section); + + { + InSequence s; + EXPECT_CALL(handler, Entry(_, 0xb8d347b5, 0x825e55dc, 1, "", 0x9f)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +// The return address column field is a byte in CFI version 1 +// (DWARF2), but a ULEB128 value in version 3 (DWARF3). +TEST_F(LulDwarfCFI, CIEVersion3ReturnColumn) { + CFISection section(kBigEndian, 4); + Label cie; + section + // CIE, using the version 3 format: return column is a ULEB128. + .Mark(&cie) + // Use a value for the return column that is parsed differently + // as a ubyte and as a ULEB128. + .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 3, "") + .FinishEntry() + // FDE, citing that CIE. + .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section); + + { + InSequence s; + EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 3, "", 0x89)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + string contents; + EXPECT_TRUE(section.GetContents(&contents)); + ByteReader reader(ENDIANNESS_BIG); + reader.SetAddressSize(4); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter); + EXPECT_TRUE(parser.Start()); +} + +struct CFIInsnFixture: public CFIFixture { + CFIInsnFixture() : CFIFixture() { + data_factor = 0xb6f; + return_register = 0x9be1ed9f; + version = 3; + cfa_base_register = 0x383a3aa; + cfa_offset = 0xf748; + } + + // Prepare SECTION to receive FDE instructions. + // + // - Append a stock CIE header that establishes the fixture's + // code_factor, data_factor, return_register, version, and + // augmentation values. + // - Have the CIE set up a CFA rule using cfa_base_register and + // cfa_offset. + // - Append a stock FDE header, referring to the above CIE, for the + // fde_size bytes at fde_start. Choose fde_start and fde_size + // appropriately for the section's address size. + // - Set appropriate expectations on handler in sequence s for the + // frame description entry and the CIE's CFA rule. + // + // On return, SECTION is ready to have FDE instructions appended to + // it, and its FinishEntry member called. + void StockCIEAndFDE(CFISection *section) { + // Choose appropriate constants for our address size. + if (section->AddressSize() == 4) { + fde_start = 0xc628ecfbU; + fde_size = 0x5dee04a2; + code_factor = 0x60b; + } else { + assert(section->AddressSize() == 8); + fde_start = 0x0005c57ce7806bd3ULL; + fde_size = 0x2699521b5e333100ULL; + code_factor = 0x01008e32855274a8ULL; + } + + // Create the CIE. + (*section) + .Mark(&cie_label) + .CIEHeader(code_factor, data_factor, return_register, version, + "") + .D8(lul::DW_CFA_def_cfa) + .ULEB128(cfa_base_register) + .ULEB128(cfa_offset) + .FinishEntry(); + + // Create the FDE. + section->FDEHeader(cie_label, fde_start, fde_size); + + // Expect an Entry call for the FDE and a ValOffsetRule call for the + // CIE's CFA rule. + EXPECT_CALL(handler, Entry(_, fde_start, fde_size, version, "", + return_register)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start, kCFARegister, + cfa_base_register, cfa_offset)) + .InSequence(s) + .WillOnce(Return(true)); + } + + // Run the contents of SECTION through a CallFrameInfo parser, + // expecting parser.Start to return SUCCEEDS. Caller may optionally + // supply, via READER, its own ByteReader. If that's absent, a + // local one is used. + void ParseSection(CFISection *section, + bool succeeds = true, ByteReader* reader = nullptr) { + string contents; + EXPECT_TRUE(section->GetContents(&contents)); + lul::Endianness endianness; + if (section->endianness() == kBigEndian) + endianness = ENDIANNESS_BIG; + else { + assert(section->endianness() == kLittleEndian); + endianness = ENDIANNESS_LITTLE; + } + ByteReader local_reader(endianness); + ByteReader* reader_to_use = reader ? reader : &local_reader; + reader_to_use->SetAddressSize(section->AddressSize()); + CallFrameInfo parser(contents.data(), contents.size(), + reader_to_use, &handler, &reporter); + if (succeeds) + EXPECT_TRUE(parser.Start()); + else + EXPECT_FALSE(parser.Start()); + } + + Label cie_label; + Sequence s; + uint64 code_factor; + int data_factor; + unsigned return_register; + unsigned version; + unsigned cfa_base_register; + int cfa_offset; + uint64 fde_start, fde_size; +}; + +class LulDwarfCFIInsn: public CFIInsnFixture, public Test { }; + +TEST_F(LulDwarfCFIInsn, DW_CFA_set_loc) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_set_loc).D32(0xb1ee3e7a) + // Use DW_CFA_def_cfa to force a handler call that we can use to + // check the effect of the DW_CFA_set_loc. + .D8(lul::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section); + + EXPECT_CALL(handler, + ValOffsetRule(0xb1ee3e7a, kCFARegister, 0x4defb431, 0x6d17b0ee)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_advance_loc) { + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_advance_loc | 0x2a) + // Use DW_CFA_def_cfa to force a handler call that we can use to + // check the effect of the DW_CFA_advance_loc. + .D8(lul::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start + 0x2a * code_factor, + kCFARegister, 0x5bbb3715, 0x0186c7bf)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_advance_loc1) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_advance_loc1).D8(0xd8) + .D8(lul::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section); + + EXPECT_CALL(handler, + ValOffsetRule((fde_start + 0xd8 * code_factor), + kCFARegister, 0x69d5696a, 0x1eb7fc93)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_advance_loc2) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_advance_loc2).D16(0x3adb) + .D8(lul::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section); + + EXPECT_CALL(handler, + ValOffsetRule((fde_start + 0x3adb * code_factor), + kCFARegister, 0x3a368bed, 0x3194ee37)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_advance_loc4) { + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_advance_loc4).D32(0x15813c88) + .D8(lul::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section); + + EXPECT_CALL(handler, + ValOffsetRule((fde_start + 0x15813c88ULL * code_factor), + kCFARegister, 0x135270c5, 0x24bad7cb)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_MIPS_advance_loc8) { + code_factor = 0x2d; + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL) + .D8(lul::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section); + + EXPECT_CALL(handler, + ValOffsetRule((fde_start + 0x3c4f3945b92c14ULL * code_factor), + kCFARegister, 0xe17ed602, 0x3d162e7f)) + .InSequence(s) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x4e363a85, 0x815f9aa7)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_sf) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea) + .D8(lul::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x8ccb32b7, + 0x9ea * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x9b40f5da, + -0x40a2 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_register) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x3e7e9363, cfa_offset)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +// DW_CFA_def_cfa_register should have no effect when applied to a +// non-base/offset rule. +TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_registerBadRule) { + ByteReader reader(ENDIANNESS_BIG); + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_def_cfa_expression).Block("needle in a haystack") + .D8(lul::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49) + .FinishEntry(); + + EXPECT_CALL(handler, + ValExpressionRule(fde_start, kCFARegister, + "needle in a haystack")) + .WillRepeatedly(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_offset) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, cfa_base_register, + 0x1e8e3b9b)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_offset_sf) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_def_cfa_offset_sf).LEB128(0x970) + .D8(lul::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, cfa_base_register, + 0x970 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, cfa_base_register, + -0x2cd * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +// DW_CFA_def_cfa_offset should have no effect when applied to a +// non-base/offset rule. +TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_offsetBadRule) { + ByteReader reader(ENDIANNESS_BIG); + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_def_cfa_expression).Block("six ways to Sunday") + .D8(lul::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) + .FinishEntry(); + + EXPECT_CALL(handler, + ValExpressionRule(fde_start, kCFARegister, "six ways to Sunday")) + .WillRepeatedly(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + + +TEST_F(LulDwarfCFIInsn, DW_CFA_def_cfa_expression) { + ByteReader reader(ENDIANNESS_LITTLE); + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_def_cfa_expression).Block("eating crow") + .FinishEntry(); + + EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister, + "eating crow")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_undefined) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_undefined).ULEB128(0x300ce45d) + .FinishEntry(); + + EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_same_value) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_same_value).ULEB128(0x3865a760) + .FinishEntry(); + + EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_offset) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_offset | 0x2c).ULEB128(0x9f6) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x2c, kCFARegister, 0x9f6 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_offset_extended) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, + 0x402b, kCFARegister, 0xb48 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_offset_extended_sf) { + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_offset_extended_sf) + .ULEB128(0x997c23ee).LEB128(0x2d00) + .D8(lul::DW_CFA_offset_extended_sf) + .ULEB128(0x9519eb82).LEB128(-0xa77) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x997c23ee, + kCFARegister, 0x2d00 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x9519eb82, + kCFARegister, -0xa77 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_val_offset) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, 0x623562fe, + kCFARegister, 0x673 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_val_offset_sf) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab) + .D8(lul::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, 0x6f4f, + kCFARegister, 0xaab * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, + ValOffsetRule(fde_start, 0x2483, + kCFARegister, -0x8a2 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_register) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414) + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_expression) { + ByteReader reader(ENDIANNESS_BIG); + CFISection section(kBigEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_expression).ULEB128(0xa1619fb2) + .Block("plus ça change, plus c'est la même chose") + .FinishEntry(); + + EXPECT_CALL(handler, + ExpressionRule(fde_start, 0xa1619fb2, + "plus ça change, plus c'est la même chose")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_val_expression) { + ByteReader reader(ENDIANNESS_BIG); + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_val_expression).ULEB128(0xc5e4a9e3) + .Block("he who has the gold makes the rules") + .FinishEntry(); + + EXPECT_CALL(handler, + ValExpressionRule(fde_start, 0xc5e4a9e3, + "he who has the gold makes the rules")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_restore) { + CFISection section(kLittleEndian, 8); + code_factor = 0x01bd188a9b1fa083ULL; + data_factor = -0x1ac8; + return_register = 0x8c35b049; + version = 2; + fde_start = 0x2d70fe998298bbb1ULL; + fde_size = 0x46ccc2e63cf0b108ULL; + Label cie; + section + .Mark(&cie) + .CIEHeader(code_factor, data_factor, return_register, version, + "") + // Provide a CFA rule, because register rules require them. + .D8(lul::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8) + // Provide an offset(N) rule for register 0x3c. + .D8(lul::DW_CFA_offset | 0x3c).ULEB128(0xb348) + .FinishEntry() + // In the FDE... + .FDEHeader(cie, fde_start, fde_size) + // At a second address, provide a new offset(N) rule for register 0x3c. + .D8(lul::DW_CFA_advance_loc | 0x13) + .D8(lul::DW_CFA_offset | 0x3c).ULEB128(0x9a50) + // At a third address, restore the original rule for register 0x3c. + .D8(lul::DW_CFA_advance_loc | 0x01) + .D8(lul::DW_CFA_restore | 0x3c) + .FinishEntry(); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, fde_start, fde_size, version, "", return_register)) + .WillOnce(Return(true)); + // CIE's CFA rule. + EXPECT_CALL(handler, + ValOffsetRule(fde_start, + kCFARegister, 0x6ca1d50e, 0x372e38e8)) + .WillOnce(Return(true)); + // CIE's rule for register 0x3c. + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x3c, + kCFARegister, 0xb348 * data_factor)) + .WillOnce(Return(true)); + // FDE's rule for register 0x3c. + EXPECT_CALL(handler, + OffsetRule(fde_start + 0x13 * code_factor, 0x3c, + kCFARegister, 0x9a50 * data_factor)) + .WillOnce(Return(true)); + // Restore CIE's rule for register 0x3c. + EXPECT_CALL(handler, + OffsetRule(fde_start + (0x13 + 0x01) * code_factor, 0x3c, + kCFARegister, 0xb348 * data_factor)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_restoreNoRule) { + CFISection section(kBigEndian, 4); + code_factor = 0x005f78143c1c3b82ULL; + data_factor = 0x25d0; + return_register = 0xe8; + version = 1; + fde_start = 0x4062e30f; + fde_size = 0x5302a389; + Label cie; + section + .Mark(&cie) + .CIEHeader(code_factor, data_factor, return_register, version, "") + // Provide a CFA rule, because register rules require them. + .D8(lul::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127) + .FinishEntry() + // In the FDE... + .FDEHeader(cie, fde_start, fde_size) + // At a second address, provide an offset(N) rule for register 0x2c. + .D8(lul::DW_CFA_advance_loc | 0x7) + .D8(lul::DW_CFA_offset | 0x2c).ULEB128(0x1f47) + // At a third address, restore the (missing) CIE rule for register 0x2c. + .D8(lul::DW_CFA_advance_loc | 0xb) + .D8(lul::DW_CFA_restore | 0x2c) + .FinishEntry(); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, fde_start, fde_size, version, "", return_register)) + .WillOnce(Return(true)); + // CIE's CFA rule. + EXPECT_CALL(handler, + ValOffsetRule(fde_start, + kCFARegister, 0x470aa334, 0x099ef127)) + .WillOnce(Return(true)); + // FDE's rule for register 0x2c. + EXPECT_CALL(handler, + OffsetRule(fde_start + 0x7 * code_factor, 0x2c, + kCFARegister, 0x1f47 * data_factor)) + .WillOnce(Return(true)); + // Restore CIE's (missing) rule for register 0x2c. + EXPECT_CALL(handler, + SameValueRule(fde_start + (0x7 + 0xb) * code_factor, 0x2c)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_restore_extended) { + CFISection section(kBigEndian, 4); + code_factor = 0x126e; + data_factor = -0xd8b; + return_register = 0x77711787; + version = 3; + fde_start = 0x01f55a45; + fde_size = 0x452adb80; + Label cie; + section + .Mark(&cie) + .CIEHeader(code_factor, data_factor, return_register, version, + "", true /* dwarf64 */ ) + // Provide a CFA rule, because register rules require them. + .D8(lul::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5) + // Provide an offset(N) rule for register 0x0f9b8a1c. + .D8(lul::DW_CFA_offset_extended) + .ULEB128(0x0f9b8a1c).ULEB128(0xc979) + .FinishEntry() + // In the FDE... + .FDEHeader(cie, fde_start, fde_size) + // At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c. + .D8(lul::DW_CFA_advance_loc | 0x3) + .D8(lul::DW_CFA_offset_extended) + .ULEB128(0x0f9b8a1c).ULEB128(0x3b7b) + // At a third address, restore the original rule for register 0x0f9b8a1c. + .D8(lul::DW_CFA_advance_loc | 0x04) + .D8(lul::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c) + .FinishEntry(); + + { + InSequence s; + EXPECT_CALL(handler, + Entry(_, fde_start, fde_size, version, "", return_register)) + .WillOnce(Return(true)); + // CIE's CFA rule. + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x56fa0edd, 0x097f78a5)) + .WillOnce(Return(true)); + // CIE's rule for register 0x0f9b8a1c. + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x0f9b8a1c, kCFARegister, + 0xc979 * data_factor)) + .WillOnce(Return(true)); + // FDE's rule for register 0x0f9b8a1c. + EXPECT_CALL(handler, + OffsetRule(fde_start + 0x3 * code_factor, 0x0f9b8a1c, + kCFARegister, 0x3b7b * data_factor)) + .WillOnce(Return(true)); + // Restore CIE's rule for register 0x0f9b8a1c. + EXPECT_CALL(handler, + OffsetRule(fde_start + (0x3 + 0x4) * code_factor, 0x0f9b8a1c, + kCFARegister, 0xc979 * data_factor)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + } + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_remember_and_restore_state) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + + // We create a state, save it, modify it, and then restore. We + // refer to the state that is overridden the restore as the + // "outgoing" state, and the restored state the "incoming" state. + // + // Register outgoing incoming expect + // 1 offset(N) no rule new "same value" rule + // 2 register(R) offset(N) report changed rule + // 3 offset(N) offset(M) report changed offset + // 4 offset(N) offset(N) no report + // 5 offset(N) no rule new "same value" rule + section + // Create the "incoming" state, which we will save and later restore. + .D8(lul::DW_CFA_offset | 2).ULEB128(0x9806) + .D8(lul::DW_CFA_offset | 3).ULEB128(0x995d) + .D8(lul::DW_CFA_offset | 4).ULEB128(0x7055) + .D8(lul::DW_CFA_remember_state) + // Advance to a new instruction; an implementation could legitimately + // ignore all but the final rule for a given register at a given address. + .D8(lul::DW_CFA_advance_loc | 1) + // Create the "outgoing" state, which we will discard. + .D8(lul::DW_CFA_offset | 1).ULEB128(0xea1a) + .D8(lul::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767) + .D8(lul::DW_CFA_offset | 3).ULEB128(0xdd29) + .D8(lul::DW_CFA_offset | 5).ULEB128(0xf1ce) + // At a third address, restore the incoming state. + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + uint64 addr = fde_start; + + // Expect the incoming rules to be reported. + EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 4, kCFARegister, 0x7055 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + + addr += code_factor; + + // After the save, we establish the outgoing rule set. + EXPECT_CALL(handler, OffsetRule(addr, 1, kCFARegister, 0xea1a * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(addr, 2, 0x1d2a3767)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0xdd29 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 5, kCFARegister, 0xf1ce * data_factor)) + .InSequence(s).WillOnce(Return(true)); + + addr += code_factor; + + // Finally, after the restore, expect to see the differences from + // the outgoing to the incoming rules reported. + EXPECT_CALL(handler, SameValueRule(addr, 1)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SameValueRule(addr, 5)) + .InSequence(s).WillOnce(Return(true)); + + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +// Check that restoring a rule set reports changes to the CFA rule. +TEST_F(LulDwarfCFIInsn, DW_CFA_remember_and_restore_stateCFA) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + + section + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_def_cfa_offset).ULEB128(0x90481102) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister, + cfa_base_register, 0x90481102)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor * 2, kCFARegister, + cfa_base_register, cfa_offset)) + .InSequence(s).WillOnce(Return(true)); + + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_nop) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_nop) + .D8(lul::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b) + .D8(lul::DW_CFA_nop) + .FinishEntry(); + + EXPECT_CALL(handler, + ValOffsetRule(fde_start, kCFARegister, 0x3fb8d4f1, 0x078dc67b)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_GNU_window_save) { + CFISection section(kBigEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_GNU_window_save) + .FinishEntry(); + + // Don't include all the rules in any particular sequence. + + // The caller's %o0-%o7 have become the callee's %i0-%i7. This is + // the GCC register numbering. + for (int i = 8; i < 16; i++) + EXPECT_CALL(handler, RegisterRule(fde_start, i, i + 16)) + .WillOnce(Return(true)); + // The caller's %l0-%l7 and %i0-%i7 have been saved at the top of + // its frame. + for (int i = 16; i < 32; i++) + EXPECT_CALL(handler, OffsetRule(fde_start, i, kCFARegister, (i-16) * 4)) + .WillOnce(Return(true)); + + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_GNU_args_size) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_GNU_args_size).ULEB128(0xeddfa520) + // Verify that we see this, meaning we parsed the above properly. + .D8(lul::DW_CFA_offset | 0x23).ULEB128(0x269) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x23, kCFARegister, 0x269 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIInsn, DW_CFA_GNU_negative_offset_extended) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_GNU_negative_offset_extended) + .ULEB128(0x430cc87a).ULEB128(0x613) + .FinishEntry(); + + EXPECT_CALL(handler, + OffsetRule(fde_start, 0x430cc87a, + kCFARegister, -0x613 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion); +} + +// Three FDEs: skip the second +TEST_F(LulDwarfCFIInsn, SkipFDE) { + CFISection section(kBigEndian, 4); + Label cie; + section + // CIE, used by all FDEs. + .Mark(&cie) + .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "") + .D8(lul::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad) + .FinishEntry() + // First FDE. + .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4) + .D8(lul::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf) + .FinishEntry() + // Second FDE. + .FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */) + .D8(lul::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18) + .FinishEntry() + // Third FDE. + .FDEHeader(cie, 0xf681cfc8, 0x7e4594e) + .D8(lul::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4) + .FinishEntry(); + + { + InSequence s; + + // Process the first FDE. + EXPECT_CALL(handler, Entry(_, 0xa870ebdd, 0x60f6aa4, 2, "", 0xedca5849)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0xa870ebdd, kCFARegister, + 0x42ed390b, 0x98f43aad)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(0xa870ebdd, 0x3a860351, 0x6c9a6bcf)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .WillOnce(Return(true)); + + // Skip the second FDE. + EXPECT_CALL(handler, Entry(_, 0xc534f7c0, 0xf6552e9, 2, "", 0xedca5849)) + .WillOnce(Return(false)); + + // Process the third FDE. + EXPECT_CALL(handler, Entry(_, 0xf681cfc8, 0x7e4594e, 2, "", 0xedca5849)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0xf681cfc8, kCFARegister, + 0x42ed390b, 0x98f43aad)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(0xf681cfc8, 0x26c53934, 0x18eeb8a4)) + .WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .WillOnce(Return(true)); + } + + ParseSection(§ion); +} + +// Quit processing in the middle of an entry's instructions. +TEST_F(LulDwarfCFIInsn, QuitMidentry) { + CFISection section(kLittleEndian, 8); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431) + .D8(lul::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat") + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431)) + .InSequence(s).WillOnce(Return(false)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseSection(§ion, false); +} + +class LulDwarfCFIRestore: public CFIInsnFixture, public Test { }; + +TEST_F(LulDwarfCFIRestore, RestoreUndefinedRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_undefined).ULEB128(0x0bac878e) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreUndefinedRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_undefined).ULEB128(0x7dedff5f) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_same_value).ULEB128(0x7dedff5f) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SameValueRule(fde_start + code_factor, 0x7dedff5f)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + 2 * code_factor, 0x7dedff5f)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreSameValueRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_same_value).ULEB128(0xadbc9b3a) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreSameValueRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_same_value).ULEB128(0x3d90dcb5) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_undefined).ULEB128(0x3d90dcb5) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x3d90dcb5)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SameValueRule(fde_start + 2 * code_factor, 0x3d90dcb5)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreOffsetRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_offset | 0x14).ULEB128(0xb6f) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, OffsetRule(fde_start, 0x14, + kCFARegister, 0xb6f * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreOffsetRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_offset | 0x21).ULEB128(0xeb7) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_undefined).ULEB128(0x21) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, + kCFARegister, 0xeb7 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x21)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, + kCFARegister, 0xeb7 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreOffsetRuleChangedOffset) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_offset | 0x21).ULEB128(0x134) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_offset | 0x21).ULEB128(0xf4f) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, + kCFARegister, 0x134 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(fde_start + code_factor, 0x21, + kCFARegister, 0xf4f * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, + kCFARegister, 0x134 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreValOffsetRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6, + kCFARegister, 0xe4c * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreValOffsetRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_undefined).ULEB128(0xf17c36d6) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6, + kCFARegister, 0xeb7 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xf17c36d6)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0xf17c36d6, + kCFARegister, 0xeb7 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreValOffsetRuleChangedValOffset) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b, + kCFARegister, 0x562 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, 0x2cf0ab1b, + kCFARegister, 0xe88 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0x2cf0ab1b, + kCFARegister, 0x562 * data_factor)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreRegisterRuleUnchanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreRegisterRuleChanged) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_undefined).ULEB128(0xe39acce5) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xe39acce5)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xe39acce5, + 0x095f1559)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreRegisterRuleChangedRegister) { + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a) + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(fde_start + code_factor, 0xd40e21b1, + 0xbabb4742)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xd40e21b1, + 0x16607d6a)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion); +} + +TEST_F(LulDwarfCFIRestore, RestoreExpressionRuleUnchanged) { + ByteReader reader(ENDIANNESS_LITTLE); + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf") + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +TEST_F(LulDwarfCFIRestore, RestoreExpressionRuleChanged) { + ByteReader reader(ENDIANNESS_LITTLE); + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf") + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_undefined).ULEB128(0xb5ca5c46) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, + "elf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +TEST_F(LulDwarfCFIRestore, RestoreExpressionRuleChangedExpression) { + ByteReader reader(ENDIANNESS_LITTLE); + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf") + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_expression).ULEB128(0x500f5739).Block("orc") + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ExpressionRule(fde_start + code_factor, 0x500f5739, + "orc")) + .InSequence(s).WillOnce(Return(true)); + // Expectations are not wishes. + EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0x500f5739, + "smurf")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +TEST_F(LulDwarfCFIRestore, RestoreValExpressionRuleUnchanged) { + ByteReader reader(ENDIANNESS_LITTLE); + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_val_expression).ULEB128(0x666ae152) + .Block("hideous") + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +TEST_F(LulDwarfCFIRestore, RestoreValExpressionRuleChanged) { + ByteReader reader(ENDIANNESS_LITTLE); + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_val_expression).ULEB128(0xb5ca5c46) + .Block("revolting") + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_undefined).ULEB128(0xb5ca5c46) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section); + + EXPECT_CALL(handler, ValExpressionRule(fde_start, 0xb5ca5c46, "revolting")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, + "revolting")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +TEST_F(LulDwarfCFIRestore, RestoreValExpressionRuleChangedValExpression) { + ByteReader reader(ENDIANNESS_LITTLE); + CFISection section(kLittleEndian, 4); + StockCIEAndFDE(§ion); + section + .D8(lul::DW_CFA_val_expression).ULEB128(0x500f5739) + .Block("repulsive") + .D8(lul::DW_CFA_remember_state) + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_val_expression).ULEB128(0x500f5739) + .Block("nauseous") + .D8(lul::DW_CFA_advance_loc | 1) + .D8(lul::DW_CFA_restore_state) + .FinishEntry(); + + PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression", + section); + + EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x500f5739, "repulsive")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValExpressionRule(fde_start + code_factor, 0x500f5739, + "nauseous")) + .InSequence(s).WillOnce(Return(true)); + // Expectations are not wishes. + EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0x500f5739, + "repulsive")) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()).WillOnce(Return(true)); + + ParseSection(§ion, true, &reader); +} + +struct EHFrameFixture: public CFIInsnFixture { + EHFrameFixture() + : CFIInsnFixture(), section(kBigEndian, 4, true) { + encoded_pointer_bases.cfi = 0x7f496cb2; + encoded_pointer_bases.text = 0x540f67b6; + encoded_pointer_bases.data = 0xe3eab768; + section.SetEncodedPointerBases(encoded_pointer_bases); + } + CFISection section; + CFISection::EncodedPointerBases encoded_pointer_bases; + + // Parse CFIInsnFixture::ParseSection, but parse the section as + // .eh_frame data, supplying stock base addresses. + void ParseEHFrameSection(CFISection *section, bool succeeds = true) { + EXPECT_TRUE(section->ContainsEHFrame()); + string contents; + EXPECT_TRUE(section->GetContents(&contents)); + lul::Endianness endianness; + if (section->endianness() == kBigEndian) + endianness = ENDIANNESS_BIG; + else { + assert(section->endianness() == kLittleEndian); + endianness = ENDIANNESS_LITTLE; + } + ByteReader reader(endianness); + reader.SetAddressSize(section->AddressSize()); + reader.SetCFIDataBase(encoded_pointer_bases.cfi, contents.data()); + reader.SetTextBase(encoded_pointer_bases.text); + reader.SetDataBase(encoded_pointer_bases.data); + CallFrameInfo parser(contents.data(), contents.size(), + &reader, &handler, &reporter, true); + if (succeeds) + EXPECT_TRUE(parser.Start()); + else + EXPECT_FALSE(parser.Start()); + } + +}; + +class LulDwarfEHFrame: public EHFrameFixture, public Test { }; + +// A simple CIE, an FDE, and a terminator. +TEST_F(LulDwarfEHFrame, Terminator) { + Label cie; + section + .Mark(&cie) + .CIEHeader(9968, 2466, 67, 1, "") + .D8(lul::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372) + .FinishEntry() + .FDEHeader(cie, 0x848037a1, 0x7b30475e) + .D8(lul::DW_CFA_set_loc).D32(0x17713850) + .D8(lul::DW_CFA_undefined).ULEB128(5721) + .FinishEntry() + .D32(0) // Terminate the sequence. + // This FDE should be ignored. + .FDEHeader(cie, 0xf19629fe, 0x439fb09b) + .FinishEntry(); + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.Terminator", section); + + EXPECT_CALL(handler, Entry(_, 0x848037a1, 0x7b30475e, 1, "", 67)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0x848037a1, kCFARegister, 3772, 1372)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(0x17713850, 5721)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(reporter, EarlyEHTerminator(_)) + .InSequence(s).WillOnce(Return()); + + ParseEHFrameSection(§ion); +} + +// The parser should recognize the Linux Standards Base 'z' augmentations. +TEST_F(LulDwarfEHFrame, SimpleFDE) { + lul::DwarfPointerEncoding lsda_encoding = + lul::DwarfPointerEncoding(lul::DW_EH_PE_indirect + | lul::DW_EH_PE_datarel + | lul::DW_EH_PE_sdata2); + lul::DwarfPointerEncoding fde_encoding = + lul::DwarfPointerEncoding(lul::DW_EH_PE_textrel + | lul::DW_EH_PE_udata2); + + section.SetPointerEncoding(fde_encoding); + section.SetEncodedPointerBases(encoded_pointer_bases); + Label cie; + section + .Mark(&cie) + .CIEHeader(4873, 7012, 100, 1, "zSLPR") + .ULEB128(7) // Augmentation data length + .D8(lsda_encoding) // LSDA pointer format + .D8(lul::DW_EH_PE_pcrel) // personality pointer format + .EncodedPointer(0x97baa00, lul::DW_EH_PE_pcrel) // and value + .D8(fde_encoding) // FDE pointer format + .D8(lul::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31) + .FinishEntry() + .FDEHeader(cie, 0x540f6b56, 0xf686) + .ULEB128(2) // Augmentation data length + .EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed + .D8(lul::DW_CFA_set_loc) + .EncodedPointer(0x540fa4ce, fde_encoding) + .D8(lul::DW_CFA_undefined).ULEB128(0x675e) + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.SimpleFDE", section); + + EXPECT_CALL(handler, Entry(_, 0x540f6b56, 0xf686, 1, "zSLPR", 100)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, PersonalityRoutine(0x97baa00, false)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, LanguageSpecificDataArea(0xe3eab475, true)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SignalHandler()) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0x540f6b56, kCFARegister, 6706, 31)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(0x540fa4ce, 0x675e)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +// Check that we can handle an empty 'z' augmentation. +TEST_F(LulDwarfEHFrame, EmptyZ) { + Label cie; + section + .Mark(&cie) + .CIEHeader(5955, 5805, 228, 1, "z") + .ULEB128(0) // Augmentation data length + .D8(lul::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247) + .FinishEntry() + .FDEHeader(cie, 0xda007738, 0xfb55c641) + .ULEB128(0) // Augmentation data length + .D8(lul::DW_CFA_advance_loc1).D8(11) + .D8(lul::DW_CFA_undefined).ULEB128(3769) + .FinishEntry(); + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section); + + EXPECT_CALL(handler, Entry(_, 0xda007738, 0xfb55c641, 1, "z", 228)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, ValOffsetRule(0xda007738, kCFARegister, 3629, 247)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, UndefinedRule(0xda007738 + 11 * 5955, 3769)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +// Check that we recognize bad 'z' augmentation characters. +TEST_F(LulDwarfEHFrame, BadZ) { + Label cie; + section + .Mark(&cie) + .CIEHeader(6937, 1045, 142, 1, "zQ") + .ULEB128(0) // Augmentation data length + .D8(lul::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725) + .FinishEntry() + .FDEHeader(cie, 0x1293efa8, 0x236f53f2) + .ULEB128(0) // Augmentation data length + .D8(lul::DW_CFA_advance_loc | 12) + .D8(lul::DW_CFA_register).ULEB128(5667).ULEB128(3462) + .FinishEntry(); + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section); + + EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "zQ")) + .WillOnce(Return()); + + ParseEHFrameSection(§ion, false); +} + +TEST_F(LulDwarfEHFrame, zL) { + Label cie; + lul::DwarfPointerEncoding lsda_encoding = + lul::DwarfPointerEncoding(lul::DW_EH_PE_funcrel | lul::DW_EH_PE_udata2); + section + .Mark(&cie) + .CIEHeader(9285, 9959, 54, 1, "zL") + .ULEB128(1) // Augmentation data length + .D8(lsda_encoding) // encoding for LSDA pointer in FDE + + .FinishEntry() + .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) + .ULEB128(2) // Augmentation data length + .EncodedPointer(0xd40099cd, lsda_encoding) // LSDA pointer + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zL", section); + + EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zL", 54)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, LanguageSpecificDataArea(0xd40099cd, false)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +TEST_F(LulDwarfEHFrame, zP) { + Label cie; + lul::DwarfPointerEncoding personality_encoding = + lul::DwarfPointerEncoding(lul::DW_EH_PE_datarel | lul::DW_EH_PE_udata2); + section + .Mark(&cie) + .CIEHeader(1097, 6313, 17, 1, "zP") + .ULEB128(3) // Augmentation data length + .D8(personality_encoding) // encoding for personality routine + .EncodedPointer(0xe3eaccac, personality_encoding) // value + .FinishEntry() + .FDEHeader(cie, 0x0c8350c9, 0xbef11087) + .ULEB128(0) // Augmentation data length + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zP", section); + + EXPECT_CALL(handler, Entry(_, 0x0c8350c9, 0xbef11087, 1, "zP", 17)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, PersonalityRoutine(0xe3eaccac, false)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +TEST_F(LulDwarfEHFrame, zR) { + Label cie; + lul::DwarfPointerEncoding pointer_encoding = + lul::DwarfPointerEncoding(lul::DW_EH_PE_textrel | lul::DW_EH_PE_sdata2); + section.SetPointerEncoding(pointer_encoding); + section + .Mark(&cie) + .CIEHeader(8011, 5496, 75, 1, "zR") + .ULEB128(1) // Augmentation data length + .D8(pointer_encoding) // encoding for FDE addresses + .FinishEntry() + .FDEHeader(cie, 0x540f9431, 0xbd0) + .ULEB128(0) // Augmentation data length + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zR", section); + + EXPECT_CALL(handler, Entry(_, 0x540f9431, 0xbd0, 1, "zR", 75)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +TEST_F(LulDwarfEHFrame, zS) { + Label cie; + section + .Mark(&cie) + .CIEHeader(9217, 7694, 57, 1, "zS") + .ULEB128(0) // Augmentation data length + .FinishEntry() + .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) + .ULEB128(0) // Augmentation data length + .FinishEntry() + .D32(0); // terminator + + PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zS", section); + + EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zS", 57)) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, SignalHandler()) + .InSequence(s).WillOnce(Return(true)); + EXPECT_CALL(handler, End()) + .InSequence(s).WillOnce(Return(true)); + + ParseEHFrameSection(§ion); +} + +// These tests require manual inspection of the test output. +struct CFIReporterFixture { + CFIReporterFixture() : reporter(gtest_logging_sink_for_LulTestDwarf, + "test file name", "test section name") { } + CallFrameInfo::Reporter reporter; +}; + +class LulDwarfCFIReporter: public CFIReporterFixture, public Test { }; + +TEST_F(LulDwarfCFIReporter, Incomplete) { + reporter.Incomplete(0x0102030405060708ULL, CallFrameInfo::kUnknown); +} + +TEST_F(LulDwarfCFIReporter, EarlyEHTerminator) { + reporter.EarlyEHTerminator(0x0102030405060708ULL); +} + +TEST_F(LulDwarfCFIReporter, CIEPointerOutOfRange) { + reporter.CIEPointerOutOfRange(0x0123456789abcdefULL, 0xfedcba9876543210ULL); +} + +TEST_F(LulDwarfCFIReporter, BadCIEId) { + reporter.BadCIEId(0x0123456789abcdefULL, 0xfedcba9876543210ULL); +} + +TEST_F(LulDwarfCFIReporter, UnrecognizedVersion) { + reporter.UnrecognizedVersion(0x0123456789abcdefULL, 43); +} + +TEST_F(LulDwarfCFIReporter, UnrecognizedAugmentation) { + reporter.UnrecognizedAugmentation(0x0123456789abcdefULL, "poodles"); +} + +TEST_F(LulDwarfCFIReporter, InvalidPointerEncoding) { + reporter.InvalidPointerEncoding(0x0123456789abcdefULL, 0x42); +} + +TEST_F(LulDwarfCFIReporter, UnusablePointerEncoding) { + reporter.UnusablePointerEncoding(0x0123456789abcdefULL, 0x42); +} + +TEST_F(LulDwarfCFIReporter, RestoreInCIE) { + reporter.RestoreInCIE(0x0123456789abcdefULL, 0xfedcba9876543210ULL); +} + +TEST_F(LulDwarfCFIReporter, BadInstruction) { + reporter.BadInstruction(0x0123456789abcdefULL, CallFrameInfo::kFDE, + 0xfedcba9876543210ULL); +} + +TEST_F(LulDwarfCFIReporter, NoCFARule) { + reporter.NoCFARule(0x0123456789abcdefULL, CallFrameInfo::kCIE, + 0xfedcba9876543210ULL); +} + +TEST_F(LulDwarfCFIReporter, EmptyStateStack) { + reporter.EmptyStateStack(0x0123456789abcdefULL, CallFrameInfo::kTerminator, + 0xfedcba9876543210ULL); +} + +TEST_F(LulDwarfCFIReporter, ClearingCFARule) { + reporter.ClearingCFARule(0x0123456789abcdefULL, CallFrameInfo::kFDE, + 0xfedcba9876543210ULL); +} + +} // namespace lul diff --git a/tools/profiler/tests/gtest/LulTestInfrastructure.cpp b/tools/profiler/tests/gtest/LulTestInfrastructure.cpp new file mode 100644 index 000000000000..ba8e2e41eeca --- /dev/null +++ b/tools/profiler/tests/gtest/LulTestInfrastructure.cpp @@ -0,0 +1,491 @@ +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// Derived from: +// test_assembler.cc: Implementation of google_breakpad::TestAssembler. +// See test_assembler.h for details. + +// Derived from: +// cfi_assembler.cc: Implementation of google_breakpad::CFISection class. +// See cfi_assembler.h for details. + +#include "LulTestInfrastructure.h" + +namespace lul_test { +namespace test_assembler { + +using std::back_insert_iterator; + +Label::Label() : value_(new Binding()) { } +Label::Label(uint64_t value) : value_(new Binding(value)) { } +Label::Label(const Label &label) { + value_ = label.value_; + value_->Acquire(); +} +Label::~Label() { + if (value_->Release()) delete value_; +} + +Label &Label::operator=(uint64_t value) { + value_->Set(NULL, value); + return *this; +} + +Label &Label::operator=(const Label &label) { + value_->Set(label.value_, 0); + return *this; +} + +Label Label::operator+(uint64_t addend) const { + Label l; + l.value_->Set(this->value_, addend); + return l; +} + +Label Label::operator-(uint64_t subtrahend) const { + Label l; + l.value_->Set(this->value_, -subtrahend); + return l; +} + +// When NDEBUG is #defined, assert doesn't evaluate its argument. This +// means you can't simply use assert to check the return value of a +// function with necessary side effects. +// +// ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether +// NDEBUG is #defined; when NDEBUG is not #defined, it further asserts +// that x is true. +#ifdef NDEBUG +#define ALWAYS_EVALUATE_AND_ASSERT(x) x +#else +#define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x) +#endif + +uint64_t Label::operator-(const Label &label) const { + uint64_t offset; + ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset)); + return offset; +} + +bool Label::IsKnownConstant(uint64_t *value_p) const { + Binding *base; + uint64_t addend; + value_->Get(&base, &addend); + if (base != NULL) return false; + if (value_p) *value_p = addend; + return true; +} + +bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const +{ + Binding *label_base, *this_base; + uint64_t label_addend, this_addend; + label.value_->Get(&label_base, &label_addend); + value_->Get(&this_base, &this_addend); + // If this and label are related, Get will find their final + // common ancestor, regardless of how indirect the relation is. This + // comparison also handles the constant vs. constant case. + if (this_base != label_base) return false; + if (offset_p) *offset_p = this_addend - label_addend; + return true; +} + +Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { } + +Label::Binding::Binding(uint64_t addend) + : base_(NULL), addend_(addend), reference_count_(1) { } + +Label::Binding::~Binding() { + assert(reference_count_ == 0); + if (base_ && base_ != this && base_->Release()) + delete base_; +} + +void Label::Binding::Set(Binding *binding, uint64_t addend) { + if (!base_ && !binding) { + // We're equating two constants. This could be okay. + assert(addend_ == addend); + } else if (!base_) { + // We are a known constant, but BINDING may not be, so turn the + // tables and try to set BINDING's value instead. + binding->Set(NULL, addend_ - addend); + } else { + if (binding) { + // Find binding's final value. Since the final value is always either + // completely unconstrained or a constant, never a reference to + // another variable (otherwise, it wouldn't be final), this + // guarantees we won't create cycles here, even for code like this: + // l = m, m = n, n = l; + uint64_t binding_addend; + binding->Get(&binding, &binding_addend); + addend += binding_addend; + } + + // It seems likely that setting a binding to itself is a bug + // (although I can imagine this might turn out to be helpful to + // permit). + assert(binding != this); + + if (base_ != this) { + // Set the other bindings on our chain as well. Note that this + // is sufficient even though binding relationships form trees: + // All binding operations traverse their chains to the end, and + // all bindings related to us share some tail of our chain, so + // they will see the changes we make here. + base_->Set(binding, addend - addend_); + // We're not going to use base_ any more. + if (base_->Release()) delete base_; + } + + // Adopt BINDING as our base. Note that it should be correct to + // acquire here, after the release above, even though the usual + // reference-counting rules call for acquiring first, and then + // releasing: the self-reference assertion above should have + // complained if BINDING were 'this' or anywhere along our chain, + // so we didn't release BINDING. + if (binding) binding->Acquire(); + base_ = binding; + addend_ = addend; + } +} + +void Label::Binding::Get(Binding **base, uint64_t *addend) { + if (base_ && base_ != this) { + // Recurse to find the end of our reference chain (the root of our + // tree), and then rewrite every binding along the chain to refer + // to it directly, adjusting addends appropriately. (This is why + // this member function isn't this-const.) + Binding *final_base; + uint64_t final_addend; + base_->Get(&final_base, &final_addend); + if (final_base) final_base->Acquire(); + if (base_->Release()) delete base_; + base_ = final_base; + addend_ += final_addend; + } + *base = base_; + *addend = addend_; +} + +template +static inline void InsertEndian(test_assembler::Endianness endianness, + size_t size, uint64_t number, Inserter dest) { + assert(size > 0); + if (endianness == kLittleEndian) { + for (size_t i = 0; i < size; i++) { + *dest++ = (char) (number & 0xff); + number >>= 8; + } + } else { + assert(endianness == kBigEndian); + // The loop condition is odd, but it's correct for size_t. + for (size_t i = size - 1; i < size; i--) + *dest++ = (char) ((number >> (i * 8)) & 0xff); + } +} + +Section &Section::Append(Endianness endianness, size_t size, uint64_t number) { + InsertEndian(endianness, size, number, + back_insert_iterator(contents_)); + return *this; +} + +Section &Section::Append(Endianness endianness, size_t size, + const Label &label) { + // If this label's value is known, there's no reason to waste an + // entry in references_ on it. + uint64_t value; + if (label.IsKnownConstant(&value)) + return Append(endianness, size, value); + + // This will get caught when the references are resolved, but it's + // nicer to find out earlier. + assert(endianness != kUnsetEndian); + + references_.push_back(Reference(contents_.size(), endianness, size, label)); + contents_.append(size, 0); + return *this; +} + +#define ENDIANNESS_L kLittleEndian +#define ENDIANNESS_B kBigEndian +#define ENDIANNESS(e) ENDIANNESS_ ## e + +#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ + Section &Section::e ## bits(uint ## bits ## _t v) { \ + InsertEndian(ENDIANNESS(e), bits / 8, v, \ + back_insert_iterator(contents_)); \ + return *this; \ + } + +#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \ + Section &Section::e ## bits(const Label &v) { \ + return Append(ENDIANNESS(e), bits / 8, v); \ + } + +// Define L16, B32, and friends. +#define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \ + DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ + DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) + +DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8); +DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8); +DEFINE_SHORT_APPEND_ENDIAN(L, 16); +DEFINE_SHORT_APPEND_ENDIAN(L, 32); +DEFINE_SHORT_APPEND_ENDIAN(L, 64); +DEFINE_SHORT_APPEND_ENDIAN(B, 16); +DEFINE_SHORT_APPEND_ENDIAN(B, 32); +DEFINE_SHORT_APPEND_ENDIAN(B, 64); + +#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ + Section &Section::D ## bits(uint ## bits ## _t v) { \ + InsertEndian(endianness_, bits / 8, v, \ + back_insert_iterator(contents_)); \ + return *this; \ + } +#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \ + Section &Section::D ## bits(const Label &v) { \ + return Append(endianness_, bits / 8, v); \ + } +#define DEFINE_SHORT_APPEND_DEFAULT(bits) \ + DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ + DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) + +DEFINE_SHORT_APPEND_LABEL_DEFAULT(8) +DEFINE_SHORT_APPEND_DEFAULT(16); +DEFINE_SHORT_APPEND_DEFAULT(32); +DEFINE_SHORT_APPEND_DEFAULT(64); + +Section &Section::LEB128(long long value) { + while (value < -0x40 || 0x3f < value) { + contents_ += (value & 0x7f) | 0x80; + if (value < 0) + value = (value >> 7) | ~(((unsigned long long) -1) >> 7); + else + value = (value >> 7); + } + contents_ += value & 0x7f; + return *this; +} + +Section &Section::ULEB128(uint64_t value) { + while (value > 0x7f) { + contents_ += (value & 0x7f) | 0x80; + value = (value >> 7); + } + contents_ += value; + return *this; +} + +Section &Section::Align(size_t alignment, uint8_t pad_byte) { + // ALIGNMENT must be a power of two. + assert(((alignment - 1) & alignment) == 0); + size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1); + contents_.append(new_size - contents_.size(), pad_byte); + assert((contents_.size() & (alignment - 1)) == 0); + return *this; +} + +bool Section::GetContents(string *contents) { + // For each label reference, find the label's value, and patch it into + // the section's contents. + for (size_t i = 0; i < references_.size(); i++) { + Reference &r = references_[i]; + uint64_t value; + if (!r.label.IsKnownConstant(&value)) { + fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset); + return false; + } + assert(r.offset < contents_.size()); + assert(contents_.size() - r.offset >= r.size); + InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset); + } + contents->clear(); + std::swap(contents_, *contents); + references_.clear(); + return true; +} + +} // namespace test_assembler +} // namespace lul_test + + +namespace lul_test { + +CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, + int data_alignment_factor, + unsigned return_address_register, + uint8_t version, + const string &augmentation, + bool dwarf64) { + assert(!entry_length_); + entry_length_ = new PendingLength(); + in_fde_ = false; + + if (dwarf64) { + D32(kDwarf64InitialLengthMarker); + D64(entry_length_->length); + entry_length_->start = Here(); + D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier); + } else { + D32(entry_length_->length); + entry_length_->start = Here(); + D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier); + } + D8(version); + AppendCString(augmentation); + ULEB128(code_alignment_factor); + LEB128(data_alignment_factor); + if (version == 1) + D8(return_address_register); + else + ULEB128(return_address_register); + return *this; +} + +CFISection &CFISection::FDEHeader(Label cie_pointer, + uint64_t initial_location, + uint64_t address_range, + bool dwarf64) { + assert(!entry_length_); + entry_length_ = new PendingLength(); + in_fde_ = true; + fde_start_address_ = initial_location; + + if (dwarf64) { + D32(0xffffffff); + D64(entry_length_->length); + entry_length_->start = Here(); + if (eh_frame_) + D64(Here() - cie_pointer); + else + D64(cie_pointer); + } else { + D32(entry_length_->length); + entry_length_->start = Here(); + if (eh_frame_) + D32(Here() - cie_pointer); + else + D32(cie_pointer); + } + EncodedPointer(initial_location); + // The FDE length in an .eh_frame section uses the same encoding as the + // initial location, but ignores the base address (selected by the upper + // nybble of the encoding), as it's a length, not an address that can be + // made relative. + EncodedPointer(address_range, + DwarfPointerEncoding(pointer_encoding_ & 0x0f)); + return *this; +} + +CFISection &CFISection::FinishEntry() { + assert(entry_length_); + Align(address_size_, lul::DW_CFA_nop); + entry_length_->length = Here() - entry_length_->start; + delete entry_length_; + entry_length_ = NULL; + in_fde_ = false; + return *this; +} + +CFISection &CFISection::EncodedPointer(uint64_t address, + DwarfPointerEncoding encoding, + const EncodedPointerBases &bases) { + // Omitted data is extremely easy to emit. + if (encoding == lul::DW_EH_PE_omit) + return *this; + + // If (encoding & lul::DW_EH_PE_indirect) != 0, then we assume + // that ADDRESS is the address at which the pointer is stored --- in + // other words, that bit has no effect on how we write the pointer. + encoding = DwarfPointerEncoding(encoding & ~lul::DW_EH_PE_indirect); + + // Find the base address to which this pointer is relative. The upper + // nybble of the encoding specifies this. + uint64_t base; + switch (encoding & 0xf0) { + case lul::DW_EH_PE_absptr: base = 0; break; + case lul::DW_EH_PE_pcrel: base = bases.cfi + Size(); break; + case lul::DW_EH_PE_textrel: base = bases.text; break; + case lul::DW_EH_PE_datarel: base = bases.data; break; + case lul::DW_EH_PE_funcrel: base = fde_start_address_; break; + case lul::DW_EH_PE_aligned: base = 0; break; + default: abort(); + }; + + // Make ADDRESS relative. Yes, this is appropriate even for "absptr" + // values; see gcc/unwind-pe.h. + address -= base; + + // Align the pointer, if required. + if ((encoding & 0xf0) == lul::DW_EH_PE_aligned) + Align(AddressSize()); + + // Append ADDRESS to this section in the appropriate form. For the + // fixed-width forms, we don't need to differentiate between signed and + // unsigned encodings, because ADDRESS has already been extended to 64 + // bits before it was passed to us. + switch (encoding & 0x0f) { + case lul::DW_EH_PE_absptr: + Address(address); + break; + + case lul::DW_EH_PE_uleb128: + ULEB128(address); + break; + + case lul::DW_EH_PE_sleb128: + LEB128(address); + break; + + case lul::DW_EH_PE_udata2: + case lul::DW_EH_PE_sdata2: + D16(address); + break; + + case lul::DW_EH_PE_udata4: + case lul::DW_EH_PE_sdata4: + D32(address); + break; + + case lul::DW_EH_PE_udata8: + case lul::DW_EH_PE_sdata8: + D64(address); + break; + + default: + abort(); + } + + return *this; +}; + +} // namespace lul_test diff --git a/tools/profiler/tests/gtest/LulTestInfrastructure.h b/tools/profiler/tests/gtest/LulTestInfrastructure.h new file mode 100644 index 000000000000..37b1b7d49293 --- /dev/null +++ b/tools/profiler/tests/gtest/LulTestInfrastructure.h @@ -0,0 +1,666 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Original author: Jim Blandy + +// Derived from: +// cfi_assembler.h: Define CFISection, a class for creating properly +// (and improperly) formatted DWARF CFI data for unit tests. + +// Derived from: +// test-assembler.h: interface to class for building complex binary streams. + +// To test the Breakpad symbol dumper and processor thoroughly, for +// all combinations of host system and minidump processor +// architecture, we need to be able to easily generate complex test +// data like debugging information and minidump files. +// +// For example, if we want our unit tests to provide full code +// coverage for stack walking, it may be difficult to persuade the +// compiler to generate every possible sort of stack walking +// information that we want to support; there are probably DWARF CFI +// opcodes that GCC never emits. Similarly, if we want to test our +// error handling, we will need to generate damaged minidumps or +// debugging information that (we hope) the client or compiler will +// never produce on its own. +// +// google_breakpad::TestAssembler provides a predictable and +// (relatively) simple way to generate complex formatted data streams +// like minidumps and CFI. Furthermore, because TestAssembler is +// portable, developers without access to (say) Visual Studio or a +// SPARC assembler can still work on test data for those targets. + +#ifndef LUL_TEST_INFRASTRUCTURE_H +#define LUL_TEST_INFRASTRUCTURE_H + +#include +#include + +using std::string; +using std::vector; + +namespace lul_test { +namespace test_assembler { + +// A Label represents a value not yet known that we need to store in a +// section. As long as all the labels a section refers to are defined +// by the time we retrieve its contents as bytes, we can use undefined +// labels freely in that section's construction. +// +// A label can be in one of three states: +// - undefined, +// - defined as the sum of some other label and a constant, or +// - a constant. +// +// A label's value never changes, but it can accumulate constraints. +// Adding labels and integers is permitted, and yields a label. +// Subtracting a constant from a label is permitted, and also yields a +// label. Subtracting two labels that have some relationship to each +// other is permitted, and yields a constant. +// +// For example: +// +// Label a; // a's value is undefined +// Label b; // b's value is undefined +// { +// Label c = a + 4; // okay, even though a's value is unknown +// b = c + 4; // also okay; b is now a+8 +// } +// Label d = b - 2; // okay; d == a+6, even though c is gone +// d.Value(); // error: d's value is not yet known +// d - a; // is 6, even though their values are not known +// a = 12; // now b == 20, and d == 18 +// d.Value(); // 18: no longer an error +// b.Value(); // 20 +// d = 10; // error: d is already defined. +// +// Label objects' lifetimes are unconstrained: notice that, in the +// above example, even though a and b are only related through c, and +// c goes out of scope, the assignment to a sets b's value as well. In +// particular, it's not necessary to ensure that a Label lives beyond +// Sections that refer to it. +class Label { + public: + Label(); // An undefined label. + explicit Label(uint64_t value); // A label with a fixed value + Label(const Label &value); // A label equal to another. + ~Label(); + + Label &operator=(uint64_t value); + Label &operator=(const Label &value); + Label operator+(uint64_t addend) const; + Label operator-(uint64_t subtrahend) const; + uint64_t operator-(const Label &subtrahend) const; + + // We could also provide == and != that work on undefined, but + // related, labels. + + // Return true if this label's value is known. If VALUE_P is given, + // set *VALUE_P to the known value if returning true. + bool IsKnownConstant(uint64_t *value_p = NULL) const; + + // Return true if the offset from LABEL to this label is known. If + // OFFSET_P is given, set *OFFSET_P to the offset when returning true. + // + // You can think of l.KnownOffsetFrom(m, &d) as being like 'd = l-m', + // except that it also returns a value indicating whether the + // subtraction is possible given what we currently know of l and m. + // It can be possible even if we don't know l and m's values. For + // example: + // + // Label l, m; + // m = l + 10; + // l.IsKnownConstant(); // false + // m.IsKnownConstant(); // false + // uint64_t d; + // l.IsKnownOffsetFrom(m, &d); // true, and sets d to -10. + // l-m // -10 + // m-l // 10 + // m.Value() // error: m's value is not known + bool IsKnownOffsetFrom(const Label &label, uint64_t *offset_p = NULL) const; + + private: + // A label's value, or if that is not yet known, how the value is + // related to other labels' values. A binding may be: + // - a known constant, + // - constrained to be equal to some other binding plus a constant, or + // - unconstrained, and free to take on any value. + // + // Many labels may point to a single binding, and each binding may + // refer to another, so bindings and labels form trees whose leaves + // are labels, whose interior nodes (and roots) are bindings, and + // where links point from children to parents. Bindings are + // reference counted, allowing labels to be lightweight, copyable, + // assignable, placed in containers, and so on. + class Binding { + public: + Binding(); + explicit Binding(uint64_t addend); + ~Binding(); + + // Increment our reference count. + void Acquire() { reference_count_++; }; + // Decrement our reference count, and return true if it is zero. + bool Release() { return --reference_count_ == 0; } + + // Set this binding to be equal to BINDING + ADDEND. If BINDING is + // NULL, then set this binding to the known constant ADDEND. + // Update every binding on this binding's chain to point directly + // to BINDING, or to be a constant, with addends adjusted + // appropriately. + void Set(Binding *binding, uint64_t value); + + // Return what we know about the value of this binding. + // - If this binding's value is a known constant, set BASE to + // NULL, and set ADDEND to its value. + // - If this binding is not a known constant but related to other + // bindings, set BASE to the binding at the end of the relation + // chain (which will always be unconstrained), and set ADDEND to the + // value to add to that binding's value to get this binding's + // value. + // - If this binding is unconstrained, set BASE to this, and leave + // ADDEND unchanged. + void Get(Binding **base, uint64_t *addend); + + private: + // There are three cases: + // + // - A binding representing a known constant value has base_ NULL, + // and addend_ equal to the value. + // + // - A binding representing a completely unconstrained value has + // base_ pointing to this; addend_ is unused. + // + // - A binding whose value is related to some other binding's + // value has base_ pointing to that other binding, and addend_ + // set to the amount to add to that binding's value to get this + // binding's value. We only represent relationships of the form + // x = y+c. + // + // Thus, the bind_ links form a chain terminating in either a + // known constant value or a completely unconstrained value. Most + // operations on bindings do path compression: they change every + // binding on the chain to point directly to the final value, + // adjusting addends as appropriate. + Binding *base_; + uint64_t addend_; + + // The number of Labels and Bindings pointing to this binding. + // (When a binding points to itself, indicating a completely + // unconstrained binding, that doesn't count as a reference.) + int reference_count_; + }; + + // This label's value. + Binding *value_; +}; + +// Conventions for representing larger numbers as sequences of bytes. +enum Endianness { + kBigEndian, // Big-endian: the most significant byte comes first. + kLittleEndian, // Little-endian: the least significant byte comes first. + kUnsetEndian, // used internally +}; + +// A section is a sequence of bytes, constructed by appending bytes +// to the end. Sections have a convenient and flexible set of member +// functions for appending data in various formats: big-endian and +// little-endian signed and unsigned values of different sizes; +// LEB128 and ULEB128 values (see below), and raw blocks of bytes. +// +// If you need to append a value to a section that is not convenient +// to compute immediately, you can create a label, append the +// label's value to the section, and then set the label's value +// later, when it's convenient to do so. Once a label's value is +// known, the section class takes care of updating all previously +// appended references to it. +// +// Once all the labels to which a section refers have had their +// values determined, you can get a copy of the section's contents +// as a string. +// +// Note that there is no specified "start of section" label. This is +// because there are typically several different meanings for "the +// start of a section": the offset of the section within an object +// file, the address in memory at which the section's content appear, +// and so on. It's up to the code that uses the Section class to +// keep track of these explicitly, as they depend on the application. +class Section { + public: + explicit Section(Endianness endianness = kUnsetEndian) + : endianness_(endianness) { }; + + // A base class destructor should be either public and virtual, + // or protected and nonvirtual. + virtual ~Section() { }; + + // Return the default endianness of this section. + Endianness endianness() const { return endianness_; } + + // Append the SIZE bytes at DATA to the end of this section. Return + // a reference to this section. + Section &Append(const string &data) { + contents_.append(data); + return *this; + }; + + // Append SIZE copies of BYTE to the end of this section. Return a + // reference to this section. + Section &Append(size_t size, uint8_t byte) { + contents_.append(size, (char) byte); + return *this; + } + + // Append NUMBER to this section. ENDIANNESS is the endianness to + // use to write the number. SIZE is the length of the number in + // bytes. Return a reference to this section. + Section &Append(Endianness endianness, size_t size, uint64_t number); + Section &Append(Endianness endianness, size_t size, const Label &label); + + // Append SECTION to the end of this section. The labels SECTION + // refers to need not be defined yet. + // + // Note that this has no effect on any Labels' values, or on + // SECTION. If placing SECTION within 'this' provides new + // constraints on existing labels' values, then it's up to the + // caller to fiddle with those labels as needed. + Section &Append(const Section §ion); + + // Append the contents of DATA as a series of bytes terminated by + // a NULL character. + Section &AppendCString(const string &data) { + Append(data); + contents_ += '\0'; + return *this; + } + + // Append VALUE or LABEL to this section, with the given bit width and + // endianness. Return a reference to this section. + // + // The names of these functions have the form : + // is either 'L' (little-endian, least significant byte first), + // 'B' (big-endian, most significant byte first), or + // 'D' (default, the section's default endianness) + // is 8, 16, 32, or 64. + // + // Since endianness doesn't matter for a single byte, all the + // =8 functions are equivalent. + // + // These can be used to write both signed and unsigned values, as + // the compiler will properly sign-extend a signed value before + // passing it to the function, at which point the function's + // behavior is the same either way. + Section &L8(uint8_t value) { contents_ += value; return *this; } + Section &B8(uint8_t value) { contents_ += value; return *this; } + Section &D8(uint8_t value) { contents_ += value; return *this; } + Section &L16(uint16_t), &L32(uint32_t), &L64(uint64_t), + &B16(uint16_t), &B32(uint32_t), &B64(uint64_t), + &D16(uint16_t), &D32(uint32_t), &D64(uint64_t); + Section &L8(const Label &label), &L16(const Label &label), + &L32(const Label &label), &L64(const Label &label), + &B8(const Label &label), &B16(const Label &label), + &B32(const Label &label), &B64(const Label &label), + &D8(const Label &label), &D16(const Label &label), + &D32(const Label &label), &D64(const Label &label); + + // Append VALUE in a signed LEB128 (Little-Endian Base 128) form. + // + // The signed LEB128 representation of an integer N is a variable + // number of bytes: + // + // - If N is between -0x40 and 0x3f, then its signed LEB128 + // representation is a single byte whose value is N. + // + // - Otherwise, its signed LEB128 representation is (N & 0x7f) | + // 0x80, followed by the signed LEB128 representation of N / 128, + // rounded towards negative infinity. + // + // In other words, we break VALUE into groups of seven bits, put + // them in little-endian order, and then write them as eight-bit + // bytes with the high bit on all but the last. + // + // Note that VALUE cannot be a Label (we would have to implement + // relaxation). + Section &LEB128(long long value); + + // Append VALUE in unsigned LEB128 (Little-Endian Base 128) form. + // + // The unsigned LEB128 representation of an integer N is a variable + // number of bytes: + // + // - If N is between 0 and 0x7f, then its unsigned LEB128 + // representation is a single byte whose value is N. + // + // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) | + // 0x80, followed by the unsigned LEB128 representation of N / + // 128, rounded towards negative infinity. + // + // Note that VALUE cannot be a Label (we would have to implement + // relaxation). + Section &ULEB128(uint64_t value); + + // Jump to the next location aligned on an ALIGNMENT-byte boundary, + // relative to the start of the section. Fill the gap with PAD_BYTE. + // ALIGNMENT must be a power of two. Return a reference to this + // section. + Section &Align(size_t alignment, uint8_t pad_byte = 0); + + // Return the current size of the section. + size_t Size() const { return contents_.size(); } + + // Return a label representing the start of the section. + // + // It is up to the user whether this label represents the section's + // position in an object file, the section's address in memory, or + // what have you; some applications may need both, in which case + // this simple-minded interface won't be enough. This class only + // provides a single start label, for use with the Here and Mark + // member functions. + // + // Ideally, we'd provide this in a subclass that actually knows more + // about the application at hand and can provide an appropriate + // collection of start labels. But then the appending member + // functions like Append and D32 would return a reference to the + // base class, not the derived class, and the chaining won't work. + // Since the only value here is in pretty notation, that's a fatal + // flaw. + Label start() const { return start_; } + + // Return a label representing the point at which the next Appended + // item will appear in the section, relative to start(). + Label Here() const { return start_ + Size(); } + + // Set *LABEL to Here, and return a reference to this section. + Section &Mark(Label *label) { *label = Here(); return *this; } + + // If there are no undefined label references left in this + // section, set CONTENTS to the contents of this section, as a + // string, and clear this section. Return true on success, or false + // if there were still undefined labels. + bool GetContents(string *contents); + + private: + // Used internally. A reference to a label's value. + struct Reference { + Reference(size_t set_offset, Endianness set_endianness, size_t set_size, + const Label &set_label) + : offset(set_offset), endianness(set_endianness), size(set_size), + label(set_label) { } + + // The offset of the reference within the section. + size_t offset; + + // The endianness of the reference. + Endianness endianness; + + // The size of the reference. + size_t size; + + // The label to which this is a reference. + Label label; + }; + + // The default endianness of this section. + Endianness endianness_; + + // The contents of the section. + string contents_; + + // References to labels within those contents. + vector references_; + + // A label referring to the beginning of the section. + Label start_; +}; + +} // namespace test_assembler +} // namespace lul_test + + +namespace lul_test { + +using lul::DwarfPointerEncoding; +using lul_test::test_assembler::Endianness; +using lul_test::test_assembler::Label; +using lul_test::test_assembler::Section; + +class CFISection: public Section { + public: + + // CFI augmentation strings beginning with 'z', defined by the + // Linux/IA-64 C++ ABI, can specify interesting encodings for + // addresses appearing in FDE headers and call frame instructions (and + // for additional fields whose presence the augmentation string + // specifies). In particular, pointers can be specified to be relative + // to various base address: the start of the .text section, the + // location holding the address itself, and so on. These allow the + // frame data to be position-independent even when they live in + // write-protected pages. These variants are specified at the + // following two URLs: + // + // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html + // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html + // + // CFISection leaves the production of well-formed 'z'-augmented CIEs and + // FDEs to the user, but does provide EncodedPointer, to emit + // properly-encoded addresses for a given pointer encoding. + // EncodedPointer uses an instance of this structure to find the base + // addresses it should use; you can establish a default for all encoded + // pointers appended to this section with SetEncodedPointerBases. + struct EncodedPointerBases { + EncodedPointerBases() : cfi(), text(), data() { } + + // The starting address of this CFI section in memory, for + // DW_EH_PE_pcrel. DW_EH_PE_pcrel pointers may only be used in data + // that has is loaded into the program's address space. + uint64_t cfi; + + // The starting address of this file's .text section, for DW_EH_PE_textrel. + uint64_t text; + + // The starting address of this file's .got or .eh_frame_hdr section, + // for DW_EH_PE_datarel. + uint64_t data; + }; + + // Create a CFISection whose endianness is ENDIANNESS, and where + // machine addresses are ADDRESS_SIZE bytes long. If EH_FRAME is + // true, use the .eh_frame format, as described by the Linux + // Standards Base Core Specification, instead of the DWARF CFI + // format. + CFISection(Endianness endianness, size_t address_size, + bool eh_frame = false) + : Section(endianness), address_size_(address_size), eh_frame_(eh_frame), + pointer_encoding_(lul::DW_EH_PE_absptr), + encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) { + // The 'start', 'Here', and 'Mark' members of a CFISection all refer + // to section offsets. + start() = 0; + } + + // Return this CFISection's address size. + size_t AddressSize() const { return address_size_; } + + // Return true if this CFISection uses the .eh_frame format, or + // false if it contains ordinary DWARF CFI data. + bool ContainsEHFrame() const { return eh_frame_; } + + // Use ENCODING for pointers in calls to FDEHeader and EncodedPointer. + void SetPointerEncoding(DwarfPointerEncoding encoding) { + pointer_encoding_ = encoding; + } + + // Use the addresses in BASES as the base addresses for encoded + // pointers in subsequent calls to FDEHeader or EncodedPointer. + // This function makes a copy of BASES. + void SetEncodedPointerBases(const EncodedPointerBases &bases) { + encoded_pointer_bases_ = bases; + } + + // Append a Common Information Entry header to this section with the + // given values. If dwarf64 is true, use the 64-bit DWARF initial + // length format for the CIE's initial length. Return a reference to + // this section. You should call FinishEntry after writing the last + // instruction for the CIE. + // + // Before calling this function, you will typically want to use Mark + // or Here to make a label to pass to FDEHeader that refers to this + // CIE's position in the section. + CFISection &CIEHeader(uint64_t code_alignment_factor, + int data_alignment_factor, + unsigned return_address_register, + uint8_t version = 3, + const string &augmentation = "", + bool dwarf64 = false); + + // Append a Frame Description Entry header to this section with the + // given values. If dwarf64 is true, use the 64-bit DWARF initial + // length format for the CIE's initial length. Return a reference to + // this section. You should call FinishEntry after writing the last + // instruction for the CIE. + // + // This function doesn't support entries that are longer than + // 0xffffff00 bytes. (The "initial length" is always a 32-bit + // value.) Nor does it support .debug_frame sections longer than + // 0xffffff00 bytes. + CFISection &FDEHeader(Label cie_pointer, + uint64_t initial_location, + uint64_t address_range, + bool dwarf64 = false); + + // Note the current position as the end of the last CIE or FDE we + // started, after padding with DW_CFA_nops for alignment. This + // defines the label representing the entry's length, cited in the + // entry's header. Return a reference to this section. + CFISection &FinishEntry(); + + // Append the contents of BLOCK as a DW_FORM_block value: an + // unsigned LEB128 length, followed by that many bytes of data. + CFISection &Block(const string &block) { + ULEB128(block.size()); + Append(block); + return *this; + } + + // Append ADDRESS to this section, in the appropriate size and + // endianness. Return a reference to this section. + CFISection &Address(uint64_t address) { + Section::Append(endianness(), address_size_, address); + return *this; + } + + // Append ADDRESS to this section, using ENCODING and BASES. ENCODING + // defaults to this section's default encoding, established by + // SetPointerEncoding. BASES defaults to this section's bases, set by + // SetEncodedPointerBases. If the DW_EH_PE_indirect bit is set in the + // encoding, assume that ADDRESS is where the true address is stored. + // Return a reference to this section. + // + // (C++ doesn't let me use default arguments here, because I want to + // refer to members of *this in the default argument expression.) + CFISection &EncodedPointer(uint64_t address) { + return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_); + } + CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) { + return EncodedPointer(address, encoding, encoded_pointer_bases_); + } + CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, + const EncodedPointerBases &bases); + + // Restate some member functions, to keep chaining working nicely. + CFISection &Mark(Label *label) { Section::Mark(label); return *this; } + CFISection &D8(uint8_t v) { Section::D8(v); return *this; } + CFISection &D16(uint16_t v) { Section::D16(v); return *this; } + CFISection &D16(Label v) { Section::D16(v); return *this; } + CFISection &D32(uint32_t v) { Section::D32(v); return *this; } + CFISection &D32(const Label &v) { Section::D32(v); return *this; } + CFISection &D64(uint64_t v) { Section::D64(v); return *this; } + CFISection &D64(const Label &v) { Section::D64(v); return *this; } + CFISection &LEB128(long long v) { Section::LEB128(v); return *this; } + CFISection &ULEB128(uint64_t v) { Section::ULEB128(v); return *this; } + + private: + // A length value that we've appended to the section, but is not yet + // known. LENGTH is the appended value; START is a label referring + // to the start of the data whose length was cited. + struct PendingLength { + Label length; + Label start; + }; + + // Constants used in CFI/.eh_frame data: + + // If the first four bytes of an "initial length" are this constant, then + // the data uses the 64-bit DWARF format, and the length itself is the + // subsequent eight bytes. + static const uint32_t kDwarf64InitialLengthMarker = 0xffffffffU; + + // The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data. + static const uint32_t kDwarf32CIEIdentifier = ~(uint32_t)0; + static const uint64_t kDwarf64CIEIdentifier = ~(uint64_t)0; + static const uint32_t kEHFrame32CIEIdentifier = 0; + static const uint64_t kEHFrame64CIEIdentifier = 0; + + // The size of a machine address for the data in this section. + size_t address_size_; + + // If true, we are generating a Linux .eh_frame section, instead of + // a standard DWARF .debug_frame section. + bool eh_frame_; + + // The encoding to use for FDE pointers. + DwarfPointerEncoding pointer_encoding_; + + // The base addresses to use when emitting encoded pointers. + EncodedPointerBases encoded_pointer_bases_; + + // The length value for the current entry. + // + // Oddly, this must be dynamically allocated. Labels never get new + // values; they only acquire constraints on the value they already + // have, or assert if you assign them something incompatible. So + // each header needs truly fresh Label objects to cite in their + // headers and track their positions. The alternative is explicit + // destructor invocation and a placement new. Ick. + PendingLength *entry_length_; + + // True if we are currently emitting an FDE --- that is, we have + // called FDEHeader but have not yet called FinishEntry. + bool in_fde_; + + // If in_fde_ is true, this is its starting address. We use this for + // emitting DW_EH_PE_funcrel pointers. + uint64_t fde_start_address_; +}; + +} // namespace lul_test + +#endif // LUL_TEST_INFRASTRUCTURE_H diff --git a/tools/profiler/tests/gtest/moz.build b/tools/profiler/tests/gtest/moz.build index dc4a190db51e..3facd8a06397 100644 --- a/tools/profiler/tests/gtest/moz.build +++ b/tools/profiler/tests/gtest/moz.build @@ -7,6 +7,8 @@ if CONFIG['OS_TARGET'] in ('Android', 'Linux'): UNIFIED_SOURCES += [ 'LulTest.cpp', + 'LulTestDwarf.cpp', + 'LulTestInfrastructure.cpp', ] LOCAL_INCLUDES += [ From ee4e0712c1c7d36a6070a665351e0e21017197d5 Mon Sep 17 00:00:00 2001 From: Lorien Hu Date: Fri, 12 Jun 2015 16:39:16 -0400 Subject: [PATCH 21/49] Bug 1174204 - Fixed gecko to atk attribute conversion for fg-color and bg-color to be correctly formatted r=davidb --- accessible/atk/nsMaiInterfaceText.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/accessible/atk/nsMaiInterfaceText.cpp b/accessible/atk/nsMaiInterfaceText.cpp index 8641351f7610..56193f66aef7 100644 --- a/accessible/atk/nsMaiInterfaceText.cpp +++ b/accessible/atk/nsMaiInterfaceText.cpp @@ -32,13 +32,15 @@ ConvertTextAttributeToAtkAttribute(const nsACString& aName, nsAutoString atkValue; if (aName.EqualsLiteral("color")) { // The format of the atk attribute is r,g,b and the gecko one is - // rgb(r,g,b). - atkValue = Substring(aValue, 5, aValue.Length() - 1); + // rgb(r, g, b). + atkValue = Substring(aValue, 4, aValue.Length() - 5); + atkValue.StripWhitespace(); atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_FG_COLOR]; } else if (aName.EqualsLiteral("background-color")) { // The format of the atk attribute is r,g,b and the gecko one is - // rgb(r,g,b). - atkValue = Substring(aValue, 5, aValue.Length() - 1); + // rgb(r, g, b). + atkValue = Substring(aValue, 4, aValue.Length() - 5); + atkValue.StripWhitespace(); atkName = sAtkTextAttrNames[ATK_TEXT_ATTR_BG_COLOR]; } else if (aName.EqualsLiteral("font-family")) { atkValue = aValue; From f83bf6c012e7db8e58bf68532bd676c7dc35888a Mon Sep 17 00:00:00 2001 From: Michael Layzell Date: Fri, 12 Jun 2015 05:00:00 -0400 Subject: [PATCH 22/49] Bug 1173256 - Debug log for potential cause of intermittent failure. r=ehsan --HG-- extra : rebase_source : 77b2b24bac49d4b46550106554be031ff0797b32 --- dom/events/EventStateManager.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/dom/events/EventStateManager.cpp b/dom/events/EventStateManager.cpp index d58d5192416b..af8fa776b533 100644 --- a/dom/events/EventStateManager.cpp +++ b/dom/events/EventStateManager.cpp @@ -3708,8 +3708,18 @@ EventStateManager::IsHandlingUserInput() } TimeDuration timeout = nsContentUtils::HandlingUserInputTimeout(); - return timeout <= TimeDuration(0) || - (TimeStamp::Now() - sHandlingInputStart) <= timeout; + TimeDuration elapsed = TimeStamp::Now() - sHandlingInputStart; + bool inTime = timeout <= TimeDuration(0) || elapsed <= timeout; + + if (!inTime) { +#ifdef DEBUG + printf("EventStateManager::IsHandlingUserInput() has timed out " + "(timeout: %f, elapsed: %f)\n", + timeout.ToMilliseconds(), elapsed.ToMilliseconds()); +#endif + return false; + } + return true; } static void From 9eb9060846f8b073157d7be1ba137112575d5ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Fri, 12 Jun 2015 10:43:00 -0400 Subject: [PATCH 23/49] Bug 1174143 - Remove private tables for Standard Symbols L and MathJax fonts. r=karlt --HG-- extra : rebase_source : d9868dabd15f0b9da9162e0b12e292e2754ab626 --- layout/mathml/MathJaxFonts.html | 178 ------------------ layout/mathml/mathfontMathJax_Main.properties | 144 -------------- .../mathfontStandardSymbolsL.properties | 43 ----- layout/mathml/moz.build | 2 - layout/mathml/nsMathMLChar.cpp | 4 +- modules/libpref/init/all.js | 10 +- 6 files changed, 6 insertions(+), 375 deletions(-) delete mode 100644 layout/mathml/MathJaxFonts.html delete mode 100644 layout/mathml/mathfontMathJax_Main.properties delete mode 100644 layout/mathml/mathfontStandardSymbolsL.properties diff --git a/layout/mathml/MathJaxFonts.html b/layout/mathml/MathJaxFonts.html deleted file mode 100644 index a3559f248cfb..000000000000 --- a/layout/mathml/MathJaxFonts.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - MathJax fonts - - - - - - - - - - - - diff --git a/layout/mathml/mathfontMathJax_Main.properties b/layout/mathml/mathfontMathJax_Main.properties deleted file mode 100644 index 4d849c54287d..000000000000 --- a/layout/mathml/mathfontMathJax_Main.properties +++ /dev/null @@ -1,144 +0,0 @@ -# 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/. - -# Content below is generated from MathJaxFonts.html. Do not edit. - -external.1 = MathJax_Size1 -external.2 = MathJax_Size2 -external.3 = MathJax_Size3 -external.4 = MathJax_Size4 -external.5 = MathJax_AMS -# external.6 = MathJax_Main-bold - -\u0028 = \u239B@4\uFFFD\u239D@4\u239C@4\u0028\u0028@1\u0028@2\u0028@3\u0028@4 -\u0029 = \u239E@4\uFFFD\u23A0@4\u239F@4\u0029\u0029@1\u0029@2\u0029@3\u0029@4 -\u002F = \uFFFD\uFFFD\uFFFD\uFFFD\u002F\u002F@1\u002F@2\u002F@3\u002F@4 -\u005B = \u23A1@4\uFFFD\u23A3@4\u23A2@4\u005B\u005B@1\u005B@2\u005B@3\u005B@4 -\u005C = \uFFFD\uFFFD\uFFFD\uFFFD\u005C\u005C@1\u005C@2\u005C@3\u005C@4 -\u005D = \u23A4@4\uFFFD\u23A6@4\u23A5@4\u005D\u005D@1\u005D@2\u005D@3\u005D@4 -\u007B = \u23A7@4\u23A8@4\u23A9@4\u23AA@4\u007B\u007B@1\u007B@2\u007B@3\u007B@4 -\u007C = \uFFFD\uFFFD\uFFFD\u2223\u007C -\u007D = \u23AB@4\u23AC@4\u23AD@4\u23AA@4\u007D\u007D@1\u007D@2\u007D@3\u007D@4 -\u00AF = \uFFFD\uFFFD\uFFFD\u00AF\u00AF -\u02C6 = \uFFFD\uFFFD\uFFFD\uFFFD\u02C6\u02C6@1\u02C6@2\u02C6@3\u02C6@4 -\u02DC = \uFFFD\uFFFD\uFFFD\uFFFD\u02DC\u02DC@1\u02DC@2\u02DC@3\u02DC@4 -\u2016 = \uFFFD\uFFFD\uFFFD\u2225\u2016@1\u2016 -\u2190 = \u2190\uFFFD\uFFFD\u2212\u2190 -\u2191 = \u2191@1\uFFFD\uFFFD\u23D0@1\u2191 -\u2192 = \uFFFD\uFFFD\u2192\u2212\u2192 -\u2193 = \uFFFD\uFFFD\u2193@1\u23D0@1\u2193 -\u2194 = \u2190\uFFFD\u2192\u2212\u2194 -\u2195 = \u2191@1\uFFFD\u2193@1\u23D0@1\u2195 -\u21D0 = \u21D0\uFFFD\uFFFD\u003D\u21D0 -\u21D1 = \u21D1@1\uFFFD\uFFFD\u2016@1\u21D1 -\u21D2 = \uFFFD\uFFFD\u21D2\u003D\u21D2 -\u21D3 = \uFFFD\uFFFD\u21D3@1\u2016@1\u21D3 -\u21D4 = \u21D0\uFFFD\u21D2\u003D\u21D4 -\u21D5 = \u21D1@1\uFFFD\u21D3@1\u2016@1\u21D5 -\u2212 = \uFFFD\uFFFD\uFFFD\u2212\u2212 -\u221A = \uE001@4\uFFFD\u23B7@4\uE000@4\u221A\u221A@1\u221A@2\u221A@3\u221A@4 -\u2223 = \uFFFD\uFFFD\uFFFD\u2223\u2223 -\u2225 = \uFFFD\uFFFD\uFFFD\u2225\u2225 -\u2308 = \u23A1@4\uFFFD\uFFFD\u23A2@4\u2308\u2308@1\u2308@2\u2308@3\u2308@4 -\u2309 = \u23A4@4\uFFFD\uFFFD\u23A5@4\u2309\u2309@1\u2309@2\u2309@3\u2309@4 -\u230A = \uFFFD\uFFFD\u23A3@4\u23A2@4\u230A\u230A@1\u230A@2\u230A@3\u230A@4 -\u230B = \uFFFD\uFFFD\u23A6@4\u23A5@4\u230B\u230B@1\u230B@2\u230B@3\u230B@4 -\u23AA = \u23AA@4\uFFFD\u23AA@4\u23AA@4\u23AA@4 -\u23B0 = \u23A7@4\uFFFD\u23AD@4\u23AA@4\u23B0 -\u23B1 = \u23AB@4\uFFFD\u23A9@4\u23AA@4\u23B1 -\u23D0 = \uFFFD\uFFFD\uFFFD\u2223\u23D0@1\u23D0 -# \u23DE = [not supported] -# \u23DF = [not supported] -\u27E8 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E8\u27E8@1\u27E8@2\u27E8@3\u27E8@4 -\u27E9 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E9\u27E9@1\u27E9@2\u27E9@3\u27E9@4 -\u27EE = \u23A7@4\uFFFD\u23A9@4\u23AA@4\u27EE -\u27EF = \u23AB@4\uFFFD\u23AD@4\u23AA@4\u27EF -\u002D = \uFFFD\uFFFD\uFFFD\u2212\u002D -\u005E = \uFFFD\uFFFD\uFFFD\uFFFD\u005E\u005E@1\u005E@2\u005E@3\u005E@4 -\u005F = \uFFFD\uFFFD\uFFFD\u2212\u005F -\u007E = \uFFFD\uFFFD\uFFFD\uFFFD\u007E\u007E@1\u007E@2\u007E@3\u007E@4 -\u02C9 = \uFFFD\uFFFD\uFFFD\u00AF\u02C9 -\u0302 = \uFFFD\uFFFD\uFFFD\uFFFD\u0302\u0302@1\u0302@2\u0302@3\u0302@4 -\u0303 = \uFFFD\uFFFD\uFFFD\uFFFD\u0303\u0303@1\u0303@2\u0303@3\u0303@4 -\u0332 = \uFFFD\uFFFD\uFFFD\u2212\u0332 -\u2015 = \uFFFD\uFFFD\uFFFD\u2212\u2015 -\u2017 = \uFFFD\uFFFD\uFFFD\u2212\u2017 -\u203E = \uFFFD\uFFFD\uFFFD\u00AF\u203E -\u2215 = \uFFFD\uFFFD\uFFFD\uFFFD\u2215\u2215@1\u2215@2\u2215@3\u2215@4 -\u2329 = \uFFFD\uFFFD\uFFFD\uFFFD\u2329\u2329@1\u2329@2\u2329@3\u2329@4 -\u232A = \uFFFD\uFFFD\uFFFD\uFFFD\u232A\u232A@1\u232A@2\u232A@3\u232A@4 -\u23AF = \uFFFD\uFFFD\uFFFD\u2212\u23AF -\u2500 = \uFFFD\uFFFD\uFFFD\u2212\u2500 -\u2758 = \uFFFD\uFFFD\uFFFD\u2223\u2758 -\u3008 = \uFFFD\uFFFD\uFFFD\uFFFD\u3008\u3008@1\u3008@2\u3008@3\u3008@4 -\u3009 = \uFFFD\uFFFD\uFFFD\uFFFD\u3009\u3009@1\u3009@2\u3009@3\u3009@4 -# \uFE37 = [not supported] -# \uFE38 = [not supported] -\u003D = \uFFFD\uFFFD\uFFFD\u003D\u003D -\u219E = \u219E@5\uFFFD\uFFFD\u2212\u219E@5 -\u21A0 = \uFFFD\uFFFD\u21A0@5\u2212\u21A0@5 -# \u21A4 = [not supported] -# \u21A5 = [not supported] -# \u21A6 = [not supported] -# \u21A7 = [not supported] -# \u21B0 = [not supported] -# \u21B1 = [not supported] -\u21BC = \u21BC\uFFFD\uFFFD\u2212\u21BC -\u21BD = \u21BD\uFFFD\uFFFD\u2212\u21BD -# \u21BE = [not supported] -# \u21BF = [not supported] -\u21C0 = \uFFFD\uFFFD\u21C0\u2212\u21C0 -\u21C1 = \uFFFD\uFFFD\u21C1\u2212\u21C1 -# \u21C2 = [not supported] -# \u21C3 = [not supported] -\u21DA = \u21DA@5\uFFFD\uFFFD\u2261\u21DA@5 -\u21DB = \uFFFD\uFFFD\u21DB@5\u2261\u21DB@5 -# \u23B4 = [not supported] -# \u23B5 = [not supported] -\u23DC = \uE150@4\uFFFD\uE151@4\uE154@4\u23DC@5\u23DC -\u23DD = \uE152@4\uFFFD\uE153@4\uE154@4\u23DD@5\u23DD -# \u23E0 = [not supported] -# \u23E1 = [not supported] -# \u2906 = [not supported] -# \u2907 = [not supported] -\u294E = \u21BC\uFFFD\u21C0\u2212 -# \u294F = [not supported] -\u2950 = \u21BD\uFFFD\u21C1\u2212 -# \u2951 = [not supported] -# \u295A = [not supported] -# \u295B = [not supported] -# \u295C = [not supported] -# \u295D = [not supported] -# \u295E = [not supported] -# \u295F = [not supported] -# \u2960 = [not supported] -# \u2961 = [not supported] -\u27F5 = \u2190\uFFFD\uFFFD\u2212\u27F5 -\u27F6 = \uFFFD\uFFFD\u2192\u2212\u27F6 -\u27F7 = \u2190\uFFFD\u2192\u2212\u27F7 -\u27F8 = \u21D0\uFFFD\uFFFD\u003D\u27F8 -\u27F9 = \uFFFD\uFFFD\u21D2\u003D\u27F9 -\u27FA = \u21D0\uFFFD\u21D2\u003D\u27FA -# \u27FB = [not supported] -# \u27FC = [not supported] -# \u27FD = [not supported] -# \u27FE = [not supported] -\u0020 = \uFFFD\uFFFD\uFFFD\uFFFD\u0020@1\u0020@2 -\u00A0 = \uFFFD\uFFFD\uFFFD\uFFFD\u00A0@1\u00A0@2 -\u220F = \uFFFD\uFFFD\uFFFD\uFFFD\u220F@1\u220F@2 -\u2210 = \uFFFD\uFFFD\uFFFD\uFFFD\u2210@1\u2210@2 -\u2211 = \uFFFD\uFFFD\uFFFD\uFFFD\u2211@1\u2211@2 -\u222B = \uFFFD\uFFFD\uFFFD\uFFFD\u222B@1\u222B@2 -\u222C = \uFFFD\uFFFD\uFFFD\uFFFD\u222C@1\u222C@2 -\u222D = \uFFFD\uFFFD\uFFFD\uFFFD\u222D@1\u222D@2 -\u222E = \uFFFD\uFFFD\uFFFD\uFFFD\u222E@1\u222E@2 -\u22C0 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C0@1\u22C0@2 -\u22C1 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C1@1\u22C1@2 -\u22C2 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C2@1\u22C2@2 -\u22C3 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C3@1\u22C3@2 -\u2A00 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A00@1\u2A00@2 -\u2A01 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A01@1\u2A01@2 -\u2A02 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A02@1\u2A02@2 -\u2A04 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A04@1\u2A04@2 -\u2A06 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A06@1\u2A06@2 diff --git a/layout/mathml/mathfontStandardSymbolsL.properties b/layout/mathml/mathfontStandardSymbolsL.properties deleted file mode 100644 index cb88b8d4bea9..000000000000 --- a/layout/mathml/mathfontStandardSymbolsL.properties +++ /dev/null @@ -1,43 +0,0 @@ -# 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/. - -# LOCALIZATION NOTE: FILE -# Do not translate anything in this file - -# This file contains the list of all stretchy MathML chars that -# can be rendered with Standard Symbols L. - -# [ T/L | M | B/R | G | size0 ... size{N-1} ] -\u0028 = \uF8EB\uFFFD\uF8ED\uF8EC\u0028 # ( -\u0029 = \uF8F6\uFFFD\uF8F8\uF8F7\u0029 # ) -\u005B = \uF8EE\uFFFD\uF8F0\uF8EF\u005B # [ -\u005D = \uF8F9\uFFFD\uF8FB\uF8FA\u005D # ] -\u007B = \uF8F1\uF8F2\uF8F3\uF8F4\u007B # { -\u007C = \uFFFD\uFFFD\uFFFD\u007C\u007C # | -\u007D = \uF8FC\uF8FD\uF8FE\uF8F4\u007D # } - -\u00AF = \uFFFD\uFFFD\uFFFD\uF8E5\u00AF # ad-hoc: overbar is stretched with the radical extender -\u0332 = \uFFFD\uFFFD\uFFFD\u005F\u0332 # ad-hock: UnderBar (0x0332) is stretched with underscore - -\u2190 = \u2190\uFFFD\uFFFD\uF8E7\u2190 # LeftArrow, larr, leftarrow -\u2191 = \u2191\uFFFD\uFFFD\uF8E6\u2191 # UpArrow, uarr, uparrow -\u2192 = \uFFFD\uFFFD\u2192\uF8E7\u2192 # RightArrow, rarr, rightarrow -\u2193 = \uFFFD\uFFFD\u2193\uF8E6\u2193 # DownArrow, darr, downarrow -\u2194 = \u2190\uFFFD\u2192\uF8E7\u2194 # LeftRightArrow, harr, leftrightarrow -\u2195 = \u2191\uFFFD\u2193\uF8E6\u2195 # UpDownArrow, updownarrow, varr - -\u222B = \u2320\uFFFD\u2321\uF8F5\u222B # Integral, int -# If there are problems with the font-supplied glue use a rule: -# \u222B = \u2320\uFFFD\u2321\uFFFD\u222B # Integral, int - -# Using parts of [ and ] -\u2308 = \uF8EE\uFFFD\uFFFD\uF8EF\u2308 # LeftCeiling, lceil -\u2309 = \uF8F9\uFFFD\uFFFD\uF8FA\u2309 # RightCeiling, rceil -\u230A = \uFFFD\uFFFD\uF8F0\uF8EF\u230A # LeftFloor, lfloor -\u230B = \uFFFD\uFFFD\uF8FB\uF8FA\u230B # RightFloor, rfloor - -# same as normal arrows -\u27F5 = \u2190\uFFFD\uFFFD\uF8E7\u27F5 # LongLeftArrow -\u27F6 = \uFFFD\uFFFD\u2192\uF8E7\u27F6 # LongRightArrow -\u27F7 = \u2190\uFFFD\u2192\uF8E7\u27F7 # LongLeftRightArrow diff --git a/layout/mathml/moz.build b/layout/mathml/moz.build index 2e0cacbde8df..6705d44b2930 100644 --- a/layout/mathml/moz.build +++ b/layout/mathml/moz.build @@ -55,8 +55,6 @@ JAR_MANIFESTS += ['jar.mn'] RESOURCE_FILES.fonts += [ 'mathfont.properties', - 'mathfontMathJax_Main.properties', - 'mathfontStandardSymbolsL.properties', 'mathfontSTIXGeneral.properties', 'mathfontUnicode.properties', ] diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 56a7cb15477e..5175b63416d5 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -734,9 +734,7 @@ InitGlobals(nsPresContext* aPresContext) // observer and will be deleted at shutdown. We now add some private // per font-family tables for stretchy operators, in order of preference. // Do not include the Unicode table in this list. - if (!glyphTableList->AddGlyphTable(NS_LITERAL_STRING("MathJax_Main")) || - !glyphTableList->AddGlyphTable(NS_LITERAL_STRING("STIXGeneral")) || - !glyphTableList->AddGlyphTable(NS_LITERAL_STRING("Standard Symbols L")) + if (!glyphTableList->AddGlyphTable(NS_LITERAL_STRING("STIXGeneral")) #ifdef XP_WIN || !glyphTableList->AddGlyphTable(NS_LITERAL_STRING("Symbol")) #endif diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 072e41179fb4..16bd239bec74 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -1860,7 +1860,7 @@ pref("intl.hyphenation-alias.nb-*", "nb"); pref("intl.hyphenation-alias.nn-*", "nn"); pref("font.name.serif.x-math", "Latin Modern Math"); -pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Standard Symbols L, serif"); +pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, serif"); pref("font.name.sans-serif.x-math", "sans-serif"); pref("font.name.monospace.x-math", "monospace"); @@ -2976,7 +2976,7 @@ pref("font.minimum-size.th", 10); pref("font.default.x-devanagari", "sans-serif"); pref("font.name.serif.x-math", "Latin Modern Math"); // We have special support for Monotype Symbol on Windows. -pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Symbol, Times New Roman"); +pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, Symbol, Times New Roman"); pref("font.name.sans-serif.x-math", "Arial"); pref("font.name.monospace.x-math", "Courier New"); pref("font.name.cursive.x-math", "Comic Sans MS"); @@ -3407,7 +3407,7 @@ pref("font.size.variable.zh-TW", 15); pref("font.name.serif.x-math", "Latin Modern Math"); // Apple's Symbol is Unicode so use it -pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Symbol, Times"); +pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, Symbol, Times"); pref("font.name.sans-serif.x-math", "Helvetica"); pref("font.name.monospace.x-math", "Courier"); pref("font.name.cursive.x-math", "Apple Chancery"); @@ -3833,7 +3833,7 @@ pref("font.name.monospace.zh-TW", "Fira Mono"); pref("font.name-list.sans-serif.zh-TW", "Fira Sans,Droid Sans Fallback"); pref("font.name.serif.x-math", "Latin Modern Math"); -pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Charis SIL Compact"); +pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, Charis SIL Compact"); pref("font.name.sans-serif.x-math", "Fira Sans"); pref("font.name.monospace.x-math", "Fira Mono"); @@ -3911,7 +3911,7 @@ pref("font.name-list.sans-serif.zh-TW", "Roboto, Droid Sans, Noto Sans TC, Noto pref("font.name-list.monospace.zh-TW", "Droid Sans Fallback"); pref("font.name.serif.x-math", "Latin Modern Math"); -pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, MathJax_Main, STIXGeneral, DejaVu Serif, DejaVu Sans, Charis SIL Compact"); +pref("font.name-list.serif.x-math", "Latin Modern Math, XITS Math, Cambria Math, TeX Gyre Bonum Math, TeX Gyre Pagella Math, TeX Gyre Schola, TeX Gyre Termes Math, STIX Math, Asana Math, STIXGeneral, DejaVu Serif, DejaVu Sans, Charis SIL Compact"); pref("font.name.sans-serif.x-math", "Clear Sans"); pref("font.name.monospace.x-math", "Droid Sans Mono"); From 849a58bf98e70134beb0b57bd5da64a0ead726b9 Mon Sep 17 00:00:00 2001 From: Jukka Jylanki Date: Sat, 13 Jun 2015 14:02:46 +0300 Subject: [PATCH 24/49] Bug 1168471 - Implement support for SharedArrayBuffers and SharedArrayViews in WebIDL. r=bz, r=lth, r=luke --HG-- extra : rebase_source : 0eb1a42791c03a43113f6a81b066c0c932deb7c8 --- dom/bindings/TypedArray.h | 33 +++++ dom/bindings/parser/WebIDL.py | 122 +++++++++++++++++- .../parser/tests/test_distinguishability.py | 17 ++- js/src/jsfriendapi.h | 53 ++++++++ js/src/vm/ArrayBufferObject.cpp | 24 ++++ js/src/vm/SharedArrayObject.cpp | 29 ++++- js/src/vm/SharedTypedArrayObject.cpp | 99 ++++++++++++++ js/src/vm/TypedArrayObject.cpp | 12 ++ 8 files changed, 378 insertions(+), 11 deletions(-) diff --git a/dom/bindings/TypedArray.h b/dom/bindings/TypedArray.h index f4b2b7368eec..60da069152ba 100644 --- a/dom/bindings/TypedArray.h +++ b/dom/bindings/TypedArray.h @@ -223,6 +223,39 @@ typedef TypedArray ArrayBuffer; +typedef TypedArray + SharedInt8Array; +typedef TypedArray + SharedUint8Array; +typedef TypedArray + SharedUint8ClampedArray; +typedef TypedArray + SharedInt16Array; +typedef TypedArray + SharedUint16Array; +typedef TypedArray + SharedInt32Array; +typedef TypedArray + SharedUint32Array; +typedef TypedArray + SharedFloat32Array; +typedef TypedArray + SharedFloat64Array; +typedef TypedArray_base + SharedArrayBufferView; +typedef TypedArray + SharedArrayBuffer; + // A class for converting an nsTArray to a TypedArray // Note: A TypedArrayCreator must not outlive the nsTArray it was created from. // So this is best used to pass from things that understand nsTArray to diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index 1b0ec436ff23..a831924ed2f2 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -1729,9 +1729,18 @@ class IDLType(IDLObject): def isArrayBufferView(self): return False + def isSharedArrayBuffer(self): + return False + + def isSharedArrayBufferView(self): + return False + def isTypedArray(self): return False + def isSharedTypedArray(self): + return False + def isCallbackInterface(self): return False @@ -1751,7 +1760,10 @@ class IDLType(IDLObject): only returns true for the types from the TypedArray spec. """ return self.isInterface() and (self.isArrayBuffer() or \ self.isArrayBufferView() or \ - self.isTypedArray()) + self.isSharedArrayBuffer() or \ + self.isSharedArrayBufferView() or \ + self.isTypedArray() or \ + self.isSharedTypedArray()) def isDictionary(self): return False @@ -1933,9 +1945,18 @@ class IDLNullableType(IDLType): def isArrayBufferView(self): return self.inner.isArrayBufferView() + def isSharedArrayBuffer(self): + return self.inner.isSharedArrayBuffer() + + def isSharedArrayBufferView(self): + return self.inner.isSharedArrayBufferView() + def isTypedArray(self): return self.inner.isTypedArray() + def isSharedTypedArray(self): + return self.inner.isSharedTypedArray() + def isDictionary(self): return self.inner.isDictionary() @@ -2424,9 +2445,18 @@ class IDLTypedefType(IDLType): def isArrayBufferView(self): return self.inner.isArrayBufferView() + def isSharedArrayBuffer(self): + return self.inner.isSharedArrayBuffer() + + def isSharedArrayBufferView(self): + return self.inner.isSharedArrayBufferView() + def isTypedArray(self): return self.inner.isTypedArray() + def isSharedTypedArray(self): + return self.inner.isSharedTypedArray() + def isInterface(self): return self.inner.isInterface() @@ -2684,6 +2714,8 @@ class IDLBuiltinType(IDLType): # Funny stuff 'ArrayBuffer', 'ArrayBufferView', + 'SharedArrayBuffer', + 'SharedArrayBufferView', 'Int8Array', 'Uint8Array', 'Uint8ClampedArray', @@ -2692,7 +2724,16 @@ class IDLBuiltinType(IDLType): 'Int32Array', 'Uint32Array', 'Float32Array', - 'Float64Array' + 'Float64Array', + 'SharedInt8Array', + 'SharedUint8Array', + 'SharedUint8ClampedArray', + 'SharedInt16Array', + 'SharedUint16Array', + 'SharedInt32Array', + 'SharedUint32Array', + 'SharedFloat32Array', + 'SharedFloat64Array' ) TagLookup = { @@ -2718,6 +2759,8 @@ class IDLBuiltinType(IDLType): Types.void: IDLType.Tags.void, Types.ArrayBuffer: IDLType.Tags.interface, Types.ArrayBufferView: IDLType.Tags.interface, + Types.SharedArrayBuffer: IDLType.Tags.interface, + Types.SharedArrayBufferView: IDLType.Tags.interface, Types.Int8Array: IDLType.Tags.interface, Types.Uint8Array: IDLType.Tags.interface, Types.Uint8ClampedArray: IDLType.Tags.interface, @@ -2726,7 +2769,16 @@ class IDLBuiltinType(IDLType): Types.Int32Array: IDLType.Tags.interface, Types.Uint32Array: IDLType.Tags.interface, Types.Float32Array: IDLType.Tags.interface, - Types.Float64Array: IDLType.Tags.interface + Types.Float64Array: IDLType.Tags.interface, + Types.SharedInt8Array: IDLType.Tags.interface, + Types.SharedUint8Array: IDLType.Tags.interface, + Types.SharedUint8ClampedArray: IDLType.Tags.interface, + Types.SharedInt16Array: IDLType.Tags.interface, + Types.SharedUint16Array: IDLType.Tags.interface, + Types.SharedInt32Array: IDLType.Tags.interface, + Types.SharedUint32Array: IDLType.Tags.interface, + Types.SharedFloat32Array: IDLType.Tags.interface, + Types.SharedFloat64Array: IDLType.Tags.interface } def __init__(self, location, name, type): @@ -2766,17 +2818,30 @@ class IDLBuiltinType(IDLType): def isArrayBufferView(self): return self._typeTag == IDLBuiltinType.Types.ArrayBufferView + def isSharedArrayBuffer(self): + return self._typeTag == IDLBuiltinType.Types.SharedArrayBuffer + + def isSharedArrayBufferView(self): + return self._typeTag == IDLBuiltinType.Types.SharedArrayBufferView + def isTypedArray(self): return self._typeTag >= IDLBuiltinType.Types.Int8Array and \ self._typeTag <= IDLBuiltinType.Types.Float64Array + def isSharedTypedArray(self): + return self._typeTag >= IDLBuiltinType.Types.SharedInt8Array and \ + self._typeTag <= IDLBuiltinType.Types.SharedFloat64Array + def isInterface(self): # TypedArray things are interface types per the TypedArray spec, # but we handle them as builtins because SpiderMonkey implements # all of it internally. return self.isArrayBuffer() or \ self.isArrayBufferView() or \ - self.isTypedArray() + self.isSharedArrayBuffer() or \ + self.isSharedArrayBufferView() or \ + self.isTypedArray() or \ + self.isSharedTypedArray() def isNonCallbackInterface(self): # All the interfaces we can be are non-callback @@ -2847,15 +2912,20 @@ class IDLBuiltinType(IDLType): # ArrayBuffer is distinguishable from everything # that's not an ArrayBuffer or a callback interface (self.isArrayBuffer() and not other.isArrayBuffer()) or + (self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or # ArrayBufferView is distinguishable from everything # that's not an ArrayBufferView or typed array. (self.isArrayBufferView() and not other.isArrayBufferView() and not other.isTypedArray()) or + (self.isSharedArrayBufferView() and not other.isSharedArrayBufferView() and + not other.isSharedTypedArray()) or # Typed arrays are distinguishable from everything # except ArrayBufferView and the same type of typed # array (self.isTypedArray() and not other.isArrayBufferView() and not - (other.isTypedArray() and other.name == self.name))))) + (other.isTypedArray() and other.name == self.name)) or + (self.isSharedTypedArray() and not other.isSharedArrayBufferView() and not + (other.isSharedTypedArray() and other.name == self.name))))) def _getDependentObjects(self): return set() @@ -2927,6 +2997,12 @@ BuiltinTypes = { IDLBuiltinType.Types.ArrayBufferView: IDLBuiltinType(BuiltinLocation(""), "ArrayBufferView", IDLBuiltinType.Types.ArrayBufferView), + IDLBuiltinType.Types.SharedArrayBuffer: + IDLBuiltinType(BuiltinLocation(""), "SharedArrayBuffer", + IDLBuiltinType.Types.SharedArrayBuffer), + IDLBuiltinType.Types.SharedArrayBufferView: + IDLBuiltinType(BuiltinLocation(""), "SharedArrayBufferView", + IDLBuiltinType.Types.SharedArrayBufferView), IDLBuiltinType.Types.Int8Array: IDLBuiltinType(BuiltinLocation(""), "Int8Array", IDLBuiltinType.Types.Int8Array), @@ -2953,7 +3029,34 @@ BuiltinTypes = { IDLBuiltinType.Types.Float32Array), IDLBuiltinType.Types.Float64Array: IDLBuiltinType(BuiltinLocation(""), "Float64Array", - IDLBuiltinType.Types.Float64Array) + IDLBuiltinType.Types.Float64Array), + IDLBuiltinType.Types.SharedInt8Array: + IDLBuiltinType(BuiltinLocation(""), "SharedInt8Array", + IDLBuiltinType.Types.SharedInt8Array), + IDLBuiltinType.Types.SharedUint8Array: + IDLBuiltinType(BuiltinLocation(""), "SharedUint8Array", + IDLBuiltinType.Types.SharedUint8Array), + IDLBuiltinType.Types.SharedUint8ClampedArray: + IDLBuiltinType(BuiltinLocation(""), "SharedUint8ClampedArray", + IDLBuiltinType.Types.SharedUint8ClampedArray), + IDLBuiltinType.Types.SharedInt16Array: + IDLBuiltinType(BuiltinLocation(""), "SharedInt16Array", + IDLBuiltinType.Types.SharedInt16Array), + IDLBuiltinType.Types.SharedUint16Array: + IDLBuiltinType(BuiltinLocation(""), "SharedUint16Array", + IDLBuiltinType.Types.SharedUint16Array), + IDLBuiltinType.Types.SharedInt32Array: + IDLBuiltinType(BuiltinLocation(""), "SharedInt32Array", + IDLBuiltinType.Types.SharedInt32Array), + IDLBuiltinType.Types.SharedUint32Array: + IDLBuiltinType(BuiltinLocation(""), "SharedUint32Array", + IDLBuiltinType.Types.SharedUint32Array), + IDLBuiltinType.Types.SharedFloat32Array: + IDLBuiltinType(BuiltinLocation(""), "SharedFloat32Array", + IDLBuiltinType.Types.SharedFloat32Array), + IDLBuiltinType.Types.SharedFloat64Array: + IDLBuiltinType(BuiltinLocation(""), "SharedFloat64Array", + IDLBuiltinType.Types.SharedFloat64Array) } @@ -4413,6 +4516,7 @@ class Tokenizer(object): "<": "LT", ">": "GT", "ArrayBuffer": "ARRAYBUFFER", + "SharedArrayBuffer": "SHAREDARRAYBUFFER", "or": "OR" } @@ -5460,12 +5564,15 @@ class Parser(Tokenizer): """ NonAnyType : PrimitiveOrStringType TypeSuffix | ARRAYBUFFER TypeSuffix + | SHAREDARRAYBUFFER TypeSuffix | OBJECT TypeSuffix """ if p[1] == "object": type = BuiltinTypes[IDLBuiltinType.Types.object] elif p[1] == "ArrayBuffer": type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer] + elif p[1] == "SharedArrayBuffer": + type = BuiltinTypes[IDLBuiltinType.Types.SharedArrayBuffer] else: type = BuiltinTypes[p[1]] @@ -5859,7 +5966,7 @@ class Parser(Tokenizer): assert isinstance(scope, IDLScope) # xrange omits the last value. - for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): + for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.SharedFloat64Array + 1): builtin = BuiltinTypes[x] name = builtin.name typedef = IDLTypedef(BuiltinLocation(""), scope, builtin, name) @@ -5920,6 +6027,7 @@ class Parser(Tokenizer): _builtins = """ typedef unsigned long long DOMTimeStamp; typedef (ArrayBufferView or ArrayBuffer) BufferSource; + typedef (SharedArrayBufferView or SharedArrayBuffer) SharedBufferSource; """ def main(): diff --git a/dom/bindings/parser/tests/test_distinguishability.py b/dom/bindings/parser/tests/test_distinguishability.py index dbee9227c7d0..cbcd0985850d 100644 --- a/dom/bindings/parser/tests/test_distinguishability.py +++ b/dom/bindings/parser/tests/test_distinguishability.py @@ -160,7 +160,8 @@ def WebIDLTest(parser, harness): "optional Dict2", "sequence", "sequence", "MozMap", "MozMap", "MozMap", "long[]", "short[]", "Date", "Date?", "any", - "USVString" ] + "USVString", "ArrayBuffer", "ArrayBufferView", "SharedArrayBuffer", "SharedArrayBufferView", + "Uint8Array", "SharedUint8Array", "Uint16Array", "SharedUint16Array" ] # When we can parse Date and RegExp, we need to add them here. # Try to categorize things a bit to keep list lengths down @@ -175,8 +176,10 @@ def WebIDLTest(parser, harness): nonStrings = allBut(argTypes, strings) nonObjects = primitives + strings objects = allBut(argTypes, nonObjects ) + bufferSourceTypes = ["ArrayBuffer", "ArrayBufferView", "Uint8Array", "Uint16Array"] + sharedBufferSourceTypes = ["SharedArrayBuffer", "SharedArrayBufferView", "SharedUint8Array", "SharedUint16Array"] interfaces = [ "Interface", "Interface?", "AncestorInterface", - "UnrelatedInterface", "ImplementedInterface" ] + "UnrelatedInterface", "ImplementedInterface" ] + bufferSourceTypes + sharedBufferSourceTypes nullables = ["long?", "short?", "boolean?", "Interface?", "CallbackInterface?", "optional Dict", "optional Dict2", "Date?", "any"] @@ -186,7 +189,7 @@ def WebIDLTest(parser, harness): nonUserObjects = nonObjects + interfaces + dates + sequences otherObjects = allBut(argTypes, nonUserObjects + ["object"]) notRelatedInterfaces = (nonObjects + ["UnrelatedInterface"] + - otherObjects + dates + sequences) + otherObjects + dates + sequences + bufferSourceTypes + sharedBufferSourceTypes) mozMaps = [ "MozMap", "MozMap", "MozMap" ] # Build a representation of the distinguishability table as a dict @@ -235,6 +238,14 @@ def WebIDLTest(parser, harness): setDistinguishable("Date", allBut(argTypes, dates + ["object"])) setDistinguishable("Date?", allBut(argTypes, dates + nullables + ["object"])) setDistinguishable("any", []) + setDistinguishable("ArrayBuffer", allBut(argTypes, ["ArrayBuffer", "object"])) + setDistinguishable("ArrayBufferView", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "Uint16Array", "object"])) + setDistinguishable("Uint8Array", allBut(argTypes, ["ArrayBufferView", "Uint8Array", "object"])) + setDistinguishable("Uint16Array", allBut(argTypes, ["ArrayBufferView", "Uint16Array", "object"])) + setDistinguishable("SharedArrayBuffer", allBut(argTypes, ["SharedArrayBuffer", "object"])) + setDistinguishable("SharedArrayBufferView", allBut(argTypes, ["SharedArrayBufferView", "SharedUint8Array", "SharedUint16Array", "object"])) + setDistinguishable("SharedUint8Array", allBut(argTypes, ["SharedArrayBufferView", "SharedUint8Array", "object"])) + setDistinguishable("SharedUint16Array", allBut(argTypes, ["SharedArrayBufferView", "SharedUint16Array", "object"])) def areDistinguishable(type1, type2): return data[type1].get(type2, False) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 4014e8e8055c..e825b3590c71 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1697,6 +1697,12 @@ extern JS_FRIEND_API(JSObject*) JS_NewSharedFloat64ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, uint32_t length); +/* + * Create a new SharedArrayBuffer with the given byte length. + */ +extern JS_FRIEND_API(JSObject*) +JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes); + /* * Create a new ArrayBuffer with the given byte length. */ @@ -1821,6 +1827,13 @@ UnwrapSharedFloat32Array(JSObject* obj); extern JS_FRIEND_API(JSObject*) UnwrapSharedFloat64Array(JSObject* obj); +extern JS_FRIEND_API(JSObject*) +UnwrapSharedArrayBuffer(JSObject* obj); + +extern JS_FRIEND_API(JSObject*) +UnwrapSharedArrayBufferView(JSObject* obj); + + namespace detail { extern JS_FRIEND_DATA(const Class* const) Int8ArrayClassPtr; @@ -1872,6 +1885,16 @@ JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint32, uint32_t) JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float32, float) JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64, double) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(SharedInt8, int8_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(SharedUint8, uint8_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(SharedUint8Clamped, uint8_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(SharedInt16, int16_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(SharedUint16, uint16_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(SharedInt32, int32_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(SharedUint32, uint32_t) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(SharedFloat32, float) +JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(SharedFloat64, double) + #undef JS_DEFINE_DATA_AND_LENGTH_ACCESSOR // This one isn't inlined because it's rather tricky (by dint of having to deal @@ -1879,11 +1902,17 @@ JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64, double) extern JS_FRIEND_API(void) GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, uint8_t** data); +extern JS_FRIEND_API(void) +GetSharedArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, uint8_t** data); + // This one isn't inlined because there are a bunch of different ArrayBuffer // classes that would have to be individually handled here. extern JS_FRIEND_API(void) GetArrayBufferLengthAndData(JSObject* obj, uint32_t* length, uint8_t** data); +extern JS_FRIEND_API(void) +GetSharedArrayBufferLengthAndData(JSObject* obj, uint32_t* length, uint8_t** data); + } // namespace js /* @@ -1924,6 +1953,9 @@ JS_GetObjectAsArrayBuffer(JSObject* obj, uint32_t* length, uint8_t** data); extern JS_FRIEND_API(js::Scalar::Type) JS_GetArrayBufferViewType(JSObject* obj); +extern JS_FRIEND_API(js::Scalar::Type) +JS_GetSharedArrayBufferViewType(JSObject* obj); + /* * Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may * return false if a security wrapper is encountered that denies the @@ -2043,6 +2075,27 @@ JS_GetFloat32ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); extern JS_FRIEND_API(double*) JS_GetFloat64ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(uint8_t*) +JS_GetSharedArrayBufferData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(int8_t*) +JS_GetSharedInt8ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(uint8_t*) +JS_GetSharedUint8ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(uint8_t*) +JS_GetSharedUint8ClampedArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(int16_t*) +JS_GetSharedInt16ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(uint16_t*) +JS_GetSharedUint16ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(int32_t*) +JS_GetSharedInt32ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(uint32_t*) +JS_GetSharedUint32ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(float*) +JS_GetSharedFloat32ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); +extern JS_FRIEND_API(double*) +JS_GetSharedFloat64ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&); + /* * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific * versions when possible. diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 54033d847b31..d3da4999d3ca 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -42,6 +42,7 @@ #include "js/MemoryMetrics.h" #include "vm/GlobalObject.h" #include "vm/Interpreter.h" +#include "vm/SharedArrayObject.h" #include "vm/WrapperObject.h" #include "jsatominlines.h" @@ -1285,6 +1286,14 @@ js::UnwrapArrayBufferView(JSObject* obj) return nullptr; } +JS_FRIEND_API(JSObject*) +js::UnwrapSharedArrayBufferView(JSObject* obj) +{ + if (JSObject* unwrapped = CheckedUnwrap(obj)) + return unwrapped->is() ? unwrapped : nullptr; + return nullptr; +} + JS_FRIEND_API(uint32_t) JS_GetArrayBufferByteLength(JSObject* obj) { @@ -1346,6 +1355,13 @@ JS_NewArrayBuffer(JSContext* cx, uint32_t nbytes) return ArrayBufferObject::create(cx, nbytes); } +JS_FRIEND_API(JSObject*) +JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes) +{ + MOZ_ASSERT(nbytes <= INT32_MAX); + return SharedArrayBufferObject::New(cx, nbytes); +} + JS_PUBLIC_API(JSObject*) JS_NewArrayBufferWithContents(JSContext* cx, size_t nbytes, void* data) { @@ -1376,6 +1392,14 @@ js::UnwrapArrayBuffer(JSObject* obj) return nullptr; } +JS_FRIEND_API(JSObject*) +js::UnwrapSharedArrayBuffer(JSObject* obj) +{ + if (JSObject* unwrapped = CheckedUnwrap(obj)) + return unwrapped->is() ? unwrapped : nullptr; + return nullptr; +} + JS_PUBLIC_API(void*) JS_StealArrayBufferContents(JSContext* cx, HandleObject objArg) { diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp index 1774724df77e..0c2af6dcb3f6 100644 --- a/js/src/vm/SharedArrayObject.cpp +++ b/js/src/vm/SharedArrayObject.cpp @@ -382,9 +382,36 @@ js::AsSharedArrayBuffer(HandleObject obj) return obj->as(); } +JS_FRIEND_API(void) +js::GetSharedArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, uint8_t** data) +{ + MOZ_ASSERT(obj->is()); + + *length = obj->as().byteLength(); + + *data = static_cast(obj->as().viewData()); +} + +JS_FRIEND_API(void) +js::GetSharedArrayBufferLengthAndData(JSObject* obj, uint32_t* length, uint8_t** data) +{ + MOZ_ASSERT(obj->is()); + *length = obj->as().byteLength(); + *data = obj->as().dataPointer(); +} + JS_FRIEND_API(bool) JS_IsSharedArrayBufferObject(JSObject* obj) { obj = CheckedUnwrap(obj); - return obj ? obj->is() : false; + return obj ? obj->is() : false; +} + +JS_FRIEND_API(uint8_t*) +JS_GetSharedArrayBufferData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + return obj->as().dataPointer(); } diff --git a/js/src/vm/SharedTypedArrayObject.cpp b/js/src/vm/SharedTypedArrayObject.cpp index a159246b9c8e..d09c9d429c11 100644 --- a/js/src/vm/SharedTypedArrayObject.cpp +++ b/js/src/vm/SharedTypedArrayObject.cpp @@ -999,6 +999,105 @@ SharedTypedArrayObject::setElement(SharedTypedArrayObject& obj, uint32_t index, } } +JS_FRIEND_API(int8_t*) +JS_GetSharedInt8ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + SharedTypedArrayObject* tarr = &obj->as(); + MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int8); + return static_cast(tarr->viewData()); +} + +JS_FRIEND_API(uint8_t*) +JS_GetSharedUint8ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + SharedTypedArrayObject* tarr = &obj->as(); + MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8); + return static_cast(tarr->viewData()); +} + +JS_FRIEND_API(uint8_t*) +JS_GetSharedUint8ClampedArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + SharedTypedArrayObject* tarr = &obj->as(); + MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint8Clamped); + return static_cast(tarr->viewData()); +} + +JS_FRIEND_API(int16_t*) +JS_GetSharedInt16ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + SharedTypedArrayObject* tarr = &obj->as(); + MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int16); + return static_cast(tarr->viewData()); +} + +JS_FRIEND_API(uint16_t*) +JS_GetSharedUint16ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + SharedTypedArrayObject* tarr = &obj->as(); + MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint16); + return static_cast(tarr->viewData()); +} + +JS_FRIEND_API(int32_t*) +JS_GetSharedInt32ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + SharedTypedArrayObject* tarr = &obj->as(); + MOZ_ASSERT((int32_t) tarr->type() == Scalar::Int32); + return static_cast(tarr->viewData()); +} + +JS_FRIEND_API(uint32_t*) +JS_GetSharedUint32ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + SharedTypedArrayObject* tarr = &obj->as(); + MOZ_ASSERT((int32_t) tarr->type() == Scalar::Uint32); + return static_cast(tarr->viewData()); +} + +JS_FRIEND_API(float*) +JS_GetSharedFloat32ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + SharedTypedArrayObject* tarr = &obj->as(); + MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float32); + return static_cast(tarr->viewData()); +} + +JS_FRIEND_API(double*) +JS_GetSharedFloat64ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return nullptr; + SharedTypedArrayObject* tarr = &obj->as(); + MOZ_ASSERT((int32_t) tarr->type() == Scalar::Float64); + return static_cast(tarr->viewData()); +} + #undef IMPL_SHARED_TYPED_ARRAY_STATICS #undef IMPL_SHARED_TYPED_ARRAY_JSAPI_CONSTRUCTORS #undef IMPL_SHARED_TYPED_ARRAY_COMBINED_UNWRAPPERS diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index fe391658863f..b1078378f673 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -2211,6 +2211,18 @@ JS_GetArrayBufferViewType(JSObject* obj) MOZ_CRASH("invalid ArrayBufferView type"); } +JS_FRIEND_API(js::Scalar::Type) +JS_GetSharedArrayBufferViewType(JSObject* obj) +{ + obj = CheckedUnwrap(obj); + if (!obj) + return Scalar::MaxTypedArrayViewType; + + if (obj->is()) + return obj->as().type(); + MOZ_CRASH("invalid SharedArrayBufferView type"); +} + JS_FRIEND_API(int8_t*) JS_GetInt8ArrayData(JSObject* obj, const JS::AutoCheckCannotGC&) { From bc95798c008eb66ea40a09358db662a909a346d3 Mon Sep 17 00:00:00 2001 From: Andrew Comminos Date: Wed, 10 Jun 2015 12:16:00 -0400 Subject: [PATCH 25/49] Bug 1169370 - Mark tree Cairo surface dirty after borrow. r=jrmuizel --HG-- extra : rebase_source : 3e9d5349a0218a60ff2178aeec42741028427824 --- gfx/2d/DrawTargetCairo.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gfx/2d/DrawTargetCairo.cpp b/gfx/2d/DrawTargetCairo.cpp index f13a323527a3..7e87e3616790 100644 --- a/gfx/2d/DrawTargetCairo.cpp +++ b/gfx/2d/DrawTargetCairo.cpp @@ -1756,6 +1756,7 @@ BorrowedXlibDrawable::Init(DrawTarget* aDT) if (cairo_surface_get_type(surf) != CAIRO_SURFACE_TYPE_XLIB) { return false; } + cairo_surface_flush(surf); cairoDT->WillChange(); @@ -1774,6 +1775,9 @@ BorrowedXlibDrawable::Init(DrawTarget* aDT) void BorrowedXlibDrawable::Finish() { + DrawTargetCairo* cairoDT = static_cast(mDT); + cairo_surface_t* surf = cairoDT->mSurface; + cairo_surface_mark_dirty(surf); if (mDrawable) { mDrawable = None; } From d3659f3dbdebd3d08dfcaf9666ce9ffa6cdda846 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Thu, 11 Jun 2015 10:57:29 +0800 Subject: [PATCH 26/49] Bug 1169126 - Part 1: Make DrawTargetCG::CopySurface able to handle all SourceSurface types. r=gw280 --HG-- extra : rebase_source : b8288de3b9731249205203e5bca2abc356b8eb78 --- gfx/2d/DrawTargetCG.cpp | 46 +++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/gfx/2d/DrawTargetCG.cpp b/gfx/2d/DrawTargetCG.cpp index a0108107ffe7..418d014def17 100644 --- a/gfx/2d/DrawTargetCG.cpp +++ b/gfx/2d/DrawTargetCG.cpp @@ -1615,39 +1615,35 @@ DrawTargetCG::CopySurface(SourceSurface *aSurface, MarkChanged(); - if (aSurface->GetType() == SurfaceType::COREGRAPHICS_IMAGE || - aSurface->GetType() == SurfaceType::COREGRAPHICS_CGCONTEXT || - aSurface->GetType() == SurfaceType::DATA) { - CGImageRef image = GetRetainedImageFromSourceSurface(aSurface); + CGImageRef image = GetRetainedImageFromSourceSurface(aSurface); - // XXX: it might be more efficient for us to do the copy directly if we have access to the bits + // XXX: it might be more efficient for us to do the copy directly if we have access to the bits - CGContextSaveGState(mCg); - CGContextSetCTM(mCg, mOriginalTransform); + CGContextSaveGState(mCg); + CGContextSetCTM(mCg, mOriginalTransform); - // CopySurface ignores the clip, so we need to use private API to temporarily reset it - CGContextResetClip(mCg); - CGRect destRect = CGRectMake(aDestination.x, aDestination.y, - aSourceRect.width, aSourceRect.height); - CGContextClipToRect(mCg, destRect); + // CopySurface ignores the clip, so we need to use private API to temporarily reset it + CGContextResetClip(mCg); + CGRect destRect = CGRectMake(aDestination.x, aDestination.y, + aSourceRect.width, aSourceRect.height); + CGContextClipToRect(mCg, destRect); - CGContextSetBlendMode(mCg, kCGBlendModeCopy); + CGContextSetBlendMode(mCg, kCGBlendModeCopy); - CGContextScaleCTM(mCg, 1, -1); + CGContextScaleCTM(mCg, 1, -1); - CGRect flippedRect = CGRectMake(aDestination.x - aSourceRect.x, -(aDestination.y - aSourceRect.y + double(CGImageGetHeight(image))), - CGImageGetWidth(image), CGImageGetHeight(image)); + CGRect flippedRect = CGRectMake(aDestination.x - aSourceRect.x, -(aDestination.y - aSourceRect.y + double(CGImageGetHeight(image))), + CGImageGetWidth(image), CGImageGetHeight(image)); - // Quartz seems to copy A8 surfaces incorrectly if we don't initialize them - // to transparent first. - if (mFormat == SurfaceFormat::A8) { - CGContextClearRect(mCg, flippedRect); - } - CGContextDrawImage(mCg, flippedRect, image); - - CGContextRestoreGState(mCg); - CGImageRelease(image); + // Quartz seems to copy A8 surfaces incorrectly if we don't initialize them + // to transparent first. + if (mFormat == SurfaceFormat::A8) { + CGContextClearRect(mCg, flippedRect); } + CGContextDrawImage(mCg, flippedRect, image); + + CGContextRestoreGState(mCg); + CGImageRelease(image); } void From cff9cc5d906200bc591d91007da7a1efe0110dab Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 12 Jun 2015 10:17:38 +0800 Subject: [PATCH 27/49] Bug 1169126 - Part 2: Add webgl reftest for captureStream(). r=jgilbert --HG-- extra : rebase_source : b1e6fdb1638d217eca2167a6d5b9e7974887d3e5 --- dom/canvas/test/reftest/reftest.list | 3 ++ .../reftest/webgl-capturestream-test.html | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 dom/canvas/test/reftest/webgl-capturestream-test.html diff --git a/dom/canvas/test/reftest/reftest.list b/dom/canvas/test/reftest/reftest.list index f5b1626a555c..be126f60dfd2 100644 --- a/dom/canvas/test/reftest/reftest.list +++ b/dom/canvas/test/reftest/reftest.list @@ -19,6 +19,9 @@ pref(webgl.force-layers-readback,true) == webgl-clear-test.html?readback wrappe # Check that resize works: == webgl-resize-test.html wrapper.html?green.png +# Check that captureStream() displays in a local video element +pref(canvas.capturestream.enabled,true) skip-if(winWidget&&layersGPUAccelerated&&d2d) == webgl-capturestream-test.html?preserve wrapper.html?green.png + # Some of the failure conditions are a little crazy. I'm (jgilbert) setting these based on # failures encountered when running on Try, and then targetting the Try config by # differences in the `sandbox` contents. That is, I'm labeling based on symptoms rather diff --git a/dom/canvas/test/reftest/webgl-capturestream-test.html b/dom/canvas/test/reftest/webgl-capturestream-test.html new file mode 100644 index 000000000000..9a86d555978b --- /dev/null +++ b/dom/canvas/test/reftest/webgl-capturestream-test.html @@ -0,0 +1,50 @@ + + + + + + + + + + + + + +
+ + + From 9252440209b769d85fc3b43754b5a3e7ddf968c1 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 12 Jun 2015 10:17:25 +0800 Subject: [PATCH 28/49] Bug 1169126 - Part 3: Add canvas 2d reftest for captureStream(). r=gw280 --HG-- extra : rebase_source : 6744ae086ffdea49f2584fef6f53326eeff4ee19 --- dom/canvas/test/reftest/capturestream.html | 35 ++++++++++++++++++++++ dom/canvas/test/reftest/reftest.list | 3 ++ 2 files changed, 38 insertions(+) create mode 100644 dom/canvas/test/reftest/capturestream.html diff --git a/dom/canvas/test/reftest/capturestream.html b/dom/canvas/test/reftest/capturestream.html new file mode 100644 index 000000000000..06b590507fd1 --- /dev/null +++ b/dom/canvas/test/reftest/capturestream.html @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + diff --git a/dom/canvas/test/reftest/reftest.list b/dom/canvas/test/reftest/reftest.list index be126f60dfd2..9a9d9d6a5cb3 100644 --- a/dom/canvas/test/reftest/reftest.list +++ b/dom/canvas/test/reftest/reftest.list @@ -155,3 +155,6 @@ skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-color-test.html?nat # focus rings pref(canvas.focusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawFocusIfNeeded.html drawFocusIfNeeded-ref.html pref(canvas.customfocusring.enabled,true) skip-if(B2G) skip-if(Android&&AndroidVersion<15,8,500) skip-if(winWidget) needs-focus == drawCustomFocusRing.html drawCustomFocusRing-ref.html + +# Check that captureStream() displays in a local video element +pref(canvas.capturestream.enabled,true) fails-if(B2G) skip-if(winWidget&&layersGPUAccelerated&&d2d) == capturestream.html wrapper.html?green.png From 550b948a29b35157e94fec407f62294822b6c4c9 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 12 Jun 2015 18:56:27 +0800 Subject: [PATCH 29/49] Bug 1173656 - Disallow TrackID reuse in TrackUnionStream. r=roc --HG-- extra : rebase_source : 6183d00ddb28a78276469bfbf817a8641baf2cc9 --- dom/media/TrackUnionStream.cpp | 32 ++++++++++++++++---------------- dom/media/TrackUnionStream.h | 9 +++++++++ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/dom/media/TrackUnionStream.cpp b/dom/media/TrackUnionStream.cpp index 5771d883ccff..76940dcf3289 100644 --- a/dom/media/TrackUnionStream.cpp +++ b/dom/media/TrackUnionStream.cpp @@ -46,7 +46,7 @@ PRLogModuleInfo* gTrackUnionStreamLog; #define STREAM_LOG(type, msg) MOZ_LOG(gTrackUnionStreamLog, type, msg) TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : - ProcessedMediaStream(aWrapper) + ProcessedMediaStream(aWrapper), mNextAvailableTrackID(1) { if (!gTrackUnionStreamLog) { gTrackUnionStreamLog = PR_NewLogModule("TrackUnionStream"); @@ -161,23 +161,23 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack, GraphTime aFrom) { - // Use the ID of the source track if it's not already assigned to a track, - // otherwise allocate a new unique ID. TrackID id = aTrack->GetID(); - TrackID maxTrackID = 0; - for (uint32_t i = 0; i < mTrackMap.Length(); ++i) { - TrackID outID = mTrackMap[i].mOutputTrackID; - maxTrackID = std::max(maxTrackID, outID); - } - // Note: we might have removed it here, but it might still be in the - // StreamBuffer if the TrackUnionStream sees its input stream flip from - // A to B, where both A and B have a track with the same ID - while (1) { - // search until we find one not in use here, and not in mBuffer - if (!mBuffer.FindTrack(id)) { - break; + if (id > mNextAvailableTrackID && + mUsedTracks.BinaryIndexOf(id) == mUsedTracks.NoIndex) { + // Input id available. Mark it used in mUsedTracks. + mUsedTracks.InsertElementSorted(id); + } else { + // Input id taken, allocate a new one. + id = mNextAvailableTrackID; + + // Update mNextAvailableTrackID and prune any mUsedTracks members it now + // covers. + while (1) { + if (!mUsedTracks.RemoveElementSorted(++mNextAvailableTrackID)) { + // Not in use. We're done. + break; + } } - id = ++maxTrackID; } // Round up the track start time so the track, if anything, starts a diff --git a/dom/media/TrackUnionStream.h b/dom/media/TrackUnionStream.h index 307e8b2b9e91..80e8b35c2c22 100644 --- a/dom/media/TrackUnionStream.h +++ b/dom/media/TrackUnionStream.h @@ -50,6 +50,8 @@ protected: nsAutoPtr mSegment; }; + // Add the track to this stream, retaining its TrackID if it has never + // been previously used in this stream, allocating a new TrackID otherwise. uint32_t AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack, GraphTime aFrom); void EndTrack(uint32_t aIndex); @@ -58,6 +60,13 @@ protected: bool* aOutputTrackFinished); nsTArray mTrackMap; + + // The next available TrackID, starting at 1 and progressing upwards. + // All TrackIDs in [1, mNextAvailableTrackID) have implicitly been used. + TrackID mNextAvailableTrackID; + + // Sorted array of used TrackIDs that require manual tracking. + nsTArray mUsedTracks; }; } From 3eccca01aac5160ed2fbacb4037fb3bcde9cedff Mon Sep 17 00:00:00 2001 From: Mike Shal Date: Mon, 15 Jun 2015 10:45:17 -0400 Subject: [PATCH 30/49] Bug 1173998 - use localized package for previous mar; r=nthomas --- tools/update-packaging/Makefile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/update-packaging/Makefile.in b/tools/update-packaging/Makefile.in index b7ae06b7e7a2..dc1e13f90851 100644 --- a/tools/update-packaging/Makefile.in +++ b/tools/update-packaging/Makefile.in @@ -81,7 +81,7 @@ endif automation-partial-patch: complete-patch rm -rf current current.work previous mkdir current previous - latestmar=$$(ssh -l $(UPLOAD_USER) -i $(UPLOAD_SSH_KEY) $(UPLOAD_HOST) 'ls -1t $(LATEST_MAR_DIR) | grep $(MOZ_PKG_PLATFORM).complete.mar$$ | head -n 1'); \ + latestmar=$$(ssh -l $(UPLOAD_USER) -i $(UPLOAD_SSH_KEY) $(UPLOAD_HOST) 'ls -1t $(LATEST_MAR_DIR) | grep "\.$(AB_CD)\.$(MOZ_PKG_PLATFORM)\.complete\.mar$$" | head -n 1'); \ if test -n "$$latestmar"; then \ wget -O $(STAGE_DIR)/previous.mar http://$(UPLOAD_HOST)/$(LATEST_MAR_DIR)/$$latestmar && \ (cd previous; \ @@ -90,7 +90,7 @@ automation-partial-patch: complete-patch MAR=$(MAR_BIN) perl $(topsrcdir)/tools/update-packaging/unwrap_full_update.pl '$(abspath $(DIST)/$(COMPLETE_MAR))') && \ find current -name \*.pgc -print -delete && \ find previous -name \*.pgc -print -delete && \ - rm -f $(STAGE_DIR)/*.partial.*.mar && \ + rm -f $(STAGE_DIR)/*.$(AB_CD).$(MOZ_PKG_PLATFORM).partial.*.mar && \ SRC_BUILD_ID=$$(python $(topsrcdir)/config/printconfigsetting.py $$(find previous -maxdepth 4 -type f -name application.ini) App BuildID) \ DST_BUILD_ID=$$(cat $(DEPTH)/config/buildid) \ SRC_BUILD=previous DST_BUILD=current \ From 6af80a2b57e7a6b317683ec6c4a34ebe4efb7361 Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Mon, 15 Jun 2015 16:50:59 +0200 Subject: [PATCH 31/49] Bug 1153872 - GetTabOffset should be high prio. r=jimm --- dom/ipc/PBrowser.ipdl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index 938176722559..46f300494923 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -310,7 +310,7 @@ parent: * * aPoint offset values in device pixels. */ - sync GetTabOffset() returns (LayoutDeviceIntPoint aPoint); + prio(high) sync GetTabOffset() returns (LayoutDeviceIntPoint aPoint); /** * Gets the DPI of the screen corresponding to this browser. From 616a34a8b61fbfcc558541247b09b461f9fdfa06 Mon Sep 17 00:00:00 2001 From: Mike Shal Date: Mon, 15 Jun 2015 11:02:47 -0400 Subject: [PATCH 32/49] No bug - bump mozharness.json to 526075bc2e35 --- testing/mozharness/mozharness.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/mozharness/mozharness.json b/testing/mozharness/mozharness.json index 7191abd1a54d..a06dc66080ff 100644 --- a/testing/mozharness/mozharness.json +++ b/testing/mozharness/mozharness.json @@ -1,4 +1,4 @@ { "repo": "https://hg.mozilla.org/build/mozharness", - "revision": "42a7a9e793f4" + "revision": "526075bc2e35" } From 415a18b516a17c6d922160a0d9e2347c67fd5c09 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Mon, 15 Jun 2015 17:04:24 +0200 Subject: [PATCH 33/49] Backed out changeset 2cba58b2e1b4 (bug 1100498) for m-oth js crashes --HG-- extra : rebase_source : 1f90cff0e3a790d034cd73a1641fbc9c89998a58 --- js/src/jsexn.cpp | 93 +++++++++++++------------------------------- js/src/jsfriendapi.h | 3 -- 2 files changed, 26 insertions(+), 70 deletions(-) diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 31b0ce509942..1b57d6ed2d16 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -681,83 +681,42 @@ ErrorReport::~ErrorReport() js_free(const_cast(ownedReport.ucmessage)); } -void -ErrorReport::ReportAddonExceptionToTelementry(JSContext* cx) -{ - MOZ_ASSERT(exnObject); - RootedObject unwrapped(cx, UncheckedUnwrap(exnObject)); - MOZ_ASSERT(unwrapped, "UncheckedUnwrap failed?"); - - // There is not much we can report if the exception is not an ErrorObject, let's ignore those. - if (!unwrapped->is()) - return; - - Rooted errObj(cx, &unwrapped->as()); - RootedObject stack(cx, errObj->stack()); - - // Let's ignore TOP level exceptions. For regular add-ons those will not be reported anyway, - // for SDK based once it should not be a valid case either. - // At this point the frame stack is unwound but the exception object stored the stack so let's - // use that for getting the function name. - if (!stack) - return; - - JSCompartment* comp = stack->compartment(); - JSAddonId* addonId = comp->addonId; - - // We only want to send the report if the scope that just have thrown belongs to an add-on. - // Let's check the compartment of the youngest function on the stack, to determine that. - if (!addonId) - return; - - RootedString funnameString(cx); - JS::SavedFrameResult result = GetSavedFrameFunctionDisplayName(cx, stack, &funnameString); - // AccessDenied should never be the case here for add-ons but let's not risk it. - JSAutoByteString bytes; - const char* funname = nullptr; - funname = result == JS::SavedFrameResult::AccessDenied ? "unknown" - : AtomToPrintableString(cx, - &funnameString->asAtom(), - &bytes); - - UniqueChars addonIdChars(JS_EncodeString(cx, addonId)); - - const char* filename = nullptr; - if (reportp && reportp->filename) { - filename = strrchr(reportp->filename, '/'); - if (filename) - filename++; - } - if (!filename) { - filename = "FILE_NOT_FOUND"; - } - char histogramKey[64]; - JS_snprintf(histogramKey, sizeof(histogramKey), - "%s %s %s %u", - addonIdChars.get(), - funname, - filename, - (reportp ? reportp->lineno : 0) ); - cx->runtime()->addTelemetry(JS_TELEMETRY_ADDON_EXCEPTIONS, 1, histogramKey); -} - bool ErrorReport::init(JSContext* cx, HandleValue exn) { MOZ_ASSERT(!cx->isExceptionPending()); + /* + * Because ToString below could error and an exception object could become + * unrooted, we must root our exception object, if any. + */ if (exn.isObject()) { - // Because ToString below could error and an exception object could become - // unrooted, we must root our exception object, if any. exnObject = &exn.toObject(); reportp = ErrorFromException(cx, exnObject); - // Let's see if the exception is from add-on code, if so, it should be reported - // to telementry. - ReportAddonExceptionToTelementry(cx); + JSCompartment* comp = exnObject->compartment(); + JSAddonId* addonId = comp->addonId; + if (addonId) { + UniqueChars addonIdChars(JS_EncodeString(cx, addonId)); + + const char* filename = nullptr; + if (reportp && reportp->filename) { + filename = strrchr(reportp->filename, '/'); + if (filename) + filename++; + } + if (!filename) { + filename = "FILE_NOT_FOUND"; + } + char histogramKey[64]; + JS_snprintf(histogramKey, sizeof(histogramKey), + "%s %s %u", + addonIdChars.get(), + filename, + (reportp ? reportp->lineno : 0) ); + cx->runtime()->addTelemetry(JS_TELEMETRY_ADDON_EXCEPTIONS, 1, histogramKey); + } } - - // Be careful not to invoke ToString if we've already successfully extracted // an error report, since the exception might be wrapped in a security // wrapper, and ToString-ing it might throw. diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index e825b3590c71..92b5320c2d4f 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1396,9 +1396,6 @@ struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport) bool populateUncaughtExceptionReport(JSContext* cx, ...); bool populateUncaughtExceptionReportVA(JSContext* cx, va_list ap); - // Reports exceptions from add-on scopes to telementry. - void ReportAddonExceptionToTelementry(JSContext* cx); - // We may have a provided JSErrorReport, so need a way to represent that. JSErrorReport* reportp; From 33d04280a407c24c7eb21fe7777b6705970c8ec6 Mon Sep 17 00:00:00 2001 From: Felipe Gomes Date: Mon, 15 Jun 2015 12:07:03 -0300 Subject: [PATCH 34/49] Bug 1173801 - Disable intermittent browser_privatebrowsing_DownloadLastDirWithCPS.js failing on Win8 64-bit. r=RyanVM --- browser/components/privatebrowsing/test/browser/browser.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/browser/components/privatebrowsing/test/browser/browser.ini b/browser/components/privatebrowsing/test/browser/browser.ini index 18bc27fafad3..74f2c2ca06b5 100644 --- a/browser/components/privatebrowsing/test/browser/browser.ini +++ b/browser/components/privatebrowsing/test/browser/browser.ini @@ -16,6 +16,7 @@ support-files = title.sjs [browser_privatebrowsing_DownloadLastDirWithCPS.js] +skip-if = (os == "win" && os_version == "6.2") # bug 1173801 [browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js] [browser_privatebrowsing_aboutSessionRestore.js] [browser_privatebrowsing_cache.js] From cd1ab886fdc85d39d060129012f45f298b29ed0a Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 15 Jun 2015 17:26:41 +0200 Subject: [PATCH 35/49] Bug 1174372 - Initialize ExecutableAllocator static fields in JS_Init. r=luke --- js/src/jit-test/tests/asm.js/bug1174372.js | 6 ++++++ js/src/jit/ExecutableAllocator.cpp | 22 ++++++++++++++++++++++ js/src/jit/ExecutableAllocator.h | 20 ++------------------ js/src/jsapi.cpp | 2 ++ 4 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 js/src/jit-test/tests/asm.js/bug1174372.js diff --git a/js/src/jit-test/tests/asm.js/bug1174372.js b/js/src/jit-test/tests/asm.js/bug1174372.js new file mode 100644 index 000000000000..e7031ea10468 --- /dev/null +++ b/js/src/jit-test/tests/asm.js/bug1174372.js @@ -0,0 +1,6 @@ +// |jit-test| --no-baseline; --non-writable-jitcode +(function(stdlib, foreign, heap) { + "use asm"; + function f() {} + return f; +})(); diff --git a/js/src/jit/ExecutableAllocator.cpp b/js/src/jit/ExecutableAllocator.cpp index 3de8e6b4a6c0..55ad6b6d69c8 100644 --- a/js/src/jit/ExecutableAllocator.cpp +++ b/js/src/jit/ExecutableAllocator.cpp @@ -48,6 +48,28 @@ ExecutablePool::~ExecutablePool() m_allocator->releasePoolPages(this); } +/* static */ void +ExecutableAllocator::initStatic() +{ + if (!pageSize) { + pageSize = determinePageSize(); + // On Windows, VirtualAlloc effectively allocates in 64K chunks. + // (Technically, it allocates in page chunks, but the starting + // address is always a multiple of 64K, so each allocation uses up + // 64K of address space.) So a size less than that would be + // pointless. But it turns out that 64KB is a reasonable size for + // all platforms. (This assumes 4KB pages.) On 64-bit windows, + // AllocateExecutableMemory prepends an extra page for structured + // exception handling data (see comments in function) onto whatever + // is passed in, so subtract one page here. +#if defined(JS_CPU_X64) && defined(XP_WIN) + largeAllocSize = pageSize * 15; +#else + largeAllocSize = pageSize * 16; +#endif + } +} + void ExecutableAllocator::addSizeOfCode(JS::CodeSizes* sizes) const { diff --git a/js/src/jit/ExecutableAllocator.h b/js/src/jit/ExecutableAllocator.h index f453c04c6aea..dc8d79b45342 100644 --- a/js/src/jit/ExecutableAllocator.h +++ b/js/src/jit/ExecutableAllocator.h @@ -182,24 +182,6 @@ class ExecutableAllocator ExecutableAllocator() : destroyCallback(nullptr) { - if (!pageSize) { - pageSize = determinePageSize(); - // On Windows, VirtualAlloc effectively allocates in 64K chunks. - // (Technically, it allocates in page chunks, but the starting - // address is always a multiple of 64K, so each allocation uses up - // 64K of address space.) So a size less than that would be - // pointless. But it turns out that 64KB is a reasonable size for - // all platforms. (This assumes 4KB pages.) On 64-bit windows, - // AllocateExecutableMemory prepends an extra page for structured - // exception handling data (see comments in function) onto whatever - // is passed in, so subtract one page here. -#if defined(JS_CPU_X64) && defined(XP_WIN) - largeAllocSize = pageSize * 15; -#else - largeAllocSize = pageSize * 16; -#endif - } - MOZ_ASSERT(m_smallPools.empty()); } @@ -263,6 +245,8 @@ class ExecutableAllocator this->destroyCallback = destroyCallback; } + static void initStatic(); + static bool nonWritableJitCode; private: diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index b6c00b2ab836..01861a22641c 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -552,6 +552,8 @@ JS_Init(void) if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init()) return false; + jit::ExecutableAllocator::initStatic(); + if (!jit::InitializeIon()) return false; From 6eec66f1161fb8fbe267c81826027a71046c7a31 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 15 Jun 2015 17:27:13 +0200 Subject: [PATCH 36/49] Bug 1174542 - Remove unnecessary AutoWritabeJitCode from initTraceLogger. r=luke --- js/src/jit-test/tests/tracelogger/bug1174542.js | 6 ++++++ js/src/jit/BaselineJIT.cpp | 1 - 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/tracelogger/bug1174542.js diff --git a/js/src/jit-test/tests/tracelogger/bug1174542.js b/js/src/jit-test/tests/tracelogger/bug1174542.js new file mode 100644 index 000000000000..283b6bebeff9 --- /dev/null +++ b/js/src/jit-test/tests/tracelogger/bug1174542.js @@ -0,0 +1,6 @@ +var du = new Debugger(); +if (typeof du.setupTraceLogger === "function") + du.setupTraceLogger({Scripts: true}); +(function() { + for (var i = 0; i < 15; ++i) {} +})(); diff --git a/js/src/jit/BaselineJIT.cpp b/js/src/jit/BaselineJIT.cpp index 247afaac4f62..91cb266d2d75 100644 --- a/js/src/jit/BaselineJIT.cpp +++ b/js/src/jit/BaselineJIT.cpp @@ -912,7 +912,6 @@ BaselineScript::initTraceLogger(JSRuntime* runtime, JSScript* script) traceLoggerScriptEvent_ = TraceLoggerEvent(logger, TraceLogger_Scripts); if (TraceLogTextIdEnabled(TraceLogger_Engine) || TraceLogTextIdEnabled(TraceLogger_Scripts)) { - AutoWritableJitCode awjc(method_); CodeLocationLabel enter(method_, CodeOffsetLabel(traceLoggerEnterToggleOffset_)); CodeLocationLabel exit(method_, CodeOffsetLabel(traceLoggerExitToggleOffset_)); Assembler::ToggleToCmp(enter); From 38c03284be5818f38c6ce6c020ff739a3ec34984 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Mon, 15 Jun 2015 17:28:10 +0200 Subject: [PATCH 37/49] Bug 977805 followup - Fix some issues with IonCache::reset reprotection. r=luke --- js/src/jit/Ion.cpp | 2 +- js/src/jit/IonCaches.cpp | 31 +++++++++++++++---------------- js/src/jit/IonCaches.h | 12 ++++++------ 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index c1ea1deb7be6..51397877341e 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1216,7 +1216,7 @@ IonScript::purgeCaches() AutoWritableJitCode awjc(method()); for (size_t i = 0; i < numCaches(); i++) - getCacheFromIndex(i).reset(); + getCacheFromIndex(i).reset(DontReprotect); } void diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 53a153d81a8c..a86eb30b831c 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -1667,7 +1667,7 @@ GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext* cx, HandleScript outerScri // code and we will not have the same generation again for this // object, so the generation check in the existing IC would always // fail anyway. - reset(); + reset(Reprotect); } Label failures; @@ -1992,9 +1992,9 @@ GetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex } void -GetPropertyIC::reset() +GetPropertyIC::reset(ReprotectCode reprotect) { - IonCache::reset(); + IonCache::reset(reprotect); hasTypedArrayLengthStub_ = false; hasSharedTypedArrayLengthStub_ = false; hasStrictArgumentsLengthStub_ = false; @@ -2003,18 +2003,17 @@ GetPropertyIC::reset() } void -IonCache::disable(IonScript* ion) +IonCache::disable() { - AutoWritableJitCode awjc(ion->method()); - reset(); + reset(Reprotect); this->disabled_ = 1; } void -IonCache::reset() +IonCache::reset(ReprotectCode reprotect) { this->stubCount_ = 0; - PatchJump(initialJump_, fallbackLabel_); + PatchJump(initialJump_, fallbackLabel_, reprotect); lastJump_ = initialJump_; } @@ -3219,7 +3218,7 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex } else { MOZ_ASSERT(shadows == DoesntShadow || shadows == DoesntShadowUnique); if (shadows == DoesntShadowUnique) - cache.reset(); + cache.reset(Reprotect); if (!cache.attachDOMProxyUnshadowed(cx, outerScript, ion, obj, returnAddr)) return false; addedSetterStub = true; @@ -3323,9 +3322,9 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex } void -SetPropertyIC::reset() +SetPropertyIC::reset(ReprotectCode reprotect) { - IonCache::reset(); + IonCache::reset(reprotect); hasGenericProxyStub_ = false; } @@ -4037,7 +4036,7 @@ GetElementIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, cache.incFailedUpdates(); if (cache.shouldDisable()) { JitSpew(JitSpew_IonIC, "Disable inline cache"); - cache.disable(ion); + cache.disable(); } } else { cache.resetFailedUpdates(); @@ -4049,9 +4048,9 @@ GetElementIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, } void -GetElementIC::reset() +GetElementIC::reset(ReprotectCode reprotect) { - IonCache::reset(); + IonCache::reset(reprotect); hasDenseStub_ = false; hasStrictArgumentsStub_ = false; hasNormalArgumentsStub_ = false; @@ -4388,9 +4387,9 @@ SetElementIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex, } void -SetElementIC::reset() +SetElementIC::reset(ReprotectCode reprotect) { - IonCache::reset(); + IonCache::reset(reprotect); hasDenseStub_ = false; } diff --git a/js/src/jit/IonCaches.h b/js/src/jit/IonCaches.h index 72ef0819af29..cbe999cf6bb9 100644 --- a/js/src/jit/IonCaches.h +++ b/js/src/jit/IonCaches.h @@ -243,7 +243,7 @@ class IonCache { } - void disable(IonScript* ion); + void disable(); inline bool isDisabled() const { return disabled_; } @@ -269,7 +269,7 @@ class IonCache void updateBaseAddress(JitCode* code, MacroAssembler& masm); // Reset the cache around garbage collection. - virtual void reset(); + virtual void reset(ReprotectCode reprotect); bool canAttachStub() const { return stubCount_ < MAX_STUBS; @@ -412,7 +412,7 @@ class GetPropertyIC : public IonCache CACHE_HEADER(GetProperty) - void reset(); + void reset(ReprotectCode reprotect); Register object() const { return object_; @@ -547,7 +547,7 @@ class SetPropertyIC : public IonCache CACHE_HEADER(SetProperty) - void reset(); + void reset(ReprotectCode reprotect); Register object() const { return object_; @@ -641,7 +641,7 @@ class GetElementIC : public IonCache CACHE_HEADER(GetElement) - void reset(); + void reset(ReprotectCode reprotect); Register object() const { return object_; @@ -750,7 +750,7 @@ class SetElementIC : public IonCache CACHE_HEADER(SetElement) - void reset(); + void reset(ReprotectCode reprotect); Register object() const { return object_; From 037cbe67479dd2ec842c9f6d360ab8bcd0fedfcf Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Wed, 3 Jun 2015 09:00:50 -0700 Subject: [PATCH 38/49] Bug 1173864 - Make MarkStack private in GCMarker; r=jonco --HG-- extra : rebase_source : 00fafca6dc9ac4890d31a686658cc6a62bfbe3d8 --- js/src/gc/Marking.cpp | 4 ++-- js/src/gc/Marking.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index ec73db6963d8..39134f362b30 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1230,8 +1230,8 @@ GCMarker::processMarkStackTop(SliceBudget& budget) case SavedValueArrayTag: { MOZ_ASSERT(!(addr & CellMask)); JSObject* obj = reinterpret_cast(addr); - HeapValue* vp; - HeapValue* end; + HeapSlot* vp; + HeapSlot* end; if (restoreValueArray(obj, (void**)&vp, (void**)&end)) pushValueArray(&obj->as(), vp, end); else diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index 6ac96f75c329..b57bd86a810a 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -195,9 +195,6 @@ class GCMarker : public JSTracer bool shouldCheckCompartments() { return strictCompartmentChecking; } #endif - /* This is public exclusively for ScanRope. */ - MarkStack stack; - private: #ifdef DEBUG void checkZone(void* p); @@ -257,7 +254,7 @@ class GCMarker : public JSTracer delayMarkingChildren(ptr); } - void pushValueArray(JSObject* obj, void* start, void* end) { + void pushValueArray(JSObject* obj, HeapSlot* start, HeapSlot* end) { checkZone(obj); MOZ_ASSERT(start <= end); @@ -281,6 +278,9 @@ class GCMarker : public JSTracer void saveValueRanges(); inline void processMarkStackTop(SliceBudget& budget); + /* The mark stack. Pointers in this stack are "gray" in the GC sense. */ + MarkStack stack; + /* The color is only applied to objects and functions. */ uint32_t color; From 7afa7dfb049799736fe8032d5c291eaac7f03af5 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Thu, 11 Jun 2015 10:03:33 -0700 Subject: [PATCH 39/49] Bug 1173889 - Strongly type the CallbackTracer dispatch function; r=jonco, r=mccr8 --HG-- extra : rebase_source : 413319f0701f8e92b8fc1c79a51f4a09c2c5cd39 --- dom/bindings/BindingUtils.h | 2 +- js/public/HeapAPI.h | 5 +- js/public/TraceKind.h | 52 ++++++++++++ js/public/TracingAPI.h | 110 ++++++++++++------------- js/public/UbiNode.h | 2 +- js/src/builtin/TestingFunctions.cpp | 4 +- js/src/gc/GCInternals.h | 10 ++- js/src/gc/Marking.cpp | 22 ++--- js/src/gc/RootMarking.cpp | 12 +-- js/src/gc/Tracer.cpp | 11 +-- js/src/gc/Verifier.cpp | 18 ++-- js/src/jsapi-tests/testGCMarking.cpp | 8 +- js/src/jsfriendapi.cpp | 8 +- js/src/jsgc.cpp | 27 ++---- js/src/moz.build | 3 +- js/src/vm/UbiNode.cpp | 8 +- xpcom/base/CycleCollectedJSRuntime.cpp | 49 +++++------ 17 files changed, 194 insertions(+), 157 deletions(-) create mode 100644 js/public/TraceKind.h diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 142293152fd8..d94b97a9b128 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -534,7 +534,7 @@ struct VerifyTraceProtoAndIfaceCacheCalledTracer : public JS::CallbackTracer : JS::CallbackTracer(rt), ok(false) {} - void trace(void** thingp, JS::TraceKind kind) override { + void onChild(const JS::GCCellPtr&) override { // We don't do anything here, we only want to verify that // TraceProtoAndIfaceCache was called. } diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 61fdcfc026f6..8b6487b84d9a 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -9,7 +9,9 @@ #include -#include "js/TracingAPI.h" +#include "jspubtd.h" + +#include "js/TraceKind.h" #include "js/Utility.h" /* These values are private to the JS engine. */ @@ -165,6 +167,7 @@ class JS_FRIEND_API(GCCellPtr) explicit GCCellPtr(JSFunction* fun) : ptr(checkedCast(fun, JS::TraceKind::Object)) { } explicit GCCellPtr(JSString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { } explicit GCCellPtr(JSFlatString* str) : ptr(checkedCast(str, JS::TraceKind::String)) { } + explicit GCCellPtr(JS::Symbol* sym) : ptr(checkedCast(sym, JS::TraceKind::Symbol)) { } explicit GCCellPtr(JSScript* script) : ptr(checkedCast(script, JS::TraceKind::Script)) { } explicit GCCellPtr(const Value& v); diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h new file mode 100644 index 000000000000..272f577399eb --- /dev/null +++ b/js/public/TraceKind.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * 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/. */ + +#ifndef js_TraceKind_h +#define js_TraceKind_h + +namespace JS { + +// When tracing a thing, the GC needs to know about the layout of the object it +// is looking at. There are a fixed number of different layouts that the GC +// knows about. The "trace kind" is a static map which tells which layout a GC +// thing has. +// +// Although this map is public, the details are completely hidden. Not all of +// the matching C++ types are exposed, and those that are, are opaque. +// +// See Value::gcKind() and JSTraceCallback in Tracer.h for more details. +enum class TraceKind +{ + // These trace kinds have a publicly exposed, although opaque, C++ type. + // Note: The order here is determined by our Value packing. Other users + // should sort alphabetically, for consistency. + Object = 0x00, + String = 0x01, + Symbol = 0x02, + Script = 0x03, + + // Shape details are exposed through JS_TraceShapeCycleCollectorChildren. + Shape = 0x04, + + // ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren. + ObjectGroup = 0x05, + + // The kind associated with a nullptr. + Null = 0x06, + + // The following kinds do not have an exposed C++ idiom. + BaseShape = 0x0F, + JitCode = 0x1F, + LazyScript = 0x2F +}; +const static uintptr_t OutOfLineTraceKindMask = 0x07; +static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set"); +static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set"); +static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set"); + +} // namespace JS + +#endif // js_TraceKind_h diff --git a/js/public/TracingAPI.h b/js/public/TracingAPI.h index 7a2ba8441e3f..af0182112e36 100644 --- a/js/public/TracingAPI.h +++ b/js/public/TracingAPI.h @@ -8,9 +8,10 @@ #define js_TracingAPI_h #include "jsalloc.h" -#include "jspubtd.h" #include "js/HashTable.h" +#include "js/HeapAPI.h" +#include "js/TraceKind.h" class JS_PUBLIC_API(JSTracer); @@ -19,66 +20,20 @@ class JS_PUBLIC_API(CallbackTracer); template class Heap; template class TenuredHeap; -// When tracing a thing, the GC needs to know about the layout of the object it -// is looking at. There are a fixed number of different layouts that the GC -// knows about. The "trace kind" is a static map which tells which layout a GC -// thing has. -// -// Although this map is public, the details are completely hidden. Not all of -// the matching C++ types are exposed, and those that are, are opaque. -// -// See Value::gcKind() and JSTraceCallback in Tracer.h for more details. -enum class TraceKind -{ - // These trace kinds have a publicly exposed, although opaque, C++ type. - // Note: The order here is determined by our Value packing. Other users - // should sort alphabetically, for consistency. - Object = 0x00, - String = 0x01, - Symbol = 0x02, - Script = 0x03, - - // Shape details are exposed through JS_TraceShapeCycleCollectorChildren. - Shape = 0x04, - - // ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren. - ObjectGroup = 0x05, - - // The kind associated with a nullptr. - Null = 0x06, - - // The following kinds do not have an exposed C++ idiom. - BaseShape = 0x0F, - JitCode = 0x1F, - LazyScript = 0x2F -}; -const static uintptr_t OutOfLineTraceKindMask = 0x07; -static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set"); -static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set"); -static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set"); - // Returns a static string equivalent of |kind|. JS_FRIEND_API(const char*) GCTraceKindToAscii(JS::TraceKind kind); } // namespace JS -// Tracer callback, called for each traceable thing directly referenced by a -// particular object or runtime structure. It is the callback responsibility -// to ensure the traversal of the full object graph via calling eventually -// JS_TraceChildren on the passed thing. In this case the callback must be -// prepared to deal with cycles in the traversal graph. -// -// kind argument is one of JS::TraceKind::Object, JS::TraceKind::String or a -// tag denoting internal implementation-specific traversal kind. In the latter -// case the only operations on thing that the callback can do is to call -// JS_TraceChildren or JS_GetTraceThingInfo. -// -// If eagerlyTraceWeakMaps is true, when we trace a WeakMap visit all -// of its mappings. This should be used in cases where the tracer -// wants to use the existing liveness of entries. -typedef void -(* JSTraceCallback)(JS::CallbackTracer* trc, void** thingp, JS::TraceKind kind); +namespace js { +class BaseShape; +class LazyScript; +class ObjectGroup; +namespace jit { +class JitCode; +} // namespace jit +} // namespace js enum WeakMapTraceKind { DoNotTraceWeakMaps = 0, @@ -132,8 +87,34 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr) {} - // Override this method to receive notification when an edge is visited. - virtual void trace(void** thing, JS::TraceKind kind) = 0; + // Override these methods to receive notification when an edge is visited + // with the type contained in the callback. The default implementation + // dispatches to the fully-generic onChild implementation, so for cases that + // do not care about boxing overhead and do not need the actual edges, + // just override the generic onChild. + virtual void onObjectEdge(JSObject** objp) { onChild(JS::GCCellPtr(*objp)); } + virtual void onStringEdge(JSString** strp) { onChild(JS::GCCellPtr(*strp)); } + virtual void onSymbolEdge(JS::Symbol** symp) { onChild(JS::GCCellPtr(*symp)); } + virtual void onScriptEdge(JSScript** scriptp) { onChild(JS::GCCellPtr(*scriptp)); } + virtual void onShapeEdge(js::Shape** shapep) { + onChild(JS::GCCellPtr(*shapep, JS::TraceKind::Shape)); + } + virtual void onObjectGroupEdge(js::ObjectGroup** groupp) { + onChild(JS::GCCellPtr(*groupp, JS::TraceKind::ObjectGroup)); + } + virtual void onBaseShapeEdge(js::BaseShape** basep) { + onChild(JS::GCCellPtr(*basep, JS::TraceKind::BaseShape)); + } + virtual void onJitCodeEdge(js::jit::JitCode** codep) { + onChild(JS::GCCellPtr(*codep, JS::TraceKind::JitCode)); + } + virtual void onLazyScriptEdge(js::LazyScript** lazyp) { + onChild(JS::GCCellPtr(*lazyp, JS::TraceKind::LazyScript)); + } + + // Override this method to receive notification when a node in the GC + // heap graph is visited. + virtual void onChild(const JS::GCCellPtr& thing) = 0; // Access to the tracing context: // When tracing with a JS::CallbackTracer, we invoke the callback with the @@ -185,6 +166,21 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer virtual TracerKind getTracerKind() const { return TracerKind::DoNotCare; } #endif + // In C++, overriding a method hides all methods in the base class with + // that name, not just methods with that signature. Thus, the typed edge + // methods have to have distinct names to allow us to override them + // individually, which is freqently useful if, for example, we only want to + // process only one type of edge. + void dispatchToOnEdge(JSObject** objp) { onObjectEdge(objp); } + void dispatchToOnEdge(JSString** strp) { onStringEdge(strp); } + void dispatchToOnEdge(JS::Symbol** symp) { onSymbolEdge(symp); } + void dispatchToOnEdge(JSScript** scriptp) { onScriptEdge(scriptp); } + void dispatchToOnEdge(js::Shape** shapep) { onShapeEdge(shapep); } + void dispatchToOnEdge(js::ObjectGroup** groupp) { onObjectGroupEdge(groupp); } + void dispatchToOnEdge(js::BaseShape** basep) { onBaseShapeEdge(basep); } + void dispatchToOnEdge(js::jit::JitCode** codep) { onJitCodeEdge(codep); } + void dispatchToOnEdge(js::LazyScript** lazyp) { onLazyScriptEdge(lazyp); } + private: friend class AutoTracingName; const char* contextName_; diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index 595badb21aee..3bda6e33e5c9 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -331,7 +331,7 @@ class Node { // JS::ubi::Node are both essentially tagged references to other sorts of // objects, so letting conversions happen automatically is appropriate. MOZ_IMPLICIT Node(JS::HandleValue value); - Node(JS::TraceKind kind, void* ptr); + explicit Node(const JS::GCCellPtr& thing); // copy construction and copy assignment just use memcpy, since we know // instances contain nothing but a vtable pointer and a data pointer. diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 9883f63486ee..ff0038358a7e 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -808,8 +808,8 @@ class HasChildTracer : public JS::CallbackTracer RootedValue child_; bool found_; - void trace(void** thingp, JS::TraceKind kind) { - if (*thingp == child_.toGCThing()) + void onChild(const JS::GCCellPtr& thing) override { + if (thing.asCell() == child_.toGCThing()) found_ = true; } diff --git a/js/src/gc/GCInternals.h b/js/src/gc/GCInternals.h index 7ba99885d3b3..0c07eace0195 100644 --- a/js/src/gc/GCInternals.h +++ b/js/src/gc/GCInternals.h @@ -138,9 +138,15 @@ void CheckHashTablesAfterMovingGC(JSRuntime* rt); #endif -struct MovingTracer : JS::CallbackTracer { +struct MovingTracer : JS::CallbackTracer +{ explicit MovingTracer(JSRuntime* rt) : CallbackTracer(rt, TraceWeakMapKeysValues) {} - void trace(void** thingp, JS::TraceKind kind) override; + + void onObjectEdge(JSObject** objp) override; + void onChild(const JS::GCCellPtr& thing) override { + MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing.asCell())); + } + #ifdef DEBUG TracerKind getTracerKind() const override { return TracerKind::Moving; } #endif diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 39134f362b30..1239671bbd29 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2278,9 +2278,9 @@ TypeSet::MarkTypeUnbarriered(JSTracer* trc, TypeSet::Type* v, const char* name) #ifdef DEBUG struct AssertNonGrayTracer : public JS::CallbackTracer { explicit AssertNonGrayTracer(JSRuntime* rt) : JS::CallbackTracer(rt) {} - void trace(void** thingp, JS::TraceKind kind) override { - DebugOnly thing(static_cast(*thingp)); - MOZ_ASSERT_IF(thing->isTenured(), !thing->asTenured().isMarked(js::gc::GRAY)); + void onChild(const JS::GCCellPtr& thing) override { + MOZ_ASSERT_IF(thing.asCell()->isTenured(), + !thing.asCell()->asTenured().isMarked(js::gc::GRAY)); } }; #endif @@ -2305,7 +2305,7 @@ struct UnmarkGrayTracer : public JS::CallbackTracer unmarkedAny(false) {} - void trace(void** thingp, JS::TraceKind kind) override; + void onChild(const JS::GCCellPtr& thing) override; /* True iff we are tracing the immediate children of a shape. */ bool tracingShape; @@ -2348,7 +2348,7 @@ struct UnmarkGrayTracer : public JS::CallbackTracer * containers. */ void -UnmarkGrayTracer::trace(void** thingp, JS::TraceKind kind) +UnmarkGrayTracer::onChild(const JS::GCCellPtr& thing) { int stackDummy; if (!JS_CHECK_STACK_SIZE(runtime()->mainThread.nativeStackLimit[StackForSystemCode], @@ -2362,14 +2362,14 @@ UnmarkGrayTracer::trace(void** thingp, JS::TraceKind kind) return; } - Cell* cell = static_cast(*thingp); + Cell* cell = thing.asCell(); // Cells in the nursery cannot be gray, and therefore must necessarily point // to only black edges. if (!cell->isTenured()) { #ifdef DEBUG AssertNonGrayTracer nongray(runtime()); - TraceChildren(&nongray, cell, kind); + TraceChildren(&nongray, cell, thing.kind()); #endif return; } @@ -2386,16 +2386,16 @@ UnmarkGrayTracer::trace(void** thingp, JS::TraceKind kind) // The parent will later trace |tenured|. This is done to avoid increasing // the stack depth during shape tracing. It is safe to do because a shape // can only have one child that is a shape. - UnmarkGrayTracer childTracer(this, kind == JS::TraceKind::Shape); + UnmarkGrayTracer childTracer(this, thing.kind() == JS::TraceKind::Shape); - if (kind != JS::TraceKind::Shape) { - TraceChildren(&childTracer, &tenured, kind); + if (thing.kind() != JS::TraceKind::Shape) { + TraceChildren(&childTracer, &tenured, thing.kind()); MOZ_ASSERT(!childTracer.previousShape); unmarkedAny |= childTracer.unmarkedAny; return; } - MOZ_ASSERT(kind == JS::TraceKind::Shape); + MOZ_ASSERT(thing.kind() == JS::TraceKind::Shape); Shape* shape = static_cast(&tenured); if (tracingShape) { MOZ_ASSERT(!previousShape); diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index bb0681fc402b..7be17d2b755c 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -552,7 +552,7 @@ class BufferGrayRootsTracer : public JS::CallbackTracer // Set to false if we OOM while buffering gray roots. bool bufferingGrayRootsFailed; - void trace(void** thingp, JS::TraceKind kind) override; + void onChild(const JS::GCCellPtr& thing) override; public: explicit BufferGrayRootsTracer(JSRuntime* rt) @@ -605,24 +605,24 @@ struct SetMaybeAliveFunctor { }; void -BufferGrayRootsTracer::trace(void** thingp, JS::TraceKind kind) +BufferGrayRootsTracer::onChild(const JS::GCCellPtr& thing) { MOZ_ASSERT(runtime()->isHeapBusy()); if (bufferingGrayRootsFailed) return; - gc::TenuredCell* thing = gc::TenuredCell::fromPointer(*thingp); + gc::TenuredCell* tenured = gc::TenuredCell::fromPointer(thing.asCell()); - Zone* zone = thing->zone(); + Zone* zone = tenured->zone(); if (zone->isCollecting()) { // See the comment on SetMaybeAliveFlag to see why we only do this for // objects and scripts. We rely on gray root buffering for this to work, // but we only need to worry about uncollected dead compartments during // incremental GCs (when we do gray root buffering). - CallTyped(SetMaybeAliveFunctor(), thing, kind); + CallTyped(SetMaybeAliveFunctor(), tenured, thing.kind()); - if (!zone->gcGrayRoots.append(thing)) + if (!zone->gcGrayRoots.append(tenured)) bufferingGrayRootsFailed = true; } } diff --git a/js/src/gc/Tracer.cpp b/js/src/gc/Tracer.cpp index de204785d502..4a4aeb8e72ea 100644 --- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -46,9 +46,8 @@ T DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name) { CheckTracedThing(trc, *thingp); - JS::TraceKind kind = MapTypeToTraceKind::Type>::kind; JS::AutoTracingName ctx(trc, name); - trc->trace(reinterpret_cast(thingp), kind); + trc->dispatchToOnEdge(thingp); return *thingp; } #define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type, _) \ @@ -322,21 +321,19 @@ struct ObjectGroupCycleCollectorTracer : public JS::CallbackTracer innerTracer(innerTracer) {} - void trace(void** thingp, JS::TraceKind kind) override; + void onChild(const JS::GCCellPtr& thing) override; JS::CallbackTracer* innerTracer; Vector seen, worklist; }; void -ObjectGroupCycleCollectorTracer::trace(void** thingp, JS::TraceKind kind) +ObjectGroupCycleCollectorTracer::onChild(const JS::GCCellPtr& thing) { - JS::GCCellPtr thing(*thingp, kind); - if (thing.isObject() || thing.isScript()) { // Invoke the inner cycle collector callback on this child. It will not // recurse back into TraceChildren. - innerTracer->trace(thingp, kind); + innerTracer->onChild(thing); return; } diff --git a/js/src/gc/Verifier.cpp b/js/src/gc/Verifier.cpp index 0225d9c7f871..363c666133de 100644 --- a/js/src/gc/Verifier.cpp +++ b/js/src/gc/Verifier.cpp @@ -81,7 +81,7 @@ class js::VerifyPreTracer : public JS::CallbackTracer { JS::AutoDisableGenerationalGC noggc; - void trace(void** thingp, JS::TraceKind kind) override; + void onChild(const JS::GCCellPtr& thing) override; public: /* The gcNumber when the verification began. */ @@ -112,9 +112,9 @@ class js::VerifyPreTracer : public JS::CallbackTracer * node. */ void -VerifyPreTracer::trace(void** thingp, JS::TraceKind kind) +VerifyPreTracer::onChild(const JS::GCCellPtr& thing) { - MOZ_ASSERT(!IsInsideNursery(*reinterpret_cast(thingp))); + MOZ_ASSERT(!IsInsideNursery(thing.asCell())); edgeptr += sizeof(EdgeValue); if (edgeptr >= term) { @@ -125,8 +125,8 @@ VerifyPreTracer::trace(void** thingp, JS::TraceKind kind) VerifyNode* node = curnode; uint32_t i = node->count; - node->edges[i].thing = *thingp; - node->edges[i].kind = kind; + node->edges[i].thing = thing.asCell(); + node->edges[i].kind = thing.kind(); node->edges[i].label = contextName(); node->count++; } @@ -252,7 +252,7 @@ IsMarkedOrAllocated(TenuredCell* cell) struct CheckEdgeTracer : public JS::CallbackTracer { VerifyNode* node; explicit CheckEdgeTracer(JSRuntime* rt) : JS::CallbackTracer(rt), node(nullptr) {} - void trace(void** thingp, JS::TraceKind kind) override; + void onChild(const JS::GCCellPtr& thing) override; }; static const uint32_t MAX_VERIFIER_EDGES = 1000; @@ -265,15 +265,15 @@ static const uint32_t MAX_VERIFIER_EDGES = 1000; * been modified) must point to marked objects. */ void -CheckEdgeTracer::trace(void** thingp, JS::TraceKind kind) +CheckEdgeTracer::onChild(const JS::GCCellPtr& thing) { /* Avoid n^2 behavior. */ if (node->count > MAX_VERIFIER_EDGES) return; for (uint32_t i = 0; i < node->count; i++) { - if (node->edges[i].thing == *thingp) { - MOZ_ASSERT(node->edges[i].kind == kind); + if (node->edges[i].thing == thing.asCell()) { + MOZ_ASSERT(node->edges[i].kind == thing.kind()); node->edges[i].thing = nullptr; return; } diff --git a/js/src/jsapi-tests/testGCMarking.cpp b/js/src/jsapi-tests/testGCMarking.cpp index 980ee09391fd..fd3eea1449f8 100644 --- a/js/src/jsapi-tests/testGCMarking.cpp +++ b/js/src/jsapi-tests/testGCMarking.cpp @@ -8,16 +8,16 @@ #include "jsapi-tests/tests.h" class CCWTestTracer : public JS::CallbackTracer { - void trace(void** thingp, JS::TraceKind kind) { + void onChild(const JS::GCCellPtr& thing) override { numberOfThingsTraced++; - printf("*thingp = %p\n", *thingp); + printf("*thingp = %p\n", thing.asCell()); printf("*expectedThingp = %p\n", *expectedThingp); - printf("kind = %d\n", static_cast(kind)); + printf("kind = %d\n", static_cast(thing.kind())); printf("expectedKind = %d\n", static_cast(expectedKind)); - if (*thingp != *expectedThingp || kind != expectedKind) + if (thing.asCell() != *expectedThingp || thing.kind() != expectedKind) okay = false; } diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 32b36d43b15a..cd625e1edd3e 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -904,7 +904,7 @@ struct DumpHeapTracer : public JS::CallbackTracer, public WeakMapTracer map, key.asCell(), kdelegate, value.asCell()); } - void trace(void** thingp, JS::TraceKind kind) override; + void onChild(const JS::GCCellPtr& thing) override; }; static char @@ -958,14 +958,14 @@ DumpHeapVisitCell(JSRuntime* rt, void* data, void* thing, } void -DumpHeapTracer::trace(void** thingp, JS::TraceKind kind) +DumpHeapTracer::onChild(const JS::GCCellPtr& thing) { - if (gc::IsInsideNursery((js::gc::Cell*)*thingp)) + if (gc::IsInsideNursery(thing.asCell())) return; char buffer[1024]; getTracingEdgeName(buffer, sizeof(buffer)); - fprintf(output, "%s%p %c %s\n", prefix, *thingp, MarkDescriptor(*thingp), buffer); + fprintf(output, "%s%p %c %s\n", prefix, thing.asCell(), MarkDescriptor(thing.asCell()), buffer); } void diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index eafd362940f3..971b65ca9923 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2207,19 +2207,10 @@ GCRuntime::relocateArenas(Zone* zone, JS::gcreason::Reason reason, SliceBudget& } void -MovingTracer::trace(void** thingp, JS::TraceKind kind) +MovingTracer::onObjectEdge(JSObject** objp) { - TenuredCell* thing = TenuredCell::fromPointer(*thingp); - - // Currently we only relocate objects. - if (kind != JS::TraceKind::Object) { - MOZ_ASSERT(!RelocationOverlay::isCellForwarded(thing)); - return; - } - - JSObject* obj = reinterpret_cast(thing); - if (IsForwarded(obj)) - *thingp = Forwarded(obj); + if (IsForwarded(*objp)) + *objp = Forwarded(*objp); } void @@ -3677,7 +3668,7 @@ GCRuntime::shouldPreserveJITCode(JSCompartment* comp, int64_t currentTime, #ifdef DEBUG class CompartmentCheckTracer : public JS::CallbackTracer { - void trace(void** thingp, JS::TraceKind kind) override; + void onChild(const JS::GCCellPtr& thing) override; public: explicit CompartmentCheckTracer(JSRuntime* rt) @@ -3720,17 +3711,17 @@ struct MaybeCompartmentFunctor { }; void -CompartmentCheckTracer::trace(void** thingp, JS::TraceKind kind) +CompartmentCheckTracer::onChild(const JS::GCCellPtr& thing) { - TenuredCell* thing = TenuredCell::fromPointer(*thingp); + TenuredCell* tenured = TenuredCell::fromPointer(thing.asCell()); - JSCompartment* comp = CallTyped(MaybeCompartmentFunctor(), thing, kind); + JSCompartment* comp = CallTyped(MaybeCompartmentFunctor(), tenured, thing.kind()); if (comp && compartment) { MOZ_ASSERT(comp == compartment || runtime()->isAtomsCompartment(comp) || (srcKind == JS::TraceKind::Object && - InCrossCompartmentMap(static_cast(src), thing, kind))); + InCrossCompartmentMap(static_cast(src), tenured, thing.kind()))); } else { - MOZ_ASSERT(thing->zone() == zone || thing->zone()->isAtomsZone()); + MOZ_ASSERT(tenured->zone() == zone || tenured->zone()->isAtomsZone()); } } diff --git a/js/src/moz.build b/js/src/moz.build index d7c93b679419..ff0efa4ae8e3 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -31,7 +31,7 @@ with Files('jit/**'): for gcfile in ['jsgc*', 'devtools/rootAnalysis', 'devtools/gc-ubench', 'devtools/gctrace']: with Files(gcfile): BUG_COMPONENT = component_gc -for header in ('GCAPI.h', 'HeapAPI.h', 'RootingAPI.h', 'SliceBudget.h', 'TracingAPI.h', 'WeakMapPtr.h'): +for header in ('GCAPI.h', 'HeapAPI.h', 'RootingAPI.h', 'SliceBudget.h', 'TraceKind.h', 'TracingAPI.h', 'WeakMapPtr.h'): with Files('../public/' + header): BUG_COMPONENT = component_gc @@ -122,6 +122,7 @@ EXPORTS.js += [ '../public/RootingAPI.h', '../public/SliceBudget.h', '../public/StructuredClone.h', + '../public/TraceKind.h', '../public/TracingAPI.h', '../public/TrackedOptimizationInfo.h', '../public/TypeDecls.h', diff --git a/js/src/vm/UbiNode.cpp b/js/src/vm/UbiNode.cpp index 53efbc41eea8..c2d25e55b42f 100644 --- a/js/src/vm/UbiNode.cpp +++ b/js/src/vm/UbiNode.cpp @@ -65,9 +65,9 @@ struct Node::ConstructFunctor : public js::BoolDefaultAdaptor { template bool operator()(T* t, Node* node) { node->construct(t); return true; } }; -Node::Node(JS::TraceKind kind, void* ptr) +Node::Node(const JS::GCCellPtr &thing) { - js::gc::CallTyped(ConstructFunctor(), ptr, kind, this); + js::gc::CallTyped(ConstructFunctor(), thing.asCell(), thing.kind(), this); } Node::Node(HandleValue value) @@ -111,7 +111,7 @@ class SimpleEdgeVectorTracer : public JS::CallbackTracer { // True if we should populate the edge's names. bool wantNames; - void trace(void** thingp, JS::TraceKind kind) { + void onChild(const JS::GCCellPtr& thing) override { if (!okay) return; @@ -139,7 +139,7 @@ class SimpleEdgeVectorTracer : public JS::CallbackTracer { // ownership of name; if the append succeeds, the vector element // then takes ownership; if the append fails, then the temporary // retains it, and its destructor will free it. - if (!vec->append(mozilla::Move(SimpleEdge(name16, Node(kind, *thingp))))) { + if (!vec->append(mozilla::Move(SimpleEdge(name16, Node(thing))))) { okay = false; return; } diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 57aeb51b45fc..00d8f10b52b3 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -128,7 +128,7 @@ struct NoteWeakMapChildrenTracer : public JS::CallbackTracer mKey(nullptr), mKeyDelegate(nullptr) { } - void trace(void** aThingp, JS::TraceKind aKind) override; + void onChild(const JS::GCCellPtr& aThing) override; nsCycleCollectionNoteRootCallback& mCb; bool mTracedAny; JSObject* mMap; @@ -137,23 +137,21 @@ struct NoteWeakMapChildrenTracer : public JS::CallbackTracer }; void -NoteWeakMapChildrenTracer::trace(void** aThingp, JS::TraceKind aKind) +NoteWeakMapChildrenTracer::onChild(const JS::GCCellPtr& aThing) { - JS::GCCellPtr thing(*aThingp, aKind); - - if (thing.isString()) { + if (aThing.isString()) { return; } - if (!JS::GCThingIsMarkedGray(thing) && !mCb.WantAllTraces()) { + if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) { return; } - if (AddToCCKind(thing.kind())) { - mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, thing); + if (AddToCCKind(aThing.kind())) { + mCb.NoteWeakMapping(mMap, mKey, mKeyDelegate, aThing); mTracedAny = true; } else { - JS_TraceChildren(this, thing.asCell(), thing.kind()); + JS_TraceChildren(this, aThing.asCell(), aThing.kind()); } } @@ -359,15 +357,15 @@ struct TraversalTracer : public JS::CallbackTracer : JS::CallbackTracer(aRt, DoNotTraceWeakMaps), mCb(aCb) { } - void trace(void** aThingp, JS::TraceKind aTraceKind) override; + void onChild(const JS::GCCellPtr& aThing) override; nsCycleCollectionTraversalCallback& mCb; }; -static void -NoteJSChild(TraversalTracer* aTrc, JS::GCCellPtr aThing) +void +TraversalTracer::onChild(const JS::GCCellPtr& aThing) { // Don't traverse non-gray objects, unless we want all traces. - if (!JS::GCThingIsMarkedGray(aThing) && !aTrc->mCb.WantAllTraces()) { + if (!JS::GCThingIsMarkedGray(aThing) && !mCb.WantAllTraces()) { return; } @@ -379,42 +377,35 @@ NoteJSChild(TraversalTracer* aTrc, JS::GCCellPtr aThing) * use special APIs to handle such chains iteratively. */ if (AddToCCKind(aThing.kind())) { - if (MOZ_UNLIKELY(aTrc->mCb.WantDebugInfo())) { + if (MOZ_UNLIKELY(mCb.WantDebugInfo())) { char buffer[200]; - aTrc->getTracingEdgeName(buffer, sizeof(buffer)); - aTrc->mCb.NoteNextEdgeName(buffer); + getTracingEdgeName(buffer, sizeof(buffer)); + mCb.NoteNextEdgeName(buffer); } if (aThing.isObject()) { - aTrc->mCb.NoteJSObject(aThing.toObject()); + mCb.NoteJSObject(aThing.toObject()); } else { - aTrc->mCb.NoteJSScript(aThing.toScript()); + mCb.NoteJSScript(aThing.toScript()); } } else if (aThing.isShape()) { // The maximum depth of traversal when tracing a Shape is unbounded, due to // the parent pointers on the shape. - JS_TraceShapeCycleCollectorChildren(aTrc, aThing); + JS_TraceShapeCycleCollectorChildren(this, aThing); } else if (aThing.isObjectGroup()) { // The maximum depth of traversal when tracing an ObjectGroup is unbounded, // due to information attached to the groups which can lead other groups to // be traced. - JS_TraceObjectGroupCycleCollectorChildren(aTrc, aThing); + JS_TraceObjectGroupCycleCollectorChildren(this, aThing); } else if (!aThing.isString()) { - JS_TraceChildren(aTrc, aThing.asCell(), aThing.kind()); + JS_TraceChildren(this, aThing.asCell(), aThing.kind()); } } -void -TraversalTracer::trace(void** aThingp, JS::TraceKind aTraceKind) -{ - JS::GCCellPtr thing(*aThingp, aTraceKind); - NoteJSChild(this, thing); -} - static void NoteJSChildGrayWrapperShim(void* aData, JS::GCCellPtr aThing) { TraversalTracer* trc = static_cast(aData); - NoteJSChild(trc, aThing); + trc->onChild(aThing); } /* From a50e7d609c01b0bdc554788ae94c4c98b7e2e6d5 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 15 Jun 2015 16:42:42 +0100 Subject: [PATCH 40/49] Bug 952139 - Enable MessagePort/MessageChannel by default, r=smaug --- .../tests/test_messageChannel_pref.html | 12 +++++++++--- modules/libpref/init/all.js | 3 +++ .../meta/html/dom/interfaces.html.ini | 18 ------------------ ...hannel_MessagePort_initial_disabled.htm.ini | 6 ------ ...Channel_MessagePort_onmessage_start.htm.ini | 6 ------ .../Channel_postMessage_DataCloneErr.htm.ini | 5 ----- .../Channel_postMessage_clone_port.htm.ini | 6 ------ ...hannel_postMessage_clone_port_error.htm.ini | 5 ----- ...hannel_postMessage_event_properties.htm.ini | 6 ------ ...el_postMessage_ports_readonly_array.htm.ini | 3 +-- .../Channel_postMessage_target_source.htm.ini | 6 ------ .../Transferred_objects_unusable.sub.htm.ini | 9 --------- .../meta/webmessaging/event.ports.sub.htm.ini | 9 --------- .../webmessaging/message-channels/001.html.ini | 5 ----- .../webmessaging/message-channels/002.html.ini | 5 ----- .../webmessaging/message-channels/003.html.ini | 5 ----- .../webmessaging/message-channels/004.html.ini | 5 ----- .../postMessage_MessagePorts_sorigin.htm.ini | 9 --------- ...ostMessage_MessagePorts_xorigin.sub.htm.ini | 9 --------- .../webmessaging/without-ports/023.html.ini | 5 ----- .../webmessaging/without-ports/024.html.ini | 5 ----- .../webmessaging/without-ports/025.html.ini | 8 -------- .../MessagePort_initial_disabled.htm.ini | 6 ------ .../MessagePort_onmessage_start.htm.ini | 6 ------ .../workers/postMessage_clone_port.htm.ini | 5 ----- .../postMessage_clone_port_error.htm.ini | 5 ----- .../postMessage_event_properties.htm.ini | 6 ------ .../postMessage_ports_readonly_array.htm.ini | 5 ----- .../workers/postMessage_target_source.htm.ini | 5 ----- .../semantics/multiple-workers/008.html.ini | 6 ------ 30 files changed, 13 insertions(+), 181 deletions(-) delete mode 100644 testing/web-platform/meta/webmessaging/Channel_MessagePort_initial_disabled.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/Channel_MessagePort_onmessage_start.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_DataCloneErr.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port_error.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_event_properties.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_target_source.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/Transferred_objects_unusable.sub.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/event.ports.sub.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/message-channels/001.html.ini delete mode 100644 testing/web-platform/meta/webmessaging/message-channels/002.html.ini delete mode 100644 testing/web-platform/meta/webmessaging/message-channels/003.html.ini delete mode 100644 testing/web-platform/meta/webmessaging/message-channels/004.html.ini delete mode 100644 testing/web-platform/meta/webmessaging/postMessage_MessagePorts_sorigin.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/postMessage_MessagePorts_xorigin.sub.htm.ini delete mode 100644 testing/web-platform/meta/webmessaging/without-ports/023.html.ini delete mode 100644 testing/web-platform/meta/webmessaging/without-ports/024.html.ini delete mode 100644 testing/web-platform/meta/webmessaging/without-ports/025.html.ini delete mode 100644 testing/web-platform/meta/workers/MessagePort_initial_disabled.htm.ini delete mode 100644 testing/web-platform/meta/workers/MessagePort_onmessage_start.htm.ini delete mode 100644 testing/web-platform/meta/workers/postMessage_clone_port.htm.ini delete mode 100644 testing/web-platform/meta/workers/postMessage_clone_port_error.htm.ini delete mode 100644 testing/web-platform/meta/workers/postMessage_event_properties.htm.ini delete mode 100644 testing/web-platform/meta/workers/postMessage_ports_readonly_array.htm.ini delete mode 100644 testing/web-platform/meta/workers/postMessage_target_source.htm.ini delete mode 100644 testing/web-platform/meta/workers/semantics/multiple-workers/008.html.ini diff --git a/dom/messagechannel/tests/test_messageChannel_pref.html b/dom/messagechannel/tests/test_messageChannel_pref.html index ab2c9385a8ce..4930fec3f5e1 100644 --- a/dom/messagechannel/tests/test_messageChannel_pref.html +++ b/dom/messagechannel/tests/test_messageChannel_pref.html @@ -28,9 +28,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=677638 SimpleTest.waitForExplicitFinish(); - runTest(false); - SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, - function() { runTest(true); SimpleTest.finish(); }); + SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", false]]}, + function() { + runTest(false); + SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, + function() { + runTest(true); + SimpleTest.finish(); + }); + }); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 16bd239bec74..7cd0d2d7c659 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4796,6 +4796,9 @@ pref("camera.control.low_memory_thresholdMB", 404); // UDPSocket API pref("dom.udpsocket.enabled", false); +// MessageChannel enabled by default. +pref("dom.messageChannel.enabled", true); + // Disable before keyboard events and after keyboard events by default. pref("dom.beforeAfterKeyboardEvent.enabled", false); diff --git a/testing/web-platform/meta/html/dom/interfaces.html.ini b/testing/web-platform/meta/html/dom/interfaces.html.ini index e880ab89333d..92350c684f68 100644 --- a/testing/web-platform/meta/html/dom/interfaces.html.ini +++ b/testing/web-platform/meta/html/dom/interfaces.html.ini @@ -2382,24 +2382,6 @@ [MessageEvent interface: operation initMessageEvent(DOMString,boolean,boolean,any,DOMString,DOMString,[object Object\],[object Object\],MessagePort)] expected: FAIL - [MessageChannel interface: existence and properties of interface object] - expected: FAIL - - [MessageChannel interface object length] - expected: FAIL - - [MessageChannel interface: existence and properties of interface prototype object] - expected: FAIL - - [MessageChannel interface: existence and properties of interface prototype object's "constructor" property] - expected: FAIL - - [MessageChannel interface: attribute port1] - expected: FAIL - - [MessageChannel interface: attribute port2] - expected: FAIL - [PortCollection interface: existence and properties of interface object] expected: FAIL diff --git a/testing/web-platform/meta/webmessaging/Channel_MessagePort_initial_disabled.htm.ini b/testing/web-platform/meta/webmessaging/Channel_MessagePort_initial_disabled.htm.ini deleted file mode 100644 index ea74c4361829..000000000000 --- a/testing/web-platform/meta/webmessaging/Channel_MessagePort_initial_disabled.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[Channel_MessagePort_initial_disabled.htm] - type: testharness - expected: ERROR - [Test Description: A port message queue can be enabled or disabled, and is initially disabled.] - expected: NOTRUN - diff --git a/testing/web-platform/meta/webmessaging/Channel_MessagePort_onmessage_start.htm.ini b/testing/web-platform/meta/webmessaging/Channel_MessagePort_onmessage_start.htm.ini deleted file mode 100644 index 7b1afa876601..000000000000 --- a/testing/web-platform/meta/webmessaging/Channel_MessagePort_onmessage_start.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[Channel_MessagePort_onmessage_start.htm] - type: testharness - expected: ERROR - [Test Description: The first time a MessagePort object's onmessage IDL attribute is set, the port's port message queue must be enabled, as if the start() method had been called.] - expected: NOTRUN - diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_DataCloneErr.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_DataCloneErr.htm.ini deleted file mode 100644 index dac8542ffff5..000000000000 --- a/testing/web-platform/meta/webmessaging/Channel_postMessage_DataCloneErr.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[Channel_postMessage_DataCloneErr.htm] - type: testharness - [Throw a DataCloneError when a host object (e.g. a DOM node) is used with postMessage.] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port.htm.ini deleted file mode 100644 index 9b25f27c07b8..000000000000 --- a/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[Channel_postMessage_clone_port.htm] - type: testharness - expected: ERROR - [Test Description: Test Description: When the user agent is to clone a port original port, with the clone being owned by owner, it must return a new MessagePort object] - expected: NOTRUN - diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port_error.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port_error.htm.ini deleted file mode 100644 index 330df924b0b2..000000000000 --- a/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port_error.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[Channel_postMessage_clone_port_error.htm] - type: testharness - [Test Description: Throw a DataCloneError if transfer array in postMessage contains source port.] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_event_properties.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_event_properties.htm.ini deleted file mode 100644 index cfc90a1f7483..000000000000 --- a/testing/web-platform/meta/webmessaging/Channel_postMessage_event_properties.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[Channel_postMessage_event_properties.htm] - type: testharness - expected: ERROR - [Test Description: The postMessage() method - Create an event that uses the MessageEvent interface, with the name message, which does not bubble and is not cancelable.] - expected: NOTRUN - diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_ports_readonly_array.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_ports_readonly_array.htm.ini index 5d2add90e3a1..68ba68685c7d 100644 --- a/testing/web-platform/meta/webmessaging/Channel_postMessage_ports_readonly_array.htm.ini +++ b/testing/web-platform/meta/webmessaging/Channel_postMessage_ports_readonly_array.htm.ini @@ -1,6 +1,5 @@ [Channel_postMessage_ports_readonly_array.htm] type: testharness - expected: ERROR [Test Description: The postMessage() method - Make new ports into a read only array.] - expected: NOTRUN + expected: FAIL diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_target_source.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_target_source.htm.ini deleted file mode 100644 index 5da2d69ac890..000000000000 --- a/testing/web-platform/meta/webmessaging/Channel_postMessage_target_source.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[Channel_postMessage_target_source.htm] - type: testharness - expected: ERROR - [Test Description: The postMessage() method - Let target port be the port with which source port is entangled, if any.] - expected: NOTRUN - diff --git a/testing/web-platform/meta/webmessaging/Transferred_objects_unusable.sub.htm.ini b/testing/web-platform/meta/webmessaging/Transferred_objects_unusable.sub.htm.ini deleted file mode 100644 index 3e560e05ba40..000000000000 --- a/testing/web-platform/meta/webmessaging/Transferred_objects_unusable.sub.htm.ini +++ /dev/null @@ -1,9 +0,0 @@ -[Transferred_objects_unusable.sub.htm] - type: testharness - expected: TIMEOUT - [Test Description: Objects listed in transfer are transferred, not just cloned, meaning that they are no longer usable on the sending side.] - expected: NOTRUN - - [MessageChannel is supported.] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/event.ports.sub.htm.ini b/testing/web-platform/meta/webmessaging/event.ports.sub.htm.ini deleted file mode 100644 index fcc0b8c4bc16..000000000000 --- a/testing/web-platform/meta/webmessaging/event.ports.sub.htm.ini +++ /dev/null @@ -1,9 +0,0 @@ -[event.ports.sub.htm] - type: testharness - expected: TIMEOUT - [Test Description: event.ports returns the MessagePort array sent with the message.] - expected: NOTRUN - - [MessageChannel is supported.] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/message-channels/001.html.ini b/testing/web-platform/meta/webmessaging/message-channels/001.html.ini deleted file mode 100644 index 6d8185315d36..000000000000 --- a/testing/web-platform/meta/webmessaging/message-channels/001.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[001.html] - type: testharness - [basic messagechannel test] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/message-channels/002.html.ini b/testing/web-platform/meta/webmessaging/message-channels/002.html.ini deleted file mode 100644 index 7ed4ac89cfbe..000000000000 --- a/testing/web-platform/meta/webmessaging/message-channels/002.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[002.html] - type: testharness - [without start()] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/message-channels/003.html.ini b/testing/web-platform/meta/webmessaging/message-channels/003.html.ini deleted file mode 100644 index 9041937757e0..000000000000 --- a/testing/web-platform/meta/webmessaging/message-channels/003.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[003.html] - type: testharness - [onmessage implied start()] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/message-channels/004.html.ini b/testing/web-platform/meta/webmessaging/message-channels/004.html.ini deleted file mode 100644 index 9a69457ce62d..000000000000 --- a/testing/web-platform/meta/webmessaging/message-channels/004.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[004.html] - type: testharness - [cross-document channel] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_sorigin.htm.ini b/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_sorigin.htm.ini deleted file mode 100644 index 08206d624c5a..000000000000 --- a/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_sorigin.htm.ini +++ /dev/null @@ -1,9 +0,0 @@ -[postMessage_MessagePorts_sorigin.htm] - type: testharness - expected: TIMEOUT - [Test Description: postMessage to same-origin iframe with MessagePort array containing 100 ports.] - expected: NOTRUN - - [MessageChannel is supported.] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_xorigin.sub.htm.ini b/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_xorigin.sub.htm.ini deleted file mode 100644 index b8924fed41cc..000000000000 --- a/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_xorigin.sub.htm.ini +++ /dev/null @@ -1,9 +0,0 @@ -[postMessage_MessagePorts_xorigin.sub.htm] - type: testharness - expected: TIMEOUT - [Test Description: postMessage to cross-origin iframe with MessagePort array containing 100 ports.] - expected: NOTRUN - - [MessageChannel is supported.] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/without-ports/023.html.ini b/testing/web-platform/meta/webmessaging/without-ports/023.html.ini deleted file mode 100644 index e3ef5e7a005d..000000000000 --- a/testing/web-platform/meta/webmessaging/without-ports/023.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[023.html] - type: testharness - [Object cloning: own properties only, don't follow prototype] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/without-ports/024.html.ini b/testing/web-platform/meta/webmessaging/without-ports/024.html.ini deleted file mode 100644 index 1e41c9bc68a3..000000000000 --- a/testing/web-platform/meta/webmessaging/without-ports/024.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[024.html] - type: testharness - [Object cloning: throw an exception if function values encountered] - expected: FAIL - diff --git a/testing/web-platform/meta/webmessaging/without-ports/025.html.ini b/testing/web-platform/meta/webmessaging/without-ports/025.html.ini deleted file mode 100644 index 35cd8304aa43..000000000000 --- a/testing/web-platform/meta/webmessaging/without-ports/025.html.ini +++ /dev/null @@ -1,8 +0,0 @@ -[025.html] - type: testharness - [MessagePort constructor properties] - expected: FAIL - - [Worker MessageChannel's port should be an instance of MessagePort] - expected: FAIL - diff --git a/testing/web-platform/meta/workers/MessagePort_initial_disabled.htm.ini b/testing/web-platform/meta/workers/MessagePort_initial_disabled.htm.ini deleted file mode 100644 index b73019ab98b6..000000000000 --- a/testing/web-platform/meta/workers/MessagePort_initial_disabled.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[MessagePort_initial_disabled.htm] - type: testharness - [ MessageChannel: port message queue is initially disabled ] - expected: FAIL - bug: https://bugzilla.mozilla.org/show_bug.cgi?id=952139 - diff --git a/testing/web-platform/meta/workers/MessagePort_onmessage_start.htm.ini b/testing/web-platform/meta/workers/MessagePort_onmessage_start.htm.ini deleted file mode 100644 index ad6a4484ea3a..000000000000 --- a/testing/web-platform/meta/workers/MessagePort_onmessage_start.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[MessagePort_onmessage_start.htm] - type: testharness - [ MessageChannel: port.onmessage enables message queue ] - expected: FAIL - bug: https://bugzilla.mozilla.org/show_bug.cgi?id=952139 - diff --git a/testing/web-platform/meta/workers/postMessage_clone_port.htm.ini b/testing/web-platform/meta/workers/postMessage_clone_port.htm.ini deleted file mode 100644 index 8065dc352276..000000000000 --- a/testing/web-platform/meta/workers/postMessage_clone_port.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[postMessage_clone_port.htm] - type: testharness - [ postMessage(): clone a port ] - expected: FAIL - diff --git a/testing/web-platform/meta/workers/postMessage_clone_port_error.htm.ini b/testing/web-platform/meta/workers/postMessage_clone_port_error.htm.ini deleted file mode 100644 index afc617adbfca..000000000000 --- a/testing/web-platform/meta/workers/postMessage_clone_port_error.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[postMessage_clone_port_error.htm] - type: testharness - [ postMessage(): cloning source port ] - expected: FAIL - diff --git a/testing/web-platform/meta/workers/postMessage_event_properties.htm.ini b/testing/web-platform/meta/workers/postMessage_event_properties.htm.ini deleted file mode 100644 index f757a6627716..000000000000 --- a/testing/web-platform/meta/workers/postMessage_event_properties.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[postMessage_event_properties.htm] - type: testharness - [ postMessage(): MessageEvent properties ] - expected: FAIL - bug: https://bugzilla.mozilla.org/show_bug.cgi?id=952139 - diff --git a/testing/web-platform/meta/workers/postMessage_ports_readonly_array.htm.ini b/testing/web-platform/meta/workers/postMessage_ports_readonly_array.htm.ini deleted file mode 100644 index aa4e1ca91c55..000000000000 --- a/testing/web-platform/meta/workers/postMessage_ports_readonly_array.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[postMessage_ports_readonly_array.htm] - type: testharness - [ postMessage(): read-only ports array ] - expected: FAIL - diff --git a/testing/web-platform/meta/workers/postMessage_target_source.htm.ini b/testing/web-platform/meta/workers/postMessage_target_source.htm.ini deleted file mode 100644 index b86366d8577f..000000000000 --- a/testing/web-platform/meta/workers/postMessage_target_source.htm.ini +++ /dev/null @@ -1,5 +0,0 @@ -[postMessage_target_source.htm] - type: testharness - [ postMessage(): target port and source port ] - expected: FAIL - diff --git a/testing/web-platform/meta/workers/semantics/multiple-workers/008.html.ini b/testing/web-platform/meta/workers/semantics/multiple-workers/008.html.ini deleted file mode 100644 index 30ef565a4a42..000000000000 --- a/testing/web-platform/meta/workers/semantics/multiple-workers/008.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[008.html] - type: testharness - expected: ERROR - [messagechannel in shared worker] - expected: TIMEOUT - From d9bbdbb005b5dc534dc93b446def6f8bfca0a7e1 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Mon, 15 Jun 2015 08:53:20 -0700 Subject: [PATCH 41/49] Bug 1173617. Don't cache titlebar caption sizes unless the widget has a titlebar. r=jimm --- widget/windows/nsUXThemeData.cpp | 12 +++++++++++- widget/windows/nsWindow.cpp | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/widget/windows/nsUXThemeData.cpp b/widget/windows/nsUXThemeData.cpp index 96d04b02d131..04b0f42e72fd 100644 --- a/widget/windows/nsUXThemeData.cpp +++ b/widget/windows/nsUXThemeData.cpp @@ -30,7 +30,8 @@ nsUXThemeData::sFlatMenus = false; bool nsUXThemeData::sTitlebarInfoPopulatedAero = false; bool nsUXThemeData::sTitlebarInfoPopulatedThemed = false; -SIZE nsUXThemeData::sCommandButtons[4]; +const int NUM_COMMAND_BUTTONS = 4; +SIZE nsUXThemeData::sCommandButtons[NUM_COMMAND_BUTTONS]; void nsUXThemeData::Teardown() { @@ -221,6 +222,15 @@ nsUXThemeData::UpdateTitlebarInfo(HWND aWnd) sCommandButtons[2].cx = info.rgrect[5].right - info.rgrect[5].left; sCommandButtons[2].cy = info.rgrect[5].bottom - info.rgrect[5].top; +#ifdef DEBUG + // Verify that all values for the command buttons are positive values + // otherwise we have cached bad values for the caption buttons + for (int i = 0; i < NUM_COMMAND_BUTTONS; i++) { + MOZ_ASSERT(sCommandButtons[i].cx > 0); + MOZ_ASSERT(sCommandButtons[i].cy > 0); + } +#endif + sTitlebarInfoPopulatedThemed = true; } diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 394892ba1315..ec1f72de0e59 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -458,6 +458,16 @@ int32_t nsWindow::GetHeight(int32_t aProposedHeight) return aProposedHeight; } +static bool +ShouldCacheTitleBarInfo(nsWindowType aWindowType, nsBorderStyle aBorderStyle) +{ + return (aWindowType == eWindowType_toplevel) && + (aBorderStyle == eBorderStyle_default || + aBorderStyle == eBorderStyle_all) && + (!nsUXThemeData::sTitlebarInfoPopulatedThemed || + !nsUXThemeData::sTitlebarInfoPopulatedAero); +} + // Create the proper widget nsresult nsWindow::Create(nsIWidget *aParent, @@ -645,10 +655,8 @@ nsWindow::Create(nsIWidget *aParent, } // Query for command button metric data for rendering the titlebar. We - // only do this once on the first window. - if (mWindowType == eWindowType_toplevel && - (!nsUXThemeData::sTitlebarInfoPopulatedThemed || - !nsUXThemeData::sTitlebarInfoPopulatedAero)) { + // only do this once on the first window that has an actual titlebar + if (ShouldCacheTitleBarInfo(mWindowType, mBorderStyle)) { nsUXThemeData::UpdateTitlebarInfo(mWnd); } From 0213fe8121322d6aefba750564d9dcdf402c715e Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 15 Jun 2015 11:55:30 -0400 Subject: [PATCH 42/49] Backed out changeset 6943b5034e0c (bug 1173656) for OSX crashes/asserts. --- dom/media/TrackUnionStream.cpp | 32 ++++++++++++++++---------------- dom/media/TrackUnionStream.h | 9 --------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/dom/media/TrackUnionStream.cpp b/dom/media/TrackUnionStream.cpp index 76940dcf3289..5771d883ccff 100644 --- a/dom/media/TrackUnionStream.cpp +++ b/dom/media/TrackUnionStream.cpp @@ -46,7 +46,7 @@ PRLogModuleInfo* gTrackUnionStreamLog; #define STREAM_LOG(type, msg) MOZ_LOG(gTrackUnionStreamLog, type, msg) TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : - ProcessedMediaStream(aWrapper), mNextAvailableTrackID(1) + ProcessedMediaStream(aWrapper) { if (!gTrackUnionStreamLog) { gTrackUnionStreamLog = PR_NewLogModule("TrackUnionStream"); @@ -161,23 +161,23 @@ TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) : uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack, GraphTime aFrom) { + // Use the ID of the source track if it's not already assigned to a track, + // otherwise allocate a new unique ID. TrackID id = aTrack->GetID(); - if (id > mNextAvailableTrackID && - mUsedTracks.BinaryIndexOf(id) == mUsedTracks.NoIndex) { - // Input id available. Mark it used in mUsedTracks. - mUsedTracks.InsertElementSorted(id); - } else { - // Input id taken, allocate a new one. - id = mNextAvailableTrackID; - - // Update mNextAvailableTrackID and prune any mUsedTracks members it now - // covers. - while (1) { - if (!mUsedTracks.RemoveElementSorted(++mNextAvailableTrackID)) { - // Not in use. We're done. - break; - } + TrackID maxTrackID = 0; + for (uint32_t i = 0; i < mTrackMap.Length(); ++i) { + TrackID outID = mTrackMap[i].mOutputTrackID; + maxTrackID = std::max(maxTrackID, outID); + } + // Note: we might have removed it here, but it might still be in the + // StreamBuffer if the TrackUnionStream sees its input stream flip from + // A to B, where both A and B have a track with the same ID + while (1) { + // search until we find one not in use here, and not in mBuffer + if (!mBuffer.FindTrack(id)) { + break; } + id = ++maxTrackID; } // Round up the track start time so the track, if anything, starts a diff --git a/dom/media/TrackUnionStream.h b/dom/media/TrackUnionStream.h index 80e8b35c2c22..307e8b2b9e91 100644 --- a/dom/media/TrackUnionStream.h +++ b/dom/media/TrackUnionStream.h @@ -50,8 +50,6 @@ protected: nsAutoPtr mSegment; }; - // Add the track to this stream, retaining its TrackID if it has never - // been previously used in this stream, allocating a new TrackID otherwise. uint32_t AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack, GraphTime aFrom); void EndTrack(uint32_t aIndex); @@ -60,13 +58,6 @@ protected: bool* aOutputTrackFinished); nsTArray mTrackMap; - - // The next available TrackID, starting at 1 and progressing upwards. - // All TrackIDs in [1, mNextAvailableTrackID) have implicitly been used. - TrackID mNextAvailableTrackID; - - // Sorted array of used TrackIDs that require manual tracking. - nsTArray mUsedTracks; }; } From aa072e5e64dcbe370643e96876be02892d35a444 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 15 Jun 2015 17:08:50 +0100 Subject: [PATCH 43/49] Bug 1170326 - nsHTMLCSSUtils::ParseLength should check if the input is an empty string, r=ehsan --- editor/libeditor/nsHTMLCSSUtils.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/editor/libeditor/nsHTMLCSSUtils.cpp b/editor/libeditor/nsHTMLCSSUtils.cpp index b20b91835dd4..6fc50dd1bf35 100644 --- a/editor/libeditor/nsHTMLCSSUtils.cpp +++ b/editor/libeditor/nsHTMLCSSUtils.cpp @@ -613,12 +613,19 @@ nsHTMLCSSUtils::GetDefaultLengthUnit(nsAString & aLengthUnit) } } -// Unfortunately, CSSStyleDeclaration::GetPropertyCSSValue is not yet implemented... -// We need then a way to determine the number part and the unit from aString, aString -// being the result of a GetPropertyValue query... +// Unfortunately, CSSStyleDeclaration::GetPropertyCSSValue is not yet +// implemented... We need then a way to determine the number part and the unit +// from aString, aString being the result of a GetPropertyValue query... void -nsHTMLCSSUtils::ParseLength(const nsAString & aString, float * aValue, nsIAtom ** aUnit) +nsHTMLCSSUtils::ParseLength(const nsAString& aString, float* aValue, + nsIAtom** aUnit) { + if (aString.IsEmpty()) { + *aValue = 0; + *aUnit = NS_NewAtom(aString).take(); + return; + } + nsAString::const_iterator iter; aString.BeginReading(iter); From ddad2ed2eb6d9f849867906ef3b453902018c824 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Mon, 15 Jun 2015 12:18:50 -0400 Subject: [PATCH 44/49] Bug 1173719 - Prevent crashes when passing touch events across the PBrowser interface with APZ disabled. r=botond --- dom/ipc/TabParent.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 18ac6be2224e..6723f96b7d68 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -2702,6 +2702,13 @@ TabParent::ApzAwareEventRoutingToChild(ScrollableLayerGuid* aOutTargetGuid, // Let the widget know that the event will be sent to the child process, // which will (hopefully) send a confirmation notice back to APZ. InputAPZContext::SetRoutedToChildProcess(); + } else { + if (aOutInputBlockId) { + *aOutInputBlockId = 0; + } + if (aOutApzResponse) { + *aOutApzResponse = nsEventStatus_eIgnore; + } } } From 5925a945d186c1aa9f26f6a1e42a5aa495b325a4 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Mon, 15 Jun 2015 12:30:34 -0400 Subject: [PATCH 45/49] Bug 1173983 - Use R8 textures for d3d11 alpha textures since it appears to be better supported. r=Bas --- gfx/2d/HelpersD2D.h | 1 + gfx/layers/IMFYCbCrImage.cpp | 2 +- gfx/layers/d3d11/CompositorD3D11.hlsl | 18 +- gfx/layers/d3d11/CompositorD3D11Shaders.h | 695 +++++++++++--------- gfx/layers/d3d11/CompositorD3D11ShadersVR.h | 162 ++--- gfx/layers/d3d11/TextureD3D11.cpp | 4 +- gfx/thebes/gfxWindowsPlatform.cpp | 18 +- 7 files changed, 475 insertions(+), 425 deletions(-) diff --git a/gfx/2d/HelpersD2D.h b/gfx/2d/HelpersD2D.h index 2b9d3c40b8c4..683f5f8859ba 100644 --- a/gfx/2d/HelpersD2D.h +++ b/gfx/2d/HelpersD2D.h @@ -127,6 +127,7 @@ static inline SurfaceFormat ToPixelFormat(const D2D1_PIXEL_FORMAT &aFormat) { switch(aFormat.format) { case DXGI_FORMAT_A8_UNORM: + case DXGI_FORMAT_R8_UNORM: return SurfaceFormat::A8; case DXGI_FORMAT_B8G8R8A8_UNORM: if (aFormat.alphaMode == D2D1_ALPHA_MODE_IGNORE) { diff --git a/gfx/layers/IMFYCbCrImage.cpp b/gfx/layers/IMFYCbCrImage.cpp index a7dd2404d506..c28f4cd8ed32 100644 --- a/gfx/layers/IMFYCbCrImage.cpp +++ b/gfx/layers/IMFYCbCrImage.cpp @@ -237,7 +237,7 @@ IMFYCbCrImage::GetTextureClient(CompositableClient* aClient) RefPtr ctx; device->GetImmediateContext(byRef(ctx)); - CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_A8_UNORM, + CD3D11_TEXTURE2D_DESC newDesc(DXGI_FORMAT_R8_UNORM, mData.mYSize.width, mData.mYSize.height, 1, 1); newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; diff --git a/gfx/layers/d3d11/CompositorD3D11.hlsl b/gfx/layers/d3d11/CompositorD3D11.hlsl index e5a586e8f347..c435da0a6d7a 100644 --- a/gfx/layers/d3d11/CompositorD3D11.hlsl +++ b/gfx/layers/d3d11/CompositorD3D11.hlsl @@ -159,14 +159,14 @@ VS_MASK_3D_OUTPUT LayerQuadMask3DVS(const VS_INPUT aVertex) float4 RGBAShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target { float2 maskCoords = aVertex.vMaskCoords; - float mask = tMask.Sample(sSampler, maskCoords).a; + float mask = tMask.Sample(sSampler, maskCoords).r; return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity * mask; } float4 RGBAShaderMask3D(const VS_MASK_3D_OUTPUT aVertex) : SV_Target { float2 maskCoords = aVertex.vMaskCoords.xy / aVertex.vMaskCoords.z; - float mask = tMask.Sample(LayerTextureSamplerLinear, maskCoords).a; + float mask = tMask.Sample(LayerTextureSamplerLinear, maskCoords).r; return tRGB.Sample(sSampler, aVertex.vTexCoords) * fLayerOpacity * mask; } @@ -177,7 +177,7 @@ float4 RGBShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target result.a = fLayerOpacity; float2 maskCoords = aVertex.vMaskCoords; - float mask = tMask.Sample(sSampler, maskCoords).a; + float mask = tMask.Sample(sSampler, maskCoords).r; return result * mask; } @@ -196,9 +196,9 @@ float4 CalculateYCbCrColor(const float2 aTexCoords) float4 yuv; float4 color; - yuv.r = tCr.Sample(sSampler, aTexCoords).a - 0.50196; - yuv.g = tY.Sample(sSampler, aTexCoords).a - 0.06275; - yuv.b = tCb.Sample(sSampler, aTexCoords).a - 0.50196; + yuv.r = tCr.Sample(sSampler, aTexCoords).r - 0.50196; + yuv.g = tY.Sample(sSampler, aTexCoords).r - 0.06275; + yuv.b = tCb.Sample(sSampler, aTexCoords).r - 0.50196; color.r = yuv.g * 1.16438 + yuv.r * 1.59603; color.g = yuv.g * 1.16438 - 0.81297 * yuv.r - 0.39176 * yuv.b; @@ -211,7 +211,7 @@ float4 CalculateYCbCrColor(const float2 aTexCoords) float4 YCbCrShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target { float2 maskCoords = aVertex.vMaskCoords; - float mask = tMask.Sample(sSampler, maskCoords).a; + float mask = tMask.Sample(sSampler, maskCoords).r; return CalculateYCbCrColor(aVertex.vTexCoords) * fLayerOpacity * mask; } @@ -225,7 +225,7 @@ PS_OUTPUT ComponentAlphaShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target result.vSrc.a = result.vAlpha.g; float2 maskCoords = aVertex.vMaskCoords; - float mask = tMask.Sample(sSampler, maskCoords).a; + float mask = tMask.Sample(sSampler, maskCoords).r; result.vSrc *= fLayerOpacity * mask; result.vAlpha *= fLayerOpacity * mask; @@ -235,7 +235,7 @@ PS_OUTPUT ComponentAlphaShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target float4 SolidColorShaderMask(const VS_MASK_OUTPUT aVertex) : SV_Target { float2 maskCoords = aVertex.vMaskCoords; - float mask = tMask.Sample(sSampler, maskCoords).a; + float mask = tMask.Sample(sSampler, maskCoords).r; return fLayerColor * mask; } diff --git a/gfx/layers/d3d11/CompositorD3D11Shaders.h b/gfx/layers/d3d11/CompositorD3D11Shaders.h index 18b99663296b..c525b9aa1827 100644 --- a/gfx/layers/d3d11/CompositorD3D11Shaders.h +++ b/gfx/layers/d3d11/CompositorD3D11Shaders.h @@ -1,6 +1,10 @@ #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11.hlsl -ELayerQuadVS +// -VnLayerQuadVS -FhtmpShaderHeader // // // Buffer Definitions: @@ -30,17 +34,17 @@ // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// POSITION 0 xy 0 NONE float xy +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// POSITION 0 xy 0 NONE float xy // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float xyzw -// TEXCOORD 0 xy 1 NONE float xy +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float xyzw +// TEXCOORD 0 xy 1 NONE float xy // // // Constant buffer to DX9 shader constant mappings: @@ -103,10 +107,10 @@ ret const BYTE LayerQuadVS[] = { - 68, 88, 66, 67, 200, 251, - 64, 251, 166, 240, 101, 137, - 191, 140, 75, 217, 9, 168, - 61, 163, 1, 0, 0, 0, + 68, 88, 66, 67, 26, 156, + 32, 249, 73, 220, 32, 91, + 64, 185, 136, 143, 133, 249, + 140, 206, 1, 0, 0, 0, 180, 6, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 152, 1, 0, 0, 160, 3, @@ -261,7 +265,7 @@ const BYTE LayerQuadVS[] = 65, 84, 116, 0, 0, 0, 13, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 12, 0, + 3, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, @@ -271,7 +275,7 @@ const BYTE LayerQuadVS[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -362,10 +366,10 @@ const BYTE LayerQuadVS[] = 41, 32, 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, - 105, 108, 101, 114, 32, 54, - 46, 51, 46, 57, 54, 48, - 48, 46, 49, 54, 51, 56, - 52, 0, 171, 171, 73, 83, + 105, 108, 101, 114, 32, 57, + 46, 50, 57, 46, 57, 53, + 50, 46, 51, 49, 49, 49, + 0, 171, 171, 171, 73, 83, 71, 78, 44, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 32, 0, 0, 0, @@ -392,7 +396,11 @@ const BYTE LayerQuadVS[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ESolidColorShader +// -VnSolidColorShader -FhtmpShaderHeader // // // Buffer Definitions: @@ -422,17 +430,17 @@ const BYTE LayerQuadVS[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -458,10 +466,10 @@ ret const BYTE SolidColorShader[] = { - 68, 88, 66, 67, 30, 148, - 104, 202, 165, 39, 58, 182, - 100, 205, 95, 195, 52, 137, - 197, 241, 1, 0, 0, 0, + 68, 88, 66, 67, 204, 8, + 5, 100, 51, 20, 107, 176, + 111, 165, 149, 245, 134, 187, + 83, 96, 1, 0, 0, 0, 224, 3, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 132, 0, 0, 0, 204, 0, @@ -597,9 +605,9 @@ const BYTE SolidColorShader[] = 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, - 114, 32, 54, 46, 51, 46, - 57, 54, 48, 48, 46, 49, - 54, 51, 56, 52, 0, 171, + 114, 32, 57, 46, 50, 57, + 46, 57, 53, 50, 46, 51, + 49, 49, 49, 0, 171, 171, 73, 83, 71, 78, 80, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 56, 0, @@ -627,7 +635,11 @@ const BYTE SolidColorShader[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBShader +// -VnRGBShader -FhtmpShaderHeader // // // Buffer Definitions: @@ -659,17 +671,17 @@ const BYTE SolidColorShader[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -713,10 +725,10 @@ ret const BYTE RGBShader[] = { - 68, 88, 66, 67, 239, 198, - 87, 206, 69, 92, 245, 30, - 125, 195, 239, 77, 37, 241, - 175, 187, 1, 0, 0, 0, + 68, 88, 66, 67, 20, 109, + 176, 198, 26, 112, 108, 185, + 246, 240, 143, 18, 57, 236, + 126, 68, 1, 0, 0, 0, 232, 4, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 204, 0, 0, 0, 136, 1, @@ -896,9 +908,9 @@ const BYTE RGBShader[] = 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, - 114, 32, 54, 46, 51, 46, - 57, 54, 48, 48, 46, 49, - 54, 51, 56, 52, 0, 171, + 114, 32, 57, 46, 50, 57, + 46, 57, 53, 50, 46, 51, + 49, 49, 49, 0, 171, 171, 73, 83, 71, 78, 80, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 56, 0, @@ -926,7 +938,11 @@ const BYTE RGBShader[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBAShader +// -VnRGBAShader -FhtmpShaderHeader // // // Buffer Definitions: @@ -958,17 +974,17 @@ const BYTE RGBShader[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -1010,10 +1026,10 @@ ret const BYTE RGBAShader[] = { - 68, 88, 66, 67, 230, 59, - 90, 23, 60, 77, 18, 113, - 14, 129, 183, 152, 233, 55, - 111, 42, 1, 0, 0, 0, + 68, 88, 66, 67, 214, 26, + 168, 112, 65, 151, 75, 99, + 196, 63, 136, 104, 158, 202, + 217, 7, 1, 0, 0, 0, 196, 4, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 192, 0, 0, 0, 100, 1, @@ -1187,9 +1203,9 @@ const BYTE RGBAShader[] = 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, - 114, 32, 54, 46, 51, 46, - 57, 54, 48, 48, 46, 49, - 54, 51, 56, 52, 0, 171, + 114, 32, 57, 46, 50, 57, + 46, 57, 53, 50, 46, 51, + 49, 49, 49, 0, 171, 171, 73, 83, 71, 78, 80, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 56, 0, @@ -1217,7 +1233,11 @@ const BYTE RGBAShader[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -EComponentAlphaShader +// -VnComponentAlphaShader -FhtmpShaderHeader // // // Buffer Definitions: @@ -1250,18 +1270,18 @@ const BYTE RGBAShader[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw -// SV_Target 1 xyzw 1 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// SV_Target 1 xyzw 1 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -1319,10 +1339,10 @@ ret const BYTE ComponentAlphaShader[] = { - 68, 88, 66, 67, 186, 162, - 72, 42, 69, 36, 160, 68, - 108, 121, 216, 238, 108, 37, - 6, 145, 1, 0, 0, 0, + 68, 88, 66, 67, 207, 238, + 180, 151, 111, 52, 137, 3, + 45, 243, 229, 223, 99, 172, + 89, 3, 1, 0, 0, 0, 68, 6, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 64, 1, 0, 0, 160, 2, @@ -1445,7 +1465,7 @@ const BYTE ComponentAlphaShader[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1556,9 +1576,9 @@ const BYTE ComponentAlphaShader[] = 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, - 114, 32, 54, 46, 51, 46, - 57, 54, 48, 48, 46, 49, - 54, 51, 56, 52, 0, 171, + 114, 32, 57, 46, 50, 57, + 46, 57, 53, 50, 46, 51, + 49, 49, 49, 0, 171, 171, 73, 83, 71, 78, 80, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 56, 0, @@ -1590,7 +1610,11 @@ const BYTE ComponentAlphaShader[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -EYCbCrShader +// -VnYCbCrShader -FhtmpShaderHeader // // // Buffer Definitions: @@ -1624,17 +1648,17 @@ const BYTE ComponentAlphaShader[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -1664,16 +1688,16 @@ const BYTE ComponentAlphaShader[] = dcl_2d s2 texld r0, t0, s0 texld r1, t0, s2 - add r0.x, r1.w, c1.x - mul r0.xy, r0.x, c1.zwzw - add r0.z, r0.w, c1.y - mad r0.y, r0.z, c2.x, -r0.y - mad r1.x, r0.z, c2.x, r0.x + add r0.y, r1.x, c1.x + mul r0.yz, r0.y, c1.xzww + add r0.x, r0.x, c1.y + mad r0.z, r0.x, c2.x, -r0.z + mad r1.x, r0.x, c2.x, r0.y texld r2, t0, s1 - add r0.x, r2.w, c1.x - mad r1.y, r0.x, -c2.z, r0.y - mul r0.x, r0.x, c2.y - mad r1.z, r0.z, c2.x, r0.x + add r0.y, r2.x, c1.x + mad r1.y, r0.y, -c2.z, r0.z + mul r0.y, r0.y, c2.y + mad r1.z, r0.x, c2.x, r0.y mov r1.w, c2.w mul r0, r1, c0.x mov oC0, r0 @@ -1689,14 +1713,14 @@ dcl_input_ps linear v1.xy dcl_output o0.xyzw dcl_temps 3 sample r0.xyzw, v1.xyxx, t2.xyzw, s0 -add r0.x, r0.w, l(-0.501960) +add r0.x, r0.x, l(-0.501960) mul r0.xy, r0.xxxx, l(1.596030, 0.812970, 0.000000, 0.000000) sample r1.xyzw, v1.xyxx, t0.xyzw, s0 -add r0.z, r1.w, l(-0.062750) +add r0.z, r1.x, l(-0.062750) mad r0.y, r0.z, l(1.164380), -r0.y mad r1.x, r0.z, l(1.164380), r0.x sample r2.xyzw, v1.xyxx, t1.xyzw, s0 -add r0.x, r2.w, l(-0.501960) +add r0.x, r2.x, l(-0.501960) mad r1.y, -r0.x, l(0.391760), r0.y mul r0.x, r0.x, l(2.017230) mad r1.z, r0.z, l(1.164380), r0.x @@ -1708,10 +1732,10 @@ ret const BYTE YCbCrShader[] = { - 68, 88, 66, 67, 181, 118, - 100, 53, 248, 120, 136, 92, - 59, 190, 18, 201, 139, 224, - 32, 141, 1, 0, 0, 0, + 68, 88, 66, 67, 54, 63, + 153, 7, 84, 231, 22, 28, + 117, 160, 57, 24, 123, 163, + 52, 109, 1, 0, 0, 0, 212, 7, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 220, 1, 0, 0, 44, 4, @@ -1751,35 +1775,35 @@ const BYTE YCbCrShader[] = 66, 0, 0, 3, 1, 0, 15, 128, 0, 0, 228, 176, 2, 8, 228, 160, 2, 0, - 0, 3, 0, 0, 1, 128, - 1, 0, 255, 128, 1, 0, + 0, 3, 0, 0, 2, 128, + 1, 0, 0, 128, 1, 0, 0, 160, 5, 0, 0, 3, - 0, 0, 3, 128, 0, 0, - 0, 128, 1, 0, 238, 160, + 0, 0, 6, 128, 0, 0, + 85, 128, 1, 0, 248, 160, 2, 0, 0, 3, 0, 0, - 4, 128, 0, 0, 255, 128, + 1, 128, 0, 0, 0, 128, 1, 0, 85, 160, 4, 0, - 0, 4, 0, 0, 2, 128, - 0, 0, 170, 128, 2, 0, - 0, 160, 0, 0, 85, 129, + 0, 4, 0, 0, 4, 128, + 0, 0, 0, 128, 2, 0, + 0, 160, 0, 0, 170, 129, 4, 0, 0, 4, 1, 0, - 1, 128, 0, 0, 170, 128, + 1, 128, 0, 0, 0, 128, 2, 0, 0, 160, 0, 0, - 0, 128, 66, 0, 0, 3, + 85, 128, 66, 0, 0, 3, 2, 0, 15, 128, 0, 0, 228, 176, 1, 8, 228, 160, 2, 0, 0, 3, 0, 0, - 1, 128, 2, 0, 255, 128, + 2, 128, 2, 0, 0, 128, 1, 0, 0, 160, 4, 0, 0, 4, 1, 0, 2, 128, - 0, 0, 0, 128, 2, 0, - 170, 161, 0, 0, 85, 128, + 0, 0, 85, 128, 2, 0, + 170, 161, 0, 0, 170, 128, 5, 0, 0, 3, 0, 0, - 1, 128, 0, 0, 0, 128, + 2, 128, 0, 0, 85, 128, 2, 0, 85, 160, 4, 0, 0, 4, 1, 0, 4, 128, - 0, 0, 170, 128, 2, 0, - 0, 160, 0, 0, 0, 128, + 0, 0, 0, 128, 2, 0, + 0, 160, 0, 0, 85, 128, 1, 0, 0, 2, 1, 0, 8, 128, 2, 0, 255, 160, 5, 0, 0, 3, 0, 0, @@ -1816,7 +1840,7 @@ const BYTE YCbCrShader[] = 16, 0, 0, 0, 0, 0, 0, 0, 0, 7, 18, 0, 16, 0, 0, 0, 0, 0, - 58, 0, 16, 0, 0, 0, + 10, 0, 16, 0, 0, 0, 0, 0, 1, 64, 0, 0, 115, 128, 0, 191, 56, 0, 0, 10, 50, 0, 16, 0, @@ -1833,7 +1857,7 @@ const BYTE YCbCrShader[] = 0, 96, 16, 0, 0, 0, 0, 0, 0, 0, 0, 7, 66, 0, 16, 0, 0, 0, - 0, 0, 58, 0, 16, 0, + 0, 0, 10, 0, 16, 0, 1, 0, 0, 0, 1, 64, 0, 0, 18, 131, 128, 189, 50, 0, 0, 10, 34, 0, @@ -1856,7 +1880,7 @@ const BYTE YCbCrShader[] = 0, 0, 0, 96, 16, 0, 0, 0, 0, 0, 0, 0, 0, 7, 18, 0, 16, 0, - 0, 0, 0, 0, 58, 0, + 0, 0, 0, 0, 10, 0, 16, 0, 2, 0, 0, 0, 1, 64, 0, 0, 115, 128, 0, 191, 50, 0, 0, 10, @@ -1890,7 +1914,7 @@ const BYTE YCbCrShader[] = 0, 0, 15, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, - 10, 0, 0, 0, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2016,9 +2040,9 @@ const BYTE YCbCrShader[] = 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, - 54, 46, 51, 46, 57, 54, - 48, 48, 46, 49, 54, 51, - 56, 52, 0, 171, 73, 83, + 57, 46, 50, 57, 46, 57, + 53, 50, 46, 51, 49, 49, + 49, 0, 171, 171, 73, 83, 71, 78, 80, 0, 0, 0, 2, 0, 0, 0, 8, 0, 0, 0, 56, 0, 0, 0, @@ -2045,7 +2069,11 @@ const BYTE YCbCrShader[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11.hlsl -ELayerQuadMaskVS +// -VnLayerQuadMaskVS -FhtmpShaderHeader // // // Buffer Definitions: @@ -2075,18 +2103,18 @@ const BYTE YCbCrShader[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// POSITION 0 xy 0 NONE float xy +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// POSITION 0 xy 0 NONE float xy // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float xyzw -// TEXCOORD 0 xy 1 NONE float xy -// TEXCOORD 1 zw 1 NONE float zw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float xyzw +// TEXCOORD 0 xy 1 NONE float xy +// TEXCOORD 1 zw 1 NONE float zw // // // Constant buffer to DX9 shader constant mappings: @@ -2158,10 +2186,10 @@ ret const BYTE LayerQuadMaskVS[] = { - 68, 88, 66, 67, 223, 251, - 10, 17, 13, 90, 47, 25, - 119, 198, 20, 157, 124, 193, - 251, 234, 1, 0, 0, 0, + 68, 88, 66, 67, 15, 196, + 252, 199, 211, 188, 92, 26, + 46, 113, 249, 29, 135, 110, + 83, 119, 1, 0, 0, 0, 120, 7, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 224, 1, 0, 0, 76, 4, @@ -2345,7 +2373,7 @@ const BYTE LayerQuadMaskVS[] = 116, 0, 0, 0, 16, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 4, 0, - 0, 0, 14, 0, 0, 0, + 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2446,9 +2474,9 @@ const BYTE LayerQuadMaskVS[] = 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, - 101, 114, 32, 54, 46, 51, - 46, 57, 54, 48, 48, 46, - 49, 54, 51, 56, 52, 0, + 101, 114, 32, 57, 46, 50, + 57, 46, 57, 53, 50, 46, + 51, 49, 49, 49, 0, 171, 171, 171, 73, 83, 71, 78, 44, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, @@ -2480,7 +2508,11 @@ const BYTE LayerQuadMaskVS[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11.hlsl -ELayerQuadMask3DVS +// -VnLayerQuadMask3DVS -FhtmpShaderHeader // // // Buffer Definitions: @@ -2510,18 +2542,18 @@ const BYTE LayerQuadMaskVS[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// POSITION 0 xy 0 NONE float xy +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// POSITION 0 xy 0 NONE float xy // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float xyzw -// TEXCOORD 0 xy 1 NONE float xy -// TEXCOORD 1 xyz 2 NONE float xyz +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float xyzw +// TEXCOORD 0 xy 1 NONE float xy +// TEXCOORD 1 xyz 2 NONE float xyz // // // Constant buffer to DX9 shader constant mappings: @@ -2597,10 +2629,10 @@ ret const BYTE LayerQuadMask3DVS[] = { - 68, 88, 66, 67, 151, 141, - 11, 11, 111, 244, 17, 242, - 119, 116, 248, 53, 235, 192, - 38, 193, 1, 0, 0, 0, + 68, 88, 66, 67, 100, 40, + 55, 29, 238, 71, 107, 78, + 214, 182, 73, 149, 138, 22, + 163, 187, 1, 0, 0, 0, 204, 7, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 24, 2, 0, 0, 160, 4, @@ -2798,7 +2830,7 @@ const BYTE LayerQuadMask3DVS[] = 116, 0, 0, 0, 17, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, - 0, 0, 15, 0, 0, 0, + 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2808,7 +2840,7 @@ const BYTE LayerQuadMask3DVS[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -2899,9 +2931,9 @@ const BYTE LayerQuadMask3DVS[] = 72, 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, - 101, 114, 32, 54, 46, 51, - 46, 57, 54, 48, 48, 46, - 49, 54, 51, 56, 52, 0, + 101, 114, 32, 57, 46, 50, + 57, 46, 57, 53, 50, 46, + 51, 49, 49, 49, 0, 171, 171, 171, 73, 83, 71, 78, 44, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, @@ -2933,7 +2965,11 @@ const BYTE LayerQuadMask3DVS[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ESolidColorShaderMask +// -VnSolidColorShaderMask -FhtmpShaderHeader // // // Buffer Definitions: @@ -2965,18 +3001,18 @@ const BYTE LayerQuadMask3DVS[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float -// TEXCOORD 1 zw 1 NONE float zw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float +// TEXCOORD 1 zw 1 NONE float zw // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -3000,7 +3036,7 @@ const BYTE LayerQuadMask3DVS[] = dcl_2d s0 mov r0.xy, t0.wzzw texld r0, r0, s0 - mul r0, r0.w, c0 + mul r0, r0.x, c0 mov oC0, r0 // approximately 4 instruction slots used (1 texture, 3 arithmetic) @@ -3012,17 +3048,17 @@ dcl_input_ps linear v1.zw dcl_output o0.xyzw dcl_temps 1 sample r0.xyzw, v1.zwzz, t3.xyzw, s0 -mul o0.xyzw, r0.wwww, cb0[0].xyzw +mul o0.xyzw, r0.xxxx, cb0[0].xyzw ret // Approximately 3 instruction slots used #endif const BYTE SolidColorShaderMask[] = { - 68, 88, 66, 67, 236, 109, - 19, 151, 23, 187, 157, 205, - 112, 188, 91, 187, 108, 106, - 138, 14, 1, 0, 0, 0, + 68, 88, 66, 67, 218, 73, + 87, 32, 206, 67, 79, 54, + 31, 104, 228, 152, 133, 115, + 245, 3, 1, 0, 0, 0, 232, 4, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 204, 0, 0, 0, 112, 1, @@ -3049,7 +3085,7 @@ const BYTE SolidColorShaderMask[] = 15, 128, 0, 0, 228, 128, 0, 8, 228, 160, 5, 0, 0, 3, 0, 0, 15, 128, - 0, 0, 255, 128, 0, 0, + 0, 0, 0, 128, 0, 0, 228, 160, 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 128, 255, 255, 0, 0, @@ -3076,7 +3112,7 @@ const BYTE SolidColorShaderMask[] = 0, 96, 16, 0, 0, 0, 0, 0, 56, 0, 0, 8, 242, 32, 16, 0, 0, 0, - 0, 0, 246, 15, 16, 0, + 0, 0, 6, 0, 16, 0, 0, 0, 0, 0, 70, 142, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, @@ -3198,9 +3234,9 @@ const BYTE SolidColorShaderMask[] = 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, - 114, 32, 54, 46, 51, 46, - 57, 54, 48, 48, 46, 49, - 54, 51, 56, 52, 0, 171, + 114, 32, 57, 46, 50, 57, + 46, 57, 53, 50, 46, 51, + 49, 49, 49, 0, 171, 171, 73, 83, 71, 78, 104, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 80, 0, @@ -3232,7 +3268,11 @@ const BYTE SolidColorShaderMask[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBShaderMask +// -VnRGBShaderMask -FhtmpShaderHeader // // // Buffer Definitions: @@ -3265,18 +3305,18 @@ const BYTE SolidColorShaderMask[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy -// TEXCOORD 1 zw 1 NONE float zw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// TEXCOORD 1 zw 1 NONE float zw // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -3305,7 +3345,7 @@ const BYTE SolidColorShaderMask[] = texld r0, r0, s0 mul r1.xyz, r1, c0.x mov r1.w, c0.x - mul r0, r0.w, r1 + mul r0, r0.x, r1 mov oC0, r0 // approximately 7 instruction slots used (2 texture, 5 arithmetic) @@ -3322,17 +3362,17 @@ sample r0.xyzw, v1.xyxx, t0.xyzw, s0 mul r0.xyz, r0.xyzx, cb0[1].xxxx sample r1.xyzw, v1.zwzz, t3.xyzw, s0 mov r0.w, cb0[1].x -mul o0.xyzw, r0.xyzw, r1.wwww +mul o0.xyzw, r0.xyzw, r1.xxxx ret // Approximately 6 instruction slots used #endif const BYTE RGBShaderMask[] = { - 68, 88, 66, 67, 30, 30, - 87, 58, 114, 156, 251, 151, - 29, 94, 34, 100, 228, 250, - 37, 251, 1, 0, 0, 0, + 68, 88, 66, 67, 77, 94, + 252, 215, 133, 78, 101, 216, + 220, 8, 70, 254, 89, 142, + 130, 135, 1, 0, 0, 0, 192, 5, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 8, 1, 0, 0, 32, 2, @@ -3369,7 +3409,7 @@ const BYTE RGBShaderMask[] = 0, 2, 1, 0, 8, 128, 0, 0, 0, 160, 5, 0, 0, 3, 0, 0, 15, 128, - 0, 0, 255, 128, 1, 0, + 0, 0, 0, 128, 1, 0, 228, 128, 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 128, 255, 255, 0, 0, @@ -3417,7 +3457,7 @@ const BYTE RGBShaderMask[] = 0, 0, 56, 0, 0, 7, 242, 32, 16, 0, 0, 0, 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 246, 15, + 0, 0, 0, 0, 6, 0, 16, 0, 1, 0, 0, 0, 62, 0, 0, 1, 83, 84, 65, 84, 116, 0, 0, 0, @@ -3544,9 +3584,9 @@ const BYTE RGBShaderMask[] = 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, - 114, 32, 54, 46, 51, 46, - 57, 54, 48, 48, 46, 49, - 54, 51, 56, 52, 0, 171, + 114, 32, 57, 46, 50, 57, + 46, 57, 53, 50, 46, 51, + 49, 49, 49, 0, 171, 171, 73, 83, 71, 78, 104, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 80, 0, @@ -3578,7 +3618,11 @@ const BYTE RGBShaderMask[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBAShaderMask +// -VnRGBAShaderMask -FhtmpShaderHeader // // // Buffer Definitions: @@ -3611,18 +3655,18 @@ const BYTE RGBShaderMask[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy -// TEXCOORD 1 zw 1 NONE float zw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// TEXCOORD 1 zw 1 NONE float zw // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -3650,7 +3694,7 @@ const BYTE RGBShaderMask[] = texld r1, t0, s1 texld r0, r0, s0 mul r1, r1, c0.x - mul r0, r0.w, r1 + mul r0, r0.x, r1 mov oC0, r0 // approximately 6 instruction slots used (2 texture, 4 arithmetic) @@ -3666,17 +3710,17 @@ dcl_temps 2 sample r0.xyzw, v1.xyxx, t0.xyzw, s0 mul r0.xyzw, r0.xyzw, cb0[1].xxxx sample r1.xyzw, v1.zwzz, t3.xyzw, s0 -mul o0.xyzw, r0.xyzw, r1.wwww +mul o0.xyzw, r0.xyzw, r1.xxxx ret // Approximately 5 instruction slots used #endif const BYTE RGBAShaderMask[] = { - 68, 88, 66, 67, 188, 13, - 191, 168, 231, 201, 42, 209, - 88, 243, 29, 35, 226, 31, - 145, 20, 1, 0, 0, 0, + 68, 88, 66, 67, 138, 69, + 81, 181, 217, 15, 199, 10, + 146, 208, 232, 248, 24, 27, + 141, 26, 1, 0, 0, 0, 156, 5, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 252, 0, 0, 0, 252, 1, @@ -3711,7 +3755,7 @@ const BYTE RGBAShaderMask[] = 15, 128, 1, 0, 228, 128, 0, 0, 0, 160, 5, 0, 0, 3, 0, 0, 15, 128, - 0, 0, 255, 128, 1, 0, + 0, 0, 0, 128, 1, 0, 228, 128, 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 128, 255, 255, 0, 0, @@ -3755,7 +3799,7 @@ const BYTE RGBAShaderMask[] = 0, 0, 56, 0, 0, 7, 242, 32, 16, 0, 0, 0, 0, 0, 70, 14, 16, 0, - 0, 0, 0, 0, 246, 15, + 0, 0, 0, 0, 6, 0, 16, 0, 1, 0, 0, 0, 62, 0, 0, 1, 83, 84, 65, 84, 116, 0, 0, 0, @@ -3882,9 +3926,9 @@ const BYTE RGBAShaderMask[] = 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, - 114, 32, 54, 46, 51, 46, - 57, 54, 48, 48, 46, 49, - 54, 51, 56, 52, 0, 171, + 114, 32, 57, 46, 50, 57, + 46, 57, 53, 50, 46, 51, + 49, 49, 49, 0, 171, 171, 73, 83, 71, 78, 104, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 80, 0, @@ -3916,7 +3960,11 @@ const BYTE RGBAShaderMask[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -ERGBAShaderMask3D +// -VnRGBAShaderMask3D -FhtmpShaderHeader // // // Buffer Definitions: @@ -3950,18 +3998,18 @@ const BYTE RGBAShaderMask[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy -// TEXCOORD 1 xyz 2 NONE float xyz +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// TEXCOORD 1 xyz 2 NONE float xyz // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -3991,7 +4039,7 @@ const BYTE RGBAShaderMask[] = texld r1, t0, s0 texld r0, r0, s1 mul r1, r1, c0.x - mul r0, r0.w, r1 + mul r0, r0.x, r1 mov oC0, r0 // approximately 7 instruction slots used (2 texture, 5 arithmetic) @@ -4009,17 +4057,17 @@ div r0.xy, v2.xyxx, v2.zzzz sample r0.xyzw, r0.xyxx, t3.xyzw, s1 sample r1.xyzw, v1.xyxx, t0.xyzw, s0 mul r1.xyzw, r1.xyzw, cb0[1].xxxx -mul o0.xyzw, r0.wwww, r1.xyzw +mul o0.xyzw, r0.xxxx, r1.xyzw ret // Approximately 6 instruction slots used #endif const BYTE RGBAShaderMask3D[] = { - 68, 88, 66, 67, 113, 141, - 78, 23, 128, 223, 235, 10, - 0, 97, 49, 111, 47, 53, - 229, 55, 1, 0, 0, 0, + 68, 88, 66, 67, 4, 135, + 55, 9, 144, 137, 25, 77, + 92, 150, 209, 2, 32, 225, + 75, 182, 1, 0, 0, 0, 24, 6, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 24, 1, 0, 0, 64, 2, @@ -4059,7 +4107,7 @@ const BYTE RGBAShaderMask3D[] = 1, 0, 228, 128, 0, 0, 0, 160, 5, 0, 0, 3, 0, 0, 15, 128, 0, 0, - 255, 128, 1, 0, 228, 128, + 0, 128, 1, 0, 228, 128, 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 128, 255, 255, 0, 0, 83, 72, @@ -4108,7 +4156,7 @@ const BYTE RGBAShaderMask3D[] = 32, 0, 0, 0, 0, 0, 1, 0, 0, 0, 56, 0, 0, 7, 242, 32, 16, 0, - 0, 0, 0, 0, 246, 15, + 0, 0, 0, 0, 6, 0, 16, 0, 0, 0, 0, 0, 70, 14, 16, 0, 1, 0, 0, 0, 62, 0, 0, 1, @@ -4246,9 +4294,9 @@ const BYTE RGBAShaderMask3D[] = 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, - 54, 46, 51, 46, 57, 54, - 48, 48, 46, 49, 54, 51, - 56, 52, 0, 171, 73, 83, + 57, 46, 50, 57, 46, 57, + 53, 50, 46, 51, 49, 49, + 49, 0, 171, 171, 73, 83, 71, 78, 104, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 80, 0, 0, 0, @@ -4279,7 +4327,11 @@ const BYTE RGBAShaderMask3D[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl -EYCbCrShaderMask +// -VnYCbCrShaderMask -FhtmpShaderHeader // // // Buffer Definitions: @@ -4314,18 +4366,18 @@ const BYTE RGBAShaderMask3D[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy -// TEXCOORD 1 zw 1 NONE float zw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// TEXCOORD 1 zw 1 NONE float zw // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -4357,21 +4409,21 @@ const BYTE RGBAShaderMask3D[] = dcl_2d s3 texld r0, t0, s1 texld r1, t0, s3 - add r0.x, r1.w, c1.x - mul r0.xy, r0.x, c1.zwzw - add r0.z, r0.w, c1.y - mad r0.y, r0.z, c2.x, -r0.y - mad r1.x, r0.z, c2.x, r0.x + add r0.y, r1.x, c1.x + mul r0.yz, r0.y, c1.xzww + add r0.x, r0.x, c1.y + mad r0.z, r0.x, c2.x, -r0.z + mad r1.x, r0.x, c2.x, r0.y mov r2.xy, t0.wzzw texld r3, t0, s2 texld r2, r2, s0 - add r0.x, r3.w, c1.x - mad r1.y, r0.x, -c2.z, r0.y - mul r0.x, r0.x, c2.y - mad r1.z, r0.z, c2.x, r0.x + add r0.y, r3.x, c1.x + mad r1.y, r0.y, -c2.z, r0.z + mul r0.y, r0.y, c2.y + mad r1.z, r0.x, c2.x, r0.y mov r1.w, c2.w mul r0, r1, c0.x - mul r0, r2.w, r0 + mul r0, r2.x, r0 mov oC0, r0 // approximately 18 instruction slots used (4 texture, 14 arithmetic) @@ -4387,31 +4439,31 @@ dcl_input_ps linear v1.zw dcl_output o0.xyzw dcl_temps 3 sample r0.xyzw, v1.xyxx, t2.xyzw, s0 -add r0.x, r0.w, l(-0.501960) +add r0.x, r0.x, l(-0.501960) mul r0.xy, r0.xxxx, l(1.596030, 0.812970, 0.000000, 0.000000) sample r1.xyzw, v1.xyxx, t0.xyzw, s0 -add r0.z, r1.w, l(-0.062750) +add r0.z, r1.x, l(-0.062750) mad r0.y, r0.z, l(1.164380), -r0.y mad r1.x, r0.z, l(1.164380), r0.x sample r2.xyzw, v1.xyxx, t1.xyzw, s0 -add r0.x, r2.w, l(-0.501960) +add r0.x, r2.x, l(-0.501960) mad r1.y, -r0.x, l(0.391760), r0.y mul r0.x, r0.x, l(2.017230) mad r1.z, r0.z, l(1.164380), r0.x mov r1.w, l(1.000000) mul r0.xyzw, r1.xyzw, cb0[1].xxxx sample r1.xyzw, v1.zwzz, t3.xyzw, s0 -mul o0.xyzw, r0.xyzw, r1.wwww +mul o0.xyzw, r0.xyzw, r1.xxxx ret // Approximately 17 instruction slots used #endif const BYTE YCbCrShaderMask[] = { - 68, 88, 66, 67, 103, 162, - 223, 236, 236, 142, 143, 151, - 73, 154, 187, 112, 81, 114, - 229, 251, 1, 0, 0, 0, + 68, 88, 66, 67, 74, 33, + 155, 235, 22, 178, 84, 169, + 113, 91, 240, 98, 157, 143, + 221, 19, 1, 0, 0, 0, 168, 8, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 24, 2, 0, 0, 196, 4, @@ -4454,20 +4506,20 @@ const BYTE YCbCrShaderMask[] = 0, 3, 1, 0, 15, 128, 0, 0, 228, 176, 3, 8, 228, 160, 2, 0, 0, 3, - 0, 0, 1, 128, 1, 0, - 255, 128, 1, 0, 0, 160, + 0, 0, 2, 128, 1, 0, + 0, 128, 1, 0, 0, 160, 5, 0, 0, 3, 0, 0, - 3, 128, 0, 0, 0, 128, - 1, 0, 238, 160, 2, 0, - 0, 3, 0, 0, 4, 128, - 0, 0, 255, 128, 1, 0, + 6, 128, 0, 0, 85, 128, + 1, 0, 248, 160, 2, 0, + 0, 3, 0, 0, 1, 128, + 0, 0, 0, 128, 1, 0, 85, 160, 4, 0, 0, 4, - 0, 0, 2, 128, 0, 0, - 170, 128, 2, 0, 0, 160, - 0, 0, 85, 129, 4, 0, + 0, 0, 4, 128, 0, 0, + 0, 128, 2, 0, 0, 160, + 0, 0, 170, 129, 4, 0, 0, 4, 1, 0, 1, 128, - 0, 0, 170, 128, 2, 0, - 0, 160, 0, 0, 0, 128, + 0, 0, 0, 128, 2, 0, + 0, 160, 0, 0, 85, 128, 1, 0, 0, 2, 2, 0, 3, 128, 0, 0, 235, 176, 66, 0, 0, 3, 3, 0, @@ -4476,24 +4528,24 @@ const BYTE YCbCrShaderMask[] = 0, 3, 2, 0, 15, 128, 2, 0, 228, 128, 0, 8, 228, 160, 2, 0, 0, 3, - 0, 0, 1, 128, 3, 0, - 255, 128, 1, 0, 0, 160, + 0, 0, 2, 128, 3, 0, + 0, 128, 1, 0, 0, 160, 4, 0, 0, 4, 1, 0, - 2, 128, 0, 0, 0, 128, + 2, 128, 0, 0, 85, 128, 2, 0, 170, 161, 0, 0, - 85, 128, 5, 0, 0, 3, - 0, 0, 1, 128, 0, 0, - 0, 128, 2, 0, 85, 160, + 170, 128, 5, 0, 0, 3, + 0, 0, 2, 128, 0, 0, + 85, 128, 2, 0, 85, 160, 4, 0, 0, 4, 1, 0, - 4, 128, 0, 0, 170, 128, + 4, 128, 0, 0, 0, 128, 2, 0, 0, 160, 0, 0, - 0, 128, 1, 0, 0, 2, + 85, 128, 1, 0, 0, 2, 1, 0, 8, 128, 2, 0, 255, 160, 5, 0, 0, 3, 0, 0, 15, 128, 1, 0, 228, 128, 0, 0, 0, 160, 5, 0, 0, 3, 0, 0, - 15, 128, 2, 0, 255, 128, + 15, 128, 2, 0, 0, 128, 0, 0, 228, 128, 1, 0, 0, 2, 0, 8, 15, 128, 0, 0, 228, 128, 255, 255, @@ -4530,7 +4582,7 @@ const BYTE YCbCrShaderMask[] = 0, 0, 0, 96, 16, 0, 0, 0, 0, 0, 0, 0, 0, 7, 18, 0, 16, 0, - 0, 0, 0, 0, 58, 0, + 0, 0, 0, 0, 10, 0, 16, 0, 0, 0, 0, 0, 1, 64, 0, 0, 115, 128, 0, 191, 56, 0, 0, 10, @@ -4548,7 +4600,7 @@ const BYTE YCbCrShaderMask[] = 16, 0, 0, 0, 0, 0, 0, 0, 0, 7, 66, 0, 16, 0, 0, 0, 0, 0, - 58, 0, 16, 0, 1, 0, + 10, 0, 16, 0, 1, 0, 0, 0, 1, 64, 0, 0, 18, 131, 128, 189, 50, 0, 0, 10, 34, 0, 16, 0, @@ -4571,7 +4623,7 @@ const BYTE YCbCrShaderMask[] = 0, 96, 16, 0, 0, 0, 0, 0, 0, 0, 0, 7, 18, 0, 16, 0, 0, 0, - 0, 0, 58, 0, 16, 0, + 0, 0, 10, 0, 16, 0, 2, 0, 0, 0, 1, 64, 0, 0, 115, 128, 0, 191, 50, 0, 0, 10, 34, 0, @@ -4609,13 +4661,13 @@ const BYTE YCbCrShaderMask[] = 56, 0, 0, 7, 242, 32, 16, 0, 0, 0, 0, 0, 70, 14, 16, 0, 0, 0, - 0, 0, 246, 15, 16, 0, + 0, 0, 6, 0, 16, 0, 1, 0, 0, 0, 62, 0, 0, 1, 83, 84, 65, 84, 116, 0, 0, 0, 17, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, - 0, 0, 11, 0, 0, 0, + 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -4747,9 +4799,9 @@ const BYTE YCbCrShaderMask[] = 76, 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, - 114, 32, 54, 46, 51, 46, - 57, 54, 48, 48, 46, 49, - 54, 51, 56, 52, 0, 171, + 114, 32, 57, 46, 50, 57, + 46, 57, 53, 50, 46, 51, + 49, 49, 49, 0, 171, 171, 73, 83, 71, 78, 104, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 80, 0, @@ -4781,7 +4833,12 @@ const BYTE YCbCrShaderMask[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11.hlsl +// -EComponentAlphaShaderMask -VnComponentAlphaShaderMask +// -FhtmpShaderHeader // // // Buffer Definitions: @@ -4815,19 +4872,19 @@ const BYTE YCbCrShaderMask[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xy 1 NONE float xy -// TEXCOORD 1 zw 1 NONE float zw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xy 1 NONE float xy +// TEXCOORD 1 zw 1 NONE float zw // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw -// SV_Target 1 xyzw 1 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw +// SV_Target 1 xyzw 1 TARGET float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -4856,7 +4913,7 @@ const BYTE YCbCrShaderMask[] = dcl_2d s2 mov r0.xy, t0.wzzw texld r0, r0, s0 - mul r0.x, r0.w, c0.x + mul r0.x, r0.x, c0.x texld r1, t0, s1 texld r2, t0, s2 add r2, r1, -r2 @@ -4885,7 +4942,7 @@ add r0.xyzw, -r0.xyzw, r1.xyzw add r0.xyzw, r0.xyzw, l(1.000000, 1.000000, 1.000000, 1.000000) mov r1.w, r0.y sample r2.xyzw, v1.zwzz, t3.xyzw, s0 -mul r2.x, r2.w, cb0[1].x +mul r2.x, r2.x, cb0[1].x mul o0.xyzw, r1.xyzw, r2.xxxx mul o1.xyzw, r0.xyzw, r2.xxxx ret @@ -4894,10 +4951,10 @@ ret const BYTE ComponentAlphaShaderMask[] = { - 68, 88, 66, 67, 245, 71, - 211, 223, 156, 101, 223, 204, - 145, 138, 53, 12, 16, 220, - 106, 83, 1, 0, 0, 0, + 68, 88, 66, 67, 214, 67, + 206, 69, 12, 117, 144, 46, + 127, 133, 145, 240, 56, 186, + 119, 195, 1, 0, 0, 0, 20, 7, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 124, 1, 0, 0, 52, 3, @@ -4933,7 +4990,7 @@ const BYTE ComponentAlphaShaderMask[] = 0, 0, 15, 128, 0, 0, 228, 128, 0, 8, 228, 160, 5, 0, 0, 3, 0, 0, - 1, 128, 0, 0, 255, 128, + 1, 128, 0, 0, 0, 128, 0, 0, 0, 160, 66, 0, 0, 3, 1, 0, 15, 128, 0, 0, 228, 176, 1, 8, @@ -5017,7 +5074,7 @@ const BYTE ComponentAlphaShaderMask[] = 0, 96, 16, 0, 0, 0, 0, 0, 56, 0, 0, 8, 18, 0, 16, 0, 2, 0, - 0, 0, 58, 0, 16, 0, + 0, 0, 10, 0, 16, 0, 2, 0, 0, 0, 10, 128, 32, 0, 0, 0, 0, 0, 1, 0, 0, 0, 56, 0, @@ -5044,7 +5101,7 @@ const BYTE ComponentAlphaShaderMask[] = 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -5162,9 +5219,9 @@ const BYTE ComponentAlphaShaderMask[] = 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, - 54, 46, 51, 46, 57, 54, - 48, 48, 46, 49, 54, 51, - 56, 52, 0, 171, 73, 83, + 57, 46, 50, 57, 46, 57, + 53, 50, 46, 51, 49, 49, + 49, 0, 171, 171, 73, 83, 71, 78, 104, 0, 0, 0, 3, 0, 0, 0, 8, 0, 0, 0, 80, 0, 0, 0, diff --git a/gfx/layers/d3d11/CompositorD3D11ShadersVR.h b/gfx/layers/d3d11/CompositorD3D11ShadersVR.h index f4ed05e4a27c..0046d4fd3f53 100644 --- a/gfx/layers/d3d11/CompositorD3D11ShadersVR.h +++ b/gfx/layers/d3d11/CompositorD3D11ShadersVR.h @@ -1,6 +1,10 @@ #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tvs_4_0_level_9_3 CompositorD3D11VR.hlsl +// -EOculusVRDistortionVS -VnOculusVRDistortionVS -FhtmpShaderHeader // // // Buffer Definitions: @@ -24,24 +28,24 @@ // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// POSITION 0 xy 0 NONE float xy -// TEXCOORD 0 xy 1 NONE float xy -// TEXCOORD 1 xy 2 NONE float xy -// TEXCOORD 2 xy 3 NONE float xy -// COLOR 0 xyzw 4 NONE float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// POSITION 0 xy 0 NONE float xy +// TEXCOORD 0 xy 1 NONE float xy +// TEXCOORD 1 xy 2 NONE float xy +// TEXCOORD 2 xy 3 NONE float xy +// COLOR 0 xyzw 4 NONE float xyzw // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float xyzw -// TEXCOORD 0 xyz 1 NONE float xyz -// TEXCOORD 1 xyz 2 NONE float xyz -// TEXCOORD 2 xyz 3 NONE float xyz -// COLOR 0 xyzw 4 NONE float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float xyzw +// TEXCOORD 0 xyz 1 NONE float xyz +// TEXCOORD 1 xyz 2 NONE float xyz +// TEXCOORD 2 xyz 3 NONE float xyz +// COLOR 0 xyzw 4 NONE float xyzw // // // Constant buffer to DX9 shader constant mappings: @@ -106,10 +110,10 @@ ret const BYTE OculusVRDistortionVS[] = { - 68, 88, 66, 67, 3, 61, - 196, 122, 10, 53, 44, 234, - 18, 242, 195, 238, 42, 90, - 72, 193, 1, 0, 0, 0, + 68, 88, 66, 67, 206, 154, + 203, 64, 121, 47, 121, 169, + 222, 206, 108, 175, 167, 227, + 154, 37, 1, 0, 0, 0, 244, 5, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 108, 1, 0, 0, 44, 3, @@ -245,7 +249,7 @@ const BYTE OculusVRDistortionVS[] = 116, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, - 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -303,9 +307,9 @@ const BYTE OculusVRDistortionVS[] = 83, 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, - 32, 54, 46, 51, 46, 57, - 54, 48, 48, 46, 49, 54, - 51, 56, 52, 0, 171, 171, + 32, 57, 46, 50, 57, 46, + 57, 53, 50, 46, 51, 49, + 49, 49, 0, 171, 171, 171, 73, 83, 71, 78, 152, 0, 0, 0, 5, 0, 0, 0, 8, 0, 0, 0, 128, 0, @@ -363,7 +367,11 @@ const BYTE OculusVRDistortionVS[] = }; #if 0 // -// Generated by Microsoft (R) HLSL Shader Compiler 6.3.9600.16384 +// Generated by Microsoft (R) HLSL Shader Compiler 9.29.952.3111 +// +// +// fxc -nologo -Tps_4_0_level_9_3 CompositorD3D11VR.hlsl +// -EOculusVRDistortionPS -VnOculusVRDistortionPS -FhtmpShaderHeader // // // Resource Bindings: @@ -377,20 +385,20 @@ const BYTE OculusVRDistortionVS[] = // // Input signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Position 0 xyzw 0 POS float -// TEXCOORD 0 xyz 1 NONE float xy -// TEXCOORD 1 xyz 2 NONE float xy -// TEXCOORD 2 xyz 3 NONE float xy -// COLOR 0 xyzw 4 NONE float x +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Position 0 xyzw 0 POS float +// TEXCOORD 0 xyz 1 NONE float xy +// TEXCOORD 1 xyz 2 NONE float xy +// TEXCOORD 2 xyz 3 NONE float xy +// COLOR 0 xyzw 4 NONE float x // // // Output signature: // -// Name Index Mask Register SysValue Format Used -// -------------------- ----- ------ -------- -------- ------- ------ -// SV_Target 0 xyzw 0 TARGET float xyzw +// Name Index Mask Register SysValue Format Used +// -------------------- ----- ------ -------- -------- ------ ------ +// SV_Target 0 xyzw 0 TARGET float xyzw // // // Sampler/Resource to DX9 shader sampler mappings: @@ -441,15 +449,15 @@ ret const BYTE OculusVRDistortionPS[] = { - 68, 88, 66, 67, 108, 219, - 61, 216, 27, 0, 27, 222, - 242, 132, 183, 21, 166, 141, - 130, 39, 1, 0, 0, 0, - 128, 4, 0, 0, 6, 0, + 68, 88, 66, 67, 48, 161, + 127, 216, 149, 107, 53, 57, + 164, 84, 84, 154, 58, 227, + 125, 61, 1, 0, 0, 0, + 124, 4, 0, 0, 6, 0, 0, 0, 56, 0, 0, 0, 60, 1, 0, 0, 132, 2, 0, 0, 0, 3, 0, 0, - 168, 3, 0, 0, 76, 4, + 164, 3, 0, 0, 72, 4, 0, 0, 65, 111, 110, 57, 252, 0, 0, 0, 252, 0, 0, 0, 0, 2, 255, 255, @@ -569,7 +577,7 @@ const BYTE OculusVRDistortionPS[] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 82, 68, 69, 70, 160, 0, + 82, 68, 69, 70, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 28, 0, 0, 0, @@ -594,43 +602,43 @@ const BYTE OculusVRDistortionPS[] = 76, 32, 83, 104, 97, 100, 101, 114, 32, 67, 111, 109, 112, 105, 108, 101, 114, 32, - 54, 46, 51, 46, 57, 54, - 48, 48, 46, 49, 54, 51, - 56, 52, 0, 171, 171, 171, - 73, 83, 71, 78, 156, 0, - 0, 0, 5, 0, 0, 0, - 8, 0, 0, 0, 128, 0, - 0, 0, 0, 0, 0, 0, - 1, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 140, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 1, 0, 0, 0, - 7, 3, 0, 0, 140, 0, - 0, 0, 1, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 2, 0, 0, 0, - 7, 3, 0, 0, 140, 0, - 0, 0, 2, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 3, 0, 0, 0, - 7, 3, 0, 0, 149, 0, - 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 3, 0, - 0, 0, 4, 0, 0, 0, - 15, 1, 0, 0, 83, 86, - 95, 80, 111, 115, 105, 116, - 105, 111, 110, 0, 84, 69, - 88, 67, 79, 79, 82, 68, - 0, 67, 79, 76, 79, 82, - 0, 171, 79, 83, 71, 78, - 44, 0, 0, 0, 1, 0, + 57, 46, 50, 57, 46, 57, + 53, 50, 46, 51, 49, 49, + 49, 0, 73, 83, 71, 78, + 156, 0, 0, 0, 5, 0, 0, 0, 8, 0, 0, 0, - 32, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, + 128, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, - 83, 86, 95, 84, 97, 114, - 103, 101, 116, 0, 171, 171 + 140, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 1, 0, + 0, 0, 7, 3, 0, 0, + 140, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 2, 0, + 0, 0, 7, 3, 0, 0, + 140, 0, 0, 0, 2, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 3, 0, + 0, 0, 7, 3, 0, 0, + 149, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 4, 0, + 0, 0, 15, 1, 0, 0, + 83, 86, 95, 80, 111, 115, + 105, 116, 105, 111, 110, 0, + 84, 69, 88, 67, 79, 79, + 82, 68, 0, 67, 79, 76, + 79, 82, 0, 171, 79, 83, + 71, 78, 44, 0, 0, 0, + 1, 0, 0, 0, 8, 0, + 0, 0, 32, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, + 0, 0, 0, 0, 15, 0, + 0, 0, 83, 86, 95, 84, + 97, 114, 103, 101, 116, 0, + 171, 171 }; diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index a1baca00bad5..42ec2f5e587f 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -34,7 +34,7 @@ SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat) case SurfaceFormat::R8G8B8X8: return DXGI_FORMAT_R8G8B8A8_UNORM; case SurfaceFormat::A8: - return DXGI_FORMAT_A8_UNORM; + return DXGI_FORMAT_R8_UNORM; default: MOZ_ASSERT(false, "unsupported format"); return DXGI_FORMAT_UNKNOWN; @@ -451,7 +451,7 @@ TextureClientD3D11::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFlag if (gfxPrefs::Direct2DUse1_1() && d3d11device) { - CD3D11_TEXTURE2D_DESC newDesc(mFormat == SurfaceFormat::A8 ? DXGI_FORMAT_A8_UNORM : DXGI_FORMAT_B8G8R8A8_UNORM, + CD3D11_TEXTURE2D_DESC newDesc(mFormat == SurfaceFormat::A8 ? DXGI_FORMAT_R8_UNORM : DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE); diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 1b24cb4233d6..6d04d76afe49 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1830,23 +1830,7 @@ bool DoesD3D11TextureSharingWork(ID3D11Device *device) bool DoesD3D11AlphaTextureSharingWork(ID3D11Device *device) { - nsCOMPtr gfxInfo = do_GetService("@mozilla.org/gfx/info;1"); - if (gfxInfo) { - // A8 texture sharing crashes on this intel driver version (and no others) - // so just avoid using it in that case. - nsString adapterVendor; - nsString driverVersion; - gfxInfo->GetAdapterVendorID(adapterVendor); - gfxInfo->GetAdapterDriverVersion(driverVersion); - - nsAString &intelVendorID = (nsAString &)GfxDriverInfo::GetDeviceVendor(VendorIntel); - if (adapterVendor.Equals(intelVendorID, nsCaseInsensitiveStringComparator()) && - driverVersion.Equals(NS_LITERAL_STRING("8.15.10.2086"))) { - return false; - } - } - - return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_A8_UNORM, D3D11_BIND_SHADER_RESOURCE); + return DoesD3D11TextureSharingWorkInternal(device, DXGI_FORMAT_R8_UNORM, D3D11_BIND_SHADER_RESOURCE); } void From fca5598e0a1c8fd550f7e6167838bd5fe30e8a4a Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Sat, 13 Jun 2015 20:55:33 -0400 Subject: [PATCH 46/49] bug 1174414 - Fix build without profiler. r=mconley --HG-- extra : commitid : 9feSETPZSKa extra : rebase_source : 025c9a8bdfee42be8926a87b8e6f9da51c0134c5 --- dom/ipc/ContentParent.cpp | 6 ++++++ dom/ipc/ContentParent.h | 4 ++++ dom/plugins/ipc/PluginModuleParent.cpp | 9 ++++++++- dom/plugins/ipc/PluginModuleParent.h | 6 ++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 2e988129f8de..1b80fa383e52 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -79,7 +79,9 @@ #include "mozilla/Preferences.h" #include "mozilla/ProcessHangMonitor.h" #include "mozilla/ProcessHangMonitorIPC.h" +#ifdef MOZ_ENABLE_PROFILER_SPS #include "mozilla/ProfileGatherer.h" +#endif #include "mozilla/Services.h" #include "mozilla/StaticPtr.h" #include "mozilla/Telemetry.h" @@ -239,7 +241,9 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); using base::ChildPrivileges; using base::KillProcess; +#ifdef MOZ_ENABLE_PROFILER_SPS using mozilla::ProfileGatherer; +#endif #ifdef MOZ_CRASHREPORTER using namespace CrashReporter; @@ -5106,12 +5110,14 @@ ContentParent::RecvGamepadListenerRemoved() bool ContentParent::RecvProfile(const nsCString& aProfile) { +#ifdef MOZ_ENABLE_PROFILER_SPS if (NS_WARN_IF(!mGatherer)) { return true; } mProfile = aProfile; mGatherer->GatheredOOPProfile(); mGatherer = nullptr; +#endif return true; } diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 02e19a391a68..56410e89abd9 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -37,7 +37,9 @@ class nsIWidget; namespace mozilla { class PRemoteSpellcheckEngineParent; +#ifdef MOZ_ENABLE_PROFILER_SPS class ProfileGatherer; +#endif namespace ipc { class OptionalURIParams; @@ -933,7 +935,9 @@ private: #endif PProcessHangMonitorParent* mHangMonitorActor; +#ifdef MOZ_ENABLE_PROFILER_SPS nsRefPtr mGatherer; +#endif nsCString mProfile; }; diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index dddaabc4e935..0c1547e0e74c 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -22,7 +22,9 @@ #include "mozilla/plugins/PluginBridge.h" #include "mozilla/plugins/PluginInstanceParent.h" #include "mozilla/Preferences.h" +#ifdef MOZ_ENABLE_PROFILER_SPS #include "mozilla/ProfileGatherer.h" +#endif #include "mozilla/ProcessHangMonitor.h" #include "mozilla/Services.h" #include "mozilla/Telemetry.h" @@ -59,7 +61,9 @@ using base::KillProcess; using mozilla::PluginLibrary; +#ifdef MOZ_ENABLE_PROFILER_SPS using mozilla::ProfileGatherer; +#endif using mozilla::ipc::MessageChannel; using mozilla::ipc::GeckoChildProcessHost; using mozilla::dom::PCrashReporterParent; @@ -3106,10 +3110,12 @@ PluginModuleChromeParent::GatheredAsyncProfile(nsIProfileSaveEvent* aSaveEvent) mProfile.Truncate(); } } +#endif // MOZ_ENABLE_PROFILER_SPS bool PluginModuleChromeParent::RecvProfile(const nsCString& aProfile) { +#ifdef MOZ_ENABLE_PROFILER_SPS if (NS_WARN_IF(!mGatherer)) { return true; } @@ -3117,7 +3123,8 @@ PluginModuleChromeParent::RecvProfile(const nsCString& aProfile) mProfile = aProfile; mGatherer->GatheredOOPProfile(); mGatherer = nullptr; +#endif return true; } -#endif + diff --git a/dom/plugins/ipc/PluginModuleParent.h b/dom/plugins/ipc/PluginModuleParent.h index 504936dbf9b6..32ea0b647813 100644 --- a/dom/plugins/ipc/PluginModuleParent.h +++ b/dom/plugins/ipc/PluginModuleParent.h @@ -35,7 +35,9 @@ class nsIProfileSaveEvent; class nsPluginTag; namespace mozilla { +#ifdef MOZ_ENABLE_PROFILER_SPS class ProfileGatherer; +#endif namespace dom { class PCrashReporterParent; class CrashReporterParent; @@ -417,8 +419,10 @@ class PluginModuleChromeParent void OnEnteredSyncSend() override; void OnExitedSyncSend() override; +#ifdef MOZ_ENABLE_PROFILER_SPS void GatherAsyncProfile(mozilla::ProfileGatherer* aGatherer); void GatheredAsyncProfile(nsIProfileSaveEvent* aSaveEvent); +#endif virtual bool RecvProfile(const nsCString& aProfile) override; @@ -580,7 +584,9 @@ private: NPError mAsyncInitError; dom::ContentParent* mContentParent; nsCOMPtr mOfflineObserver; +#ifdef MOZ_ENABLE_PROFILER_SPS nsRefPtr mGatherer; +#endif nsCString mProfile; bool mIsBlocklisted; static bool sInstantiated; From d87596f0b2e7797f73c0cc32f905e32bcf2e65ea Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 15 Jun 2015 17:44:08 +0100 Subject: [PATCH 47/49] Bug 952139 - patch 2 - Expose MessageChannel to workers in mochitests, r=smaug CLOSED TREE --- .../test/serviceworkers/test_serviceworker_interfaces.js | 2 ++ dom/workers/test/test_worker_interfaces.js | 2 ++ 2 files changed, 4 insertions(+) diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js index e41cf5d50335..02797d335880 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -146,6 +146,8 @@ var interfaceNamesInGlobalScope = "IDBVersionChangeEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageData", +// IMPORTANT: Do not change this list without review from a DOM peer! + "MessageChannel", // IMPORTANT: Do not change this list without review from a DOM peer! "MessageEvent", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index f35f589d039c..36f5f2b182c7 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -138,6 +138,8 @@ var interfaceNamesInGlobalScope = "IDBVersionChangeEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageData", +// IMPORTANT: Do not change this list without review from a DOM peer! + "MessageChannel", // IMPORTANT: Do not change this list without review from a DOM peer! "MessageEvent", // IMPORTANT: Do not change this list without review from a DOM peer! From faad1a38af60967cd7e4cb2cdf97784fbe9ca734 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 15 Jun 2015 13:04:02 -0400 Subject: [PATCH 48/49] Backed out changesets 465dfc26cccb and bd11384b3241 (bug 952139) because it depends on bug 911972. --- .../tests/test_messageChannel_pref.html | 12 +++--------- .../test_serviceworker_interfaces.js | 2 -- dom/workers/test/test_worker_interfaces.js | 2 -- modules/libpref/init/all.js | 3 --- .../meta/html/dom/interfaces.html.ini | 18 ++++++++++++++++++ ...hannel_MessagePort_initial_disabled.htm.ini | 6 ++++++ ...Channel_MessagePort_onmessage_start.htm.ini | 6 ++++++ .../Channel_postMessage_DataCloneErr.htm.ini | 5 +++++ .../Channel_postMessage_clone_port.htm.ini | 6 ++++++ ...hannel_postMessage_clone_port_error.htm.ini | 5 +++++ ...hannel_postMessage_event_properties.htm.ini | 6 ++++++ ...el_postMessage_ports_readonly_array.htm.ini | 3 ++- .../Channel_postMessage_target_source.htm.ini | 6 ++++++ .../Transferred_objects_unusable.sub.htm.ini | 9 +++++++++ .../meta/webmessaging/event.ports.sub.htm.ini | 9 +++++++++ .../webmessaging/message-channels/001.html.ini | 5 +++++ .../webmessaging/message-channels/002.html.ini | 5 +++++ .../webmessaging/message-channels/003.html.ini | 5 +++++ .../webmessaging/message-channels/004.html.ini | 5 +++++ .../postMessage_MessagePorts_sorigin.htm.ini | 9 +++++++++ ...ostMessage_MessagePorts_xorigin.sub.htm.ini | 9 +++++++++ .../webmessaging/without-ports/023.html.ini | 5 +++++ .../webmessaging/without-ports/024.html.ini | 5 +++++ .../webmessaging/without-ports/025.html.ini | 8 ++++++++ .../MessagePort_initial_disabled.htm.ini | 6 ++++++ .../MessagePort_onmessage_start.htm.ini | 6 ++++++ .../workers/postMessage_clone_port.htm.ini | 5 +++++ .../postMessage_clone_port_error.htm.ini | 5 +++++ .../postMessage_event_properties.htm.ini | 6 ++++++ .../postMessage_ports_readonly_array.htm.ini | 5 +++++ .../workers/postMessage_target_source.htm.ini | 5 +++++ .../semantics/multiple-workers/008.html.ini | 6 ++++++ 32 files changed, 181 insertions(+), 17 deletions(-) create mode 100644 testing/web-platform/meta/webmessaging/Channel_MessagePort_initial_disabled.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/Channel_MessagePort_onmessage_start.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_DataCloneErr.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port_error.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_event_properties.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/Channel_postMessage_target_source.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/Transferred_objects_unusable.sub.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/event.ports.sub.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/message-channels/001.html.ini create mode 100644 testing/web-platform/meta/webmessaging/message-channels/002.html.ini create mode 100644 testing/web-platform/meta/webmessaging/message-channels/003.html.ini create mode 100644 testing/web-platform/meta/webmessaging/message-channels/004.html.ini create mode 100644 testing/web-platform/meta/webmessaging/postMessage_MessagePorts_sorigin.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/postMessage_MessagePorts_xorigin.sub.htm.ini create mode 100644 testing/web-platform/meta/webmessaging/without-ports/023.html.ini create mode 100644 testing/web-platform/meta/webmessaging/without-ports/024.html.ini create mode 100644 testing/web-platform/meta/webmessaging/without-ports/025.html.ini create mode 100644 testing/web-platform/meta/workers/MessagePort_initial_disabled.htm.ini create mode 100644 testing/web-platform/meta/workers/MessagePort_onmessage_start.htm.ini create mode 100644 testing/web-platform/meta/workers/postMessage_clone_port.htm.ini create mode 100644 testing/web-platform/meta/workers/postMessage_clone_port_error.htm.ini create mode 100644 testing/web-platform/meta/workers/postMessage_event_properties.htm.ini create mode 100644 testing/web-platform/meta/workers/postMessage_ports_readonly_array.htm.ini create mode 100644 testing/web-platform/meta/workers/postMessage_target_source.htm.ini create mode 100644 testing/web-platform/meta/workers/semantics/multiple-workers/008.html.ini diff --git a/dom/messagechannel/tests/test_messageChannel_pref.html b/dom/messagechannel/tests/test_messageChannel_pref.html index 4930fec3f5e1..ab2c9385a8ce 100644 --- a/dom/messagechannel/tests/test_messageChannel_pref.html +++ b/dom/messagechannel/tests/test_messageChannel_pref.html @@ -28,15 +28,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=677638 SimpleTest.waitForExplicitFinish(); - SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", false]]}, - function() { - runTest(false); - SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, - function() { - runTest(true); - SimpleTest.finish(); - }); - }); + runTest(false); + SpecialPowers.pushPrefEnv({"set": [["dom.messageChannel.enabled", true]]}, + function() { runTest(true); SimpleTest.finish(); }); diff --git a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js index 02797d335880..e41cf5d50335 100644 --- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.js @@ -146,8 +146,6 @@ var interfaceNamesInGlobalScope = "IDBVersionChangeEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageData", -// IMPORTANT: Do not change this list without review from a DOM peer! - "MessageChannel", // IMPORTANT: Do not change this list without review from a DOM peer! "MessageEvent", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/workers/test/test_worker_interfaces.js b/dom/workers/test/test_worker_interfaces.js index 36f5f2b182c7..f35f589d039c 100644 --- a/dom/workers/test/test_worker_interfaces.js +++ b/dom/workers/test/test_worker_interfaces.js @@ -138,8 +138,6 @@ var interfaceNamesInGlobalScope = "IDBVersionChangeEvent", // IMPORTANT: Do not change this list without review from a DOM peer! "ImageData", -// IMPORTANT: Do not change this list without review from a DOM peer! - "MessageChannel", // IMPORTANT: Do not change this list without review from a DOM peer! "MessageEvent", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 7cd0d2d7c659..16bd239bec74 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4796,9 +4796,6 @@ pref("camera.control.low_memory_thresholdMB", 404); // UDPSocket API pref("dom.udpsocket.enabled", false); -// MessageChannel enabled by default. -pref("dom.messageChannel.enabled", true); - // Disable before keyboard events and after keyboard events by default. pref("dom.beforeAfterKeyboardEvent.enabled", false); diff --git a/testing/web-platform/meta/html/dom/interfaces.html.ini b/testing/web-platform/meta/html/dom/interfaces.html.ini index 92350c684f68..e880ab89333d 100644 --- a/testing/web-platform/meta/html/dom/interfaces.html.ini +++ b/testing/web-platform/meta/html/dom/interfaces.html.ini @@ -2382,6 +2382,24 @@ [MessageEvent interface: operation initMessageEvent(DOMString,boolean,boolean,any,DOMString,DOMString,[object Object\],[object Object\],MessagePort)] expected: FAIL + [MessageChannel interface: existence and properties of interface object] + expected: FAIL + + [MessageChannel interface object length] + expected: FAIL + + [MessageChannel interface: existence and properties of interface prototype object] + expected: FAIL + + [MessageChannel interface: existence and properties of interface prototype object's "constructor" property] + expected: FAIL + + [MessageChannel interface: attribute port1] + expected: FAIL + + [MessageChannel interface: attribute port2] + expected: FAIL + [PortCollection interface: existence and properties of interface object] expected: FAIL diff --git a/testing/web-platform/meta/webmessaging/Channel_MessagePort_initial_disabled.htm.ini b/testing/web-platform/meta/webmessaging/Channel_MessagePort_initial_disabled.htm.ini new file mode 100644 index 000000000000..ea74c4361829 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/Channel_MessagePort_initial_disabled.htm.ini @@ -0,0 +1,6 @@ +[Channel_MessagePort_initial_disabled.htm] + type: testharness + expected: ERROR + [Test Description: A port message queue can be enabled or disabled, and is initially disabled.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/webmessaging/Channel_MessagePort_onmessage_start.htm.ini b/testing/web-platform/meta/webmessaging/Channel_MessagePort_onmessage_start.htm.ini new file mode 100644 index 000000000000..7b1afa876601 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/Channel_MessagePort_onmessage_start.htm.ini @@ -0,0 +1,6 @@ +[Channel_MessagePort_onmessage_start.htm] + type: testharness + expected: ERROR + [Test Description: The first time a MessagePort object's onmessage IDL attribute is set, the port's port message queue must be enabled, as if the start() method had been called.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_DataCloneErr.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_DataCloneErr.htm.ini new file mode 100644 index 000000000000..dac8542ffff5 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/Channel_postMessage_DataCloneErr.htm.ini @@ -0,0 +1,5 @@ +[Channel_postMessage_DataCloneErr.htm] + type: testharness + [Throw a DataCloneError when a host object (e.g. a DOM node) is used with postMessage.] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port.htm.ini new file mode 100644 index 000000000000..9b25f27c07b8 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port.htm.ini @@ -0,0 +1,6 @@ +[Channel_postMessage_clone_port.htm] + type: testharness + expected: ERROR + [Test Description: Test Description: When the user agent is to clone a port original port, with the clone being owned by owner, it must return a new MessagePort object] + expected: NOTRUN + diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port_error.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port_error.htm.ini new file mode 100644 index 000000000000..330df924b0b2 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/Channel_postMessage_clone_port_error.htm.ini @@ -0,0 +1,5 @@ +[Channel_postMessage_clone_port_error.htm] + type: testharness + [Test Description: Throw a DataCloneError if transfer array in postMessage contains source port.] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_event_properties.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_event_properties.htm.ini new file mode 100644 index 000000000000..cfc90a1f7483 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/Channel_postMessage_event_properties.htm.ini @@ -0,0 +1,6 @@ +[Channel_postMessage_event_properties.htm] + type: testharness + expected: ERROR + [Test Description: The postMessage() method - Create an event that uses the MessageEvent interface, with the name message, which does not bubble and is not cancelable.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_ports_readonly_array.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_ports_readonly_array.htm.ini index 68ba68685c7d..5d2add90e3a1 100644 --- a/testing/web-platform/meta/webmessaging/Channel_postMessage_ports_readonly_array.htm.ini +++ b/testing/web-platform/meta/webmessaging/Channel_postMessage_ports_readonly_array.htm.ini @@ -1,5 +1,6 @@ [Channel_postMessage_ports_readonly_array.htm] type: testharness + expected: ERROR [Test Description: The postMessage() method - Make new ports into a read only array.] - expected: FAIL + expected: NOTRUN diff --git a/testing/web-platform/meta/webmessaging/Channel_postMessage_target_source.htm.ini b/testing/web-platform/meta/webmessaging/Channel_postMessage_target_source.htm.ini new file mode 100644 index 000000000000..5da2d69ac890 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/Channel_postMessage_target_source.htm.ini @@ -0,0 +1,6 @@ +[Channel_postMessage_target_source.htm] + type: testharness + expected: ERROR + [Test Description: The postMessage() method - Let target port be the port with which source port is entangled, if any.] + expected: NOTRUN + diff --git a/testing/web-platform/meta/webmessaging/Transferred_objects_unusable.sub.htm.ini b/testing/web-platform/meta/webmessaging/Transferred_objects_unusable.sub.htm.ini new file mode 100644 index 000000000000..3e560e05ba40 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/Transferred_objects_unusable.sub.htm.ini @@ -0,0 +1,9 @@ +[Transferred_objects_unusable.sub.htm] + type: testharness + expected: TIMEOUT + [Test Description: Objects listed in transfer are transferred, not just cloned, meaning that they are no longer usable on the sending side.] + expected: NOTRUN + + [MessageChannel is supported.] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/event.ports.sub.htm.ini b/testing/web-platform/meta/webmessaging/event.ports.sub.htm.ini new file mode 100644 index 000000000000..fcc0b8c4bc16 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/event.ports.sub.htm.ini @@ -0,0 +1,9 @@ +[event.ports.sub.htm] + type: testharness + expected: TIMEOUT + [Test Description: event.ports returns the MessagePort array sent with the message.] + expected: NOTRUN + + [MessageChannel is supported.] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/message-channels/001.html.ini b/testing/web-platform/meta/webmessaging/message-channels/001.html.ini new file mode 100644 index 000000000000..6d8185315d36 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/message-channels/001.html.ini @@ -0,0 +1,5 @@ +[001.html] + type: testharness + [basic messagechannel test] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/message-channels/002.html.ini b/testing/web-platform/meta/webmessaging/message-channels/002.html.ini new file mode 100644 index 000000000000..7ed4ac89cfbe --- /dev/null +++ b/testing/web-platform/meta/webmessaging/message-channels/002.html.ini @@ -0,0 +1,5 @@ +[002.html] + type: testharness + [without start()] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/message-channels/003.html.ini b/testing/web-platform/meta/webmessaging/message-channels/003.html.ini new file mode 100644 index 000000000000..9041937757e0 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/message-channels/003.html.ini @@ -0,0 +1,5 @@ +[003.html] + type: testharness + [onmessage implied start()] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/message-channels/004.html.ini b/testing/web-platform/meta/webmessaging/message-channels/004.html.ini new file mode 100644 index 000000000000..9a69457ce62d --- /dev/null +++ b/testing/web-platform/meta/webmessaging/message-channels/004.html.ini @@ -0,0 +1,5 @@ +[004.html] + type: testharness + [cross-document channel] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_sorigin.htm.ini b/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_sorigin.htm.ini new file mode 100644 index 000000000000..08206d624c5a --- /dev/null +++ b/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_sorigin.htm.ini @@ -0,0 +1,9 @@ +[postMessage_MessagePorts_sorigin.htm] + type: testharness + expected: TIMEOUT + [Test Description: postMessage to same-origin iframe with MessagePort array containing 100 ports.] + expected: NOTRUN + + [MessageChannel is supported.] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_xorigin.sub.htm.ini b/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_xorigin.sub.htm.ini new file mode 100644 index 000000000000..b8924fed41cc --- /dev/null +++ b/testing/web-platform/meta/webmessaging/postMessage_MessagePorts_xorigin.sub.htm.ini @@ -0,0 +1,9 @@ +[postMessage_MessagePorts_xorigin.sub.htm] + type: testharness + expected: TIMEOUT + [Test Description: postMessage to cross-origin iframe with MessagePort array containing 100 ports.] + expected: NOTRUN + + [MessageChannel is supported.] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/without-ports/023.html.ini b/testing/web-platform/meta/webmessaging/without-ports/023.html.ini new file mode 100644 index 000000000000..e3ef5e7a005d --- /dev/null +++ b/testing/web-platform/meta/webmessaging/without-ports/023.html.ini @@ -0,0 +1,5 @@ +[023.html] + type: testharness + [Object cloning: own properties only, don't follow prototype] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/without-ports/024.html.ini b/testing/web-platform/meta/webmessaging/without-ports/024.html.ini new file mode 100644 index 000000000000..1e41c9bc68a3 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/without-ports/024.html.ini @@ -0,0 +1,5 @@ +[024.html] + type: testharness + [Object cloning: throw an exception if function values encountered] + expected: FAIL + diff --git a/testing/web-platform/meta/webmessaging/without-ports/025.html.ini b/testing/web-platform/meta/webmessaging/without-ports/025.html.ini new file mode 100644 index 000000000000..35cd8304aa43 --- /dev/null +++ b/testing/web-platform/meta/webmessaging/without-ports/025.html.ini @@ -0,0 +1,8 @@ +[025.html] + type: testharness + [MessagePort constructor properties] + expected: FAIL + + [Worker MessageChannel's port should be an instance of MessagePort] + expected: FAIL + diff --git a/testing/web-platform/meta/workers/MessagePort_initial_disabled.htm.ini b/testing/web-platform/meta/workers/MessagePort_initial_disabled.htm.ini new file mode 100644 index 000000000000..b73019ab98b6 --- /dev/null +++ b/testing/web-platform/meta/workers/MessagePort_initial_disabled.htm.ini @@ -0,0 +1,6 @@ +[MessagePort_initial_disabled.htm] + type: testharness + [ MessageChannel: port message queue is initially disabled ] + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=952139 + diff --git a/testing/web-platform/meta/workers/MessagePort_onmessage_start.htm.ini b/testing/web-platform/meta/workers/MessagePort_onmessage_start.htm.ini new file mode 100644 index 000000000000..ad6a4484ea3a --- /dev/null +++ b/testing/web-platform/meta/workers/MessagePort_onmessage_start.htm.ini @@ -0,0 +1,6 @@ +[MessagePort_onmessage_start.htm] + type: testharness + [ MessageChannel: port.onmessage enables message queue ] + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=952139 + diff --git a/testing/web-platform/meta/workers/postMessage_clone_port.htm.ini b/testing/web-platform/meta/workers/postMessage_clone_port.htm.ini new file mode 100644 index 000000000000..8065dc352276 --- /dev/null +++ b/testing/web-platform/meta/workers/postMessage_clone_port.htm.ini @@ -0,0 +1,5 @@ +[postMessage_clone_port.htm] + type: testharness + [ postMessage(): clone a port ] + expected: FAIL + diff --git a/testing/web-platform/meta/workers/postMessage_clone_port_error.htm.ini b/testing/web-platform/meta/workers/postMessage_clone_port_error.htm.ini new file mode 100644 index 000000000000..afc617adbfca --- /dev/null +++ b/testing/web-platform/meta/workers/postMessage_clone_port_error.htm.ini @@ -0,0 +1,5 @@ +[postMessage_clone_port_error.htm] + type: testharness + [ postMessage(): cloning source port ] + expected: FAIL + diff --git a/testing/web-platform/meta/workers/postMessage_event_properties.htm.ini b/testing/web-platform/meta/workers/postMessage_event_properties.htm.ini new file mode 100644 index 000000000000..f757a6627716 --- /dev/null +++ b/testing/web-platform/meta/workers/postMessage_event_properties.htm.ini @@ -0,0 +1,6 @@ +[postMessage_event_properties.htm] + type: testharness + [ postMessage(): MessageEvent properties ] + expected: FAIL + bug: https://bugzilla.mozilla.org/show_bug.cgi?id=952139 + diff --git a/testing/web-platform/meta/workers/postMessage_ports_readonly_array.htm.ini b/testing/web-platform/meta/workers/postMessage_ports_readonly_array.htm.ini new file mode 100644 index 000000000000..aa4e1ca91c55 --- /dev/null +++ b/testing/web-platform/meta/workers/postMessage_ports_readonly_array.htm.ini @@ -0,0 +1,5 @@ +[postMessage_ports_readonly_array.htm] + type: testharness + [ postMessage(): read-only ports array ] + expected: FAIL + diff --git a/testing/web-platform/meta/workers/postMessage_target_source.htm.ini b/testing/web-platform/meta/workers/postMessage_target_source.htm.ini new file mode 100644 index 000000000000..b86366d8577f --- /dev/null +++ b/testing/web-platform/meta/workers/postMessage_target_source.htm.ini @@ -0,0 +1,5 @@ +[postMessage_target_source.htm] + type: testharness + [ postMessage(): target port and source port ] + expected: FAIL + diff --git a/testing/web-platform/meta/workers/semantics/multiple-workers/008.html.ini b/testing/web-platform/meta/workers/semantics/multiple-workers/008.html.ini new file mode 100644 index 000000000000..30ef565a4a42 --- /dev/null +++ b/testing/web-platform/meta/workers/semantics/multiple-workers/008.html.ini @@ -0,0 +1,6 @@ +[008.html] + type: testharness + expected: ERROR + [messagechannel in shared worker] + expected: TIMEOUT + From c366b2c3f3c48b919f98c6714aec4fae3aaec6e7 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Mon, 15 Jun 2015 13:06:23 -0400 Subject: [PATCH 49/49] Backed out changeset 1d67d747b3eb (bug 911972) for frequent linux64 debug e10s test_post_message_advanced.html timeouts. CLOSED TREE --HG-- rename : dom/messagechannel/MessageChannel.cpp => dom/base/MessageChannel.cpp rename : dom/messagechannel/MessageChannel.h => dom/base/MessageChannel.h rename : dom/messagechannel/MessagePort.cpp => dom/base/MessagePort.cpp rename : dom/messagechannel/MessagePort.h => dom/base/MessagePort.h rename : dom/messagechannel/MessagePortList.cpp => dom/base/MessagePortList.cpp rename : dom/messagechannel/MessagePortList.h => dom/base/MessagePortList.h rename : dom/messagechannel/tests/iframe_messageChannel_chrome.html => dom/base/test/iframe_messageChannel_chrome.html rename : dom/messagechannel/tests/iframe_messageChannel_cloning.html => dom/base/test/iframe_messageChannel_cloning.html rename : dom/messagechannel/tests/iframe_messageChannel_pingpong.html => dom/base/test/iframe_messageChannel_pingpong.html rename : dom/messagechannel/tests/iframe_messageChannel_post.html => dom/base/test/iframe_messageChannel_post.html rename : dom/messagechannel/tests/test_messageChannel.html => dom/base/test/test_messageChannel.html rename : dom/messagechannel/tests/test_messageChannel.xul => dom/base/test/test_messageChannel.xul rename : dom/messagechannel/tests/test_messageChannel_cloning.html => dom/base/test/test_messageChannel_cloning.html rename : dom/messagechannel/tests/test_messageChannel_pingpong.html => dom/base/test/test_messageChannel_pingpong.html rename : dom/messagechannel/tests/test_messageChannel_post.html => dom/base/test/test_messageChannel_post.html rename : dom/messagechannel/tests/test_messageChannel_pref.html => dom/base/test/test_messageChannel_pref.html rename : dom/messagechannel/tests/test_messageChannel_start.html => dom/base/test/test_messageChannel_start.html rename : dom/messagechannel/tests/test_messageChannel_transferable.html => dom/base/test/test_messageChannel_transferable.html rename : dom/messagechannel/tests/test_messageChannel_unshipped.html => dom/base/test/test_messageChannel_unshipped.html --- dom/base/MessageChannel.cpp | 104 +++ dom/{messagechannel => base}/MessageChannel.h | 3 +- dom/base/MessagePort.cpp | 564 ++++++++++++ dom/base/MessagePort.h | 115 +++ .../MessagePortList.cpp | 0 .../MessagePortList.h | 0 dom/base/NodeInfo.cpp | 6 +- dom/base/PostMessageEvent.cpp | 389 -------- dom/base/PostMessageEvent.h | 108 --- dom/base/ProcessGlobal.cpp | 1 - dom/base/moz.build | 8 +- dom/base/nsContentUtils.cpp | 22 - dom/base/nsContentUtils.h | 7 - dom/base/nsCopySupport.cpp | 1 - dom/base/nsFrameMessageManager.cpp | 15 +- dom/base/nsGlobalWindow.cpp | 382 +++++++- dom/base/nsGlobalWindow.h | 3 +- dom/base/test/chrome.ini | 1 + .../test}/iframe_messageChannel_chrome.html | 0 .../test}/iframe_messageChannel_cloning.html | 0 .../test}/iframe_messageChannel_pingpong.html | 0 .../test}/iframe_messageChannel_post.html | 0 dom/base/test/mochitest.ini | 12 + .../test}/test_messageChannel.html | 0 .../test}/test_messageChannel.xul | 2 +- .../test}/test_messageChannel_cloning.html | 0 .../test}/test_messageChannel_pingpong.html | 0 .../test}/test_messageChannel_post.html | 0 .../test}/test_messageChannel_pref.html | 0 .../test}/test_messageChannel_start.html | 0 .../test_messageChannel_transferable.html | 58 +- .../test}/test_messageChannel_unshipped.html | 0 dom/bindings/Bindings.conf | 3 + dom/broadcastchannel/BroadcastChannel.cpp | 17 +- .../BroadcastChannelChild.cpp | 7 +- dom/ipc/StructuredCloneUtils.cpp | 12 +- dom/ipc/StructuredCloneUtils.h | 2 +- dom/messagechannel/MessageChannel.cpp | 228 ----- dom/messagechannel/MessagePort.cpp | 867 ------------------ dom/messagechannel/MessagePort.h | 210 ----- dom/messagechannel/MessagePortChild.cpp | 49 - dom/messagechannel/MessagePortChild.h | 52 -- dom/messagechannel/MessagePortParent.cpp | 163 ---- dom/messagechannel/MessagePortParent.h | 61 -- dom/messagechannel/MessagePortService.cpp | 328 ------- dom/messagechannel/MessagePortService.h | 61 -- dom/messagechannel/MessagePortUtils.cpp | 277 ------ dom/messagechannel/MessagePortUtils.h | 55 -- dom/messagechannel/PMessagePort.ipdl | 62 -- .../SharedMessagePortMessage.cpp | 180 ---- dom/messagechannel/SharedMessagePortMessage.h | 58 -- dom/messagechannel/moz.build | 41 - dom/messagechannel/tests/chrome.ini | 5 - .../iframe_messageChannel_sharedWorker2.html | 14 - .../iframe_messageChannel_transferable.html | 26 - dom/messagechannel/tests/mochitest.ini | 25 - dom/messagechannel/tests/moz.build | 8 - .../tests/sharedWorker2_messageChannel.js | 7 - .../tests/sharedWorker_messageChannel.js | 8 - .../tests/test_messageChannel_any.html | 115 --- .../test_messageChannel_selfTransferring.html | 38 - .../test_messageChannel_sharedWorker.html | 39 - .../test_messageChannel_sharedWorker2.html | 37 - .../tests/test_messageChannel_worker.html | 60 -- .../tests/worker_messageChannel.js | 119 --- .../tests/worker_messageChannel_any.js | 7 - dom/moz.build | 1 - dom/webidl/MessageChannel.webidl | 3 +- dom/workers/MessagePort.cpp | 13 +- dom/workers/MessagePort.h | 10 +- dom/workers/ServiceWorkerClient.cpp | 22 +- dom/workers/WorkerPrivate.cpp | 226 ++--- dom/workers/WorkerPrivate.h | 3 +- dom/workers/WorkerStructuredClone.h | 53 -- dom/workers/XMLHttpRequest.cpp | 62 +- dom/workers/XMLHttpRequest.h | 3 +- dom/workers/test/sharedWorker_sharedWorker.js | 4 +- ipc/glue/BackgroundChild.h | 5 - ipc/glue/BackgroundChildImpl.cpp | 23 - ipc/glue/BackgroundChildImpl.h | 7 - ipc/glue/BackgroundImpl.cpp | 20 +- ipc/glue/BackgroundParentImpl.cpp | 38 - ipc/glue/BackgroundParentImpl.h | 14 - ipc/glue/PBackground.ipdl | 4 - js/public/StructuredClone.h | 2 +- js/src/vm/StructuredClone.cpp | 6 +- .../event-ports-dedicated.html.ini | 5 + 87 files changed, 1349 insertions(+), 4217 deletions(-) create mode 100644 dom/base/MessageChannel.cpp rename dom/{messagechannel => base}/MessageChannel.h (99%) create mode 100644 dom/base/MessagePort.cpp create mode 100644 dom/base/MessagePort.h rename dom/{messagechannel => base}/MessagePortList.cpp (100%) rename dom/{messagechannel => base}/MessagePortList.h (100%) delete mode 100644 dom/base/PostMessageEvent.cpp delete mode 100644 dom/base/PostMessageEvent.h rename dom/{messagechannel/tests => base/test}/iframe_messageChannel_chrome.html (100%) rename dom/{messagechannel/tests => base/test}/iframe_messageChannel_cloning.html (100%) rename dom/{messagechannel/tests => base/test}/iframe_messageChannel_pingpong.html (100%) rename dom/{messagechannel/tests => base/test}/iframe_messageChannel_post.html (100%) rename dom/{messagechannel/tests => base/test}/test_messageChannel.html (100%) rename dom/{messagechannel/tests => base/test}/test_messageChannel.xul (91%) rename dom/{messagechannel/tests => base/test}/test_messageChannel_cloning.html (100%) rename dom/{messagechannel/tests => base/test}/test_messageChannel_pingpong.html (100%) rename dom/{messagechannel/tests => base/test}/test_messageChannel_post.html (100%) rename dom/{messagechannel/tests => base/test}/test_messageChannel_pref.html (100%) rename dom/{messagechannel/tests => base/test}/test_messageChannel_start.html (100%) rename dom/{messagechannel/tests => base/test}/test_messageChannel_transferable.html (57%) rename dom/{messagechannel/tests => base/test}/test_messageChannel_unshipped.html (100%) delete mode 100644 dom/messagechannel/MessageChannel.cpp delete mode 100644 dom/messagechannel/MessagePort.cpp delete mode 100644 dom/messagechannel/MessagePort.h delete mode 100644 dom/messagechannel/MessagePortChild.cpp delete mode 100644 dom/messagechannel/MessagePortChild.h delete mode 100644 dom/messagechannel/MessagePortParent.cpp delete mode 100644 dom/messagechannel/MessagePortParent.h delete mode 100644 dom/messagechannel/MessagePortService.cpp delete mode 100644 dom/messagechannel/MessagePortService.h delete mode 100644 dom/messagechannel/MessagePortUtils.cpp delete mode 100644 dom/messagechannel/MessagePortUtils.h delete mode 100644 dom/messagechannel/PMessagePort.ipdl delete mode 100644 dom/messagechannel/SharedMessagePortMessage.cpp delete mode 100644 dom/messagechannel/SharedMessagePortMessage.h delete mode 100644 dom/messagechannel/moz.build delete mode 100644 dom/messagechannel/tests/chrome.ini delete mode 100644 dom/messagechannel/tests/iframe_messageChannel_sharedWorker2.html delete mode 100644 dom/messagechannel/tests/iframe_messageChannel_transferable.html delete mode 100644 dom/messagechannel/tests/mochitest.ini delete mode 100644 dom/messagechannel/tests/moz.build delete mode 100644 dom/messagechannel/tests/sharedWorker2_messageChannel.js delete mode 100644 dom/messagechannel/tests/sharedWorker_messageChannel.js delete mode 100644 dom/messagechannel/tests/test_messageChannel_any.html delete mode 100644 dom/messagechannel/tests/test_messageChannel_selfTransferring.html delete mode 100644 dom/messagechannel/tests/test_messageChannel_sharedWorker.html delete mode 100644 dom/messagechannel/tests/test_messageChannel_sharedWorker2.html delete mode 100644 dom/messagechannel/tests/test_messageChannel_worker.html delete mode 100644 dom/messagechannel/tests/worker_messageChannel.js delete mode 100644 dom/messagechannel/tests/worker_messageChannel_any.js delete mode 100644 dom/workers/WorkerStructuredClone.h create mode 100644 testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html.ini diff --git a/dom/base/MessageChannel.cpp b/dom/base/MessageChannel.cpp new file mode 100644 index 000000000000..e04ca2fc72d3 --- /dev/null +++ b/dom/base/MessageChannel.cpp @@ -0,0 +1,104 @@ +/* -*- Mode: C++; tab-width: 8; 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 "MessageChannel.h" + +#include "mozilla/Preferences.h" +#include "mozilla/dom/MessageChannelBinding.h" +#include "mozilla/dom/MessagePort.h" +#include "nsContentUtils.h" +#include "nsPIDOMWindow.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mWindow, mPort1, mPort2) +NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel) +NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +namespace { + bool gPrefInitialized = false; + bool gPrefEnabled = false; + +} + +/* static */ bool +MessageChannel::Enabled(JSContext* aCx, JSObject* aObj) +{ + if (!gPrefInitialized) { + Preferences::AddBoolVarCache(&gPrefEnabled, "dom.messageChannel.enabled"); + gPrefInitialized = true; + } + + // Enabled by pref + if (gPrefEnabled) { + return true; + } + + // Chrome callers are allowed. + if (nsContentUtils::ThreadsafeIsCallerChrome()) { + return true; + } + + nsCOMPtr principal = nsContentUtils::SubjectPrincipal(); + MOZ_ASSERT(principal); + + nsCOMPtr uri; + if (NS_FAILED(principal->GetURI(getter_AddRefs(uri))) || !uri) { + return false; + } + + bool isResource = false; + if (NS_FAILED(uri->SchemeIs("resource", &isResource))) { + return false; + } + + return isResource; +} + +MessageChannel::MessageChannel(nsPIDOMWindow* aWindow) + : mWindow(aWindow) +{ + MOZ_COUNT_CTOR(MessageChannel); + + mPort1 = new MessagePort(mWindow); + mPort2 = new MessagePort(mWindow); + + mPort1->Entangle(mPort2); + mPort2->Entangle(mPort1); +} + +MessageChannel::~MessageChannel() +{ + MOZ_COUNT_DTOR(MessageChannel); +} + +JSObject* +MessageChannel::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return MessageChannelBinding::Wrap(aCx, this, aGivenProto); +} + +/* static */ already_AddRefed +MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) +{ + nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); + if (!window) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsRefPtr channel = new MessageChannel(window); + return channel.forget(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/messagechannel/MessageChannel.h b/dom/base/MessageChannel.h similarity index 99% rename from dom/messagechannel/MessageChannel.h rename to dom/base/MessageChannel.h index a20921dfa8e8..14a14b5c5d6c 100644 --- a/dom/messagechannel/MessageChannel.h +++ b/dom/base/MessageChannel.h @@ -31,6 +31,8 @@ public: static bool Enabled(JSContext* aCx, JSObject* aGlobal); public: + explicit MessageChannel(nsPIDOMWindow* aWindow); + nsPIDOMWindow* GetParentObject() const { @@ -56,7 +58,6 @@ public: } private: - explicit MessageChannel(nsPIDOMWindow* aWindow); ~MessageChannel(); nsCOMPtr mWindow; diff --git a/dom/base/MessagePort.cpp b/dom/base/MessagePort.cpp new file mode 100644 index 000000000000..fbbafbdbf464 --- /dev/null +++ b/dom/base/MessagePort.cpp @@ -0,0 +1,564 @@ +/* -*- Mode: C++; tab-width: 8; 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 "MessagePort.h" +#include "MessageEvent.h" +#include "mozilla/dom/BlobBinding.h" +#include "mozilla/dom/Event.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/MessageChannel.h" +#include "mozilla/dom/MessagePortBinding.h" +#include "mozilla/dom/MessagePortList.h" +#include "mozilla/dom/StructuredCloneTags.h" +#include "nsContentUtils.h" +#include "nsGlobalWindow.h" +#include "nsPresContext.h" +#include "ScriptSettings.h" + +#include "nsIDocument.h" +#include "nsIDOMFileList.h" +#include "nsIPresShell.h" + +namespace mozilla { +namespace dom { + +class DispatchEventRunnable : public nsRunnable +{ + friend class MessagePort; + + public: + explicit DispatchEventRunnable(MessagePort* aPort) + : mPort(aPort) + { + } + + NS_IMETHOD + Run() + { + nsRefPtr mKungFuDeathGrip(this); + + mPort->mDispatchRunnable = nullptr; + mPort->Dispatch(); + + return NS_OK; + } + + private: + nsRefPtr mPort; +}; + +class PostMessageRunnable : public nsRunnable +{ + friend class MessagePort; + + public: + NS_DECL_NSIRUNNABLE + + PostMessageRunnable() + { + } + + ~PostMessageRunnable() + { + } + + JSAutoStructuredCloneBuffer& Buffer() + { + return mBuffer; + } + + bool StoreISupports(nsISupports* aSupports) + { + mSupportsArray.AppendElement(aSupports); + return true; + } + + void Dispatch(MessagePort* aPort) + { + mPort = aPort; + NS_DispatchToCurrentThread(this); + } + + private: + nsRefPtr mPort; + JSAutoStructuredCloneBuffer mBuffer; + + nsTArray > mSupportsArray; +}; + +namespace { + +struct StructuredCloneInfo +{ + PostMessageRunnable* mEvent; + MessagePort* mPort; + nsRefPtrHashtable, MessagePortBase> mPorts; +}; + +static JSObject* +PostMessageReadStructuredClone(JSContext* cx, + JSStructuredCloneReader* reader, + uint32_t tag, + uint32_t data, + void* closure) +{ + StructuredCloneInfo* scInfo = static_cast(closure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (tag == SCTAG_DOM_BLOB) { + NS_ASSERTION(!data, "Data should be empty"); + + // What we get back from the reader is a BlobImpl. + // From that we create a new File. + BlobImpl* blobImpl; + if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) { + MOZ_ASSERT(blobImpl); + + // nsRefPtr needs to go out of scope before toObjectOrNull() is + // called because the static analysis thinks dereferencing XPCOM objects + // can GC (because in some cases it can!), and a return statement with a + // JSObject* type means that JSObject* is on the stack as a raw pointer + // while destructors are running. + JS::Rooted val(cx); + { + nsRefPtr blob = Blob::Create(scInfo->mPort->GetParentObject(), + blobImpl); + if (!ToJSValue(cx, blob, &val)) { + return nullptr; + } + } + + return &val.toObject(); + } + } + + if (tag == SCTAG_DOM_FILELIST) { + NS_ASSERTION(!data, "Data should be empty"); + + nsISupports* supports; + if (JS_ReadBytes(reader, &supports, sizeof(supports))) { + JS::Rooted val(cx); + if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) { + return val.toObjectOrNull(); + } + } + } + + const JSStructuredCloneCallbacks* runtimeCallbacks = + js::GetContextStructuredCloneCallbacks(cx); + + if (runtimeCallbacks) { + return runtimeCallbacks->read(cx, reader, tag, data, nullptr); + } + + return nullptr; +} + +static bool +PostMessageWriteStructuredClone(JSContext* cx, + JSStructuredCloneWriter* writer, + JS::Handle obj, + void *closure) +{ + StructuredCloneInfo* scInfo = static_cast(closure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + // See if this is a File/Blob object. + { + Blob* blob = nullptr; + if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) { + BlobImpl* blobImpl = blob->Impl(); + if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) && + JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) { + scInfo->mEvent->StoreISupports(blobImpl); + return true; + } + } + } + + nsCOMPtr wrappedNative; + nsContentUtils::XPConnect()-> + GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative)); + if (wrappedNative) { + uint32_t scTag = 0; + nsISupports* supports = wrappedNative->Native(); + + nsCOMPtr list = do_QueryInterface(supports); + if (list) { + scTag = SCTAG_DOM_FILELIST; + } + + if (scTag) { + return JS_WriteUint32Pair(writer, scTag, 0) && + JS_WriteBytes(writer, &supports, sizeof(supports)) && + scInfo->mEvent->StoreISupports(supports); + } + } + + const JSStructuredCloneCallbacks* runtimeCallbacks = + js::GetContextStructuredCloneCallbacks(cx); + + if (runtimeCallbacks) { + return runtimeCallbacks->write(cx, writer, obj, nullptr); + } + + return false; +} + +static bool +PostMessageReadTransferStructuredClone(JSContext* aCx, + JSStructuredCloneReader* reader, + uint32_t tag, void* data, + uint64_t unused, + void* aClosure, + JS::MutableHandle returnObject) +{ + StructuredCloneInfo* scInfo = static_cast(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (tag == SCTAG_DOM_MAP_MESSAGEPORT) { + MessagePort* port = static_cast(data); + port->BindToOwner(scInfo->mPort->GetOwner()); + scInfo->mPorts.Put(port, nullptr); + + JS::Rooted obj(aCx, port->WrapObject(aCx, nullptr)); + if (!obj || !JS_WrapObject(aCx, &obj)) { + return false; + } + + MOZ_ASSERT(port->GetOwner() == scInfo->mPort->GetOwner()); + returnObject.set(obj); + return true; + } + + return false; +} + +static bool +PostMessageTransferStructuredClone(JSContext* aCx, + JS::Handle aObj, + void* aClosure, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t *aExtraData) +{ + StructuredCloneInfo* scInfo = static_cast(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + MessagePortBase *port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); + if (NS_SUCCEEDED(rv)) { + nsRefPtr newPort; + if (scInfo->mPorts.Get(port, getter_AddRefs(newPort))) { + // No duplicate. + return false; + } + + newPort = port->Clone(); + scInfo->mPorts.Put(port, newPort); + + *aTag = SCTAG_DOM_MAP_MESSAGEPORT; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = newPort; + *aExtraData = 0; + + return true; + } + + return false; +} + +static void +PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership, + void* aData, + uint64_t aExtraData, + void* aClosure) +{ + StructuredCloneInfo* scInfo = static_cast(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { + MOZ_ASSERT(aOwnership == JS::SCTAG_TMO_CUSTOM); + nsRefPtr port(static_cast(aData)); + scInfo->mPorts.Remove(port); + } +} + +const JSStructuredCloneCallbacks kPostMessageCallbacks = { + PostMessageReadStructuredClone, + PostMessageWriteStructuredClone, + nullptr, + PostMessageReadTransferStructuredClone, + PostMessageTransferStructuredClone, + PostMessageFreeTransferStructuredClone +}; + +} // anonymous namespace + +static PLDHashOperator +PopulateMessagePortList(MessagePortBase* aKey, MessagePortBase* aValue, void* aClosure) +{ + nsTArray > *array = + static_cast > *>(aClosure); + + array->AppendElement(aKey); + return PL_DHASH_NEXT; +} + +NS_IMETHODIMP +PostMessageRunnable::Run() +{ + MOZ_ASSERT(mPort); + + AutoJSAPI jsapi; + if (NS_WARN_IF(!jsapi.Init(mPort->GetParentObject()))) { + return NS_ERROR_UNEXPECTED; + } + JSContext* cx = jsapi.cx(); + + // Deserialize the structured clone data + JS::Rooted messageData(cx); + StructuredCloneInfo scInfo; + scInfo.mEvent = this; + scInfo.mPort = mPort; + + if (!mBuffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo)) { + return NS_ERROR_DOM_DATA_CLONE_ERR; + } + + // Create the event + nsCOMPtr eventTarget = + do_QueryInterface(mPort->GetOwner()); + nsRefPtr event = + new MessageEvent(eventTarget, nullptr, nullptr); + + event->InitMessageEvent(NS_LITERAL_STRING("message"), false /* non-bubbling */, + false /* cancelable */, messageData, EmptyString(), + EmptyString(), nullptr); + event->SetTrusted(true); + event->SetSource(mPort); + + nsTArray > ports; + scInfo.mPorts.EnumerateRead(PopulateMessagePortList, &ports); + event->SetPorts(new MessagePortList(static_cast(event.get()), ports)); + + bool status; + mPort->DispatchEvent(static_cast(event.get()), &status); + return status ? NS_OK : NS_ERROR_FAILURE; +} + +MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow) + : DOMEventTargetHelper(aWindow) +{ +} + +MessagePortBase::MessagePortBase() +{ +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mEntangledPort) + + // Custom unlink loop because this array contains nsRunnable objects + // which are not cycle colleactable. + while (!tmp->mMessageQueue.IsEmpty()) { + NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mPort); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessageQueue[0]->mSupportsArray); + tmp->mMessageQueue.RemoveElementAt(0); + } + + if (tmp->mDispatchRunnable) { + NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort); + } + +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort, + DOMEventTargetHelper) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEntangledPort) + + // Custom unlink loop because this array contains nsRunnable objects + // which are not cycle colleactable. + for (uint32_t i = 0, len = tmp->mMessageQueue.Length(); i < len; ++i) { + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mPort); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMessageQueue[i]->mSupportsArray); + } + + if (tmp->mDispatchRunnable) { + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort); + } + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper) + +MessagePort::MessagePort(nsPIDOMWindow* aWindow) + : MessagePortBase(aWindow) + , mMessageQueueEnabled(false) +{ +} + +MessagePort::~MessagePort() +{ + Close(); +} + +JSObject* +MessagePort::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return MessagePortBinding::Wrap(aCx, this, aGivenProto); +} + +void +MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) +{ + nsRefPtr event = new PostMessageRunnable(); + + // We *must* clone the data here, or the JS::Value could be modified + // by script + StructuredCloneInfo scInfo; + scInfo.mEvent = event; + scInfo.mPort = this; + + JS::Rooted transferable(aCx, JS::UndefinedValue()); + if (aTransferable.WasPassed()) { + const Sequence& realTransferable = aTransferable.Value(); + + // The input sequence only comes from the generated bindings code, which + // ensures it is rooted. + JS::HandleValueArray elements = + JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), + realTransferable.Elements()); + + JSObject* array = + JS_NewArrayObject(aCx, elements); + if (!array) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + transferable.setObject(*array); + } + + if (!event->Buffer().write(aCx, aMessage, transferable, + &kPostMessageCallbacks, &scInfo)) { + aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); + return; + } + + if (!mEntangledPort) { + return; + } + + mEntangledPort->mMessageQueue.AppendElement(event); + mEntangledPort->Dispatch(); +} + +void +MessagePort::Start() +{ + if (mMessageQueueEnabled) { + return; + } + + mMessageQueueEnabled = true; + Dispatch(); +} + +void +MessagePort::Dispatch() +{ + if (!mMessageQueueEnabled || mMessageQueue.IsEmpty() || mDispatchRunnable) { + return; + } + + nsRefPtr event = mMessageQueue.ElementAt(0); + mMessageQueue.RemoveElementAt(0); + + event->Dispatch(this); + + mDispatchRunnable = new DispatchEventRunnable(this); + NS_DispatchToCurrentThread(mDispatchRunnable); +} + +void +MessagePort::Close() +{ + if (!mEntangledPort) { + return; + } + + // This avoids loops. + nsRefPtr port = mEntangledPort; + mEntangledPort = nullptr; + + // Let's disentangle the 2 ports symmetrically. + port->Close(); +} + +EventHandlerNonNull* +MessagePort::GetOnmessage() +{ + if (NS_IsMainThread()) { + return GetEventHandler(nsGkAtoms::onmessage, EmptyString()); + } + return GetEventHandler(nullptr, NS_LITERAL_STRING("message")); +} + +void +MessagePort::SetOnmessage(EventHandlerNonNull* aCallback) +{ + if (NS_IsMainThread()) { + SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback); + } else { + SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback); + } + + // When using onmessage, the call to start() is implied. + Start(); +} + +void +MessagePort::Entangle(MessagePort* aMessagePort) +{ + MOZ_ASSERT(aMessagePort); + MOZ_ASSERT(aMessagePort != this); + + Close(); + + mEntangledPort = aMessagePort; +} + +already_AddRefed +MessagePort::Clone() +{ + nsRefPtr newPort = new MessagePort(nullptr); + + // Move all the events in the port message queue of original port. + newPort->mMessageQueue.SwapElements(mMessageQueue); + + if (mEntangledPort) { + nsRefPtr port = mEntangledPort; + mEntangledPort = nullptr; + + newPort->Entangle(port); + port->Entangle(newPort); + } + + return newPort.forget(); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/base/MessagePort.h b/dom/base/MessagePort.h new file mode 100644 index 000000000000..fe51bc295fd0 --- /dev/null +++ b/dom/base/MessagePort.h @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 8; 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/. */ + +#ifndef mozilla_dom_MessagePort_h +#define mozilla_dom_MessagePort_h + +#include "mozilla/Attributes.h" +#include "mozilla/DOMEventTargetHelper.h" + +class nsPIDOMWindow; + +namespace mozilla { +namespace dom { + +class DispatchEventRunnable; +class PostMessageRunnable; + +class MessagePortBase : public DOMEventTargetHelper +{ +protected: + explicit MessagePortBase(nsPIDOMWindow* aWindow); + MessagePortBase(); + +public: + + virtual void + PostMessageMoz(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) = 0; + + virtual void + Start() = 0; + + virtual void + Close() = 0; + + // The 'message' event handler has to call |Start()| method, so we + // cannot use IMPL_EVENT_HANDLER macro here. + virtual EventHandlerNonNull* + GetOnmessage() = 0; + + virtual void + SetOnmessage(EventHandlerNonNull* aCallback) = 0; + + // Duplicate this message port. This method is used by the Structured Clone + // Algorithm and makes the new MessagePort active with the entangled + // MessagePort of this object. + virtual already_AddRefed + Clone() = 0; +}; + +class MessagePort final : public MessagePortBase +{ + friend class DispatchEventRunnable; + friend class PostMessageRunnable; + +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, + DOMEventTargetHelper) + + explicit MessagePort(nsPIDOMWindow* aWindow); + + virtual JSObject* + WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + virtual void + PostMessageMoz(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) override; + + virtual void + Start() override; + + virtual void + Close() override; + + virtual EventHandlerNonNull* + GetOnmessage() override; + + virtual void + SetOnmessage(EventHandlerNonNull* aCallback) override; + + // Non WebIDL methods + + // This method entangles this MessagePort with another one. + // If it is already entangled, it's disentangled first and enatangle to the + // new one. + void + Entangle(MessagePort* aMessagePort); + + virtual already_AddRefed + Clone() override; + +private: + ~MessagePort(); + + // Dispatch events from the Message Queue using a nsRunnable. + void Dispatch(); + + nsRefPtr mDispatchRunnable; + + nsRefPtr mEntangledPort; + + nsTArray > mMessageQueue; + bool mMessageQueueEnabled; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_MessagePort_h diff --git a/dom/messagechannel/MessagePortList.cpp b/dom/base/MessagePortList.cpp similarity index 100% rename from dom/messagechannel/MessagePortList.cpp rename to dom/base/MessagePortList.cpp diff --git a/dom/messagechannel/MessagePortList.h b/dom/base/MessagePortList.h similarity index 100% rename from dom/messagechannel/MessagePortList.h rename to dom/base/MessagePortList.h diff --git a/dom/base/NodeInfo.cpp b/dom/base/NodeInfo.cpp index 00166783758f..8c60eee4f455 100644 --- a/dom/base/NodeInfo.cpp +++ b/dom/base/NodeInfo.cpp @@ -111,7 +111,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(NodeInfo) NS_IMPL_CYCLE_COLLECTION_UNLINK_0(NodeInfo) -static const char* kNodeInfoNSURIs[] = { +static const char* kNSURIs[] = { " ([none])", " (xmlns)", " (xml)", @@ -129,8 +129,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(NodeInfo) char name[72]; uint32_t nsid = tmp->NamespaceID(); nsAtomCString localName(tmp->NameAtom()); - if (nsid < ArrayLength(kNodeInfoNSURIs)) { - PR_snprintf(name, sizeof(name), "NodeInfo%s %s", kNodeInfoNSURIs[nsid], + if (nsid < ArrayLength(kNSURIs)) { + PR_snprintf(name, sizeof(name), "NodeInfo%s %s", kNSURIs[nsid], localName.get()); } else { diff --git a/dom/base/PostMessageEvent.cpp b/dom/base/PostMessageEvent.cpp deleted file mode 100644 index 6070015a8322..000000000000 --- a/dom/base/PostMessageEvent.cpp +++ /dev/null @@ -1,389 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; 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 "PostMessageEvent.h" - -#include "MessageEvent.h" -#include "mozilla/dom/BlobBinding.h" -#include "mozilla/dom/MessagePort.h" -#include "mozilla/dom/MessagePortBinding.h" -#include "mozilla/dom/PMessagePort.h" -#include "mozilla/dom/StructuredCloneTags.h" -#include "mozilla/EventDispatcher.h" -#include "nsGlobalWindow.h" -#include "nsIPresShell.h" -#include "nsIPrincipal.h" - -namespace mozilla { -namespace dom { - -namespace { - -struct StructuredCloneInfo -{ - PostMessageEvent* event; - bool subsumes; - nsPIDOMWindow* window; - - // This hashtable contains the transferred ports - used to avoid duplicates. - nsTArray> transferredPorts; - - // This array is populated when the ports are cloned. - nsTArray> clonedPorts; -}; - -} // anonymous namespace - -const JSStructuredCloneCallbacks PostMessageEvent::sPostMessageCallbacks = { - PostMessageEvent::ReadStructuredClone, - PostMessageEvent::WriteStructuredClone, - nullptr, - PostMessageEvent::ReadTransferStructuredClone, - PostMessageEvent::TransferStructuredClone, - PostMessageEvent::FreeTransferStructuredClone -}; - -/* static */ JSObject* -PostMessageEvent::ReadStructuredClone(JSContext* cx, - JSStructuredCloneReader* reader, - uint32_t tag, - uint32_t data, - void* closure) -{ - StructuredCloneInfo* scInfo = static_cast(closure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (tag == SCTAG_DOM_BLOB) { - NS_ASSERTION(!data, "Data should be empty"); - - // What we get back from the reader is a BlobImpl. - // From that we create a new File. - BlobImpl* blobImpl; - if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) { - MOZ_ASSERT(blobImpl); - - // nsRefPtr needs to go out of scope before toObjectOrNull() is - // called because the static analysis thinks dereferencing XPCOM objects - // can GC (because in some cases it can!), and a return statement with a - // JSObject* type means that JSObject* is on the stack as a raw pointer - // while destructors are running. - JS::Rooted val(cx); - { - nsRefPtr blob = Blob::Create(scInfo->window, blobImpl); - if (!ToJSValue(cx, blob, &val)) { - return nullptr; - } - } - - return &val.toObject(); - } - } - - if (tag == SCTAG_DOM_FILELIST) { - NS_ASSERTION(!data, "Data should be empty"); - - nsISupports* supports; - if (JS_ReadBytes(reader, &supports, sizeof(supports))) { - JS::Rooted val(cx); - if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) { - return val.toObjectOrNull(); - } - } - } - - const JSStructuredCloneCallbacks* runtimeCallbacks = - js::GetContextStructuredCloneCallbacks(cx); - - if (runtimeCallbacks) { - return runtimeCallbacks->read(cx, reader, tag, data, nullptr); - } - - return nullptr; -} - -/* static */ bool -PostMessageEvent::WriteStructuredClone(JSContext* cx, - JSStructuredCloneWriter* writer, - JS::Handle obj, - void *closure) -{ - StructuredCloneInfo* scInfo = static_cast(closure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - // See if this is a File/Blob object. - { - Blob* blob = nullptr; - if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) { - BlobImpl* blobImpl = blob->Impl(); - if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) && - JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) { - scInfo->event->StoreISupports(blobImpl); - return true; - } - } - } - - nsCOMPtr wrappedNative; - nsContentUtils::XPConnect()-> - GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative)); - if (wrappedNative) { - uint32_t scTag = 0; - nsISupports* supports = wrappedNative->Native(); - - nsCOMPtr list = do_QueryInterface(supports); - if (list && scInfo->subsumes) - scTag = SCTAG_DOM_FILELIST; - - if (scTag) - return JS_WriteUint32Pair(writer, scTag, 0) && - JS_WriteBytes(writer, &supports, sizeof(supports)) && - scInfo->event->StoreISupports(supports); - } - - const JSStructuredCloneCallbacks* runtimeCallbacks = - js::GetContextStructuredCloneCallbacks(cx); - - if (runtimeCallbacks) { - return runtimeCallbacks->write(cx, writer, obj, nullptr); - } - - return false; -} - -/* static */ bool -PostMessageEvent::ReadTransferStructuredClone(JSContext* aCx, - JSStructuredCloneReader* reader, - uint32_t tag, void* aData, - uint64_t aExtraData, - void* aClosure, - JS::MutableHandle returnObject) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - if (tag == SCTAG_DOM_MAP_MESSAGEPORT) { - MOZ_ASSERT(!aData); - // aExtraData is the index of this port identifier. - ErrorResult rv; - nsRefPtr port = - MessagePort::Create(scInfo->window, - scInfo->event->GetPortIdentifier(aExtraData), - rv); - if (NS_WARN_IF(rv.Failed())) { - return false; - } - - scInfo->clonedPorts.AppendElement(port); - - JS::Rooted value(aCx); - if (!GetOrCreateDOMReflector(aCx, port, &value)) { - JS_ClearPendingException(aCx); - return false; - } - - returnObject.set(&value.toObject()); - return true; - } - - return false; -} - -/* static */ bool -PostMessageEvent::TransferStructuredClone(JSContext* aCx, - JS::Handle aObj, - void* aClosure, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t* aExtraData) -{ - StructuredCloneInfo* scInfo = static_cast(aClosure); - NS_ASSERTION(scInfo, "Must have scInfo!"); - - MessagePortBase* port = nullptr; - nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); - if (NS_SUCCEEDED(rv)) { - if (scInfo->transferredPorts.Contains(port)) { - // No duplicates. - return false; - } - - // We use aExtraData to store the index of this new port identifier. - MessagePortIdentifier* identifier = - scInfo->event->NewPortIdentifier(aExtraData); - - if (!port->CloneAndDisentangle(*identifier)) { - return false; - } - - scInfo->transferredPorts.AppendElement(port); - - *aTag = SCTAG_DOM_MAP_MESSAGEPORT; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = nullptr; - - return true; - } - - return false; -} - -/* static */ void -PostMessageEvent::FreeTransferStructuredClone(uint32_t aTag, - JS::TransferableOwnership aOwnership, - void *aContent, - uint64_t aExtraData, - void* aClosure) -{ - // Nothing to do. -} - -PostMessageEvent::PostMessageEvent(nsGlobalWindow* aSource, - const nsAString& aCallerOrigin, - nsGlobalWindow* aTargetWindow, - nsIPrincipal* aProvidedPrincipal, - bool aTrustedCaller) -: mSource(aSource), - mCallerOrigin(aCallerOrigin), - mTargetWindow(aTargetWindow), - mProvidedPrincipal(aProvidedPrincipal), - mTrustedCaller(aTrustedCaller) -{ - MOZ_COUNT_CTOR(PostMessageEvent); -} - -PostMessageEvent::~PostMessageEvent() -{ - MOZ_COUNT_DTOR(PostMessageEvent); -} - -const MessagePortIdentifier& -PostMessageEvent::GetPortIdentifier(uint64_t aId) -{ - MOZ_ASSERT(aId < mPortIdentifiers.Length()); - return mPortIdentifiers[aId]; -} - -MessagePortIdentifier* -PostMessageEvent::NewPortIdentifier(uint64_t* aPosition) -{ - *aPosition = mPortIdentifiers.Length(); - return mPortIdentifiers.AppendElement(); -} - -NS_IMETHODIMP -PostMessageEvent::Run() -{ - MOZ_ASSERT(mTargetWindow->IsOuterWindow(), - "should have been passed an outer window!"); - MOZ_ASSERT(!mSource || mSource->IsOuterWindow(), - "should have been passed an outer window!"); - - AutoJSAPI jsapi; - jsapi.Init(); - JSContext* cx = jsapi.cx(); - - // If we bailed before this point we're going to leak mMessage, but - // that's probably better than crashing. - - nsRefPtr targetWindow; - if (mTargetWindow->IsClosedOrClosing() || - !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) || - targetWindow->IsClosedOrClosing()) - return NS_OK; - - MOZ_ASSERT(targetWindow->IsInnerWindow(), - "we ordered an inner window!"); - JSAutoCompartment ac(cx, targetWindow->GetWrapperPreserveColor()); - - // Ensure that any origin which might have been provided is the origin of this - // window's document. Note that we do this *now* instead of when postMessage - // is called because the target window might have been navigated to a - // different location between then and now. If this check happened when - // postMessage was called, it would be fairly easy for a malicious webpage to - // intercept messages intended for another site by carefully timing navigation - // of the target window so it changed location after postMessage but before - // now. - if (mProvidedPrincipal) { - // 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 - // document. - nsIPrincipal* targetPrin = targetWindow->GetPrincipal(); - if (NS_WARN_IF(!targetPrin)) - return NS_OK; - - // Note: This is contrary to the spec with respect to file: URLs, which - // 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 - // now. Long-term, we want HTML5 to address this so that we can - // be compliant while being safer. - if (!targetPrin->Equals(mProvidedPrincipal)) { - return NS_OK; - } - } - - // Deserialize the structured clone data - JS::Rooted messageData(cx); - StructuredCloneInfo scInfo; - scInfo.event = this; - scInfo.window = targetWindow; - - if (!mBuffer.read(cx, &messageData, &sPostMessageCallbacks, &scInfo)) { - return NS_ERROR_DOM_DATA_CLONE_ERR; - } - - // Create the event - nsCOMPtr eventTarget = - do_QueryInterface(static_cast(targetWindow.get())); - nsRefPtr event = - new MessageEvent(eventTarget, nullptr, nullptr); - - event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */, - false /*cancelable */, messageData, mCallerOrigin, - EmptyString(), mSource); - - event->SetPorts(new MessagePortList(static_cast(event.get()), - scInfo.clonedPorts)); - - // We can't simply call dispatchEvent on the window because doing so ends - // up flipping the trusted bit on the event, and we don't want that to - // happen because then untrusted content can call postMessage on a chrome - // window if it can get a reference to it. - - nsIPresShell *shell = targetWindow->GetExtantDoc()->GetShell(); - nsRefPtr presContext; - if (shell) - presContext = shell->GetPresContext(); - - event->SetTrusted(mTrustedCaller); - WidgetEvent* internalEvent = event->GetInternalNSEvent(); - - nsEventStatus status = nsEventStatus_eIgnore; - EventDispatcher::Dispatch(static_cast(mTargetWindow), - presContext, - internalEvent, - static_cast(event.get()), - &status); - return NS_OK; -} - -bool -PostMessageEvent::Write(JSContext* aCx, JS::Handle aMessage, - JS::Handle aTransfer, bool aSubsumes, - nsPIDOMWindow* aWindow) -{ - // We *must* clone the data here, or the JS::Value could be modified - // by script - StructuredCloneInfo scInfo; - scInfo.event = this; - scInfo.window = aWindow; - - return mBuffer.write(aCx, aMessage, aTransfer, &sPostMessageCallbacks, - &scInfo); -} - -} // dom namespace -} // mozilla namespace diff --git a/dom/base/PostMessageEvent.h b/dom/base/PostMessageEvent.h deleted file mode 100644 index 917d4da05558..000000000000 --- a/dom/base/PostMessageEvent.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; 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/. */ - -#ifndef mozilla_dom_PostMessageEvent_h -#define mozilla_dom_PostMessageEvent_h - -#include "js/StructuredClone.h" -#include "nsCOMPtr.h" -#include "nsRefPtr.h" -#include "nsTArray.h" - -class nsGlobalWindow; -class nsIPrincipal; - -namespace mozilla { -namespace dom { - -class MessagePortBase; -class MessagePortIdentifier; - -/** - * Class used to represent events generated by calls to Window.postMessage, - * which asynchronously creates and dispatches events. - */ -class PostMessageEvent final : public nsRunnable -{ -public: - NS_DECL_NSIRUNNABLE - - PostMessageEvent(nsGlobalWindow* aSource, - const nsAString& aCallerOrigin, - nsGlobalWindow* aTargetWindow, - nsIPrincipal* aProvidedPrincipal, - bool aTrustedCaller); - - bool Write(JSContext* aCx, JS::Handle aMessage, - JS::Handle aTransfer, bool aSubsumes, - nsPIDOMWindow* aWindow); - -private: - ~PostMessageEvent(); - - const MessagePortIdentifier& GetPortIdentifier(uint64_t aId); - - MessagePortIdentifier* NewPortIdentifier(uint64_t* aPosition); - - bool StoreISupports(nsISupports* aSupports) - { - mSupportsArray.AppendElement(aSupports); - return true; - } - - static JSObject* - ReadStructuredClone(JSContext* cx, - JSStructuredCloneReader* reader, - uint32_t tag, - uint32_t data, - void* closure); - - static bool - WriteStructuredClone(JSContext* cx, - JSStructuredCloneWriter* writer, - JS::Handle obj, - void *closure); - - static bool - ReadTransferStructuredClone(JSContext* aCx, - JSStructuredCloneReader* reader, - uint32_t tag, void* aData, - uint64_t aExtraData, - void* aClosure, - JS::MutableHandle returnObject); - - static bool - TransferStructuredClone(JSContext* aCx, - JS::Handle aObj, - void* aClosure, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t* aExtraData); - - static void - FreeTransferStructuredClone(uint32_t aTag, - JS::TransferableOwnership aOwnership, - void *aContent, - uint64_t aExtraData, - void* aClosure); - - static const JSStructuredCloneCallbacks sPostMessageCallbacks; - - JSAutoStructuredCloneBuffer mBuffer; - nsRefPtr mSource; - nsString mCallerOrigin; - nsRefPtr mTargetWindow; - nsCOMPtr mProvidedPrincipal; - bool mTrustedCaller; - nsTArray> mSupportsArray; - nsTArray mPortIdentifiers; -}; - -} // dom namespace -} // mozilla namespace - -#endif // mozilla_dom_PostMessageEvent_h diff --git a/dom/base/ProcessGlobal.cpp b/dom/base/ProcessGlobal.cpp index dbd2e6700e50..21d89565de92 100644 --- a/dom/base/ProcessGlobal.cpp +++ b/dom/base/ProcessGlobal.cpp @@ -7,7 +7,6 @@ #include "ProcessGlobal.h" #include "nsContentCID.h" -#include "nsDOMClassInfoID.h" using namespace mozilla; using namespace mozilla::dom; diff --git a/dom/base/moz.build b/dom/base/moz.build index d2a15365bcc9..da333ad85598 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -179,6 +179,9 @@ EXPORTS.mozilla.dom += [ 'ImageEncoder.h', 'ImportManager.h', 'Link.h', + 'MessageChannel.h', + 'MessagePort.h', + 'MessagePortList.h', 'NameSpaceConstants.h', 'Navigator.h', 'NodeInfo.h', @@ -234,6 +237,8 @@ UNIFIED_SOURCES += [ 'ImageEncoder.cpp', 'ImportManager.cpp', 'Link.cpp', + 'MessageChannel.cpp', + 'MessagePortList.cpp', 'MultipartBlobImpl.cpp', 'Navigator.cpp', 'NodeInfo.cpp', @@ -324,7 +329,6 @@ UNIFIED_SOURCES += [ 'PerformanceMark.cpp', 'PerformanceMeasure.cpp', 'PerformanceResourceTiming.cpp', - 'PostMessageEvent.cpp', 'ProcessGlobal.cpp', 'ResponsiveImageSelector.cpp', 'SameProcessMessageQueue.cpp', @@ -349,6 +353,8 @@ if CONFIG['MOZ_WEBRTC']: # these files couldn't be in UNIFIED_SOURCES for now for reasons given below: SOURCES += [ + # this file doesn't like windows.h + 'MessagePort.cpp', # Because of OS X headers. 'nsContentUtils.cpp', # this file doesn't like windows.h diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 3349e65b57d8..922866c59760 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -218,7 +218,6 @@ nsIPrincipal *nsContentUtils::sNullSubjectPrincipal; nsIParserService *nsContentUtils::sParserService = nullptr; nsNameSpaceManager *nsContentUtils::sNameSpaceManager; nsIIOService *nsContentUtils::sIOService; -nsIUUIDGenerator *nsContentUtils::sUUIDGenerator; nsIConsoleService *nsContentUtils::sConsoleService; nsDataHashtable* nsContentUtils::sAtomEventTable = nullptr; nsDataHashtable* nsContentUtils::sStringEventTable = nullptr; @@ -552,13 +551,6 @@ nsContentUtils::Init() Element::InitCCCallbacks(); - nsCOMPtr uuidGenerator = - do_GetService("@mozilla.org/uuid-generator;1", &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - uuidGenerator.forget(&sUUIDGenerator); - sInitialized = true; return NS_OK; @@ -1811,7 +1803,6 @@ nsContentUtils::Shutdown() NS_IF_RELEASE(sNullSubjectPrincipal); NS_IF_RELEASE(sParserService); NS_IF_RELEASE(sIOService); - NS_IF_RELEASE(sUUIDGenerator); NS_IF_RELEASE(sLineBreaker); NS_IF_RELEASE(sWordBreaker); NS_IF_RELEASE(sBidiKeyboard); @@ -7160,19 +7151,6 @@ nsContentUtils::IsJavascriptMIMEType(const nsAString& aMIMEType) return false; } -nsresult -nsContentUtils::GenerateUUIDInPlace(nsID& aUUID) -{ - MOZ_ASSERT(sUUIDGenerator); - - nsresult rv = sUUIDGenerator->GenerateUUIDInPlace(&aUUID); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - return NS_OK; -} - uint64_t nsContentUtils::GetInnerWindowID(nsIRequest* aRequest) { diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 479cb67482e6..6ab02face49d 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -85,7 +85,6 @@ class nsIStringBundleService; class nsISupportsArray; class nsISupportsHashKey; class nsIURI; -class nsIUUIDGenerator; class nsIWidget; class nsIWordBreaker; class nsIXPConnect; @@ -854,11 +853,6 @@ public: */ static uint32_t ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr); - /** - * Helper function that generates a UUID. - */ - static nsresult GenerateUUIDInPlace(nsID& aUUID); - /** * Fill (with the parameters given) the localized string named |aKey| in @@ -2444,7 +2438,6 @@ private: static nsNameSpaceManager *sNameSpaceManager; static nsIIOService *sIOService; - static nsIUUIDGenerator *sUUIDGenerator; static bool sImgLoaderInitialized; static void InitImgLoader(); diff --git a/dom/base/nsCopySupport.cpp b/dom/base/nsCopySupport.cpp index 0885f275c203..bde0e70b9172 100644 --- a/dom/base/nsCopySupport.cpp +++ b/dom/base/nsCopySupport.cpp @@ -11,7 +11,6 @@ #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsIClipboard.h" -#include "nsIFormControl.h" #include "nsISelection.h" #include "nsWidgetsCID.h" #include "nsXPCOM.h" diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 7c6e3d20dfc1..e385c7997230 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -277,15 +277,15 @@ BuildClonedMessageData(typename BlobTraits::ConcreteContentManagerType* SerializedStructuredCloneBuffer& buffer = aClonedData.data(); buffer.data = aData.mData; buffer.dataLength = aData.mDataLength; - const nsTArray>& blobImpls = aData.mClosure.mBlobImpls; - if (!blobImpls.IsEmpty()) { + const nsTArray>& blobs = aData.mClosure.mBlobs; + if (!blobs.IsEmpty()) { typedef typename BlobTraits::ProtocolType ProtocolType; InfallibleTArray& blobList = DataBlobs::Blobs(aClonedData); - uint32_t length = blobImpls.Length(); + uint32_t length = blobs.Length(); blobList.SetCapacity(length); for (uint32_t i = 0; i < length; ++i) { typename BlobTraits::BlobType* protocolActor = - aManager->GetOrCreateActorForBlobImpl(blobImpls[i]); + aManager->GetOrCreateActorForBlob(blobs[i]); if (!protocolActor) { return false; } @@ -323,7 +323,7 @@ UnpackClonedMessageData(const ClonedMessageData& aData) cloneData.mDataLength = buffer.dataLength; if (!blobs.IsEmpty()) { uint32_t length = blobs.Length(); - cloneData.mClosure.mBlobImpls.SetCapacity(length); + cloneData.mClosure.mBlobs.SetCapacity(length); for (uint32_t i = 0; i < length; ++i) { auto* blob = static_cast::BlobType*>(blobs[i]); @@ -332,7 +332,10 @@ UnpackClonedMessageData(const ClonedMessageData& aData) nsRefPtr blobImpl = blob->GetBlobImpl(); MOZ_ASSERT(blobImpl); - cloneData.mClosure.mBlobImpls.AppendElement(blobImpl); + // This object will be duplicated with a correct parent before being + // exposed to JS. + nsRefPtr domBlob = Blob::Create(nullptr, blobImpl); + cloneData.mClosure.mBlobs.AppendElement(domBlob); } } return cloneData; diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index a48f08e661ee..7252824b72f0 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -59,6 +59,7 @@ #include "nsLayoutStatics.h" #include "nsCCUncollectableMarker.h" #include "mozilla/dom/workers/Workers.h" +#include "mozilla/dom/MessagePortList.h" #include "mozilla/dom/ToJSValue.h" #include "nsJSPrincipals.h" #include "mozilla/Attributes.h" @@ -68,9 +69,9 @@ #include "mozilla/MouseEvents.h" #include "mozilla/ProcessHangMonitor.h" #include "AudioChannelService.h" +#include "MessageEvent.h" #include "nsAboutProtocolUtils.h" #include "nsCharTraits.h" // NS_IS_HIGH/LOW_SURROGATE -#include "PostMessageEvent.h" // Interfaces Needed #include "nsIFrame.h" @@ -178,9 +179,13 @@ #include "prprf.h" #include "mozilla/dom/MessageChannel.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/indexedDB/IDBFactory.h" #include "mozilla/dom/Promise.h" +#include "mozilla/dom/StructuredCloneTags.h" + #ifdef MOZ_GAMEPAD #include "mozilla/dom/Gamepad.h" #include "mozilla/dom/GamepadService.h" @@ -202,6 +207,7 @@ #include "TimeChangeObserver.h" #include "TouchCaret.h" #include "mozilla/dom/AudioContext.h" +#include "mozilla/dom/BlobBinding.h" #include "mozilla/dom/BrowserElementDictionariesBinding.h" #include "mozilla/dom/cache/CacheStorage.h" #include "mozilla/dom/Console.h" @@ -8032,6 +8038,367 @@ nsGlobalWindow::CallerInnerWindow() return static_cast(win.get()); } +/** + * Class used to represent events generated by calls to Window.postMessage, + * which asynchronously creates and dispatches events. + */ +class PostMessageEvent : public nsRunnable +{ + public: + NS_DECL_NSIRUNNABLE + + PostMessageEvent(nsGlobalWindow* aSource, + const nsAString& aCallerOrigin, + nsGlobalWindow* aTargetWindow, + nsIPrincipal* aProvidedPrincipal, + bool aTrustedCaller) + : mSource(aSource), + mCallerOrigin(aCallerOrigin), + mTargetWindow(aTargetWindow), + mProvidedPrincipal(aProvidedPrincipal), + mTrustedCaller(aTrustedCaller) + { + MOZ_COUNT_CTOR(PostMessageEvent); + } + +protected: + ~PostMessageEvent() + { + MOZ_COUNT_DTOR(PostMessageEvent); + } + +public: + JSAutoStructuredCloneBuffer& Buffer() + { + return mBuffer; + } + + bool StoreISupports(nsISupports* aSupports) + { + mSupportsArray.AppendElement(aSupports); + return true; + } + + private: + JSAutoStructuredCloneBuffer mBuffer; + nsRefPtr mSource; + nsString mCallerOrigin; + nsRefPtr mTargetWindow; + nsCOMPtr mProvidedPrincipal; + bool mTrustedCaller; + nsTArray > mSupportsArray; +}; + +namespace { + +struct StructuredCloneInfo { + PostMessageEvent* event; + bool subsumes; + nsPIDOMWindow* window; + nsRefPtrHashtable, MessagePortBase> ports; +}; + +static JSObject* +PostMessageReadStructuredClone(JSContext* cx, + JSStructuredCloneReader* reader, + uint32_t tag, + uint32_t data, + void* closure) +{ + StructuredCloneInfo* scInfo = static_cast(closure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (tag == SCTAG_DOM_BLOB) { + NS_ASSERTION(!data, "Data should be empty"); + + // What we get back from the reader is a BlobImpl. + // From that we create a new File. + BlobImpl* blobImpl; + if (JS_ReadBytes(reader, &blobImpl, sizeof(blobImpl))) { + MOZ_ASSERT(blobImpl); + + // nsRefPtr needs to go out of scope before toObjectOrNull() is + // called because the static analysis thinks dereferencing XPCOM objects + // can GC (because in some cases it can!), and a return statement with a + // JSObject* type means that JSObject* is on the stack as a raw pointer + // while destructors are running. + JS::Rooted val(cx); + { + nsRefPtr blob = Blob::Create(scInfo->window, blobImpl); + if (!ToJSValue(cx, blob, &val)) { + return nullptr; + } + } + + return &val.toObject(); + } + } + + if (tag == SCTAG_DOM_FILELIST) { + NS_ASSERTION(!data, "Data should be empty"); + + nsISupports* supports; + if (JS_ReadBytes(reader, &supports, sizeof(supports))) { + JS::Rooted val(cx); + if (NS_SUCCEEDED(nsContentUtils::WrapNative(cx, supports, &val))) { + return val.toObjectOrNull(); + } + } + } + + const JSStructuredCloneCallbacks* runtimeCallbacks = + js::GetContextStructuredCloneCallbacks(cx); + + if (runtimeCallbacks) { + return runtimeCallbacks->read(cx, reader, tag, data, nullptr); + } + + return nullptr; +} + +static bool +PostMessageWriteStructuredClone(JSContext* cx, + JSStructuredCloneWriter* writer, + JS::Handle obj, + void *closure) +{ + StructuredCloneInfo* scInfo = static_cast(closure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + // See if this is a File/Blob object. + { + Blob* blob = nullptr; + if (scInfo->subsumes && NS_SUCCEEDED(UNWRAP_OBJECT(Blob, obj, blob))) { + BlobImpl* blobImpl = blob->Impl(); + if (JS_WriteUint32Pair(writer, SCTAG_DOM_BLOB, 0) && + JS_WriteBytes(writer, &blobImpl, sizeof(blobImpl))) { + scInfo->event->StoreISupports(blobImpl); + return true; + } + } + } + + nsCOMPtr wrappedNative; + nsContentUtils::XPConnect()-> + GetWrappedNativeOfJSObject(cx, obj, getter_AddRefs(wrappedNative)); + if (wrappedNative) { + uint32_t scTag = 0; + nsISupports* supports = wrappedNative->Native(); + + nsCOMPtr list = do_QueryInterface(supports); + if (list && scInfo->subsumes) + scTag = SCTAG_DOM_FILELIST; + + if (scTag) + return JS_WriteUint32Pair(writer, scTag, 0) && + JS_WriteBytes(writer, &supports, sizeof(supports)) && + scInfo->event->StoreISupports(supports); + } + + const JSStructuredCloneCallbacks* runtimeCallbacks = + js::GetContextStructuredCloneCallbacks(cx); + + if (runtimeCallbacks) { + return runtimeCallbacks->write(cx, writer, obj, nullptr); + } + + return false; +} + +static bool +PostMessageReadTransferStructuredClone(JSContext* aCx, + JSStructuredCloneReader* reader, + uint32_t tag, void* aData, + uint64_t aExtraData, + void* aClosure, + JS::MutableHandle returnObject) +{ + StructuredCloneInfo* scInfo = static_cast(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (tag == SCTAG_DOM_MAP_MESSAGEPORT) { + MessagePort* port = static_cast(aData); + port->BindToOwner(scInfo->window); + scInfo->ports.Put(port, nullptr); + + JS::Rooted obj(aCx, port->WrapObject(aCx, nullptr)); + if (JS_WrapObject(aCx, &obj)) { + MOZ_ASSERT(port->GetOwner() == scInfo->window); + returnObject.set(obj); + } + + return true; + } + + return false; +} + +static bool +PostMessageTransferStructuredClone(JSContext* aCx, + JS::Handle aObj, + void* aClosure, + uint32_t* aTag, + JS::TransferableOwnership* aOwnership, + void** aContent, + uint64_t* aExtraData) +{ + StructuredCloneInfo* scInfo = static_cast(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + MessagePortBase* port = nullptr; + nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); + if (NS_SUCCEEDED(rv)) { + nsRefPtr newPort; + if (scInfo->ports.Get(port, getter_AddRefs(newPort))) { + // No duplicate. + return false; + } + + newPort = port->Clone(); + scInfo->ports.Put(port, newPort); + + *aTag = SCTAG_DOM_MAP_MESSAGEPORT; + *aOwnership = JS::SCTAG_TMO_CUSTOM; + *aContent = newPort; + *aExtraData = 0; + + return true; + } + + return false; +} + +void +PostMessageFreeTransferStructuredClone(uint32_t aTag, JS::TransferableOwnership aOwnership, + void *aContent, uint64_t aExtraData, void* aClosure) +{ + StructuredCloneInfo* scInfo = static_cast(aClosure); + NS_ASSERTION(scInfo, "Must have scInfo!"); + + if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { + nsRefPtr port(static_cast(aContent)); + scInfo->ports.Remove(port); + } +} + +const JSStructuredCloneCallbacks kPostMessageCallbacks = { + PostMessageReadStructuredClone, + PostMessageWriteStructuredClone, + nullptr, + PostMessageReadTransferStructuredClone, + PostMessageTransferStructuredClone, + PostMessageFreeTransferStructuredClone +}; + +} // anonymous namespace + +static PLDHashOperator +PopulateMessagePortList(MessagePortBase* aKey, MessagePortBase* aValue, void* aClosure) +{ + nsTArray > *array = + static_cast > *>(aClosure); + + array->AppendElement(aKey); + return PL_DHASH_NEXT; +} + +NS_IMETHODIMP +PostMessageEvent::Run() +{ + MOZ_ASSERT(mTargetWindow->IsOuterWindow(), + "should have been passed an outer window!"); + MOZ_ASSERT(!mSource || mSource->IsOuterWindow(), + "should have been passed an outer window!"); + + AutoJSAPI jsapi; + jsapi.Init(); + JSContext* cx = jsapi.cx(); + + // If we bailed before this point we're going to leak mMessage, but + // that's probably better than crashing. + + nsRefPtr targetWindow; + if (mTargetWindow->IsClosedOrClosing() || + !(targetWindow = mTargetWindow->GetCurrentInnerWindowInternal()) || + targetWindow->IsClosedOrClosing()) + return NS_OK; + + MOZ_ASSERT(targetWindow->IsInnerWindow(), + "we ordered an inner window!"); + JSAutoCompartment ac(cx, targetWindow->GetWrapperPreserveColor()); + + // Ensure that any origin which might have been provided is the origin of this + // window's document. Note that we do this *now* instead of when postMessage + // is called because the target window might have been navigated to a + // different location between then and now. If this check happened when + // postMessage was called, it would be fairly easy for a malicious webpage to + // intercept messages intended for another site by carefully timing navigation + // of the target window so it changed location after postMessage but before + // now. + if (mProvidedPrincipal) { + // 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 + // document. + nsIPrincipal* targetPrin = targetWindow->GetPrincipal(); + if (NS_WARN_IF(!targetPrin)) + return NS_OK; + + // Note: This is contrary to the spec with respect to file: URLs, which + // 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 + // now. Long-term, we want HTML5 to address this so that we can + // be compliant while being safer. + if (!targetPrin->Equals(mProvidedPrincipal)) { + return NS_OK; + } + } + + // Deserialize the structured clone data + JS::Rooted messageData(cx); + StructuredCloneInfo scInfo; + scInfo.event = this; + scInfo.window = targetWindow; + + if (!mBuffer.read(cx, &messageData, &kPostMessageCallbacks, &scInfo)) { + return NS_ERROR_DOM_DATA_CLONE_ERR; + } + + // Create the event + nsCOMPtr eventTarget = + do_QueryInterface(static_cast(targetWindow.get())); + nsRefPtr event = + new MessageEvent(eventTarget, nullptr, nullptr); + + event->InitMessageEvent(NS_LITERAL_STRING("message"), false /*non-bubbling */, + false /*cancelable */, messageData, mCallerOrigin, + EmptyString(), mSource); + + nsTArray > ports; + scInfo.ports.EnumerateRead(PopulateMessagePortList, &ports); + event->SetPorts(new MessagePortList(static_cast(event.get()), ports)); + + // We can't simply call dispatchEvent on the window because doing so ends + // up flipping the trusted bit on the event, and we don't want that to + // happen because then untrusted content can call postMessage on a chrome + // window if it can get a reference to it. + + nsIPresShell *shell = targetWindow->mDoc->GetShell(); + nsRefPtr presContext; + if (shell) + presContext = shell->GetPresContext(); + + event->SetTrusted(mTrustedCaller); + WidgetEvent* internalEvent = event->GetInternalNSEvent(); + + nsEventStatus status = nsEventStatus_eIgnore; + EventDispatcher::Dispatch(static_cast(mTargetWindow), + presContext, + internalEvent, + static_cast(event.get()), + &status); + return NS_OK; +} + void nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, const nsAString& aTargetOrigin, @@ -8155,13 +8522,18 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, providedPrincipal, nsContentUtils::IsCallerChrome()); + // We *must* clone the data here, or the JS::Value could be modified + // by script + StructuredCloneInfo scInfo; + scInfo.event = event; + scInfo.window = this; + nsIPrincipal* principal = GetPrincipal(); JS::Rooted message(aCx, aMessage); JS::Rooted transfer(aCx, aTransfer); - bool subsumes; - - if (NS_FAILED(callerPrin->Subsumes(principal, &subsumes)) || - !event->Write(aCx, message, transfer, subsumes, this)) { + if (NS_FAILED(callerPrin->Subsumes(principal, &scInfo.subsumes)) || + !event->Buffer().write(aCx, message, transfer, &kPostMessageCallbacks, + &scInfo)) { aError.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index b38ab2e77d3a..15871c2c8ff1 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -111,7 +111,6 @@ class MozSelfSupport; class Navigator; class OwningExternalOrWindowProxy; class Promise; -class PostMessageEvent; struct RequestInit; class RequestOrUSVString; class Selection; @@ -1753,7 +1752,7 @@ protected: friend class nsDOMScriptableHelper; friend class nsDOMWindowUtils; - friend class mozilla::dom::PostMessageEvent; + friend class PostMessageEvent; friend class DesktopNotification; static WindowByIdTable* sWindowsById; diff --git a/dom/base/test/chrome.ini b/dom/base/test/chrome.ini index 9684ee8dba5a..34f81ead9d99 100644 --- a/dom/base/test/chrome.ini +++ b/dom/base/test/chrome.ini @@ -13,6 +13,7 @@ support-files = [test_domrequesthelper.xul] [test_url.xul] [test_console.xul] +[test_messageChannel.xul] [test_navigator_resolve_identity_xrays.xul] [test_sendQueryContentAndSelectionSetEvent.html] [test_bug1016960.html] diff --git a/dom/messagechannel/tests/iframe_messageChannel_chrome.html b/dom/base/test/iframe_messageChannel_chrome.html similarity index 100% rename from dom/messagechannel/tests/iframe_messageChannel_chrome.html rename to dom/base/test/iframe_messageChannel_chrome.html diff --git a/dom/messagechannel/tests/iframe_messageChannel_cloning.html b/dom/base/test/iframe_messageChannel_cloning.html similarity index 100% rename from dom/messagechannel/tests/iframe_messageChannel_cloning.html rename to dom/base/test/iframe_messageChannel_cloning.html diff --git a/dom/messagechannel/tests/iframe_messageChannel_pingpong.html b/dom/base/test/iframe_messageChannel_pingpong.html similarity index 100% rename from dom/messagechannel/tests/iframe_messageChannel_pingpong.html rename to dom/base/test/iframe_messageChannel_pingpong.html diff --git a/dom/messagechannel/tests/iframe_messageChannel_post.html b/dom/base/test/iframe_messageChannel_post.html similarity index 100% rename from dom/messagechannel/tests/iframe_messageChannel_post.html rename to dom/base/test/iframe_messageChannel_post.html diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index c6479fdbc53a..cb92be425c36 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -4,6 +4,10 @@ support-files = iframe_bug976673.html iframe_main_bug1022229.html iframe_sandbox_bug1022229.html + iframe_messageChannel_cloning.html + iframe_messageChannel_chrome.html + iframe_messageChannel_pingpong.html + iframe_messageChannel_post.html file_empty.html iframe_postMessage_solidus.html file_setname.html @@ -282,7 +286,15 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1 [test_history_state_null.html] [test_Image_constructor.html] [test_innersize_scrollport.html] +[test_messageChannel.html] +[test_messageChannel_cloning.html] +[test_messageChannel_pingpong.html] +[test_messageChannel_post.html] +[test_messageChannel_pref.html] +[test_messageChannel_start.html] [test_messagemanager_targetchain.html] +[test_messageChannel_transferable.html] +[test_messageChannel_unshipped.html] [test_named_frames.html] [test_navigator_resolve_identity.html] [test_navigator_language.html] diff --git a/dom/messagechannel/tests/test_messageChannel.html b/dom/base/test/test_messageChannel.html similarity index 100% rename from dom/messagechannel/tests/test_messageChannel.html rename to dom/base/test/test_messageChannel.html diff --git a/dom/messagechannel/tests/test_messageChannel.xul b/dom/base/test/test_messageChannel.xul similarity index 91% rename from dom/messagechannel/tests/test_messageChannel.xul rename to dom/base/test/test_messageChannel.xul index 3d8e3485c6be..ab2fae4d93f7 100644 --- a/dom/messagechannel/tests/test_messageChannel.xul +++ b/dom/base/test/test_messageChannel.xul @@ -23,7 +23,7 @@ } var ifr = document.createElement('browser'); - ifr.setAttribute("src", "iframe_messageChannel_chrome.html"); + ifr.setAttribute("src", "http://mochi.test:8888/tests/dom/base/test/iframe_messageChannel_chrome.html"); ifr.setAttribute("flex", "1"); ifr.addEventListener('load', function() { ifr.contentWindow.postMessage(channel.port2, '*', [channel.port2]); diff --git a/dom/messagechannel/tests/test_messageChannel_cloning.html b/dom/base/test/test_messageChannel_cloning.html similarity index 100% rename from dom/messagechannel/tests/test_messageChannel_cloning.html rename to dom/base/test/test_messageChannel_cloning.html diff --git a/dom/messagechannel/tests/test_messageChannel_pingpong.html b/dom/base/test/test_messageChannel_pingpong.html similarity index 100% rename from dom/messagechannel/tests/test_messageChannel_pingpong.html rename to dom/base/test/test_messageChannel_pingpong.html diff --git a/dom/messagechannel/tests/test_messageChannel_post.html b/dom/base/test/test_messageChannel_post.html similarity index 100% rename from dom/messagechannel/tests/test_messageChannel_post.html rename to dom/base/test/test_messageChannel_post.html diff --git a/dom/messagechannel/tests/test_messageChannel_pref.html b/dom/base/test/test_messageChannel_pref.html similarity index 100% rename from dom/messagechannel/tests/test_messageChannel_pref.html rename to dom/base/test/test_messageChannel_pref.html diff --git a/dom/messagechannel/tests/test_messageChannel_start.html b/dom/base/test/test_messageChannel_start.html similarity index 100% rename from dom/messagechannel/tests/test_messageChannel_start.html rename to dom/base/test/test_messageChannel_start.html diff --git a/dom/messagechannel/tests/test_messageChannel_transferable.html b/dom/base/test/test_messageChannel_transferable.html similarity index 57% rename from dom/messagechannel/tests/test_messageChannel_transferable.html rename to dom/base/test/test_messageChannel_transferable.html index 82b575bac666..c1e661ead89e 100644 --- a/dom/messagechannel/tests/test_messageChannel_transferable.html +++ b/dom/base/test/test_messageChannel_transferable.html @@ -16,15 +16,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=677638 diff --git a/dom/messagechannel/tests/test_messageChannel_unshipped.html b/dom/base/test/test_messageChannel_unshipped.html similarity index 100% rename from dom/messagechannel/tests/test_messageChannel_unshipped.html rename to dom/base/test/test_messageChannel_unshipped.html diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 110bb45572a8..2b0181dd8a95 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -729,6 +729,9 @@ DOMInterfaces = { 'MessagePort': { 'nativeType': 'mozilla::dom::MessagePortBase', 'headerFile': 'mozilla/dom/MessagePort.h', + 'binaryNames': { + 'postMessage': 'postMessageMoz', + }, }, 'MimeType': { diff --git a/dom/broadcastchannel/BroadcastChannel.cpp b/dom/broadcastchannel/BroadcastChannel.cpp index ae00470858a6..325722cfcaab 100644 --- a/dom/broadcastchannel/BroadcastChannel.cpp +++ b/dom/broadcastchannel/BroadcastChannel.cpp @@ -212,15 +212,14 @@ public: PBackgroundChild* backgroundManager = mActor->Manager(); MOZ_ASSERT(backgroundManager); - const nsTArray>& blobImpls = mData->mClosure.mBlobImpls; + const nsTArray>& blobs = mData->mClosure.mBlobs; - if (!blobImpls.IsEmpty()) { - message.blobsChild().SetCapacity(blobImpls.Length()); + if (!blobs.IsEmpty()) { + message.blobsChild().SetCapacity(blobs.Length()); - for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { + for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) { PBlobChild* blobChild = - BackgroundChild::GetOrCreateActorForBlobImpl(backgroundManager, - blobImpls[i]); + BackgroundChild::GetOrCreateActorForBlob(backgroundManager, blobs[i]); MOZ_ASSERT(blobChild); message.blobsChild().AppendElement(blobChild); @@ -542,9 +541,9 @@ BroadcastChannel::PostMessageInternal(JSContext* aCx, return; } - const nsTArray>& blobImpls = data->mClosure.mBlobImpls; - for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { - if (!blobImpls[i]->MayBeClonedToOtherThreads()) { + const nsTArray>& blobs = data->mClosure.mBlobs; + for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) { + if (!blobs[i]->Impl()->MayBeClonedToOtherThreads()) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } diff --git a/dom/broadcastchannel/BroadcastChannelChild.cpp b/dom/broadcastchannel/BroadcastChannelChild.cpp index 6b8647064581..40c394e68729 100644 --- a/dom/broadcastchannel/BroadcastChannelChild.cpp +++ b/dom/broadcastchannel/BroadcastChannelChild.cpp @@ -42,7 +42,7 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData) { // Make sure to retrieve all blobs from the message before returning to avoid // leaking their actors. - nsTArray> blobs; + nsTArray> blobs; if (!aData.blobsChild().IsEmpty()) { blobs.SetCapacity(aData.blobsChild().Length()); @@ -50,7 +50,8 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData) nsRefPtr impl = static_cast(aData.blobsChild()[i])->GetBlobImpl(); - blobs.AppendElement(impl); + nsRefPtr blob = Blob::Create(mBC ? mBC->GetOwner() : nullptr, impl); + blobs.AppendElement(blob); } } @@ -91,7 +92,7 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData) StructuredCloneData cloneData; cloneData.mData = buffer.data; cloneData.mDataLength = buffer.dataLength; - cloneData.mClosure.mBlobImpls.SwapElements(blobs); + cloneData.mClosure.mBlobs.SwapElements(blobs); JS::Rooted value(cx, JS::NullValue()); if (cloneData.mDataLength && !ReadStructuredClone(cx, cloneData, &value)) { diff --git a/dom/ipc/StructuredCloneUtils.cpp b/dom/ipc/StructuredCloneUtils.cpp index f7ced0cdb034..cba261c1f7a0 100644 --- a/dom/ipc/StructuredCloneUtils.cpp +++ b/dom/ipc/StructuredCloneUtils.cpp @@ -50,14 +50,14 @@ Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, // while destructors are running. JS::Rooted val(aCx); { - MOZ_ASSERT(aData < closure->mBlobImpls.Length()); - nsRefPtr blobImpl = closure->mBlobImpls[aData]; + MOZ_ASSERT(aData < closure->mBlobs.Length()); + nsRefPtr blob = closure->mBlobs[aData]; #ifdef DEBUG { // Blob should not be mutable. bool isMutable; - MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable))); + MOZ_ASSERT(NS_SUCCEEDED(blob->GetMutable(&isMutable))); MOZ_ASSERT(!isMutable); } #endif @@ -66,7 +66,7 @@ Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)); MOZ_ASSERT(global); - nsRefPtr newBlob = Blob::Create(global, blobImpl); + nsRefPtr newBlob = Blob::Create(global, blob->Impl()); if (!ToJSValue(aCx, newBlob, &val)) { return nullptr; } @@ -93,8 +93,8 @@ Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) && NS_SUCCEEDED(blob->SetMutable(false)) && JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, - closure->mBlobImpls.Length())) { - closure->mBlobImpls.AppendElement(blob->Impl()); + closure->mBlobs.Length())) { + closure->mBlobs.AppendElement(blob); return true; } } diff --git a/dom/ipc/StructuredCloneUtils.h b/dom/ipc/StructuredCloneUtils.h index f8d1c37d7dbe..b103d54a4122 100644 --- a/dom/ipc/StructuredCloneUtils.h +++ b/dom/ipc/StructuredCloneUtils.h @@ -19,7 +19,7 @@ namespace dom { struct StructuredCloneClosure { - nsTArray> mBlobImpls; + nsTArray> mBlobs; }; struct diff --git a/dom/messagechannel/MessageChannel.cpp b/dom/messagechannel/MessageChannel.cpp deleted file mode 100644 index a2635d10c2e5..000000000000 --- a/dom/messagechannel/MessageChannel.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; 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 "MessageChannel.h" - -#include "mozilla/Preferences.h" -#include "mozilla/dom/MessageChannelBinding.h" -#include "mozilla/dom/MessagePort.h" -#include "mozilla/dom/Navigator.h" -#include "mozilla/dom/WorkerPrivate.h" -#include "mozilla/dom/WorkerRunnable.h" -#include "nsContentUtils.h" -#include "nsIDocument.h" -#include "nsIPrincipal.h" -#include "nsPIDOMWindow.h" -#include "nsServiceManagerUtils.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MessageChannel, mWindow, mPort1, mPort2) -NS_IMPL_CYCLE_COLLECTING_ADDREF(MessageChannel) -NS_IMPL_CYCLE_COLLECTING_RELEASE(MessageChannel) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MessageChannel) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END - -namespace { -bool gPrefInitialized = false; -bool gPrefEnabled = false; - -bool -CheckPermission(nsIPrincipal* aPrincipal, bool aCallerChrome) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!gPrefInitialized) { - Preferences::AddBoolVarCache(&gPrefEnabled, "dom.messageChannel.enabled"); - gPrefInitialized = true; - } - - // Enabled by pref - if (gPrefEnabled) { - return true; - } - - // Chrome callers are allowed. - if (aCallerChrome) { - return true; - } - - nsCOMPtr uri; - if (NS_FAILED(aPrincipal->GetURI(getter_AddRefs(uri))) || !uri) { - return false; - } - - bool isResource = false; - if (NS_FAILED(uri->SchemeIs("resource", &isResource))) { - return false; - } - - return isResource; -} - -nsIPrincipal* -GetPrincipalFromWorkerPrivate(workers::WorkerPrivate* aWorkerPrivate) -{ - MOZ_ASSERT(NS_IsMainThread()); - - nsIPrincipal* principal = aWorkerPrivate->GetPrincipal(); - if (principal) { - return principal; - } - - // Walk up to our containing page - workers::WorkerPrivate* wp = aWorkerPrivate; - while (wp->GetParent()) { - wp = wp->GetParent(); - } - - nsPIDOMWindow* window = wp->GetWindow(); - if (!window) { - return nullptr; - } - - nsIDocument* doc = window->GetExtantDoc(); - if (!doc) { - return nullptr; - } - - return doc->NodePrincipal(); -} - -// A WorkerMainThreadRunnable to synchronously dispatch the call of -// CheckPermission() from the worker thread to the main thread. -class CheckPermissionRunnable final : public workers::WorkerMainThreadRunnable -{ -public: - bool mResult; - bool mCallerChrome; - - explicit CheckPermissionRunnable(workers::WorkerPrivate* aWorkerPrivate) - : workers::WorkerMainThreadRunnable(aWorkerPrivate) - , mResult(false) - , mCallerChrome(false) - { - MOZ_ASSERT(aWorkerPrivate); - aWorkerPrivate->AssertIsOnWorkerThread(); - mCallerChrome = aWorkerPrivate->UsesSystemPrincipal(); - } - -protected: - virtual bool - MainThreadRun() override - { - MOZ_ASSERT(NS_IsMainThread()); - - nsIPrincipal* principal = GetPrincipalFromWorkerPrivate(mWorkerPrivate); - if (!principal) { - return true; - } - - bool isNullPrincipal; - nsresult rv = principal->GetIsNullPrincipal(&isNullPrincipal); - if (NS_WARN_IF(NS_FAILED(rv))) { - return true; - } - - if (NS_WARN_IF(isNullPrincipal)) { - return true; - } - - mResult = CheckPermission(principal, mCallerChrome); - return true; - } -}; - -} // anonymous namespace - -/* static */ bool -MessageChannel::Enabled(JSContext* aCx, JSObject* aGlobal) -{ - if (NS_IsMainThread()) { - JS::Rooted global(aCx, aGlobal); - - nsCOMPtr win = Navigator::GetWindowFromGlobal(global); - if (!win) { - return false; - } - - nsIDocument* doc = win->GetExtantDoc(); - if (!doc) { - return false; - } - - return CheckPermission(doc->NodePrincipal(), - nsContentUtils::IsCallerChrome()); - } - - workers::WorkerPrivate* workerPrivate = - workers::GetWorkerPrivateFromContext(aCx); - workerPrivate->AssertIsOnWorkerThread(); - - nsRefPtr runnable = - new CheckPermissionRunnable(workerPrivate); - runnable->Dispatch(aCx); - - return runnable->mResult; -} - -MessageChannel::MessageChannel(nsPIDOMWindow* aWindow) - : mWindow(aWindow) -{ -} - -MessageChannel::~MessageChannel() -{ -} - -JSObject* -MessageChannel::WrapObject(JSContext* aCx, JS::Handle aGivenProto) -{ - return MessageChannelBinding::Wrap(aCx, this, aGivenProto); -} - -/* static */ already_AddRefed -MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) -{ - // window can be null in workers. - nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); - - nsID portUUID1; - aRv = nsContentUtils::GenerateUUIDInPlace(portUUID1); - if (aRv.Failed()) { - return nullptr; - } - - nsID portUUID2; - aRv = nsContentUtils::GenerateUUIDInPlace(portUUID2); - if (aRv.Failed()) { - return nullptr; - } - - nsRefPtr channel = new MessageChannel(window); - - channel->mPort1 = MessagePort::Create(window, portUUID1, portUUID2, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - channel->mPort2 = MessagePort::Create(window, portUUID2, portUUID1, aRv); - if (NS_WARN_IF(aRv.Failed())) { - return nullptr; - } - - channel->mPort1->UnshippedEntangle(channel->mPort2); - channel->mPort2->UnshippedEntangle(channel->mPort1); - - return channel.forget(); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/messagechannel/MessagePort.cpp b/dom/messagechannel/MessagePort.cpp deleted file mode 100644 index 6a328bb969ee..000000000000 --- a/dom/messagechannel/MessagePort.cpp +++ /dev/null @@ -1,867 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; 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 "MessagePort.h" - -#include "MessageEvent.h" -#include "MessagePortChild.h" -#include "mozilla/dom/BlobBinding.h" -#include "mozilla/dom/Event.h" -#include "mozilla/dom/File.h" -#include "mozilla/dom/MessageChannel.h" -#include "mozilla/dom/MessagePortBinding.h" -#include "mozilla/dom/MessagePortChild.h" -#include "mozilla/dom/MessagePortList.h" -#include "mozilla/dom/PMessagePort.h" -#include "mozilla/dom/StructuredCloneTags.h" -#include "mozilla/dom/WorkerPrivate.h" -#include "mozilla/dom/WorkerScope.h" -#include "mozilla/ipc/BackgroundChild.h" -#include "mozilla/ipc/PBackgroundChild.h" -#include "nsContentUtils.h" -#include "nsGlobalWindow.h" -#include "nsPresContext.h" -#include "ScriptSettings.h" -#include "SharedMessagePortMessage.h" - -#include "nsIBFCacheEntry.h" -#include "nsIDocument.h" -#include "nsIDOMFileList.h" -#include "nsIPresShell.h" -#include "nsISupportsPrimitives.h" -#include "nsServiceManagerUtils.h" - -#ifdef XP_WIN -#undef PostMessage -#endif - -using namespace mozilla::dom::workers; - -namespace mozilla { -namespace dom { - -class DispatchEventRunnable final : public nsICancelableRunnable -{ - friend class MessagePort; - -public: - NS_DECL_ISUPPORTS - - explicit DispatchEventRunnable(MessagePort* aPort) - : mPort(aPort) - { } - - NS_IMETHOD - Run() override - { - MOZ_ASSERT(mPort); - MOZ_ASSERT(mPort->mDispatchRunnable == this); - mPort->mDispatchRunnable = nullptr; - mPort->Dispatch(); - - return NS_OK; - } - - NS_IMETHOD - Cancel() override - { - mPort = nullptr; - return NS_OK; - } - -private: - ~DispatchEventRunnable() - {} - - nsRefPtr mPort; -}; - -NS_IMPL_ISUPPORTS(DispatchEventRunnable, nsICancelableRunnable, nsIRunnable) - -class PostMessageRunnable final : public nsICancelableRunnable -{ -public: - NS_DECL_ISUPPORTS - - PostMessageRunnable(MessagePort* aPort, SharedMessagePortMessage* aData) - : mPort(aPort) - , mData(aData) - { - MOZ_ASSERT(aPort); - MOZ_ASSERT(aData); - } - - NS_IMETHOD - Run() override - { - nsCOMPtr globalObject; - - if (NS_IsMainThread()) { - globalObject = do_QueryInterface(mPort->GetParentObject()); - } else { - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - globalObject = workerPrivate->GlobalScope(); - } - - AutoJSAPI jsapi; - if (!globalObject || !jsapi.Init(globalObject)) { - NS_WARNING("Failed to initialize AutoJSAPI object."); - return NS_ERROR_FAILURE; - } - - JSContext* cx = jsapi.cx(); - - nsTArray> ports; - nsCOMPtr window = - do_QueryInterface(mPort->GetParentObject()); - - JS::Rooted value(cx); - if (!mData->mData.IsEmpty()) { - bool ok = ReadStructuredCloneWithTransfer(cx, mData->mData, - mData->mClosure, - &value, window, ports); - FreeStructuredClone(mData->mData, mData->mClosure); - - if (!ok) { - return NS_ERROR_FAILURE; - } - } - - // The data should be already be cleaned. - MOZ_ASSERT(!mData->mData.Length()); - - // Create the event - nsCOMPtr eventTarget = - do_QueryInterface(mPort->GetOwner()); - nsRefPtr event = - new MessageEvent(eventTarget, nullptr, nullptr); - - event->InitMessageEvent(NS_LITERAL_STRING("message"), - false /* non-bubbling */, - false /* cancelable */, value, EmptyString(), - EmptyString(), nullptr); - event->SetTrusted(true); - event->SetSource(mPort); - - nsTArray> array; - array.SetCapacity(ports.Length()); - for (uint32_t i = 0; i < ports.Length(); ++i) { - array.AppendElement(ports[i]); - } - - nsRefPtr portList = - new MessagePortList(static_cast(event.get()), array); - event->SetPorts(portList); - - bool dummy; - mPort->DispatchEvent(static_cast(event.get()), &dummy); - return NS_OK; - } - - NS_IMETHOD - Cancel() override - { - mPort = nullptr; - mData = nullptr; - return NS_OK; - } - -private: - ~PostMessageRunnable() - {} - - nsRefPtr mPort; - nsRefPtr mData; -}; - -NS_IMPL_ISUPPORTS(PostMessageRunnable, nsICancelableRunnable, nsIRunnable) - -MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow) - : DOMEventTargetHelper(aWindow) -{ -} - -MessagePortBase::MessagePortBase() -{ -} - -NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort, - MessagePortBase) - if (tmp->mDispatchRunnable) { - NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort); - } - - NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessages); - NS_IMPL_CYCLE_COLLECTION_UNLINK(mMessagesForTheOtherPort); - NS_IMPL_CYCLE_COLLECTION_UNLINK(mUnshippedEntangledPort); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort, - MessagePortBase) - if (tmp->mDispatchRunnable) { - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort); - } - - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUnshippedEntangledPort); -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort) - NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback) - NS_INTERFACE_MAP_ENTRY(nsIObserver) -NS_INTERFACE_MAP_END_INHERITING(MessagePortBase) - -NS_IMPL_ADDREF_INHERITED(MessagePort, MessagePortBase) -NS_IMPL_RELEASE_INHERITED(MessagePort, MessagePortBase) - -namespace { - -class MessagePortFeature final : public workers::WorkerFeature -{ - MessagePort* mPort; - -public: - explicit MessagePortFeature(MessagePort* aPort) - : mPort(aPort) - { - MOZ_ASSERT(aPort); - MOZ_COUNT_CTOR(MessagePortFeature); - } - - virtual bool Notify(JSContext* aCx, workers::Status aStatus) override - { - if (mPort && aStatus > Running) { - mPort->Close(); - } - - return true; - } - -private: - ~MessagePortFeature() - { - MOZ_COUNT_DTOR(MessagePortFeature); - } -}; - -} // anonymous namespace - -MessagePort::MessagePort(nsPIDOMWindow* aWindow) - : MessagePortBase(aWindow) - , mInnerID(0) - , mMessageQueueEnabled(false) - , mIsKeptAlive(false) -{ - mIdentifier = new MessagePortIdentifier(); - mIdentifier->neutered() = true; - mIdentifier->sequenceId() = 0; -} - -MessagePort::~MessagePort() -{ - Close(); - MOZ_ASSERT(!mWorkerFeature); -} - -/* static */ already_AddRefed -MessagePort::Create(nsPIDOMWindow* aWindow, const nsID& aUUID, - const nsID& aDestinationUUID, ErrorResult& aRv) -{ - nsRefPtr mp = new MessagePort(aWindow); - mp->Initialize(aUUID, aDestinationUUID, 1 /* 0 is an invalid sequence ID */, - false /* Neutered */, eStateUnshippedEntangled, aRv); - return mp.forget(); -} - -/* static */ already_AddRefed -MessagePort::Create(nsPIDOMWindow* aWindow, - const MessagePortIdentifier& aIdentifier, - ErrorResult& aRv) -{ - nsRefPtr mp = new MessagePort(aWindow); - mp->Initialize(aIdentifier.uuid(), aIdentifier.destinationUuid(), - aIdentifier.sequenceId(), aIdentifier.neutered(), - eStateEntangling, aRv); - return mp.forget(); -} - -void -MessagePort::UnshippedEntangle(MessagePort* aEntangledPort) -{ - MOZ_ASSERT(aEntangledPort); - MOZ_ASSERT(!mUnshippedEntangledPort); - - mUnshippedEntangledPort = aEntangledPort; -} - -void -MessagePort::Initialize(const nsID& aUUID, - const nsID& aDestinationUUID, - uint32_t aSequenceID, bool mNeutered, - State aState, ErrorResult& aRv) -{ - MOZ_ASSERT(mIdentifier); - mIdentifier->uuid() = aUUID; - mIdentifier->destinationUuid() = aDestinationUUID; - mIdentifier->sequenceId() = aSequenceID; - - mState = aState; - mNextStep = eNextStepNone; - - if (mNeutered) { - mState = eStateDisentangled; - } else if (mState == eStateEntangling) { - ConnectToPBackground(); - } else { - MOZ_ASSERT(mState == eStateUnshippedEntangled); - } - - // The port has to keep itself alive until it's entangled. - UpdateMustKeepAlive(); - - if (NS_IsMainThread()) { - MOZ_ASSERT(GetOwner()); - MOZ_ASSERT(GetOwner()->IsInnerWindow()); - mInnerID = GetOwner()->WindowID(); - - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->AddObserver(this, "inner-window-destroyed", false); - } - } else { - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - MOZ_ASSERT(!mWorkerFeature); - - nsAutoPtr feature(new MessagePortFeature(this)); - JSContext* cx = workerPrivate->GetJSContext(); - if (NS_WARN_IF(!workerPrivate->AddFeature(cx, feature))) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - mWorkerFeature = Move(feature); - } -} - -JSObject* -MessagePort::WrapObject(JSContext* aCx, JS::Handle aGivenProto) -{ - return MessagePortBinding::Wrap(aCx, this, aGivenProto); -} - -void -MessagePort::PostMessage(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) -{ - // We *must* clone the data here, or the JS::Value could be modified - // by script - - JS::Rooted transferable(aCx, JS::UndefinedValue()); - if (aTransferable.WasPassed()) { - const Sequence& realTransferable = aTransferable.Value(); - - // Here we want to check if the transerable object list contains - // this port. No other checks are done. - for (const JS::Value& value : realTransferable) { - if (!value.isObject()) { - continue; - } - - MessagePortBase* port = nullptr; - nsresult rv = UNWRAP_OBJECT(MessagePort, &value.toObject(), port); - if (NS_FAILED(rv)) { - continue; - } - - if (port == this) { - aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); - return; - } - } - - // The input sequence only comes from the generated bindings code, which - // ensures it is rooted. - JS::HandleValueArray elements = - JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(), - realTransferable.Elements()); - - JSObject* array = - JS_NewArrayObject(aCx, elements); - if (!array) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - transferable.setObject(*array); - } - - nsRefPtr data = new SharedMessagePortMessage(); - - if (!WriteStructuredCloneWithTransfer(aCx, aMessage, transferable, - data->mData, data->mClosure)) { - aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); - return; - } - - // This message has to be ignored. - if (mState > eStateEntangled) { - return; - } - - // If we are unshipped we are connected to the other port on the same thread. - if (mState == eStateUnshippedEntangled) { - MOZ_ASSERT(mUnshippedEntangledPort); - mUnshippedEntangledPort->mMessages.AppendElement(data); - mUnshippedEntangledPort->Dispatch(); - return; - } - - // Not entangled yet, but already closed. - if (mNextStep != eNextStepNone) { - return; - } - - RemoveDocFromBFCache(); - - // Not entangled yet. - if (mState == eStateEntangling) { - mMessagesForTheOtherPort.AppendElement(data); - return; - } - - MOZ_ASSERT(mActor); - MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty()); - - nsAutoTArray, 1> array; - array.AppendElement(data); - - nsAutoTArray messages; - SharedMessagePortMessage::FromSharedToMessagesChild(mActor, array, messages); - mActor->SendPostMessages(messages); -} - -void -MessagePort::Start() -{ - if (mMessageQueueEnabled) { - return; - } - - mMessageQueueEnabled = true; - Dispatch(); -} - -void -MessagePort::Dispatch() -{ - if (!mMessageQueueEnabled || mMessages.IsEmpty() || mDispatchRunnable || - mState > eStateEntangled || mNextStep != eNextStepNone) { - return; - } - - nsRefPtr data = mMessages.ElementAt(0); - mMessages.RemoveElementAt(0); - - nsRefPtr runnable = new PostMessageRunnable(this, data); - - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(runnable))); - - mDispatchRunnable = new DispatchEventRunnable(this); - - MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToCurrentThread(mDispatchRunnable))); -} - -void -MessagePort::Close() -{ - // Not entangled yet, but already closed. - if (mNextStep != eNextStepNone) { - return; - } - - if (mState == eStateUnshippedEntangled) { - MOZ_ASSERT(mUnshippedEntangledPort); - - // This avoids loops. - nsRefPtr port = Move(mUnshippedEntangledPort); - MOZ_ASSERT(mUnshippedEntangledPort == nullptr); - - mState = eStateDisentangled; - port->Close(); - - UpdateMustKeepAlive(); - return; - } - - // Not entangled yet, we have to wait. - if (mState < eStateEntangling) { - mNextStep = eNextStepClose; - return; - } - - if (mState > eStateEntangled) { - return; - } - - // We don't care about stopping the sending of messages because from now all - // the incoming messages will be ignored. - mState = eStateDisentangled; - - MOZ_ASSERT(mActor); - - mActor->SendClose(); - mActor->SetPort(nullptr); - mActor = nullptr; - - UpdateMustKeepAlive(); -} - -EventHandlerNonNull* -MessagePort::GetOnmessage() -{ - if (NS_IsMainThread()) { - return GetEventHandler(nsGkAtoms::onmessage, EmptyString()); - } - return GetEventHandler(nullptr, NS_LITERAL_STRING("message")); -} - -void -MessagePort::SetOnmessage(EventHandlerNonNull* aCallback) -{ - if (NS_IsMainThread()) { - SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback); - } else { - SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback); - } - - // When using onmessage, the call to start() is implied. - Start(); -} - -// This method is called when the PMessagePortChild actor is entangled to -// another actor. It receives a list of messages to be dispatch. It can be that -// we were waiting for this entangling step in order to disentangle the port or -// to close it. -void -MessagePort::Entangled(nsTArray& aMessages) -{ - MOZ_ASSERT(mState == eStateEntangling); - - mState = eStateEntangled; - - // If we have pending messages, these have to be sent. - if (!mMessagesForTheOtherPort.IsEmpty()) { - nsTArray messages; - SharedMessagePortMessage::FromSharedToMessagesChild(mActor, - mMessagesForTheOtherPort, - messages); - mMessagesForTheOtherPort.Clear(); - mActor->SendPostMessages(messages); - } - - // We must convert the messages into SharedMessagePortMessages to avoid leaks. - FallibleTArray> data; - if (NS_WARN_IF(!SharedMessagePortMessage::FromMessagesToSharedChild(aMessages, - data))) { - // OOM, we cannot continue. - return; - } - - if (mNextStep == eNextStepClose) { - Close(); - return; - } - - mMessages.AppendElements(data); - - // We were waiting for the entangling callback in order to disentangle this - // port immediately after. - if (mNextStep == eNextStepDisentangle) { - StartDisentangling(); - return; - } - - MOZ_ASSERT(mNextStep == eNextStepNone); - Dispatch(); -} - -void -MessagePort::StartDisentangling() -{ - MOZ_ASSERT(mActor); - MOZ_ASSERT(mState == eStateEntangled); - - mState = eStateDisentangling; - mNextStep = eNextStepNone; - - // Sending this message we communicate to the parent actor that we don't want - // to receive any new messages. It is possible that a message has been - // already sent but not received yet. So we have to collect all of them and - // we send them in the SendDispatch() request. - mActor->SendStopSendingData(); -} - -void -MessagePort::MessagesReceived(nsTArray& aMessages) -{ - MOZ_ASSERT(mState == eStateEntangled || mState == eStateDisentangling); - MOZ_ASSERT(mNextStep == eNextStepNone); - MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty()); - - RemoveDocFromBFCache(); - - FallibleTArray> data; - if (!NS_WARN_IF(SharedMessagePortMessage::FromMessagesToSharedChild(aMessages, - data))) { - // OOM, We cannot continue. - return; - } - - mMessages.AppendElements(data); - - if (mState == eStateEntangled) { - Dispatch(); - } -} - -void -MessagePort::StopSendingDataConfirmed() -{ - MOZ_ASSERT(mState == eStateDisentangling); - MOZ_ASSERT(mActor); - - Disentangle(); -} - -void -MessagePort::Disentangle() -{ - MOZ_ASSERT(mState == eStateDisentangling); - MOZ_ASSERT(mActor); - - mState = eStateDisentangled; - - nsTArray messages; - SharedMessagePortMessage::FromSharedToMessagesChild(mActor, mMessages, - messages); - mMessages.Clear(); - mActor->SendDisentangle(messages); - - mActor->SetPort(nullptr); - mActor = nullptr; - - UpdateMustKeepAlive(); -} - -bool -MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier) -{ - MOZ_ASSERT(mIdentifier); - - // We can clone a port that has already been transfered. In this case, on the - // otherside will have a neutered port. Here we set neutered to true so that - // we are safe in case a early return. - aIdentifier.neutered() = true; - - if (mState > eStateEntangled) { - return true; - } - - // We already have a 'next step'. We have to consider this port as already - // cloned/closed/disentangled. - if (mNextStep != eNextStepNone) { - return true; - } - - aIdentifier.uuid() = mIdentifier->uuid(); - aIdentifier.destinationUuid() = mIdentifier->destinationUuid(); - aIdentifier.sequenceId() = mIdentifier->sequenceId() + 1; - aIdentifier.neutered() = false; - - // We have to entangle first. - if (mState == eStateUnshippedEntangled) { - MOZ_ASSERT(mUnshippedEntangledPort); - MOZ_ASSERT(mMessagesForTheOtherPort.IsEmpty()); - - // Disconnect the entangled port and connect it to PBackground. - mUnshippedEntangledPort->ConnectToPBackground(); - mUnshippedEntangledPort = nullptr; - - // In this case, we don't need to be connected to the PBackground service. - if (mMessages.IsEmpty()) { - aIdentifier.sequenceId() = mIdentifier->sequenceId(); - - mState = eStateDisentangled; - UpdateMustKeepAlive(); - return true; - } - - // Register this component to PBackground. - ConnectToPBackground(); - - mNextStep = eNextStepDisentangle; - return true; - } - - // Not entangled yet, we have to wait. - if (mState < eStateEntangled) { - mNextStep = eNextStepDisentangle; - return true; - } - - StartDisentangling(); - return true; -} - -void -MessagePort::Closed() -{ - if (mState == eStateDisentangled) { - return; - } - - mState = eStateDisentangled; - - if (mActor) { - mActor->SetPort(nullptr); - mActor = nullptr; - } - - UpdateMustKeepAlive(); -} - -void -MessagePort::ConnectToPBackground() -{ - mState = eStateEntangling; - - PBackgroundChild* actor = - mozilla::ipc::BackgroundChild::GetForCurrentThread(); - if (actor) { - ActorCreated(actor); - } else { - if (NS_WARN_IF( - !mozilla::ipc::BackgroundChild::GetOrCreateForCurrentThread(this))) { - MOZ_CRASH(); - } - } -} - -void -MessagePort::ActorFailed() -{ - MOZ_CRASH("Failed to create a PBackgroundChild actor!"); -} - -void -MessagePort::ActorCreated(mozilla::ipc::PBackgroundChild* aActor) -{ - MOZ_ASSERT(aActor); - MOZ_ASSERT(!mActor); - MOZ_ASSERT(mIdentifier); - MOZ_ASSERT(mState == eStateEntangling); - - PMessagePortChild* actor = - aActor->SendPMessagePortConstructor(mIdentifier->uuid(), - mIdentifier->destinationUuid(), - mIdentifier->sequenceId()); - - mActor = static_cast(actor); - MOZ_ASSERT(mActor); - - mActor->SetPort(this); -} - -void -MessagePort::UpdateMustKeepAlive() -{ - if (mState == eStateDisentangled && mIsKeptAlive) { - mIsKeptAlive = false; - - if (mWorkerFeature) { - WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); - MOZ_ASSERT(workerPrivate); - - workerPrivate->RemoveFeature(workerPrivate->GetJSContext(), - mWorkerFeature); - mWorkerFeature = nullptr; - } - - Release(); - return; - } - - if (mState < eStateDisentangled && !mIsKeptAlive) { - mIsKeptAlive = true; - AddRef(); - } -} - -NS_IMETHODIMP -MessagePort::Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (strcmp(aTopic, "inner-window-destroyed")) { - return NS_OK; - } - - // If the window id destroyed we have to release the reference that we are - // keeping. - if (!mIsKeptAlive) { - return NS_OK; - } - - nsCOMPtr wrapper = do_QueryInterface(aSubject); - NS_ENSURE_TRUE(wrapper, NS_ERROR_FAILURE); - - uint64_t innerID; - nsresult rv = wrapper->GetData(&innerID); - NS_ENSURE_SUCCESS(rv, rv); - - if (innerID == mInnerID) { - nsCOMPtr obs = - do_GetService("@mozilla.org/observer-service;1"); - if (obs) { - obs->RemoveObserver(this, "inner-window-destroyed"); - } - - Close(); - } - - return NS_OK; -} - -void -MessagePort::RemoveDocFromBFCache() -{ - if (!NS_IsMainThread()) { - return; - } - - nsPIDOMWindow* window = GetOwner(); - MOZ_ASSERT(window); - - nsIDocument* doc = window->GetExtantDoc(); - if (!doc) { - return; - } - - nsCOMPtr bfCacheEntry = doc->GetBFCacheEntry(); - if (!bfCacheEntry) { - return; - } - - bfCacheEntry->RemoveFromBFCacheSync(); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/messagechannel/MessagePort.h b/dom/messagechannel/MessagePort.h deleted file mode 100644 index 63081a083323..000000000000 --- a/dom/messagechannel/MessagePort.h +++ /dev/null @@ -1,210 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; 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/. */ - -#ifndef mozilla_dom_MessagePort_h -#define mozilla_dom_MessagePort_h - -#include "mozilla/Attributes.h" -#include "mozilla/DOMEventTargetHelper.h" -#include "nsIIPCBackgroundChildCreateCallback.h" -#include "nsTArray.h" - -#ifdef XP_WIN -#undef PostMessage -#endif - -class nsPIDOMWindow; - -namespace mozilla { -namespace dom { - -class DispatchEventRunnable; -class MessagePortChild; -class MessagePortIdentifier; -class MessagePortMessage; -class SharedMessagePortMessage; - -namespace workers { -class WorkerFeature; -} - -class MessagePortBase : public DOMEventTargetHelper -{ -protected: - explicit MessagePortBase(nsPIDOMWindow* aWindow); - MessagePortBase(); - -public: - - virtual void - PostMessage(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) = 0; - - virtual void - Start() = 0; - - virtual void - Close() = 0; - - // The 'message' event handler has to call |Start()| method, so we - // cannot use IMPL_EVENT_HANDLER macro here. - virtual EventHandlerNonNull* - GetOnmessage() = 0; - - virtual void - SetOnmessage(EventHandlerNonNull* aCallback) = 0; - - // Duplicate this message port. This method is used by the Structured Clone - // Algorithm and populates a MessagePortIdentifier object with the information - // useful to create new MessagePort. - virtual bool - CloneAndDisentangle(MessagePortIdentifier& aIdentifier) = 0; -}; - -class MessagePort final : public MessagePortBase - , public nsIIPCBackgroundChildCreateCallback - , public nsIObserver -{ - friend class DispatchEventRunnable; - -public: - NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK - NS_DECL_NSIOBSERVER - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, - DOMEventTargetHelper) - - static already_AddRefed - Create(nsPIDOMWindow* aWindow, const nsID& aUUID, - const nsID& aDestinationUUID, ErrorResult& aRv); - - static already_AddRefed - Create(nsPIDOMWindow* aWindow, const MessagePortIdentifier& aIdentifier, - ErrorResult& aRv); - - virtual JSObject* - WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - - virtual void - PostMessage(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) override; - - virtual void Start() override; - - virtual void Close() override; - - virtual EventHandlerNonNull* GetOnmessage() override; - - virtual void SetOnmessage(EventHandlerNonNull* aCallback) override; - - // Non WebIDL methods - - void UnshippedEntangle(MessagePort* aEntangledPort); - - virtual bool CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override; - - // These methods are useful for MessagePortChild - - void Entangled(nsTArray& aMessages); - void MessagesReceived(nsTArray& aMessages); - void StopSendingDataConfirmed(); - void Closed(); - -private: - explicit MessagePort(nsPIDOMWindow* aWindow); - ~MessagePort(); - - enum State { - // When a port is created by a MessageChannel it is entangled with the - // other. They both run on the same thread, same event loop and the - // messages are added to the queues without using PBackground actors. - // When one of the port is shipped, the state is changed to - // StateEntangling. - eStateUnshippedEntangled, - - // If the port is closed or cloned when we are in this state, we set the - // mNextStep. This 'next' operation will be done when entangled() message - // is received. - eStateEntangling, - - // When entangled() is received we send all the messages in the - // mMessagesForTheOtherPort to the actor and we change the state to - // StateEntangled. At this point the port is entangled with the other. We - // send and receive messages. - // If the port queue is not enabled, the received messages are stored in - // the mMessages. - eStateEntangled, - - // When the port is cloned or disentangled we want to stop receiving - // messages. We call 'SendStopSendingData' to the actor and we wait for an - // answer. All the messages received between now and the - // 'StopSendingDataComfirmed are queued in the mMessages but not - // dispatched. - eStateDisentangling, - - // When 'StopSendingDataConfirmed' is received, we can disentangle the port - // calling SendDisentangle in the actor because we are 100% sure that we - // don't receive any other message, so nothing will be lost. - // Disentangling the port we send all the messages from the mMessages - // though the actor. - eStateDisentangled - }; - - void Initialize(const nsID& aUUID, const nsID& aDestinationUUID, - uint32_t aSequenceID, bool mNeutered, State aState, - ErrorResult& aRv); - - void ConnectToPBackground(); - - // Dispatch events from the Message Queue using a nsRunnable. - void Dispatch(); - - void StartDisentangling(); - void Disentangle(); - - void RemoveDocFromBFCache(); - - // This method is meant to keep alive the MessagePort when this object is - // creating the actor and until the actor is entangled. - // We release the object when the port is closed or disentangled. - void UpdateMustKeepAlive(); - - nsAutoPtr mWorkerFeature; - - nsRefPtr mDispatchRunnable; - - nsRefPtr mActor; - - nsRefPtr mUnshippedEntangledPort; - - nsTArray> mMessages; - nsTArray> mMessagesForTheOtherPort; - - nsAutoPtr mIdentifier; - - uint64_t mInnerID; - - State mState; - - // This 'nextStep' is used when we are waiting to be entangled but the - // content has called Clone() or Close(). - enum { - eNextStepNone, - eNextStepDisentangle, - eNextStepClose - } mNextStep; - - bool mMessageQueueEnabled; - - bool mIsKeptAlive; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_MessagePort_h diff --git a/dom/messagechannel/MessagePortChild.cpp b/dom/messagechannel/MessagePortChild.cpp deleted file mode 100644 index baa1b3771316..000000000000 --- a/dom/messagechannel/MessagePortChild.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "MessagePortChild.h" -#include "MessagePort.h" -#include "mozilla/dom/MessageEvent.h" -#include "mozilla/ipc/PBackgroundChild.h" - -namespace mozilla { -namespace dom { - -bool -MessagePortChild::RecvStopSendingDataConfirmed() -{ - MOZ_ASSERT(mPort); - mPort->StopSendingDataConfirmed(); - MOZ_ASSERT(!mPort); - return true; -} - -bool -MessagePortChild::RecvEntangled(nsTArray&& aMessages) -{ - MOZ_ASSERT(mPort); - mPort->Entangled(aMessages); - return true; -} - -bool -MessagePortChild::RecvReceiveData(nsTArray&& aMessages) -{ - MOZ_ASSERT(mPort); - mPort->MessagesReceived(aMessages); - return true; -} - -void -MessagePortChild::ActorDestroy(ActorDestroyReason aWhy) -{ - if (mPort) { - mPort->Closed(); - MOZ_ASSERT(!mPort); - } -} - -} // dom namespace -} // mozilla namespace diff --git a/dom/messagechannel/MessagePortChild.h b/dom/messagechannel/MessagePortChild.h deleted file mode 100644 index 7ab954ad0687..000000000000 --- a/dom/messagechannel/MessagePortChild.h +++ /dev/null @@ -1,52 +0,0 @@ -/* 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/. */ - -#ifndef mozilla_dom_MessagePortChild_h -#define mozilla_dom_MessagePortChild_h - -#include "mozilla/Assertions.h" -#include "mozilla/dom/PMessagePortChild.h" -#include "nsISupportsImpl.h" - -namespace mozilla { -namespace dom { - -class MessagePort; - -class MessagePortChild final : public PMessagePortChild -{ -public: - NS_INLINE_DECL_REFCOUNTING(MessagePortChild) - - MessagePortChild() {} - - void SetPort(MessagePort* aPort) - { - mPort = aPort; - } - -private: - ~MessagePortChild() - { - MOZ_ASSERT(!mPort); - } - - virtual bool - RecvEntangled(nsTArray&& aMessages) override; - - virtual bool - RecvReceiveData(nsTArray&& aMessages) override; - - virtual bool RecvStopSendingDataConfirmed() override; - - virtual void ActorDestroy(ActorDestroyReason aWhy) override; - - // This is a raw pointer because this child is owned by this MessagePort. - MessagePort* mPort; -}; - -} // dom namespace -} // mozilla namespace - -#endif // mozilla_dom_MessagePortChild_h diff --git a/dom/messagechannel/MessagePortParent.cpp b/dom/messagechannel/MessagePortParent.cpp deleted file mode 100644 index 25dadafdab3b..000000000000 --- a/dom/messagechannel/MessagePortParent.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "MessagePortParent.h" -#include "MessagePortService.h" -#include "SharedMessagePortMessage.h" -#include "mozilla/unused.h" - -namespace mozilla { -namespace dom { - -MessagePortParent::MessagePortParent(const nsID& aUUID) - : mService(MessagePortService::GetOrCreate()) - , mUUID(aUUID) - , mEntangled(false) - , mCanSendData(true) -{ - MOZ_ASSERT(mService); -} - -MessagePortParent::~MessagePortParent() -{ - MOZ_ASSERT(!mService); - MOZ_ASSERT(!mEntangled); -} - -bool -MessagePortParent::Entangle(const nsID& aDestinationUUID, - const uint32_t& aSequenceID) -{ - if (!mService) { - NS_WARNING("Entangle is called after a shutdown!"); - return false; - } - - MOZ_ASSERT(!mEntangled); - - return mService->RequestEntangling(this, aDestinationUUID, aSequenceID); -} - -bool -MessagePortParent::RecvPostMessages(nsTArray&& aMessages) -{ - // This converts the object in a data struct where we have BlobImpls. - FallibleTArray> messages; - if (NS_WARN_IF( - !SharedMessagePortMessage::FromMessagesToSharedParent(aMessages, - messages))) { - return false; - } - - if (!mEntangled) { - return false; - } - - if (!mService) { - NS_WARNING("Entangle is called after a shutdown!"); - return false; - } - - if (messages.IsEmpty()) { - return false; - } - - return mService->PostMessages(this, messages); -} - -bool -MessagePortParent::RecvDisentangle(nsTArray&& aMessages) -{ - // This converts the object in a data struct where we have BlobImpls. - FallibleTArray> messages; - if (NS_WARN_IF( - !SharedMessagePortMessage::FromMessagesToSharedParent(aMessages, - messages))) { - return false; - } - - if (!mEntangled) { - return false; - } - - if (!mService) { - NS_WARNING("Entangle is called after a shutdown!"); - return false; - } - - if (!mService->DisentanglePort(this, messages)) { - return false; - } - - CloseAndDelete(); - return true; -} - -bool -MessagePortParent::RecvStopSendingData() -{ - if (!mEntangled) { - return true; - } - - mCanSendData = false; - unused << SendStopSendingDataConfirmed(); - return true; -} - -bool -MessagePortParent::RecvClose() -{ - if (mService) { - MOZ_ASSERT(mEntangled); - - if (!mService->ClosePort(this)) { - return false; - } - - Close(); - } - - MOZ_ASSERT(!mEntangled); - - unused << Send__delete__(this); - return true; -} - -void -MessagePortParent::ActorDestroy(ActorDestroyReason aWhy) -{ - if (mService && mEntangled) { - // When the last parent is deleted, this service is freed but this cannot - // be done when the hashtables are written by CloseAll. - nsRefPtr kungFuDeathGrip = mService; - mService->ParentDestroy(this); - } -} - -bool -MessagePortParent::Entangled(const nsTArray& aMessages) -{ - MOZ_ASSERT(!mEntangled); - mEntangled = true; - return SendEntangled(aMessages); -} - -void -MessagePortParent::CloseAndDelete() -{ - Close(); - unused << Send__delete__(this); -} - -void -MessagePortParent::Close() -{ - mService = nullptr; - mEntangled = false; -} - -} // dom namespace -} // mozilla namespace diff --git a/dom/messagechannel/MessagePortParent.h b/dom/messagechannel/MessagePortParent.h deleted file mode 100644 index 46dbb19ff0cc..000000000000 --- a/dom/messagechannel/MessagePortParent.h +++ /dev/null @@ -1,61 +0,0 @@ -/* 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/. */ - -#ifndef mozilla_dom_MessagePortParent_h -#define mozilla_dom_MessagePortParent_h - -#include "mozilla/dom/PMessagePortParent.h" - -namespace mozilla { -namespace dom { - -class MessagePortService; - -class MessagePortParent final : public PMessagePortParent -{ -public: - explicit MessagePortParent(const nsID& aUUID); - ~MessagePortParent(); - - bool Entangle(const nsID& aDestinationUUID, - const uint32_t& aSequenceID); - - bool Entangled(const nsTArray& aMessages); - - void Close(); - void CloseAndDelete(); - - bool CanSendData() const - { - return mCanSendData; - } - - const nsID& ID() const - { - return mUUID; - } - -private: - virtual bool RecvPostMessages(nsTArray&& aMessages) - override; - - virtual bool RecvDisentangle(nsTArray&& aMessages) - override; - - virtual bool RecvStopSendingData() override; - - virtual bool RecvClose() override; - - virtual void ActorDestroy(ActorDestroyReason aWhy) override; - - nsRefPtr mService; - const nsID mUUID; - bool mEntangled; - bool mCanSendData; -}; - -} // dom namespace -} // mozilla namespace - -#endif // mozilla_dom_MessagePortParent_h diff --git a/dom/messagechannel/MessagePortService.cpp b/dom/messagechannel/MessagePortService.cpp deleted file mode 100644 index 0d75e6ba1951..000000000000 --- a/dom/messagechannel/MessagePortService.cpp +++ /dev/null @@ -1,328 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "MessagePortService.h" -#include "MessagePortParent.h" -#include "SharedMessagePortMessage.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/unused.h" -#include "nsDataHashtable.h" -#include "nsTArray.h" - -namespace mozilla { -namespace dom { - -namespace { -StaticRefPtr gInstance; -} // anonymous namespace - -class MessagePortService::MessagePortServiceData final -{ -public: - explicit MessagePortServiceData(const nsID& aDestinationUUID) - : mDestinationUUID(aDestinationUUID) - , mSequenceID(1) - , mParent(nullptr) - { - MOZ_COUNT_CTOR(MessagePortServiceData); - } - - MessagePortServiceData(const MessagePortServiceData& aOther) = delete; - MessagePortServiceData& operator=(const MessagePortServiceData&) = delete; - - ~MessagePortServiceData() - { - MOZ_COUNT_DTOR(MessagePortServiceData); - } - - nsID mDestinationUUID; - - uint32_t mSequenceID; - MessagePortParent* mParent; - - struct NextParent - { - uint32_t mSequenceID; - // MessagePortParent keeps the service alive, and we don't want a cycle. - MessagePortParent* mParent; - }; - - FallibleTArray mNextParents; - FallibleTArray> mMessages; -}; - -/* static */ MessagePortService* -MessagePortService::GetOrCreate() -{ - if (!gInstance) { - gInstance = new MessagePortService(); - } - - return gInstance; -} - -bool -MessagePortService::RequestEntangling(MessagePortParent* aParent, - const nsID& aDestinationUUID, - const uint32_t& aSequenceID) -{ - MOZ_ASSERT(aParent); - MessagePortServiceData* data; - - // If we don't have a MessagePortServiceData, we must create 2 of them for - // both ports. - if (!mPorts.Get(aParent->ID(), &data)) { - // Create the MessagePortServiceData for the destination. - if (mPorts.Get(aDestinationUUID, nullptr)) { - MOZ_ASSERT(false, "The creation of the 2 ports should be in sync."); - return false; - } - - data = new MessagePortServiceData(aParent->ID()); - mPorts.Put(aDestinationUUID, data); - - data = new MessagePortServiceData(aDestinationUUID); - mPorts.Put(aParent->ID(), data); - } - - // This is a security check. - if (!data->mDestinationUUID.Equals(aDestinationUUID)) { - MOZ_ASSERT(false, "DestinationUUIDs do not match!"); - return false; - } - - if (aSequenceID < data->mSequenceID) { - MOZ_ASSERT(false, "Invalid sequence ID!"); - return false; - } - - if (aSequenceID == data->mSequenceID) { - if (data->mParent) { - MOZ_ASSERT(false, "Two ports cannot have the same sequenceID."); - return false; - } - - // We activate this port, sending all the messages. - data->mParent = aParent; - FallibleTArray array; - if (!SharedMessagePortMessage::FromSharedToMessagesParent(aParent, - data->mMessages, - array)) { - return false; - } - - data->mMessages.Clear(); - return aParent->Entangled(array); - } - - // This new parent will be the next one when a Disentangle request is - // received from the current parent. - MessagePortServiceData::NextParent* nextParent = - data->mNextParents.AppendElement(mozilla::fallible); - if (!nextParent) { - return false; - } - - nextParent->mSequenceID = aSequenceID; - nextParent->mParent = aParent; - - return true; -} - -bool -MessagePortService::DisentanglePort( - MessagePortParent* aParent, - FallibleTArray>& aMessages) -{ - MessagePortServiceData* data; - if (!mPorts.Get(aParent->ID(), &data)) { - MOZ_ASSERT(false, "Unknown MessagePortParent should not happen."); - return false; - } - - if (data->mParent != aParent) { - MOZ_ASSERT(false, "DisentanglePort() should be called just from the correct parent."); - return false; - } - - // Let's put the messages in the correct order. |aMessages| contains the - // unsent messages so they have to go first. - if (!aMessages.AppendElements(data->mMessages, mozilla::fallible)) { - return false; - } - - data->mMessages.Clear(); - - ++data->mSequenceID; - - // If we don't have a parent, we have to store the pending messages and wait. - uint32_t index = 0; - MessagePortParent* nextParent = nullptr; - for (; index < data->mNextParents.Length(); ++index) { - if (data->mNextParents[index].mSequenceID == data->mSequenceID) { - nextParent = data->mNextParents[index].mParent; - break; - } - } - - // We didn't find the parent. - if (!nextParent) { - data->mMessages.SwapElements(aMessages); - data->mParent = nullptr; - return true; - } - - data->mParent = nextParent; - data->mNextParents.RemoveElementAt(index); - - FallibleTArray array; - if (!SharedMessagePortMessage::FromSharedToMessagesParent(data->mParent, - aMessages, - array)) { - return false; - } - - unused << data->mParent->Entangled(array); - return true; -} - -bool -MessagePortService::ClosePort(MessagePortParent* aParent) -{ - MessagePortServiceData* data; - if (!mPorts.Get(aParent->ID(), &data)) { - MOZ_ASSERT(false, "Unknown MessagePortParent should not happend."); - return false; - } - - if (data->mParent != aParent) { - MOZ_ASSERT(false, "ClosePort() should be called just from the correct parent."); - return false; - } - - if (!data->mNextParents.IsEmpty()) { - MOZ_ASSERT(false, "ClosePort() should be called when there are not next parents."); - return false; - } - - // We don't want to send a message to this parent. - data->mParent = nullptr; - - CloseAll(aParent->ID()); - return true; -} - -#ifdef DEBUG -PLDHashOperator -MessagePortService::CloseAllDebugCheck(const nsID& aID, - MessagePortServiceData* aData, - void* aPtr) -{ - nsID* id = static_cast(aPtr); - MOZ_ASSERT(!id->Equals(aID)); - return PL_DHASH_NEXT; -} -#endif - -void -MessagePortService::CloseAll(const nsID& aUUID) -{ - MessagePortServiceData* data; - if (!mPorts.Get(aUUID, &data)) { - MaybeShutdown(); - return; - } - - if (data->mParent) { - data->mParent->Close(); - } - - for (const MessagePortServiceData::NextParent& parent : data->mNextParents) { - parent.mParent->CloseAndDelete(); - } - - nsID destinationUUID = data->mDestinationUUID; - mPorts.Remove(aUUID); - - CloseAll(destinationUUID); - -#ifdef DEBUG - mPorts.EnumerateRead(CloseAllDebugCheck, const_cast(&aUUID)); -#endif - - MaybeShutdown(); -} - -// This service can be dismissed when there are not active ports. -void -MessagePortService::MaybeShutdown() -{ - if (mPorts.Count() == 0) { - gInstance = nullptr; - } -} - -bool -MessagePortService::PostMessages( - MessagePortParent* aParent, - FallibleTArray>& aMessages) -{ - MessagePortServiceData* data; - if (!mPorts.Get(aParent->ID(), &data)) { - MOZ_ASSERT(false, "Unknown MessagePortParent should not happend."); - return false; - } - - if (data->mParent != aParent) { - MOZ_ASSERT(false, "PostMessages() should be called just from the correct parent."); - return false; - } - - MOZ_ALWAYS_TRUE(mPorts.Get(data->mDestinationUUID, &data)); - - if (!data->mMessages.AppendElements(aMessages, mozilla::fallible)) { - return false; - } - - // If the parent can send data to the child, let's proceed. - if (data->mParent && data->mParent->CanSendData()) { - FallibleTArray messages; - if (!SharedMessagePortMessage::FromSharedToMessagesParent(data->mParent, - data->mMessages, - messages)) { - return false; - } - - data->mMessages.Clear(); - unused << data->mParent->SendReceiveData(messages); - } - - return true; -} - -void -MessagePortService::ParentDestroy(MessagePortParent* aParent) -{ - // This port has already been destroyed. - MessagePortServiceData* data; - if (!mPorts.Get(aParent->ID(), &data)) { - return; - } - - if (data->mParent != aParent) { - // We don't want to send a message to this parent. - for (uint32_t i = 0; i < data->mNextParents.Length(); ++i) { - if (aParent == data->mNextParents[i].mParent) { - data->mNextParents.RemoveElementAt(i); - break; - } - } - } - - CloseAll(aParent->ID()); -} - -} // dom namespace -} // mozilla namespace diff --git a/dom/messagechannel/MessagePortService.h b/dom/messagechannel/MessagePortService.h deleted file mode 100644 index 437cf2393c11..000000000000 --- a/dom/messagechannel/MessagePortService.h +++ /dev/null @@ -1,61 +0,0 @@ -/* 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/. */ - -#ifndef mozilla_dom_MessagePortService_h -#define mozilla_dom_MessagePortService_h - -#include "nsClassHashtable.h" -#include "nsHashKeys.h" -#include "nsISupportsImpl.h" - -namespace mozilla { -namespace dom { - -class MessagePortParent; -class SharedMessagePortMessage; - -class MessagePortService final -{ -public: - NS_INLINE_DECL_REFCOUNTING(MessagePortService) - - static MessagePortService* GetOrCreate(); - - bool RequestEntangling(MessagePortParent* aParent, - const nsID& aDestinationUUID, - const uint32_t& aSequenceID); - - bool DisentanglePort( - MessagePortParent* aParent, - FallibleTArray>& aMessages); - - bool ClosePort(MessagePortParent* aParent); - - bool PostMessages( - MessagePortParent* aParent, - FallibleTArray>& aMessages); - - void ParentDestroy(MessagePortParent* aParent); - -private: - ~MessagePortService() {} - - void CloseAll(const nsID& aUUID); - void MaybeShutdown(); - - class MessagePortServiceData; - -#ifdef DEBUG - static PLDHashOperator - CloseAllDebugCheck(const nsID& aID, MessagePortServiceData* aData, - void* aPtr); -#endif - - nsClassHashtable mPorts; -}; - -} // dom namespace -} // mozilla namespace - -#endif // mozilla_dom_MessagePortService_h diff --git a/dom/messagechannel/MessagePortUtils.cpp b/dom/messagechannel/MessagePortUtils.cpp deleted file mode 100644 index 06b330b7f426..000000000000 --- a/dom/messagechannel/MessagePortUtils.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "MessagePortUtils.h" -#include "MessagePort.h" -#include "mozilla/dom/BlobBinding.h" -#include "mozilla/dom/File.h" -#include "mozilla/dom/MessagePortBinding.h" -#include "mozilla/dom/StructuredCloneTags.h" - -namespace mozilla { -namespace dom { -namespace messageport { - -namespace { - -struct MOZ_STACK_CLASS StructuredCloneClosureInternal -{ - StructuredCloneClosureInternal( - StructuredCloneClosure& aClosure, nsPIDOMWindow* aWindow) - : mClosure(aClosure) - , mWindow(aWindow) - { } - - StructuredCloneClosure& mClosure; - nsPIDOMWindow* mWindow; - nsTArray> mMessagePorts; - nsTArray> mTransferredPorts; -}; - -struct MOZ_STACK_CLASS StructuredCloneClosureInternalReadOnly -{ - StructuredCloneClosureInternalReadOnly( - const StructuredCloneClosure& aClosure, nsPIDOMWindow* aWindow) - : mClosure(aClosure) - , mWindow(aWindow) - { } - - const StructuredCloneClosure& mClosure; - nsPIDOMWindow* mWindow; - nsTArray> mMessagePorts; - nsTArray> mTransferredPorts; -}; - -void -Error(JSContext* aCx, uint32_t aErrorId) -{ - if (NS_IsMainThread()) { - NS_DOMStructuredCloneError(aCx, aErrorId); - } else { - Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); - } -} - -JSObject* -Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, - uint32_t aData, void* aClosure) -{ - MOZ_ASSERT(aClosure); - - auto* closure = static_cast(aClosure); - - if (aTag == SCTAG_DOM_BLOB) { - // nsRefPtr needs to go out of scope before toObjectOrNull() is - // called because the static analysis thinks dereferencing XPCOM objects - // can GC (because in some cases it can!), and a return statement with a - // JSObject* type means that JSObject* is on the stack as a raw pointer - // while destructors are running. - JS::Rooted val(aCx); - { - MOZ_ASSERT(aData < closure->mClosure.mBlobImpls.Length()); - nsRefPtr blobImpl = closure->mClosure.mBlobImpls[aData]; - -#ifdef DEBUG - { - // Blob should not be mutable. - bool isMutable; - MOZ_ASSERT(NS_SUCCEEDED(blobImpl->GetMutable(&isMutable))); - MOZ_ASSERT(!isMutable); - } -#endif - - // Let's create a new blob with the correct parent. - nsIGlobalObject* global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx)); - MOZ_ASSERT(global); - - nsRefPtr newBlob = Blob::Create(global, blobImpl); - if (!ToJSValue(aCx, newBlob, &val)) { - return nullptr; - } - } - - return &val.toObject(); - } - - return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr); -} - -bool -Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj, void* aClosure) -{ - MOZ_ASSERT(aClosure); - - auto* closure = static_cast(aClosure); - - // See if the wrapped native is a File/Blob. - { - Blob* blob = nullptr; - if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob)) && - NS_SUCCEEDED(blob->SetMutable(false)) && - JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, - closure->mClosure.mBlobImpls.Length())) { - closure->mClosure.mBlobImpls.AppendElement(blob->Impl()); - return true; - } - } - - return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); -} - -bool -ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader, - uint32_t aTag, void* aContent, uint64_t aExtraData, - void* aClosure, JS::MutableHandle aReturnObject) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aClosure); - - auto* closure = static_cast(aClosure); - - if (aTag != SCTAG_DOM_MAP_MESSAGEPORT) { - return false; - } - - MOZ_ASSERT(aContent == 0); - MOZ_ASSERT(aExtraData < closure->mClosure.mMessagePortIdentifiers.Length()); - - ErrorResult rv; - nsRefPtr port = - MessagePort::Create(closure->mWindow, - closure->mClosure.mMessagePortIdentifiers[(uint32_t)aExtraData], - rv); - if (NS_WARN_IF(rv.Failed())) { - return false; - } - - closure->mMessagePorts.AppendElement(port); - - JS::Rooted value(aCx); - if (!GetOrCreateDOMReflector(aCx, port, &value)) { - JS_ClearPendingException(aCx); - return false; - } - - aReturnObject.set(&value.toObject()); - return true; -} - -bool -WriteTransfer(JSContext* aCx, JS::Handle aObj, void* aClosure, - uint32_t* aTag, JS::TransferableOwnership* aOwnership, - void** aContent, uint64_t* aExtraData) -{ - MOZ_ASSERT(aClosure); - - auto* closure = static_cast(aClosure); - - MessagePortBase* port = nullptr; - nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); - if (NS_FAILED(rv)) { - return false; - } - - if (closure->mTransferredPorts.Contains(port)) { - // No duplicates. - return false; - } - - MessagePortIdentifier identifier; - if (!port->CloneAndDisentangle(identifier)) { - return false; - } - - closure->mClosure.mMessagePortIdentifiers.AppendElement(identifier); - closure->mTransferredPorts.AppendElement(port); - - *aTag = SCTAG_DOM_MAP_MESSAGEPORT; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = nullptr; - *aExtraData = closure->mClosure.mMessagePortIdentifiers.Length() - 1; - - return true; -} - -const JSStructuredCloneCallbacks gCallbacks = { - Read, - Write, - Error, - ReadTransfer, - WriteTransfer, - nullptr -}; - -} // anonymous namespace - -bool -ReadStructuredCloneWithTransfer(JSContext* aCx, nsTArray& aData, - const StructuredCloneClosure& aClosure, - JS::MutableHandle aClone, - nsPIDOMWindow* aParentWindow, - nsTArray>& aMessagePorts) -{ - auto* data = reinterpret_cast(aData.Elements()); - size_t dataLen = aData.Length(); - MOZ_ASSERT(!(dataLen % sizeof(*data))); - - StructuredCloneClosureInternalReadOnly internalClosure(aClosure, - aParentWindow); - - bool rv = JS_ReadStructuredClone(aCx, data, dataLen, - JS_STRUCTURED_CLONE_VERSION, aClone, - &gCallbacks, &internalClosure); - if (rv) { - aMessagePorts.SwapElements(internalClosure.mMessagePorts); - } - - return rv; -} - -bool -WriteStructuredCloneWithTransfer(JSContext* aCx, JS::Handle aSource, - JS::Handle aTransferable, - nsTArray& aData, - StructuredCloneClosure& aClosure) -{ - StructuredCloneClosureInternal internalClosure(aClosure, nullptr); - JSAutoStructuredCloneBuffer buffer(&gCallbacks, &internalClosure); - - if (!buffer.write(aCx, aSource, aTransferable, &gCallbacks, - &internalClosure)) { - return false; - } - - FallibleTArray cloneData; - if (NS_WARN_IF(!cloneData.SetLength(buffer.nbytes(), mozilla::fallible))) { - return false; - } - - uint64_t* data; - size_t size; - buffer.steal(&data, &size); - - memcpy(cloneData.Elements(), data, size); - js_free(data); - - MOZ_ASSERT(aData.IsEmpty()); - aData.SwapElements(cloneData); - return true; -} - -void -FreeStructuredClone(nsTArray& aData, StructuredCloneClosure& aClosure) -{ - auto* data = reinterpret_cast(aData.Elements()); - size_t dataLen = aData.Length(); - MOZ_ASSERT(!(dataLen % sizeof(*data))); - - JS_ClearStructuredClone(data, dataLen, &gCallbacks, &aClosure, false); - aData.Clear(); -} - -} // messageport namespace -} // dom namespace -} // mozilla namespace diff --git a/dom/messagechannel/MessagePortUtils.h b/dom/messagechannel/MessagePortUtils.h deleted file mode 100644 index 9c9442700e73..000000000000 --- a/dom/messagechannel/MessagePortUtils.h +++ /dev/null @@ -1,55 +0,0 @@ -/* 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/. */ - -#ifndef mozilla_dom_MessagePortUtils_h -#define mozilla_dom_MessagePortUtils_h - -#include "MessagePort.h" -#include "mozilla/dom/File.h" -#include "mozilla/dom/PMessagePort.h" - -class nsPIDOMWindow; - -namespace mozilla { -namespace dom { -namespace messageport { - -struct -StructuredCloneClosure -{ - nsTArray> mBlobImpls; - nsTArray mMessagePortIdentifiers; -}; - -struct -StructuredCloneData -{ - StructuredCloneData() : mData(nullptr), mDataLength(0) {} - uint64_t* mData; - size_t mDataLength; - StructuredCloneClosure mClosure; -}; - -bool -ReadStructuredCloneWithTransfer(JSContext* aCx, nsTArray& aData, - const StructuredCloneClosure& aClosure, - JS::MutableHandle aClone, - nsPIDOMWindow* aParentWindow, - nsTArray>& aMessagePorts); - -bool -WriteStructuredCloneWithTransfer(JSContext* aCx, JS::Handle aSource, - JS::Handle aTransferable, - nsTArray& aData, - StructuredCloneClosure& aClosure); - -void -FreeStructuredClone(nsTArray& aData, - StructuredCloneClosure& aClosure); - -} // messageport namespace -} // dom namespace -} // mozilla namespace - -#endif // mozilla_dom_MessagePortUtils_h diff --git a/dom/messagechannel/PMessagePort.ipdl b/dom/messagechannel/PMessagePort.ipdl deleted file mode 100644 index 299b00fedf14..000000000000 --- a/dom/messagechannel/PMessagePort.ipdl +++ /dev/null @@ -1,62 +0,0 @@ -/* 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 protocol PBackground; -include protocol PBlob; - -using struct nsID from "nsID.h"; - -namespace mozilla { -namespace dom { - -struct MessagePortIdentifier -{ - nsID uuid; - nsID destinationUuid; - uint32_t sequenceId; - bool neutered; -}; - -struct MessagePortMessage -{ - MessagePortIdentifier[] transferredPorts; - uint8_t[] data; - PBlob[] blobs; -}; - -// This protocol is used for the MessageChannel/MessagePort API -protocol PMessagePort -{ - manager PBackground; - - /* Many of these methods are used just for the shutdown sequence. The - correct sequence for the child actor is: - 1. SendStopSendingData(); - 2. RecvStopSendingDataConfirmed(); - 3. SendClose(); - 4. Recv__delete__(); */ - - /* When the port is transferred the sequence is: - 1. SendStopSendingData(); - 2. RecvStopSendingDataConfirmed(); - 3. SendDisentangle(); - 4. Recv__delete__(); */ - -parent: - PostMessages(MessagePortMessage[] messages); - Disentangle(MessagePortMessage[] messages); - StopSendingData(); - Close(); - -child: - Entangled(MessagePortMessage[] messages); - ReceiveData(MessagePortMessage[] messages); - StopSendingDataConfirmed(); - - __delete__(); -}; - -} // namespace dom -} // namespace mozilla - diff --git a/dom/messagechannel/SharedMessagePortMessage.cpp b/dom/messagechannel/SharedMessagePortMessage.cpp deleted file mode 100644 index bbd8fbdbdd5d..000000000000 --- a/dom/messagechannel/SharedMessagePortMessage.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "SharedMessagePortMessage.h" -#include "MessagePort.h" -#include "MessagePortChild.h" -#include "MessagePortParent.h" -#include "mozilla/dom/ipc/BlobChild.h" -#include "mozilla/dom/ipc/BlobParent.h" -#include "mozilla/dom/File.h" -#include "mozilla/dom/PMessagePort.h" -#include "mozilla/ipc/BackgroundChild.h" -#include "mozilla/ipc/BackgroundParent.h" - -namespace mozilla { - -using namespace ipc; - -namespace dom { - -SharedMessagePortMessage::~SharedMessagePortMessage() -{ - if (!mData.IsEmpty()) { - FreeStructuredClone(mData, mClosure); - } -} - -/* static */ void -SharedMessagePortMessage::FromSharedToMessagesChild( - MessagePortChild* aActor, - const nsTArray>& aData, - nsTArray& aArray) -{ - MOZ_ASSERT(aActor); - MOZ_ASSERT(aArray.IsEmpty()); - aArray.SetCapacity(aData.Length()); - - PBackgroundChild* backgroundManager = aActor->Manager(); - MOZ_ASSERT(backgroundManager); - - for (auto& data : aData) { - MessagePortMessage* message = aArray.AppendElement(); - message->data().SwapElements(data->mData); - - const nsTArray>& blobImpls = - data->mClosure.mBlobImpls; - if (!blobImpls.IsEmpty()) { - message->blobsChild().SetCapacity(blobImpls.Length()); - - for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { - PBlobChild* blobChild = - BackgroundChild::GetOrCreateActorForBlobImpl(backgroundManager, - blobImpls[i]); - message->blobsChild().AppendElement(blobChild); - } - } - - message->transferredPorts().AppendElements( - data->mClosure.mMessagePortIdentifiers); - } -} - -/* static */ bool -SharedMessagePortMessage::FromMessagesToSharedChild( - nsTArray& aArray, - FallibleTArray>& aData) -{ - MOZ_ASSERT(aData.IsEmpty()); - - if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) { - return false; - } - - for (auto& message : aArray) { - nsRefPtr data = new SharedMessagePortMessage(); - - data->mData.SwapElements(message.data()); - - const nsTArray& blobs = message.blobsChild(); - if (!blobs.IsEmpty()) { - data->mClosure.mBlobImpls.SetCapacity(blobs.Length()); - - for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) { - nsRefPtr impl = - static_cast(blobs[i])->GetBlobImpl(); - data->mClosure.mBlobImpls.AppendElement(impl); - } - } - - data->mClosure.mMessagePortIdentifiers.AppendElements( - message.transferredPorts()); - - if (!aData.AppendElement(data, mozilla::fallible)) { - return false; - } - } - - return true; -} - -/* static */ bool -SharedMessagePortMessage::FromSharedToMessagesParent( - MessagePortParent* aActor, - const nsTArray>& aData, - FallibleTArray& aArray) -{ - MOZ_ASSERT(aArray.IsEmpty()); - - if (NS_WARN_IF(!aArray.SetCapacity(aData.Length(), mozilla::fallible))) { - return false; - } - - PBackgroundParent* backgroundManager = aActor->Manager(); - MOZ_ASSERT(backgroundManager); - - for (auto& data : aData) { - MessagePortMessage* message = aArray.AppendElement(mozilla::fallible); - message->data().SwapElements(data->mData); - - const nsTArray>& blobImpls = data->mClosure.mBlobImpls; - if (!blobImpls.IsEmpty()) { - message->blobsParent().SetCapacity(blobImpls.Length()); - - for (uint32_t i = 0, len = blobImpls.Length(); i < len; ++i) { - PBlobParent* blobParent = - BackgroundParent::GetOrCreateActorForBlobImpl(backgroundManager, - blobImpls[i]); - message->blobsParent().AppendElement(blobParent); - } - } - - message->transferredPorts().AppendElements( - data->mClosure.mMessagePortIdentifiers); - } - - return true; -} - -/* static */ bool -SharedMessagePortMessage::FromMessagesToSharedParent( - nsTArray& aArray, - FallibleTArray>& aData) -{ - MOZ_ASSERT(aData.IsEmpty()); - - if (NS_WARN_IF(!aData.SetCapacity(aArray.Length(), mozilla::fallible))) { - return false; - } - - for (auto& message : aArray) { - nsRefPtr data = new SharedMessagePortMessage(); - - data->mData.SwapElements(message.data()); - - const nsTArray& blobs = message.blobsParent(); - if (!blobs.IsEmpty()) { - data->mClosure.mBlobImpls.SetCapacity(blobs.Length()); - - for (uint32_t i = 0, len = blobs.Length(); i < len; ++i) { - nsRefPtr impl = - static_cast(blobs[i])->GetBlobImpl(); - data->mClosure.mBlobImpls.AppendElement(impl); - } - } - - data->mClosure.mMessagePortIdentifiers.AppendElements( - message.transferredPorts()); - - if (!aData.AppendElement(data, mozilla::fallible)) { - return false; - } - } - - return true; -} - -} // dom namespace -} // mozilla namespace diff --git a/dom/messagechannel/SharedMessagePortMessage.h b/dom/messagechannel/SharedMessagePortMessage.h deleted file mode 100644 index c2516874edf5..000000000000 --- a/dom/messagechannel/SharedMessagePortMessage.h +++ /dev/null @@ -1,58 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#ifndef mozilla_dom_SharedMessagePortMessage_h -#define mozilla_dom_SharedMessagePortMessage_h - -#include "MessagePortUtils.h" - -namespace mozilla { -namespace dom { - -class MessagePortChild; -class MessagePortMessage; -class MessagePortParent; - -class SharedMessagePortMessage final -{ -public: - NS_INLINE_DECL_REFCOUNTING(SharedMessagePortMessage) - - nsTArray mData; - messageport::StructuredCloneClosure mClosure; - - SharedMessagePortMessage() - {} - - static void - FromSharedToMessagesChild( - MessagePortChild* aActor, - const nsTArray>& aData, - nsTArray& aArray); - - static bool - FromMessagesToSharedChild( - nsTArray& aArray, - FallibleTArray>& aData); - - static bool - FromSharedToMessagesParent( - MessagePortParent* aActor, - const nsTArray>& aData, - FallibleTArray& aArray); - - static bool - FromMessagesToSharedParent( - nsTArray& aArray, - FallibleTArray>& aData); - -private: - ~SharedMessagePortMessage(); -}; - -} // dom namespace -} // mozilla namespace - -#endif // mozilla_dom_SharedMessagePortMessage_h diff --git a/dom/messagechannel/moz.build b/dom/messagechannel/moz.build deleted file mode 100644 index c5850dbe0bce..000000000000 --- a/dom/messagechannel/moz.build +++ /dev/null @@ -1,41 +0,0 @@ -# -*- 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/. - -TEST_DIRS += ['tests'] - -EXPORTS.mozilla.dom += [ - 'MessageChannel.h', - 'MessagePort.h', - 'MessagePortChild.h', - 'MessagePortList.h', - 'MessagePortParent.h', -] - -UNIFIED_SOURCES += [ - 'MessageChannel.cpp', - 'MessagePort.cpp', - 'MessagePortChild.cpp', - 'MessagePortList.cpp', - 'MessagePortParent.cpp', - 'MessagePortService.cpp', - 'MessagePortUtils.cpp', - 'SharedMessagePortMessage.cpp', -] - -IPDL_SOURCES += [ - 'PMessagePort.ipdl', -] - -LOCAL_INCLUDES += [ - '../base', - '../events', - '../workers', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' -FAIL_ON_WARNINGS = True diff --git a/dom/messagechannel/tests/chrome.ini b/dom/messagechannel/tests/chrome.ini deleted file mode 100644 index 8d7140d76f29..000000000000 --- a/dom/messagechannel/tests/chrome.ini +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -support-files = - iframe_messageChannel_chrome.html - -[test_messageChannel.xul] diff --git a/dom/messagechannel/tests/iframe_messageChannel_sharedWorker2.html b/dom/messagechannel/tests/iframe_messageChannel_sharedWorker2.html deleted file mode 100644 index a693cba22c2e..000000000000 --- a/dom/messagechannel/tests/iframe_messageChannel_sharedWorker2.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - diff --git a/dom/messagechannel/tests/iframe_messageChannel_transferable.html b/dom/messagechannel/tests/iframe_messageChannel_transferable.html deleted file mode 100644 index 108edeb7e6ae..000000000000 --- a/dom/messagechannel/tests/iframe_messageChannel_transferable.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - diff --git a/dom/messagechannel/tests/mochitest.ini b/dom/messagechannel/tests/mochitest.ini deleted file mode 100644 index fc5cecd1304a..000000000000 --- a/dom/messagechannel/tests/mochitest.ini +++ /dev/null @@ -1,25 +0,0 @@ -[DEFAULT] -support-files = - iframe_messageChannel_cloning.html - iframe_messageChannel_pingpong.html - iframe_messageChannel_post.html - iframe_messageChannel_transferable.html - worker_messageChannel.js - worker_messageChannel_any.js - sharedWorker_messageChannel.js - sharedWorker2_messageChannel.js - iframe_messageChannel_sharedWorker2.html - -[test_messageChannel.html] -[test_messageChannel_cloning.html] -[test_messageChannel_pingpong.html] -[test_messageChannel_post.html] -[test_messageChannel_pref.html] -[test_messageChannel_start.html] -[test_messageChannel_transferable.html] -[test_messageChannel_unshipped.html] -[test_messageChannel_worker.html] -[test_messageChannel_selfTransferring.html] -[test_messageChannel_sharedWorker.html] -[test_messageChannel_sharedWorker2.html] -[test_messageChannel_any.html] diff --git a/dom/messagechannel/tests/moz.build b/dom/messagechannel/tests/moz.build deleted file mode 100644 index 846268289f1d..000000000000 --- a/dom/messagechannel/tests/moz.build +++ /dev/null @@ -1,8 +0,0 @@ -# -*- 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'] -MOCHITEST_CHROME_MANIFESTS += ['chrome.ini'] diff --git a/dom/messagechannel/tests/sharedWorker2_messageChannel.js b/dom/messagechannel/tests/sharedWorker2_messageChannel.js deleted file mode 100644 index 8cc98aa209b8..000000000000 --- a/dom/messagechannel/tests/sharedWorker2_messageChannel.js +++ /dev/null @@ -1,7 +0,0 @@ -var mc = new MessageChannel(); -var i = 0; - -onconnect = function(evt) { - dump("CONNECTING: "+ i +"\n"); - evt.ports[0].postMessage(42, [mc['port' + ++i]]); -} diff --git a/dom/messagechannel/tests/sharedWorker_messageChannel.js b/dom/messagechannel/tests/sharedWorker_messageChannel.js deleted file mode 100644 index 4b24642f9d26..000000000000 --- a/dom/messagechannel/tests/sharedWorker_messageChannel.js +++ /dev/null @@ -1,8 +0,0 @@ -onconnect = function(evt) { - var mc = new MessageChannel(); - - evt.ports[0].postMessage(42, [mc.port2]); - mc.port1.onmessage = function(e) { - mc.port1.postMessage(e.data); - } -} diff --git a/dom/messagechannel/tests/test_messageChannel_any.html b/dom/messagechannel/tests/test_messageChannel_any.html deleted file mode 100644 index 2cc34443ddb4..000000000000 --- a/dom/messagechannel/tests/test_messageChannel_any.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - MessagePort/Channel any content - - - - -Mozilla Bug 677638 -
-
-
- - - diff --git a/dom/messagechannel/tests/test_messageChannel_selfTransferring.html b/dom/messagechannel/tests/test_messageChannel_selfTransferring.html deleted file mode 100644 index d84a616e4255..000000000000 --- a/dom/messagechannel/tests/test_messageChannel_selfTransferring.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - MessagePort/Channel no self tranferring - - - - -Mozilla Bug 677638 -
-
-
- - - - diff --git a/dom/messagechannel/tests/test_messageChannel_sharedWorker.html b/dom/messagechannel/tests/test_messageChannel_sharedWorker.html deleted file mode 100644 index 9bb330a851fb..000000000000 --- a/dom/messagechannel/tests/test_messageChannel_sharedWorker.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - Test for Bug 677638 - sharedWorker - - - - -Mozilla Bug 677638 -

- -
-
- - - diff --git a/dom/messagechannel/tests/test_messageChannel_sharedWorker2.html b/dom/messagechannel/tests/test_messageChannel_sharedWorker2.html deleted file mode 100644 index d8a4c624b1ab..000000000000 --- a/dom/messagechannel/tests/test_messageChannel_sharedWorker2.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - Test for Bug 677638 - sharedWorker - - - - - Mozilla Bug 677638 -
- - - - diff --git a/dom/messagechannel/tests/test_messageChannel_worker.html b/dom/messagechannel/tests/test_messageChannel_worker.html deleted file mode 100644 index 0eb8489f5170..000000000000 --- a/dom/messagechannel/tests/test_messageChannel_worker.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - Test for Bug 677638 - basic support - - - - -Mozilla Bug 677638 -

- -
-
- - - diff --git a/dom/messagechannel/tests/worker_messageChannel.js b/dom/messagechannel/tests/worker_messageChannel.js deleted file mode 100644 index 87b0b8eb0c27..000000000000 --- a/dom/messagechannel/tests/worker_messageChannel.js +++ /dev/null @@ -1,119 +0,0 @@ -function ok(a, msg) { - postMessage({ type: 'check', check: !!a, message: msg }); -} - -function is(a, b, msg) { - ok (a === b, msg); -} - -function info(msg) { - postMessage({ type: 'info', message: msg }); -} - -function finish() { - postMessage({ type: 'finish' }); -} - -function basic() -{ - var a = new MessageChannel(); - ok(a, "MessageChannel created"); - - var port1 = a.port1; - ok(port1, "MessageChannel.port1 exists"); - is(port1, a.port1, "MessageChannel.port1 is port1"); - - var port2 = a.port2; - ok(port2, "MessageChannel.port1 exists"); - is(port2, a.port2, "MessageChannel.port2 is port2"); - - [ 'postMessage', 'start', 'close' ].forEach(function(e) { - ok(e in port1, "MessagePort1." + e + " exists"); - ok(e in port2, "MessagePort2." + e + " exists"); - }); - - runTests(); -} - -function sendMessages() -{ - var a = new MessageChannel(); - ok(a, "MessageChannel created"); - - a.port1.postMessage("Hello world!"); - a.port1.onmessage = function(e) { - is(e.data, "Hello world!", "The message is back!"); - runTests(); - } - - a.port2.onmessage = function(e) { - a.port2.postMessage(e.data); - } -} - -function transferPort() -{ - var a = new MessageChannel(); - ok(a, "MessageChannel created"); - - a.port1.postMessage("Hello world!"); - a.port1.onmessage = function(e) { - is(e.data, "Hello world!", "The message is back!"); - runTests(); - } - - postMessage({ type: 'port' }, [a.port2]); -} - -function transferPort2() -{ - onmessage = function(evt) { - is(evt.ports.length, 1, "A port has been received by the worker"); - evt.ports[0].onmessage = function(e) { - is(e.data, 42, "Data is 42!"); - runTests(); - } - } - - postMessage({ type: 'newport' }); -} - -var tests = [ - basic, - sendMessages, - transferPort, - transferPort2, -]; - -function runTests() { - if (!tests.length) { - finish(); - return; - } - - var t = tests.shift(); - t(); -} - -var subworker; -onmessage = function(evt) { - if (evt.data == 0) { - runTests(); - return; - } - - if (!subworker) { - info("Create a subworkers. ID: " + evt.data); - subworker = new Worker('worker_messageChannel.js'); - subworker.onmessage = function(e) { - info("Proxy a message to the parent."); - postMessage(e.data, e.ports); - } - - subworker.postMessage(evt.data - 1); - return; - } - - info("Dispatch a message to the subworker."); - subworker.postMessage(evt.data, evt.ports); -} diff --git a/dom/messagechannel/tests/worker_messageChannel_any.js b/dom/messagechannel/tests/worker_messageChannel_any.js deleted file mode 100644 index bbb1d50f974e..000000000000 --- a/dom/messagechannel/tests/worker_messageChannel_any.js +++ /dev/null @@ -1,7 +0,0 @@ -onmessage = function(evt) { - evt.data.onmessage = function(event) { - evt.data.postMessage(event.data); - } -} - -postMessage("READY"); diff --git a/dom/moz.build b/dom/moz.build index 236e9d352f7b..41b1d209db7b 100644 --- a/dom/moz.build +++ b/dom/moz.build @@ -96,7 +96,6 @@ DIRS += [ 'camera', 'audiochannel', 'broadcastchannel', - 'messagechannel', 'promise', 'smil', 'telephony', diff --git a/dom/webidl/MessageChannel.webidl b/dom/webidl/MessageChannel.webidl index 64b1262e3611..34de4b46e207 100644 --- a/dom/webidl/MessageChannel.webidl +++ b/dom/webidl/MessageChannel.webidl @@ -7,8 +7,7 @@ * http://www.whatwg.org/specs/web-apps/current-work/#channel-messaging */ -[Constructor, Func="MessageChannel::Enabled", - Exposed=(Window,Worker)] +[Constructor, Func="MessageChannel::Enabled"] interface MessageChannel { readonly attribute MessagePort port1; readonly attribute MessagePort port2; diff --git a/dom/workers/MessagePort.cpp b/dom/workers/MessagePort.cpp index 19aa73559e31..136787777615 100644 --- a/dom/workers/MessagePort.cpp +++ b/dom/workers/MessagePort.cpp @@ -17,7 +17,6 @@ using mozilla::dom::EventHandlerNonNull; using mozilla::dom::MessagePortBase; -using mozilla::dom::MessagePortIdentifier; using mozilla::dom::Optional; using mozilla::dom::Sequence; using mozilla::dom::AutoNoJSAPI; @@ -97,9 +96,9 @@ MessagePort::~MessagePort() } void -MessagePort::PostMessage(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) +MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) { AssertCorrectThread(); @@ -199,11 +198,11 @@ MessagePort::SetOnmessage(EventHandlerNonNull* aCallback) Start(); } -bool -MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier) +already_AddRefed +MessagePort::Clone() { NS_WARNING("Haven't implemented structured clone for these ports yet!"); - return false; + return nullptr; } void diff --git a/dom/workers/MessagePort.h b/dom/workers/MessagePort.h index 30dcc3a2e13c..51b1d6c9c018 100644 --- a/dom/workers/MessagePort.h +++ b/dom/workers/MessagePort.h @@ -43,9 +43,9 @@ public: PrefEnabled(); virtual void - PostMessage(JSContext* aCx, JS::Handle aMessage, - const Optional>& aTransferable, - ErrorResult& aRv) override; + PostMessageMoz(JSContext* aCx, JS::Handle aMessage, + const Optional>& aTransferable, + ErrorResult& aRv) override; virtual void Start() override; @@ -71,8 +71,8 @@ public: virtual void SetOnmessage(EventHandlerNonNull* aCallback) override; - virtual bool - CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override; + virtual already_AddRefed + Clone() override; bool IsClosed() const diff --git a/dom/workers/ServiceWorkerClient.cpp b/dom/workers/ServiceWorkerClient.cpp index 1bfe6457a8af..41d992ac74f8 100644 --- a/dom/workers/ServiceWorkerClient.cpp +++ b/dom/workers/ServiceWorkerClient.cpp @@ -12,7 +12,6 @@ #include "nsGlobalWindow.h" #include "nsIDocument.h" #include "WorkerPrivate.h" -#include "WorkerStructuredClone.h" using namespace mozilla; using namespace mozilla::dom; @@ -76,18 +75,16 @@ class ServiceWorkerClientPostMessageRunnable final : public nsRunnable { uint64_t mWindowId; JSAutoStructuredCloneBuffer mBuffer; - WorkerStructuredCloneClosure mClosure; + nsTArray> mClonedObjects; public: ServiceWorkerClientPostMessageRunnable(uint64_t aWindowId, JSAutoStructuredCloneBuffer&& aData, - WorkerStructuredCloneClosure& aClosure) + nsTArray>& aClonedObjects) : mWindowId(aWindowId), mBuffer(Move(aData)) { - mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects); - MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty()); - mClosure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers); + mClonedObjects.SwapElements(aClonedObjects); } NS_IMETHOD @@ -121,10 +118,8 @@ private: // Release reference to objects that were AddRef'd for // cloning into worker when array goes out of scope. - WorkerStructuredCloneClosure closure; - closure.mClonedObjects.SwapElements(mClosure.mClonedObjects); - MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty()); - closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers); + nsTArray> clonedObjects; + clonedObjects.SwapElements(mClonedObjects); JS::Rooted messageData(aCx); if (!mBuffer.read(aCx, &messageData, @@ -190,17 +185,16 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle aMessage, const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks(false); - WorkerStructuredCloneClosure closure; + nsTArray> clonedObjects; JSAutoStructuredCloneBuffer buffer; - if (!buffer.write(aCx, aMessage, transferable, callbacks, &closure)) { + if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } nsRefPtr runnable = - new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer), - closure); + new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer), clonedObjects); nsresult rv = NS_DispatchToMainThread(runnable); if (NS_FAILED(rv)) { aRv.Throw(NS_ERROR_FAILURE); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index a917d6eccc52..ac29fc04989c 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -52,8 +52,6 @@ #include "mozilla/dom/ImageDataBinding.h" #include "mozilla/dom/MessageEvent.h" #include "mozilla/dom/MessageEventBinding.h" -#include "mozilla/dom/MessagePort.h" -#include "mozilla/dom/MessagePortBinding.h" #include "mozilla/dom/MessagePortList.h" #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseDebugging.h" @@ -107,7 +105,6 @@ #include "WorkerFeature.h" #include "WorkerRunnable.h" #include "WorkerScope.h" -#include "WorkerStructuredClone.h" #include "WorkerThread.h" #ifdef XP_WIN @@ -514,7 +511,7 @@ bool WriteBlobOrFile(JSContext* aCx, JSStructuredCloneWriter* aWriter, BlobImpl* aBlobOrBlobImpl, - WorkerStructuredCloneClosure& aClosure) + nsTArray>& aClonedObjects) { MOZ_ASSERT(aCx); MOZ_ASSERT(aWriter); @@ -532,7 +529,7 @@ WriteBlobOrFile(JSContext* aCx, return false; } - aClosure.mClonedObjects.AppendElement(aBlobOrBlobImpl); + aClonedObjects.AppendElement(aBlobOrBlobImpl); return true; } @@ -550,7 +547,7 @@ bool WriteFormData(JSContext* aCx, JSStructuredCloneWriter* aWriter, nsFormData* aFormData, - WorkerStructuredCloneClosure& aClosure) + nsTArray>& aClonedObjects) { MOZ_ASSERT(aCx); MOZ_ASSERT(aWriter); @@ -563,11 +560,11 @@ WriteFormData(JSContext* aCx, class MOZ_STACK_CLASS Closure { JSContext* mCx; JSStructuredCloneWriter* mWriter; - WorkerStructuredCloneClosure& mClones; + nsTArray>& mClones; public: Closure(JSContext* aCx, JSStructuredCloneWriter* aWriter, - WorkerStructuredCloneClosure& aClones) + nsTArray>& aClones) : mCx(aCx), mWriter(aWriter), mClones(aClones) { } @@ -598,7 +595,7 @@ WriteFormData(JSContext* aCx, } }; - Closure closure(aCx, aWriter, aClosure); + Closure closure(aCx, aWriter, aClonedObjects); return aFormData->ForEach(Closure::Write, &closure); } @@ -642,7 +639,9 @@ struct WorkerStructuredCloneCallbacks { NS_ASSERTION(aClosure, "Null pointer!"); - auto* closure = static_cast(aClosure); + // We'll stash any nsISupports pointers that need to be AddRef'd here. + auto* clonedObjects = + static_cast>*>(aClosure); // See if this is a Blob/File object. { @@ -651,7 +650,7 @@ struct WorkerStructuredCloneCallbacks BlobImpl* blobImpl = blob->Impl(); MOZ_ASSERT(blobImpl); - if (WriteBlobOrFile(aCx, aWriter, blobImpl, *closure)) { + if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) { return true; } } @@ -669,7 +668,7 @@ struct WorkerStructuredCloneCallbacks { nsFormData* formData = nullptr; if (NS_SUCCEEDED(UNWRAP_OBJECT(FormData, aObj, formData))) { - if (WriteFormData(aCx, aWriter, formData, *closure)) { + if (WriteFormData(aCx, aWriter, formData, *clonedObjects)) { return true; } } @@ -684,96 +683,15 @@ struct WorkerStructuredCloneCallbacks { Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); } - - static bool - ReadTransfer(JSContext* aCx, JSStructuredCloneReader* aReader, - uint32_t aTag, void* aContent, uint64_t aExtraData, - void* aClosure, JS::MutableHandle aReturnObject) - { - MOZ_ASSERT(aClosure); - - auto* closure = static_cast(aClosure); - - if (aTag == SCTAG_DOM_MAP_MESSAGEPORT) { - MOZ_ASSERT(!aContent); - MOZ_ASSERT(aExtraData < closure->mMessagePortIdentifiers.Length()); - - ErrorResult rv; - nsRefPtr port = - dom::MessagePort::Create(closure->mParentWindow, - closure->mMessagePortIdentifiers[aExtraData], - rv); - - if (NS_WARN_IF(rv.Failed())) { - return false; - } - - closure->mMessagePorts.AppendElement(port); - - JS::Rooted value(aCx); - if (!GetOrCreateDOMReflector(aCx, port, &value)) { - JS_ClearPendingException(aCx); - return false; - } - - aReturnObject.set(&value.toObject()); - return true; - } - - return false; - } - - static bool - Transfer(JSContext* aCx, JS::Handle aObj, void* aClosure, - uint32_t* aTag, JS::TransferableOwnership* aOwnership, - void** aContent, uint64_t *aExtraData) - { - MOZ_ASSERT(aClosure); - - auto* closure = static_cast(aClosure); - - MessagePortBase* port; - nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port); - if (NS_SUCCEEDED(rv)) { - if (NS_WARN_IF(closure->mTransferredPorts.Contains(port))) { - // No duplicates. - return false; - } - - MessagePortIdentifier identifier; - if (!port->CloneAndDisentangle(identifier)) { - return false; - } - - closure->mMessagePortIdentifiers.AppendElement(identifier); - closure->mTransferredPorts.AppendElement(port); - - *aTag = SCTAG_DOM_MAP_MESSAGEPORT; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = nullptr; - *aExtraData = closure->mMessagePortIdentifiers.Length() - 1; - - return true; - } - - return false; - } - - static void - FreeTransfer(uint32_t aTag, JS::TransferableOwnership aOwnership, - void *aContent, uint64_t aExtraData, void* aClosure) - { - // Nothing to do. - } }; const JSStructuredCloneCallbacks gWorkerStructuredCloneCallbacks = { WorkerStructuredCloneCallbacks::Read, WorkerStructuredCloneCallbacks::Write, WorkerStructuredCloneCallbacks::Error, - WorkerStructuredCloneCallbacks::ReadTransfer, - WorkerStructuredCloneCallbacks::Transfer, - WorkerStructuredCloneCallbacks::FreeTransfer + nullptr, + nullptr, + nullptr }; struct MainThreadWorkerStructuredCloneCallbacks @@ -813,7 +731,9 @@ struct MainThreadWorkerStructuredCloneCallbacks NS_ASSERTION(aClosure, "Null pointer!"); - auto* closure = static_cast(aClosure); + // We'll stash any nsISupports pointers that need to be AddRef'd here. + auto* clonedObjects = + static_cast>*>(aClosure); // See if this is a Blob/File object. { @@ -824,7 +744,7 @@ struct MainThreadWorkerStructuredCloneCallbacks if (!blobImpl->MayBeClonedToOtherThreads()) { NS_WARNING("Not all the blob implementations can be sent between threads."); - } else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *closure)) { + } else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *clonedObjects)) { return true; } } @@ -847,9 +767,9 @@ const JSStructuredCloneCallbacks gMainThreadWorkerStructuredCloneCallbacks = { MainThreadWorkerStructuredCloneCallbacks::Read, MainThreadWorkerStructuredCloneCallbacks::Write, MainThreadWorkerStructuredCloneCallbacks::Error, - WorkerStructuredCloneCallbacks::ReadTransfer, - WorkerStructuredCloneCallbacks::Transfer, - WorkerStructuredCloneCallbacks::FreeTransfer + nullptr, + nullptr, + nullptr }; struct ChromeWorkerStructuredCloneCallbacks @@ -880,9 +800,9 @@ const JSStructuredCloneCallbacks gChromeWorkerStructuredCloneCallbacks = { ChromeWorkerStructuredCloneCallbacks::Read, ChromeWorkerStructuredCloneCallbacks::Write, ChromeWorkerStructuredCloneCallbacks::Error, - WorkerStructuredCloneCallbacks::ReadTransfer, - WorkerStructuredCloneCallbacks::Transfer, - WorkerStructuredCloneCallbacks::FreeTransfer + nullptr, + nullptr, + nullptr }; struct MainThreadChromeWorkerStructuredCloneCallbacks @@ -1233,7 +1153,7 @@ private: class MessageEventRunnable final : public WorkerRunnable { JSAutoStructuredCloneBuffer mBuffer; - WorkerStructuredCloneClosure mClosure; + nsTArray > mClonedObjects; uint64_t mMessagePortSerial; bool mToMessagePort; @@ -1243,24 +1163,15 @@ class MessageEventRunnable final : public WorkerRunnable public: MessageEventRunnable(WorkerPrivate* aWorkerPrivate, TargetAndBusyBehavior aBehavior, + JSAutoStructuredCloneBuffer&& aData, + nsTArray >& aClonedObjects, bool aToMessagePort, uint64_t aMessagePortSerial) : WorkerRunnable(aWorkerPrivate, aBehavior) + , mBuffer(Move(aData)) , mMessagePortSerial(aMessagePortSerial) , mToMessagePort(aToMessagePort) { - } - - bool - Write(JSContext* aCx, JS::Handle aValue, - JS::Handle aTransferredValue, - const JSStructuredCloneCallbacks *aCallbacks) - { - bool ok = mBuffer.write(aCx, aValue, aTransferredValue, aCallbacks, - &mClosure); - // This hashtable has to be empty because it could contain MessagePort - // objects that cannot be freed on a different thread. - mClosure.mTransferredPorts.Clear(); - return ok; + mClonedObjects.SwapElements(aClonedObjects); } void @@ -1275,19 +1186,12 @@ public: { // Release reference to objects that were AddRef'd for // cloning into worker when array goes out of scope. - WorkerStructuredCloneClosure closure; - closure.mClonedObjects.SwapElements(mClosure.mClonedObjects); - MOZ_ASSERT(mClosure.mMessagePorts.IsEmpty()); - closure.mMessagePortIdentifiers.SwapElements(mClosure.mMessagePortIdentifiers); - - if (aIsMainThread) { - closure.mParentWindow = do_QueryInterface(aTarget->GetParentObject()); - } + nsTArray> clonedObjects; + clonedObjects.SwapElements(mClonedObjects); JS::Rooted messageData(aCx); if (!mBuffer.read(aCx, &messageData, - workers::WorkerStructuredCloneCallbacks(aIsMainThread), - &closure)) { + workers::WorkerStructuredCloneCallbacks(aIsMainThread))) { xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); return false; } @@ -1313,8 +1217,7 @@ public: } event->SetTrusted(true); - event->SetPorts(new MessagePortList(static_cast(event.get()), - closure.mMessagePorts)); + nsCOMPtr domEvent = do_QueryObject(event); nsEventStatus dummy = nsEventStatus_eIgnore; @@ -1340,7 +1243,7 @@ private: aWorkerPrivate->DispatchMessageEventToMessagePort(aCx, mMessagePortSerial, Move(mBuffer), - mClosure); + mClonedObjects); } if (aWorkerPrivate->IsFrozen()) { @@ -3476,16 +3379,19 @@ WorkerPrivateParent::PostMessageInternal( transferable.setObject(*array); } - nsRefPtr runnable = - new MessageEventRunnable(ParentAsWorkerPrivate(), - WorkerRunnable::WorkerThreadModifyBusyCount, - aToMessagePort, aMessagePortSerial); + nsTArray> clonedObjects; - if (!runnable->Write(aCx, aMessage, transferable, callbacks)) { + JSAutoStructuredCloneBuffer buffer; + if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } + nsRefPtr runnable = + new MessageEventRunnable(ParentAsWorkerPrivate(), + WorkerRunnable::WorkerThreadModifyBusyCount, + Move(buffer), clonedObjects, aToMessagePort, + aMessagePortSerial); runnable->SetMessageSource(aClientInfo); if (!runnable->Dispatch(aCx)) { @@ -3526,16 +3432,14 @@ bool WorkerPrivateParent::DispatchMessageEventToMessagePort( JSContext* aCx, uint64_t aMessagePortSerial, JSAutoStructuredCloneBuffer&& aBuffer, - WorkerStructuredCloneClosure& aClosure) + nsTArray>& aClonedObjects) { AssertIsOnMainThread(); JSAutoStructuredCloneBuffer buffer(Move(aBuffer)); - WorkerStructuredCloneClosure closure; - closure.mClonedObjects.SwapElements(aClosure.mClonedObjects); - MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty()); - closure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers); + nsTArray> clonedObjects; + clonedObjects.SwapElements(aClonedObjects); SharedWorker* sharedWorker; if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) { @@ -3550,8 +3454,6 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( return true; } - closure.mParentWindow = do_QueryInterface(port->GetParentObject()); - AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) { return false; @@ -3559,8 +3461,7 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( JSContext* cx = jsapi.cx(); JS::Rooted data(cx); - if (!buffer.read(cx, &data, WorkerStructuredCloneCallbacks(true), - &closure)) { + if (!buffer.read(cx, &data, WorkerStructuredCloneCallbacks(true))) { return false; } @@ -3577,7 +3478,11 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( event->SetTrusted(true); - event->SetPorts(new MessagePortList(port, closure.mMessagePorts)); + nsTArray> ports; + ports.AppendElement(port); + + nsRefPtr portList = new MessagePortList(port, ports); + event->SetPorts(portList); nsCOMPtr domEvent; CallQueryInterface(event.get(), getter_AddRefs(domEvent)); @@ -6277,16 +6182,19 @@ WorkerPrivate::PostMessageToParentInternal( &gChromeWorkerStructuredCloneCallbacks : &gWorkerStructuredCloneCallbacks; - nsRefPtr runnable = - new MessageEventRunnable(this, - WorkerRunnable::ParentThreadUnchangedBusyCount, - aToMessagePort, aMessagePortSerial); + nsTArray> clonedObjects; - if (!runnable->Write(aCx, aMessage, transferable, callbacks)) { + JSAutoStructuredCloneBuffer buffer; + if (!buffer.write(aCx, aMessage, transferable, callbacks, &clonedObjects)) { aRv = NS_ERROR_DOM_DATA_CLONE_ERR; return; } + nsRefPtr runnable = + new MessageEventRunnable(this, + WorkerRunnable::ParentThreadUnchangedBusyCount, + Move(buffer), clonedObjects, aToMessagePort, + aMessagePortSerial); if (!runnable->Dispatch(aCx)) { aRv = NS_ERROR_FAILURE; } @@ -7440,20 +7348,4 @@ ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime) // Force instantiation. template class WorkerPrivateParent; -WorkerStructuredCloneClosure::WorkerStructuredCloneClosure() -{} - -WorkerStructuredCloneClosure::~WorkerStructuredCloneClosure() -{} - -void -WorkerStructuredCloneClosure::Clear() -{ - mParentWindow = nullptr; - mClonedObjects.Clear(); - mMessagePorts.Clear(); - mMessagePortIdentifiers.Clear(); - mTransferredPorts.Clear(); -} - END_WORKERS_NAMESPACE diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 976c05813918..ef04c31ba4e1 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -73,7 +73,6 @@ class WorkerDebuggerGlobalScope; class WorkerGlobalScope; class WorkerPrivate; class WorkerRunnable; -class WorkerStructuredCloneClosure; class WorkerThread; // SharedMutex is a small wrapper around an (internal) reference-counted Mutex @@ -350,7 +349,7 @@ public: JSContext* aCx, uint64_t aMessagePortSerial, JSAutoStructuredCloneBuffer&& aBuffer, - WorkerStructuredCloneClosure& aClosure); + nsTArray>& aClonedObjects); void UpdateRuntimeOptions(JSContext* aCx, diff --git a/dom/workers/WorkerStructuredClone.h b/dom/workers/WorkerStructuredClone.h deleted file mode 100644 index 85b7ab3f7f5f..000000000000 --- a/dom/workers/WorkerStructuredClone.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* 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/. */ - -#ifndef mozilla_dom_workers_WorkerStructuredClone_h -#define mozilla_dom_workers_WorkerStructuredClone_h - -#include "Workers.h" -#include "mozilla/dom/PMessagePort.h" - -class nsPIDOMWindow; - -namespace mozilla { -namespace dom { - -class MessagePortBase; - -namespace workers { - -// This class is implemented in WorkerPrivate.cpp -class WorkerStructuredCloneClosure final -{ -private: - WorkerStructuredCloneClosure(const WorkerStructuredCloneClosure&) = delete; - WorkerStructuredCloneClosure & operator=(const WorkerStructuredCloneClosure&) = delete; - -public: - WorkerStructuredCloneClosure(); - ~WorkerStructuredCloneClosure(); - - void Clear(); - - // This can be null if the MessagePort is created in a worker. - nsCOMPtr mParentWindow; - - nsTArray> mClonedObjects; - - // The transferred ports. - nsTArray> mMessagePorts; - - // Information for the transferring. - nsTArray mMessagePortIdentifiers; - - // To avoid duplicates in the transferred ports. - nsTArray> mTransferredPorts; -}; - -} // workers namespace -} // dom namespace -} // mozilla namespace - -#endif // mozilla_dom_workers_WorkerStructuredClone_h diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 6b61e824fe99..03479c0c51d6 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -27,7 +27,6 @@ #include "RuntimeService.h" #include "WorkerPrivate.h" #include "WorkerRunnable.h" -#include "WorkerStructuredClone.h" #include "XMLHttpRequestUpload.h" using namespace mozilla; @@ -414,7 +413,7 @@ class EventRunnable final : public MainThreadProxyRunnable nsString mType; nsString mResponseType; JSAutoStructuredCloneBuffer mResponseBuffer; - WorkerStructuredCloneClosure mResponseClosure; + nsTArray > mClonedObjects; JS::Heap mResponse; nsString mResponseText; nsString mResponseURL; @@ -795,14 +794,14 @@ class SendRunnable final : public WorkerThreadProxySyncRunnable { nsString mStringBody; JSAutoStructuredCloneBuffer mBody; - WorkerStructuredCloneClosure mClosure; + nsTArray > mClonedObjects; nsCOMPtr mSyncLoopTarget; bool mHasUploadListeners; public: SendRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy, const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody, - WorkerStructuredCloneClosure& aClosure, + nsTArray>& aClonedObjects, nsIEventTarget* aSyncLoopTarget, bool aHasUploadListeners) : WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy) , mStringBody(aStringBody) @@ -810,9 +809,7 @@ public: , mSyncLoopTarget(aSyncLoopTarget) , mHasUploadListeners(aHasUploadListeners) { - mClosure.mClonedObjects.SwapElements(aClosure.mClonedObjects); - MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty()); - MOZ_ASSERT(aClosure.mMessagePortIdentifiers.IsEmpty()); + mClonedObjects.SwapElements(aClonedObjects); } private: @@ -1232,13 +1229,11 @@ EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) workers::ChromeWorkerStructuredCloneCallbacks(true) : workers::WorkerStructuredCloneCallbacks(true); - WorkerStructuredCloneClosure closure; + nsTArray > clonedObjects; if (mResponseBuffer.write(aCx, response, transferable, callbacks, - &closure)) { - mResponseClosure.mClonedObjects.SwapElements(closure.mClonedObjects); - MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty()); - MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty()); + &clonedObjects)) { + mClonedObjects.SwapElements(clonedObjects); } else { NS_WARNING("Failed to clone response!"); mResponseResult = NS_ERROR_DOM_DATA_CLONE_ERR; @@ -1346,13 +1341,11 @@ EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) workers::ChromeWorkerStructuredCloneCallbacks(false) : workers::WorkerStructuredCloneCallbacks(false); - WorkerStructuredCloneClosure closure; - closure.mClonedObjects.SwapElements(mResponseClosure.mClonedObjects); - MOZ_ASSERT(mResponseClosure.mMessagePorts.IsEmpty()); - MOZ_ASSERT(mResponseClosure.mMessagePortIdentifiers.IsEmpty()); + nsTArray > clonedObjects; + clonedObjects.SwapElements(mClonedObjects); JS::Rooted response(aCx); - if (!responseBuffer.read(aCx, &response, callbacks, &closure)) { + if (!responseBuffer.read(aCx, &response, callbacks, &clonedObjects)) { return false; } @@ -1533,7 +1526,7 @@ SendRunnable::MainThreadRun() workers::WorkerStructuredCloneCallbacks(true); JS::Rooted body(cx); - if (mBody.read(cx, &body, callbacks, &mClosure)) { + if (mBody.read(cx, &body, callbacks, &mClonedObjects)) { if (NS_FAILED(xpc->JSValToVariant(cx, body, getter_AddRefs(variant)))) { rv = NS_ERROR_DOM_INVALID_STATE_ERR; } @@ -1543,7 +1536,7 @@ SendRunnable::MainThreadRun() } mBody.clear(); - mClosure.Clear(); + mClonedObjects.Clear(); NS_ENSURE_SUCCESS(rv, rv); } @@ -1853,7 +1846,7 @@ XMLHttpRequest::Unpin() void XMLHttpRequest::SendInternal(const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody, - WorkerStructuredCloneClosure& aClosure, + nsTArray >& aClonedObjects, ErrorResult& aRv) { mWorkerPrivate->AssertIsOnWorkerThread(); @@ -1887,7 +1880,7 @@ XMLHttpRequest::SendInternal(const nsAString& aStringBody, nsRefPtr runnable = new SendRunnable(mWorkerPrivate, mProxy, aStringBody, Move(aBody), - aClosure, syncLoopTarget, hasUploadListeners); + aClonedObjects, syncLoopTarget, hasUploadListeners); if (!runnable->Dispatch(cx)) { // Dispatch() may have spun the event loop and we may have already unrooted. // If so we don't want autoUnpin to try again. @@ -2109,9 +2102,9 @@ XMLHttpRequest::Send(ErrorResult& aRv) // Nothing to clone. JSAutoStructuredCloneBuffer buffer; - WorkerStructuredCloneClosure closure; + nsTArray > clonedObjects; - SendInternal(NullString(), Move(buffer), closure, aRv); + SendInternal(NullString(), Move(buffer), clonedObjects, aRv); } void @@ -2131,9 +2124,9 @@ XMLHttpRequest::Send(const nsAString& aBody, ErrorResult& aRv) // Nothing to clone. JSAutoStructuredCloneBuffer buffer; - WorkerStructuredCloneClosure closure; + nsTArray > clonedObjects; - SendInternal(aBody, Move(buffer), closure, aRv); + SendInternal(aBody, Move(buffer), clonedObjects, aRv); } void @@ -2174,15 +2167,15 @@ XMLHttpRequest::Send(JS::Handle aBody, ErrorResult& aRv) ChromeWorkerStructuredCloneCallbacks(false) : WorkerStructuredCloneCallbacks(false); - WorkerStructuredCloneClosure closure; + nsTArray > clonedObjects; JSAutoStructuredCloneBuffer buffer; - if (!buffer.write(cx, valToClone, callbacks, &closure)) { + if (!buffer.write(cx, valToClone, callbacks, &clonedObjects)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } - SendInternal(EmptyString(), Move(buffer), closure, aRv); + SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv); } void @@ -2220,15 +2213,15 @@ XMLHttpRequest::Send(Blob& aBody, ErrorResult& aRv) ChromeWorkerStructuredCloneCallbacks(false) : WorkerStructuredCloneCallbacks(false); - WorkerStructuredCloneClosure closure; + nsTArray > clonedObjects; JSAutoStructuredCloneBuffer buffer; - if (!buffer.write(cx, value, callbacks, &closure)) { + if (!buffer.write(cx, value, callbacks, &clonedObjects)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } - SendInternal(EmptyString(), Move(buffer), closure, aRv); + SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv); } void @@ -2258,14 +2251,15 @@ XMLHttpRequest::Send(nsFormData& aBody, ErrorResult& aRv) ChromeWorkerStructuredCloneCallbacks(false) : WorkerStructuredCloneCallbacks(false); + nsTArray> clonedObjects; + JSAutoStructuredCloneBuffer buffer; - WorkerStructuredCloneClosure closure; - if (!buffer.write(cx, value, callbacks, &closure)) { + if (!buffer.write(cx, value, callbacks, &clonedObjects)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } - SendInternal(EmptyString(), Move(buffer), closure, aRv); + SendInternal(EmptyString(), Move(buffer), clonedObjects, aRv); } void diff --git a/dom/workers/XMLHttpRequest.h b/dom/workers/XMLHttpRequest.h index a3c4d14b0d68..9475d9ad3308 100644 --- a/dom/workers/XMLHttpRequest.h +++ b/dom/workers/XMLHttpRequest.h @@ -28,7 +28,6 @@ BEGIN_WORKERS_NAMESPACE class Proxy; class XMLHttpRequestUpload; class WorkerPrivate; -class WorkerStructuredCloneClosure; class XMLHttpRequest final: public nsXHREventTarget, public WorkerFeature @@ -293,7 +292,7 @@ private: void SendInternal(const nsAString& aStringBody, JSAutoStructuredCloneBuffer&& aBody, - WorkerStructuredCloneClosure& aClosure, + nsTArray >& aClonedObjects, ErrorResult& aRv); }; diff --git a/dom/workers/test/sharedWorker_sharedWorker.js b/dom/workers/test/sharedWorker_sharedWorker.js index 6c917036b392..4df59861658d 100644 --- a/dom/workers/test/sharedWorker_sharedWorker.js +++ b/dom/workers/test/sharedWorker_sharedWorker.js @@ -79,8 +79,8 @@ onconnect = function(event) { if (!("ports" in event)) { throw new Error("'message' event doesn't have a 'ports' property!"); } - if (event.ports === null) { - throw new Error("'message' event has a null 'ports' property!"); + if (!(event.ports === null)) { + throw new Error("'message' event has a non-null 'ports' property!"); } event.target.postMessage(event.data); throw new Error(event.data); diff --git a/ipc/glue/BackgroundChild.h b/ipc/glue/BackgroundChild.h index 2b572266246d..5f3c3274b619 100644 --- a/ipc/glue/BackgroundChild.h +++ b/ipc/glue/BackgroundChild.h @@ -15,7 +15,6 @@ class nsIIPCBackgroundChildCreateCallback; namespace mozilla { namespace dom { -class BlobImpl; class ContentChild; class ContentParent; class PBlobChild; @@ -68,10 +67,6 @@ public: GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor, nsIDOMBlob* aBlob); - static mozilla::dom::PBlobChild* - GetOrCreateActorForBlobImpl(PBackgroundChild* aBackgroundActor, - mozilla::dom::BlobImpl* aBlobImpl); - // See above. static void CloseForCurrentThread(); diff --git a/ipc/glue/BackgroundChildImpl.cpp b/ipc/glue/BackgroundChildImpl.cpp index a806692a27fe..68411a91612b 100644 --- a/ipc/glue/BackgroundChildImpl.cpp +++ b/ipc/glue/BackgroundChildImpl.cpp @@ -14,7 +14,6 @@ #include "mozilla/dom/cache/ActorUtils.h" #include "mozilla/dom/indexedDB/PBackgroundIDBFactoryChild.h" #include "mozilla/dom/ipc/BlobChild.h" -#include "mozilla/dom/MessagePortChild.h" #include "mozilla/ipc/PBackgroundTestChild.h" #include "mozilla/layout/VsyncChild.h" #include "mozilla/net/PUDPSocketChild.h" @@ -341,28 +340,6 @@ BackgroundChildImpl::DeallocPMediaChild(media::PMediaChild *aActor) return media::DeallocPMediaChild(aActor); } -// ----------------------------------------------------------------------------- -// MessageChannel/MessagePort API -// ----------------------------------------------------------------------------- - -dom::PMessagePortChild* -BackgroundChildImpl::AllocPMessagePortChild(const nsID& aUUID, - const nsID& aDestinationUUID, - const uint32_t& aSequenceID) -{ - nsRefPtr agent = new dom::MessagePortChild(); - return agent.forget().take(); -} - -bool -BackgroundChildImpl::DeallocPMessagePortChild(PMessagePortChild* aActor) -{ - nsRefPtr child = - dont_AddRef(static_cast(aActor)); - MOZ_ASSERT(child); - return true; -} - } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/BackgroundChildImpl.h b/ipc/glue/BackgroundChildImpl.h index c40db905a7c5..9c2e011ed55e 100644 --- a/ipc/glue/BackgroundChildImpl.h +++ b/ipc/glue/BackgroundChildImpl.h @@ -121,13 +121,6 @@ protected: virtual bool DeallocPCacheStreamControlChild(dom::cache::PCacheStreamControlChild* aActor) override; - - virtual PMessagePortChild* - AllocPMessagePortChild(const nsID& aUUID, const nsID& aDestinationUUID, - const uint32_t& aSequenceID) override; - - virtual bool - DeallocPMessagePortChild(PMessagePortChild* aActor) override; }; class BackgroundChildImpl::ThreadLocal final diff --git a/ipc/glue/BackgroundImpl.cpp b/ipc/glue/BackgroundImpl.cpp index 10db43258268..bbe6b8d3968e 100644 --- a/ipc/glue/BackgroundImpl.cpp +++ b/ipc/glue/BackgroundImpl.cpp @@ -913,28 +913,18 @@ BackgroundChild::GetOrCreateForCurrentThread( PBlobChild* BackgroundChild::GetOrCreateActorForBlob(PBackgroundChild* aBackgroundActor, nsIDOMBlob* aBlob) -{ - MOZ_ASSERT(aBlob); - - nsRefPtr blobImpl = static_cast(aBlob)->Impl(); - MOZ_ASSERT(blobImpl); - - return GetOrCreateActorForBlobImpl(aBackgroundActor, blobImpl); -} - -// static -PBlobChild* -BackgroundChild::GetOrCreateActorForBlobImpl(PBackgroundChild* aBackgroundActor, - BlobImpl* aBlobImpl) { MOZ_ASSERT(aBackgroundActor); - MOZ_ASSERT(aBlobImpl); + MOZ_ASSERT(aBlob); MOZ_ASSERT(GetForCurrentThread(), "BackgroundChild not created on this thread yet!"); MOZ_ASSERT(aBackgroundActor == GetForCurrentThread(), "BackgroundChild is bound to a different thread!"); - BlobChild* actor = BlobChild::GetOrCreate(aBackgroundActor, aBlobImpl); + nsRefPtr blobImpl = static_cast(aBlob)->Impl(); + MOZ_ASSERT(blobImpl); + + BlobChild* actor = BlobChild::GetOrCreate(aBackgroundActor, blobImpl); if (NS_WARN_IF(!actor)) { return nullptr; } diff --git a/ipc/glue/BackgroundParentImpl.cpp b/ipc/glue/BackgroundParentImpl.cpp index e1b6849d9439..b5da95cc0931 100644 --- a/ipc/glue/BackgroundParentImpl.cpp +++ b/ipc/glue/BackgroundParentImpl.cpp @@ -11,7 +11,6 @@ #include "mozilla/Assertions.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/PBlobParent.h" -#include "mozilla/dom/MessagePortParent.h" #include "mozilla/dom/ServiceWorkerRegistrar.h" #include "mozilla/dom/cache/ActorUtils.h" #include "mozilla/dom/indexedDB/ActorsParent.h" @@ -40,8 +39,6 @@ using mozilla::ipc::AssertIsOnBackgroundThread; using mozilla::dom::cache::PCacheParent; using mozilla::dom::cache::PCacheStorageParent; using mozilla::dom::cache::PCacheStreamControlParent; -using mozilla::dom::MessagePortParent; -using mozilla::dom::PMessagePortParent; using mozilla::dom::UDPSocketParent; namespace { @@ -566,41 +563,6 @@ BackgroundParentImpl::DeallocPCacheStreamControlParent(PCacheStreamControlParent return true; } -PMessagePortParent* -BackgroundParentImpl::AllocPMessagePortParent(const nsID& aUUID, - const nsID& aDestinationUUID, - const uint32_t& aSequenceID) -{ - AssertIsInMainProcess(); - AssertIsOnBackgroundThread(); - - return new MessagePortParent(aUUID); -} - -bool -BackgroundParentImpl::RecvPMessagePortConstructor(PMessagePortParent* aActor, - const nsID& aUUID, - const nsID& aDestinationUUID, - const uint32_t& aSequenceID) -{ - AssertIsInMainProcess(); - AssertIsOnBackgroundThread(); - - MessagePortParent* mp = static_cast(aActor); - return mp->Entangle(aDestinationUUID, aSequenceID); -} - -bool -BackgroundParentImpl::DeallocPMessagePortParent(PMessagePortParent* aActor) -{ - AssertIsInMainProcess(); - AssertIsOnBackgroundThread(); - MOZ_ASSERT(aActor); - - delete static_cast(aActor); - return true; -} - } // namespace ipc } // namespace mozilla diff --git a/ipc/glue/BackgroundParentImpl.h b/ipc/glue/BackgroundParentImpl.h index b2ad232076ae..5c27512f25d8 100644 --- a/ipc/glue/BackgroundParentImpl.h +++ b/ipc/glue/BackgroundParentImpl.h @@ -129,20 +129,6 @@ protected: const nsCString& aFilter) override; virtual bool DeallocPUDPSocketParent(PUDPSocketParent*) override; - - virtual PMessagePortParent* - AllocPMessagePortParent(const nsID& aUUID, - const nsID& aDestinationUUID, - const uint32_t& aSequenceID) override; - - virtual bool - RecvPMessagePortConstructor(PMessagePortParent* aActor, - const nsID& aUUID, - const nsID& aDestinationUUID, - const uint32_t& aSequenceID) override; - - virtual bool - DeallocPMessagePortParent(PMessagePortParent* aActor) override; }; } // namespace ipc diff --git a/ipc/glue/PBackground.ipdl b/ipc/glue/PBackground.ipdl index cd3e8f2b2de4..084fe99878ac 100644 --- a/ipc/glue/PBackground.ipdl +++ b/ipc/glue/PBackground.ipdl @@ -10,7 +10,6 @@ include protocol PCache; include protocol PCacheStorage; include protocol PCacheStreamControl; include protocol PFileDescriptorSet; -include protocol PMessagePort; include protocol PMedia; include protocol PServiceWorkerManager; include protocol PUDPSocket; @@ -36,7 +35,6 @@ sync protocol PBackground manages PCacheStorage; manages PCacheStreamControl; manages PFileDescriptorSet; - manages PMessagePort; manages PMedia; manages PServiceWorkerManager; manages PUDPSocket; @@ -61,8 +59,6 @@ parent: PCacheStorage(Namespace aNamespace, PrincipalInfo aPrincipalInfo); - PMessagePort(nsID uuid, nsID destinationUuid, uint32_t sequenceId); - child: PCache(); PCacheStreamControl(); diff --git a/js/public/StructuredClone.h b/js/public/StructuredClone.h index 967eefdaf5af..50a7913d5ec4 100644 --- a/js/public/StructuredClone.h +++ b/js/public/StructuredClone.h @@ -148,7 +148,7 @@ JS_WriteStructuredClone(JSContext* cx, JS::HandleValue v, uint64_t** datap, size JS_PUBLIC_API(bool) JS_ClearStructuredClone(uint64_t* data, size_t nbytes, const JSStructuredCloneCallbacks* optionalCallbacks, - void *closure, bool freeData = true); + void* closure); JS_PUBLIC_API(bool) JS_StructuredCloneHasTransferables(const uint64_t* data, size_t nbytes, bool* hasTransferable); diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index fd12bf266106..ab17cfe40309 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -1908,12 +1908,10 @@ JS_WriteStructuredClone(JSContext* cx, HandleValue value, uint64_t** bufp, size_ JS_PUBLIC_API(bool) JS_ClearStructuredClone(uint64_t* data, size_t nbytes, const JSStructuredCloneCallbacks* optionalCallbacks, - void* closure, bool freeData) + void* closure) { DiscardTransferables(data, nbytes, optionalCallbacks, closure); - if (freeData) { - js_free(data); - } + js_free(data); return true; } diff --git a/testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html.ini b/testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html.ini new file mode 100644 index 000000000000..6dfbdc124e0e --- /dev/null +++ b/testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/event-ports-dedicated.html.ini @@ -0,0 +1,5 @@ +[event-ports-dedicated.html] + type: testharness + [e.ports in dedicated worker] + expected: FAIL +