From a2776c2e6fc55c37bceada296b86b28b0bcaadb9 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 24 Sep 2015 22:29:30 -0400 Subject: [PATCH 001/247] Bug 1208275 - Don't run make check on Linux64 debug static analysis builds; r=ted These checks are pointless. --HG-- extra : rebase_source : e7eac9470413b634401aef3770ee8937cbda4769 --- .../configs/builds/releng_sub_linux_configs/64_stat_and_debug.py | 1 - 1 file changed, 1 deletion(-) diff --git a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py index 94032575e152..9c5a1d0d73cd 100644 --- a/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py +++ b/testing/mozharness/configs/builds/releng_sub_linux_configs/64_stat_and_debug.py @@ -11,7 +11,6 @@ config = { 'build', 'upload-files', 'sendchange', - 'check-test', # 'generate-build-stats', 'update', # decided by query_is_nightly() ], From 143e9256c41708c9bb6affeddebe571fb4a38808 Mon Sep 17 00:00:00 2001 From: Andreas Pehrson Date: Fri, 25 Sep 2015 13:55:29 +0800 Subject: [PATCH 002/247] Bug 1192170 - Remove media capture indicator when all tracks have ended. r=jib --HG-- extra : commitid : 7nO1zyYTfLV extra : rebase_source : 4761874ce4d5bb2d5675d3fa8e235cb491348919 --- dom/media/MediaManager.cpp | 6 ++++-- dom/media/MediaManager.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index aa6fd9a28501..238b410e4f4a 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -314,8 +314,10 @@ public: mVideoDevice->GetSource()->Stop(source, kVideoTrack); mVideoDevice->GetSource()->Deallocate(); } - // Do this after stopping all tracks with EndTrack() - if (mBool) { + // We consider ourselves finished if all tracks have been stopped, as + // there is no way to restart them from the JS APIs. + if (mBool || ((!mAudioDevice || mAudioDevice->GetSource()->IsAvailable()) && + (!mVideoDevice || mVideoDevice->GetSource()->IsAvailable()))) { source->Finish(); } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index b87a15191885..9c2abb5be3bb 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -180,6 +180,7 @@ public: { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); return mVideoDevice && !mStopped && + !mVideoDevice->GetSource()->IsAvailable() && mVideoDevice->GetMediaSource() == dom::MediaSourceEnum::Camera && (!mVideoDevice->GetSource()->IsFake() || Preferences::GetBool("media.navigator.permission.fake")); @@ -188,6 +189,7 @@ public: { NS_ASSERTION(NS_IsMainThread(), "Only call on main thread"); return mAudioDevice && !mStopped && + !mAudioDevice->GetSource()->IsAvailable() && (!mAudioDevice->GetSource()->IsFake() || Preferences::GetBool("media.navigator.permission.fake")); } From 7b18991e85b800838f30f9a2be5e99a55fc5a16c Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 22 Sep 2015 16:13:16 -0400 Subject: [PATCH 003/247] Bug 890284 - Stop splitting textnodes in the XML content sink. r=peterv --HG-- extra : rebase_source : 0fc6b95d2cc4c00dee4a5adacb709c0ae024f587 --- dom/xml/nsXMLContentSink.cpp | 80 +++++++++++------------------------- dom/xml/nsXMLContentSink.h | 2 - 2 files changed, 24 insertions(+), 58 deletions(-) diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp index e325f8f6faa1..2562fe84416f 100644 --- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -96,8 +96,7 @@ NS_NewXMLContentSink(nsIXMLContentSink** aResult, } nsXMLContentSink::nsXMLContentSink() - : mConstrainSize(true), - mPrettyPrintXML(true) + : mPrettyPrintXML(true) { } @@ -475,7 +474,6 @@ nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount, nsCOMPtr sele = do_QueryInterface(content); sele->SetScriptLineNumber(aLineNumber); sele->SetCreatorParser(GetParser()); - mConstrainSize = false; } // XHTML needs some special attention @@ -552,7 +550,6 @@ nsXMLContentSink::CloseElement(nsIContent* aContent) if (nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML) || nodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG) ) { - mConstrainSize = true; nsCOMPtr sele = do_QueryInterface(aContent); if (mPreventScriptExecution) { @@ -778,26 +775,19 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode) if (mTextLength != 0) { if (mLastTextNode) { - if ((mLastTextNodeSize + mTextLength) > mTextSize && !mXSLTProcessor) { - mLastTextNodeSize = 0; - mLastTextNode = nullptr; - FlushText(aReleaseTextNode); - } else { - bool notify = HaveNotifiedForCurrentContent(); - // We could probably always increase mInNotification here since - // if AppendText doesn't notify it shouldn't trigger evil code. - // But just in case it does, we don't want to mask any notifications. - if (notify) { - ++mInNotification; - } - rv = mLastTextNode->AppendText(mText, mTextLength, notify); - if (notify) { - --mInNotification; - } - - mLastTextNodeSize += mTextLength; - mTextLength = 0; + bool notify = HaveNotifiedForCurrentContent(); + // We could probably always increase mInNotification here since + // if AppendText doesn't notify it shouldn't trigger evil code. + // But just in case it does, we don't want to mask any notifications. + if (notify) { + ++mInNotification; } + rv = mLastTextNode->AppendText(mText, mTextLength, notify); + if (notify) { + --mInNotification; + } + + mTextLength = 0; } else { nsRefPtr textContent = new nsTextNode(mNodeInfoManager); @@ -805,7 +795,6 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode) // Set the text in the text node textContent->SetText(mText, mTextLength, false); - mLastTextNodeSize += mTextLength; mTextLength = 0; // Add text to its parent @@ -814,7 +803,6 @@ nsXMLContentSink::FlushText(bool aReleaseTextNode) } if (aReleaseTextNode) { - mLastTextNodeSize = 0; mLastTextNode = nullptr; } @@ -1446,40 +1434,20 @@ nsXMLContentSink::AddText(const char16_t* aText, mTextSize = NS_ACCUMULATION_BUFFER_SIZE; } - // Copy data from string into our buffer; flush buffer when it fills up - int32_t offset = 0; - while (0 != aLength) { - int32_t amount = mTextSize - mTextLength; - if (0 == amount) { - // XSLT wants adjacent textnodes merged. - if (mConstrainSize && !mXSLTProcessor) { - nsresult rv = FlushText(); - if (NS_OK != rv) { - return rv; - } + // Copy data from string into our buffer, resizing the buffer if + // it's not big enough. + int32_t availableSpace = mTextSize - mTextLength; + if (availableSpace < aLength) { + mTextSize = mTextLength + aLength; + mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize); + if (nullptr == mText) { + mTextSize = 0; - amount = mTextSize - mTextLength; - } - else { - mTextSize += aLength; - mText = (char16_t *) PR_REALLOC(mText, sizeof(char16_t) * mTextSize); - if (nullptr == mText) { - mTextSize = 0; - - return NS_ERROR_OUT_OF_MEMORY; - } - - amount = aLength; - } + return NS_ERROR_OUT_OF_MEMORY; } - if (amount > aLength) { - amount = aLength; - } - memcpy(&mText[mTextLength], &aText[offset], sizeof(char16_t) * amount); - mTextLength += amount; - offset += amount; - aLength -= amount; } + memcpy(&mText[mTextLength], aText, sizeof(char16_t) * aLength); + mTextLength += aLength; return NS_OK; } diff --git a/dom/xml/nsXMLContentSink.h b/dom/xml/nsXMLContentSink.h index 7ec23dba21d2..f39f00395919 100644 --- a/dom/xml/nsXMLContentSink.h +++ b/dom/xml/nsXMLContentSink.h @@ -180,9 +180,7 @@ protected: int32_t mNotifyLevel; nsCOMPtr mLastTextNode; - int32_t mLastTextNodeSize; - uint8_t mConstrainSize : 1; uint8_t mPrettyPrintXML : 1; uint8_t mPrettyPrintHasSpecialRoot : 1; uint8_t mPrettyPrintHasFactoredElements : 1; From 4b0532f4dbac46774db50cb07bcfd309fa53290f Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Thu, 24 Sep 2015 16:52:11 +0100 Subject: [PATCH 004/247] Bug 1182112 - XML documents should not be intercepted by ServiceWorkers. r=ehsan --HG-- extra : rebase_source : cf85ffcbdcc4681013525eaaeaeb5993e5f91b70 --- dom/xslt/base/txURIUtils.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dom/xslt/base/txURIUtils.cpp b/dom/xslt/base/txURIUtils.cpp index b2a78db2e47d..27c94a5c18a4 100644 --- a/dom/xslt/base/txURIUtils.cpp +++ b/dom/xslt/base/txURIUtils.cpp @@ -6,6 +6,7 @@ #include "txURIUtils.h" #include "nsNetUtil.h" #include "nsIDocument.h" +#include "nsIHttpChannelInternal.h" #include "nsIPrincipal.h" #include "mozilla/LoadInfo.h" @@ -69,7 +70,13 @@ URIUtils::ResetWithSource(nsIDocument *aNewDoc, nsIDOMNode *aSourceNode) if (NS_FAILED(rv)) { return; } + + nsCOMPtr internalChannel = do_QueryInterface(channel); + if (internalChannel) { + internalChannel->ForceNoIntercept(); + } } + aNewDoc->Reset(channel, loadGroup); aNewDoc->SetPrincipal(sourcePrincipal); aNewDoc->SetBaseURI(sourceDoc->GetDocBaseURI()); From 65998031aea0a5730600bb99dbe16153e16cb7cd Mon Sep 17 00:00:00 2001 From: Garvan Keeley Date: Fri, 25 Sep 2015 06:20:36 +0200 Subject: [PATCH 005/247] Bug 1197211 - Switch to MLS: change geo.wifi.uri and use corelocation always. r=hannosch --HG-- extra : rebase_source : 3569539d7dc2b7a0df22d1abf2cda8f2afd66b5b --- browser/app/profile/firefox.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 245b4ec90d55..673f9716d79f 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1759,19 +1759,11 @@ pref("plain_text.wrap_long_lines", true); pref("dom.debug.propagate_gesture_events_through_content", false); // The request URL of the GeoLocation backend. -#ifdef RELEASE_BUILD -pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%GOOGLE_API_KEY%"); -#else pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%"); -#endif #ifdef XP_MACOSX -#ifdef RELEASE_BUILD -pref("geo.provider.use_corelocation", false); -#else pref("geo.provider.use_corelocation", true); #endif -#endif #ifdef XP_WIN pref("geo.provider.ms-windows-location", false); From a4526020844d04740a1d123d6896c01f7c648c97 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 23 Sep 2015 14:40:18 -0400 Subject: [PATCH 006/247] Bug 1202696 - check surface status in _cairo_surface_get_extents. r=jmuizelaar --HG-- extra : rebase_source : bf9bf49cf9829370ab20567f10ce4c20fa5c9fca --- gfx/cairo/cairo/src/cairo-surface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gfx/cairo/cairo/src/cairo-surface.c b/gfx/cairo/cairo/src/cairo-surface.c index 54b7363e05db..92dfd7fe2822 100644 --- a/gfx/cairo/cairo/src/cairo-surface.c +++ b/gfx/cairo/cairo/src/cairo-surface.c @@ -2569,7 +2569,7 @@ _cairo_surface_get_extents (cairo_surface_t *surface, cairo_bool_t bounded; bounded = FALSE; - if (surface->backend->get_extents != NULL) + if (! surface->status && surface->backend->get_extents != NULL) bounded = surface->backend->get_extents (surface, extents); if (! bounded) From 72895c72ddbde43ed3b0af10ed66241ec15d3d54 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Tue, 22 Sep 2015 21:19:49 -0400 Subject: [PATCH 007/247] Bug 1203973 - Move + + +
+
+
+
+
+
+
+
+ + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index e2bfc3869aa3..1fa6194f99ff 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1935,3 +1935,4 @@ fuzzy(1,74) fuzzy-if(gtkWidget,6,79) == 1174332-1.html 1174332-1-ref.html == 1190635-1.html 1190635-1-ref.html == 1202512-1.html 1202512-1-ref.html == 1202512-2.html 1202512-2-ref.html +!= 1207326-1.html about:blank From a10a39f8914090d79b322ea86da1ce2776ca7c23 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Thu, 20 Aug 2015 10:35:22 -0700 Subject: [PATCH 128/247] Bug 1196847 - Part 1: Allow storage of a unique id for a cell independent of address; r=jonco * * * imported patch rewrite_uid_on_ht_with_zone_sweeping --HG-- extra : rebase_source : e0d01c24e9ea7cdb9660f5cac3b65699eb091cfd --- js/public/HashTable.h | 9 +- js/public/HeapAPI.h | 3 +- js/src/ds/LockGuard.h | 38 ++++++++ js/src/ds/SpinLock.h | 40 +++++++++ js/src/gc/GCRuntime.h | 8 ++ js/src/gc/Heap.h | 36 ++++++-- js/src/gc/Marking.cpp | 6 ++ js/src/gc/Marking.h | 2 +- js/src/gc/Nursery.cpp | 19 +++- js/src/gc/Nursery.h | 29 ++++++- js/src/gc/Zone.cpp | 12 ++- js/src/gc/Zone.h | 79 +++++++++++++++++ js/src/jsapi-tests/moz.build | 1 + js/src/jsapi-tests/testGCUniqueId.cpp | 120 ++++++++++++++++++++++++++ js/src/jsgc.cpp | 47 +++++++++- js/src/jsobjinlines.h | 1 + 16 files changed, 422 insertions(+), 28 deletions(-) create mode 100644 js/src/ds/LockGuard.h create mode 100644 js/src/ds/SpinLock.h create mode 100644 js/src/jsapi-tests/testGCUniqueId.cpp diff --git a/js/public/HashTable.h b/js/public/HashTable.h index 1a5e814ff826..a251886ecbd0 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -653,8 +653,6 @@ class HashMapEntry template friend class detail::HashTableEntry; template friend class HashMap; - Key & mutableKey() { return key_; } - public: template HashMapEntry(KeyInput&& k, ValueInput&& v) @@ -670,9 +668,10 @@ class HashMapEntry typedef Key KeyType; typedef Value ValueType; - const Key & key() const { return key_; } - const Value & value() const { return value_; } - Value & value() { return value_; } + const Key& key() const { return key_; } + Key& mutableKey() { return key_; } + const Value& value() const { return value_; } + Value& value() { return value_; } private: HashMapEntry(const HashMapEntry&) = delete; diff --git a/js/public/HeapAPI.h b/js/public/HeapAPI.h index 2987b77356f3..016d9f1953b3 100644 --- a/js/public/HeapAPI.h +++ b/js/public/HeapAPI.h @@ -54,7 +54,8 @@ const size_t ChunkMarkBitmapOffset = 1032352; const size_t ChunkMarkBitmapBits = 129024; #endif const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*); -const size_t ChunkLocationOffset = ChunkSize - 2 * sizeof(void*) - sizeof(uint64_t); +const size_t ChunkTrailerSize = 2 * sizeof(uintptr_t) + sizeof(uint64_t); +const size_t ChunkLocationOffset = ChunkSize - ChunkTrailerSize; const size_t ArenaZoneOffset = 0; /* diff --git a/js/src/ds/LockGuard.h b/js/src/ds/LockGuard.h new file mode 100644 index 000000000000..7baaa896b67b --- /dev/null +++ b/js/src/ds/LockGuard.h @@ -0,0 +1,38 @@ +/* -*- 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_LockGuard_h +#define js_LockGuard_h + +#include "mozilla/GuardObjects.h" + +namespace js { + +// An implementation of C++11's std::lock_guard, enhanced with a guard object +// to help with correct usage. +template +class LockGuard +{ + LockType& lockRef_; + MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER; + + public: + explicit LockGuard(LockType& lock + MOZ_GUARD_OBJECT_NOTIFIER_PARAM) + : lockRef_(lock) + { + MOZ_GUARD_OBJECT_NOTIFIER_INIT; + lockRef_.lock(); + } + + ~LockGuard() { + lockRef_.unlock(); + } +}; + +} // namespace js + +#endif // js_LockGuard_h diff --git a/js/src/ds/SpinLock.h b/js/src/ds/SpinLock.h new file mode 100644 index 000000000000..87253d990237 --- /dev/null +++ b/js/src/ds/SpinLock.h @@ -0,0 +1,40 @@ +/* -*- 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_SpinLock_h +#define js_SpinLock_h + +#include "mozilla/Atomics.h" + +#include "ds/LockGuard.h" + +namespace js { + +// A trivial spin-lock implementation. Extremely fast when rarely-contended. +class SpinLock +{ + mozilla::Atomic locked_; + + public: + SpinLock() : locked_(false) {} + + void lock() { + do { + while (locked_) + ; // Spin until the lock seems free. + } while (!locked_.compareExchange(false, true)); // Atomically take the lock. + } + + void unlock() { + locked_ = false; + } +}; + +using AutoSpinLock = LockGuard; + +} // namespace js + +#endif // js_SpinLock_h diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index e9521ce09e3c..588f9c02575a 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -655,6 +655,11 @@ class GCRuntime size_t maxMallocBytesAllocated() { return maxMallocBytes; } + uint64_t nextCellUniqueId() { + MOZ_ASSERT(nextCellUniqueId_ > 0); + return nextCellUniqueId_++; + } + public: // Internal public interface js::gc::State state() const { return incrementalState; } @@ -1013,6 +1018,9 @@ class GCRuntime size_t maxMallocBytes; + // An incrementing id used to assign unique ids to cells that require one. + uint64_t nextCellUniqueId_; + /* * Number of the committed arenas in all GC chunks including empty chunks. */ diff --git a/js/src/gc/Heap.h b/js/src/gc/Heap.h index c0f027149215..a478ae8ee091 100644 --- a/js/src/gc/Heap.h +++ b/js/src/gc/Heap.h @@ -294,6 +294,9 @@ class TenuredCell : public Cell #endif }; +/* Cells are aligned to CellShift, so the largest tagged null pointer is: */ +const uintptr_t LargestTaggedNullCellPointer = (1 << CellShift) - 1; + /* * The mark bitmap has one bit per each GC cell. For multi-cell GC things this * wastes space but allows to avoid expensive devisions by thing's size when @@ -806,6 +809,17 @@ ArenaHeader::getThingSize() const */ struct ChunkTrailer { + /* Construct a Nursery ChunkTrailer. */ + ChunkTrailer(JSRuntime* rt, StoreBuffer* sb) + : location(gc::ChunkLocationBitNursery), storeBuffer(sb), runtime(rt) + {} + + /* Construct a Tenured heap ChunkTrailer. */ + explicit ChunkTrailer(JSRuntime* rt) + : location(gc::ChunkLocationBitTenuredHeap), storeBuffer(nullptr), runtime(rt) + {} + + public: /* The index the chunk in the nursery, or LocationTenuredHeap. */ uint32_t location; uint32_t padding; @@ -813,11 +827,12 @@ struct ChunkTrailer /* The store buffer for writes to things in this chunk or nullptr. */ StoreBuffer* storeBuffer; + /* This provides quick access to the runtime from absolutely anywhere. */ JSRuntime* runtime; }; -static_assert(sizeof(ChunkTrailer) == 2 * sizeof(uintptr_t) + sizeof(uint64_t), - "ChunkTrailer size is incorrect."); +static_assert(sizeof(ChunkTrailer) == ChunkTrailerSize, + "ChunkTrailer size must match the API defined size."); /* The chunk header (located at the end of the chunk to preserve arena alignment). */ struct ChunkInfo @@ -1006,13 +1021,16 @@ struct Chunk return reinterpret_cast(addr); } - static bool withinArenasRange(uintptr_t addr) { + static bool withinValidRange(uintptr_t addr) { uintptr_t offset = addr & ChunkMask; - return offset < ArenasPerChunk * ArenaSize; + return Chunk::fromAddress(addr)->isNurseryChunk() + ? offset < ChunkSize - sizeof(ChunkTrailer) + : offset < ArenasPerChunk * ArenaSize; } static size_t arenaIndex(uintptr_t addr) { - MOZ_ASSERT(withinArenasRange(addr)); + MOZ_ASSERT(!Chunk::fromAddress(addr)->isNurseryChunk()); + MOZ_ASSERT(withinValidRange(addr)); return (addr & ChunkMask) >> ArenaShift; } @@ -1030,6 +1048,10 @@ struct Chunk return info.numArenasFree != 0; } + bool isNurseryChunk() const { + return info.trailer.storeBuffer; + } + ArenaHeader* allocateArena(JSRuntime* rt, JS::Zone* zone, AllocKind kind, const AutoLockGC& lock); @@ -1129,7 +1151,7 @@ ArenaHeader::address() const uintptr_t addr = reinterpret_cast(this); MOZ_ASSERT(addr); MOZ_ASSERT(!(addr & ArenaMask)); - MOZ_ASSERT(Chunk::withinArenasRange(addr)); + MOZ_ASSERT(Chunk::withinValidRange(addr)); return addr; } @@ -1298,7 +1320,7 @@ Cell::address() const { uintptr_t addr = uintptr_t(this); MOZ_ASSERT(addr % CellSize == 0); - MOZ_ASSERT(Chunk::withinArenasRange(addr)); + MOZ_ASSERT(Chunk::withinValidRange(addr)); return addr; } diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index f11c621d04cd..83d8eee794e5 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2117,7 +2117,13 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind if (src->is()) tenuredSize = srcSize = sizeof(NativeObject); + // Copy the Cell contents. js_memcpy(dst, src, srcSize); + + // Move any hash code attached to the object. + src->zone()->transferUniqueId(dst, src); + + // Move the slots and elements, if we need to. if (src->isNative()) { NativeObject* ndst = &dst->as(); NativeObject* nsrc = &src->as(); diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index dcc042234d24..96ffe0f49adf 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -425,7 +425,7 @@ ToMarkable(Cell* cell) MOZ_ALWAYS_INLINE bool IsNullTaggedPointer(void* p) { - return uintptr_t(p) < 32; + return uintptr_t(p) <= LargestTaggedNullCellPointer; } // HashKeyRef represents a reference to a HashMap key. This should normally diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index 2c5b266fd9c9..a5bcb6b9696d 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -67,6 +67,9 @@ js::Nursery::init(uint32_t maxNurseryBytes) if (!mallocedBuffers.init()) return false; + if (!cellsWithUid_.init()) + return false; + void* heap = MapAlignedPages(nurserySize(), Alignment); if (!heap) return false; @@ -653,6 +656,16 @@ js::Nursery::waitBackgroundFreeEnd() void js::Nursery::sweep() { + /* Sweep unique id's in all in-use chunks. */ + for (CellsWithUniqueIdSet::Enum e(cellsWithUid_); !e.empty(); e.popFront()) { + JSObject* obj = static_cast(e.front()); + if (!IsForwarded(obj)) + obj->zone()->removeUniqueId(obj); + else + MOZ_ASSERT(Forwarded(obj)->zone()->hasUniqueId(Forwarded(obj))); + } + cellsWithUid_.clear(); + #ifdef JS_GC_ZEAL /* Poison the nursery contents so touching a freed object will crash. */ JS_POISON((void*)start(), JS_SWEPT_NURSERY_PATTERN, nurserySize()); @@ -670,10 +683,8 @@ js::Nursery::sweep() { #ifdef JS_CRASH_DIAGNOSTICS JS_POISON((void*)start(), JS_SWEPT_NURSERY_PATTERN, allocationEnd() - start()); - for (int i = 0; i < numActiveChunks_; ++i) { - chunk(i).trailer.location = gc::ChunkLocationBitNursery; - chunk(i).trailer.runtime = runtime(); - } + for (int i = 0; i < numActiveChunks_; ++i) + initChunk(i); #endif setCurrentChunk(0); } diff --git a/js/src/gc/Nursery.h b/js/src/gc/Nursery.h index 267578f25c1a..a13468e06023 100644 --- a/js/src/gc/Nursery.h +++ b/js/src/gc/Nursery.h @@ -183,6 +183,14 @@ class Nursery void waitBackgroundFreeEnd(); + bool addedUniqueIdToCell(gc::Cell* cell) { + if (!IsInsideNursery(cell) || !isEnabled()) + return true; + MOZ_ASSERT(cellsWithUid_.initialized()); + MOZ_ASSERT(!cellsWithUid_.has(cell)); + return cellsWithUid_.put(cell); + } + size_t sizeOfHeapCommitted() const { return numActiveChunks_ * gc::ChunkSize; } @@ -266,6 +274,21 @@ class Nursery typedef HashMap, SystemAllocPolicy> ForwardedBufferMap; ForwardedBufferMap forwardedBuffers; + /* + * When we assign a unique id to cell in the nursery, that almost always + * means that the cell will be in a hash table, and thus, held live, + * automatically moving the uid from the nursery to its new home in + * tenured. It is possible, if rare, for an object that acquired a uid to + * be dead before the next collection, in which case we need to know to + * remove it when we sweep. + * + * Note: we store the pointers as Cell* here, resulting in an ugly cast in + * sweep. This is because this structure is used to help implement + * stable object hashing and we have to break the cycle somehow. + */ + using CellsWithUniqueIdSet = HashSet, SystemAllocPolicy>; + CellsWithUniqueIdSet cellsWithUid_; + /* The maximum number of bytes allowed to reside in nursery buffers. */ static const size_t MaxNurseryBufferSize = 1024; @@ -287,10 +310,8 @@ class Nursery } MOZ_ALWAYS_INLINE void initChunk(int chunkno) { - NurseryChunkLayout& c = chunk(chunkno); - c.trailer.storeBuffer = JS::shadow::Runtime::asShadowRuntime(runtime())->gcStoreBufferPtr(); - c.trailer.location = gc::ChunkLocationBitNursery; - c.trailer.runtime = runtime(); + gc::StoreBuffer* sb = JS::shadow::Runtime::asShadowRuntime(runtime())->gcStoreBufferPtr(); + new (&chunk(chunkno).trailer) gc::ChunkTrailer(runtime(), sb); } MOZ_ALWAYS_INLINE void setCurrentChunk(int chunkno) { diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index b9ee0efd5fab..5821ed7ce7f2 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -66,7 +66,7 @@ Zone::~Zone() bool Zone::init(bool isSystemArg) { isSystem = isSystemArg; - return gcZoneGroupEdges.init(); + return uniqueIds_.init() && gcZoneGroupEdges.init(); } void @@ -156,7 +156,6 @@ Zone::logPromotionsToTenured() awaitingTenureLogging.clear(); } - void Zone::sweepBreakpoints(FreeOp* fop) { @@ -257,6 +256,15 @@ Zone::discardJitCode(FreeOp* fop) } } +#ifdef JSGC_HASH_TABLE_CHECKS +void +JS::Zone::checkUniqueIdTableAfterMovingGC() +{ + for (UniqueIdMap::Enum e(uniqueIds_); !e.empty(); e.popFront()) + js::gc::CheckGCThingAfterMovingGC(e.front().key()); +} +#endif + uint64_t Zone::gcNumber() { diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index 74c3a977fec0..07f71c38a616 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -13,9 +13,12 @@ #include "jscntxt.h" +#include "ds/SpinLock.h" +#include "ds/SplayTree.h" #include "gc/FindSCCs.h" #include "gc/GCRuntime.h" #include "js/TracingAPI.h" +#include "vm/MallocProvider.h" #include "vm/TypeInference.h" namespace js { @@ -58,6 +61,11 @@ class ZoneHeapThreshold const GCSchedulingTunables& tunables); }; +// Maps a Cell* to a unique, 64bit id. +using UniqueIdMap = HashMap, SystemAllocPolicy>; + +extern uint64_t NextCellUniqueId(JSRuntime* rt); + } // namespace gc } // namespace js @@ -242,6 +250,7 @@ struct Zone : public JS::shadow::Zone, LogTenurePromotionQueue awaitingTenureLogging; void sweepBreakpoints(js::FreeOp* fop); + void sweepUniqueIds(js::FreeOp* fop); void sweepWeakMaps(); void sweepCompartments(js::FreeOp* fop, bool keepAtleastOne, bool lastGC); @@ -251,6 +260,14 @@ struct Zone : public JS::shadow::Zone, return isOnList(); } + // Side map for storing a unique ids for cells, independent of address. + js::gc::UniqueIdMap uniqueIds_; + + // Guards the uniqueIds_ map, which is accessed concurrently from + // off-thread parsing and the main thread. This uses a spinlock, since it + // is normally uncontended. + js::SpinLock uniqueIdsLock_; + public: bool hasDebuggers() const { return debuggers && debuggers->length(); } DebuggerVector* getDebuggers() const { return debuggers; } @@ -323,6 +340,68 @@ struct Zone : public JS::shadow::Zone, mozilla::DebugOnly gcLastZoneGroupIndex; + // Creates a HashNumber based on getUniqueId. Returns false on OOM. + bool getHashCode(js::gc::Cell* cell, js::HashNumber* hashp) { + uint64_t uid; + if (!getUniqueId(cell, &uid)) + return false; + *hashp = js::HashNumber(uid >> 32) ^ js::HashNumber(uid & 0xFFFFFFFF); + return true; + } + + // Puts an existing UID in |uidp|, or creates a new UID for this Cell and + // puts that into |uidp|. Returns false on OOM. + bool getUniqueId(js::gc::Cell* cell, uint64_t* uidp) { + MOZ_ASSERT(uidp); + js::AutoSpinLock lock(uniqueIdsLock_); + + // Get an existing uid, if one has been set. + auto p = uniqueIds_.lookupForAdd(cell); + if (p) { + *uidp = p->value(); + return true; + } + + // Set a new uid on the cell. + *uidp = js::gc::NextCellUniqueId(runtimeFromAnyThread()); + if (!uniqueIds_.add(p, cell, *uidp)) + return false; + + // If the cell was in the nursery, hopefully unlikely, then we need to + // tell the nursery about it so that it can sweep the uid if the thing + // does not get tenured. + if (!runtimeFromAnyThread()->gc.nursery.addedUniqueIdToCell(cell)) + js::CrashAtUnhandlableOOM("failed to allocate tracking data for a nursery uid"); + return true; + } + + // Return true if this cell has a UID associated with it. + bool hasUniqueId(js::gc::Cell* cell) { + js::AutoSpinLock lock(uniqueIdsLock_); + return uniqueIds_.has(cell); + } + + // Transfer an id from another cell. This must only be called on behalf of a + // moving GC. This method is infallible. + void transferUniqueId(js::gc::Cell* tgt, js::gc::Cell* src) { + MOZ_ASSERT(src != tgt); + MOZ_ASSERT(!IsInsideNursery(tgt)); + MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtimeFromMainThread())); + js::AutoSpinLock lock(uniqueIdsLock_); + uniqueIds_.rekeyIfMoved(src, tgt); + } + + // Remove any unique id associated with this Cell. + void removeUniqueId(js::gc::Cell* cell) { + js::AutoSpinLock lock(uniqueIdsLock_); + uniqueIds_.remove(cell); + } + +#ifdef JSGC_HASH_TABLE_CHECKS + // Assert that the UniqueId table has been redirected successfully. + void checkUniqueIdTableAfterMovingGC(); +#endif + private: js::jit::JitZone* jitZone_; diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index b7f913a39fc4..6c2b3a49cd89 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -43,6 +43,7 @@ UNIFIED_SOURCES += [ 'testGCMarking.cpp', 'testGCOutOfMemory.cpp', 'testGCStoreBufferRemoval.cpp', + 'testGCUniqueId.cpp', 'testGetPropertyDescriptor.cpp', 'testHashTable.cpp', 'testIndexToString.cpp', diff --git a/js/src/jsapi-tests/testGCUniqueId.cpp b/js/src/jsapi-tests/testGCUniqueId.cpp new file mode 100644 index 000000000000..6efc8167f732 --- /dev/null +++ b/js/src/jsapi-tests/testGCUniqueId.cpp @@ -0,0 +1,120 @@ +/* -*- 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/. */ + +#include "gc/GCInternals.h" +#include "gc/Zone.h" + +static void +MinimizeHeap(JSRuntime* rt) +{ + // The second collection is to force us to wait for the background + // sweeping that the first GC started to finish. + JS_GC(rt); + JS_GC(rt); + js::gc::AutoFinishGC finish(rt); +} + +BEGIN_TEST(testGCUID) +{ +#ifdef JS_GC_ZEAL + AutoLeaveZeal nozeal(cx); +#endif /* JS_GC_ZEAL */ + + uint64_t uid = 0; + uint64_t tmp = 0; + + // Ensure the heap is as minimal as it can get. + MinimizeHeap(rt); + + JS::RootedObject obj(cx, JS_NewPlainObject(cx)); + uintptr_t nurseryAddr = uintptr_t(obj.get()); + CHECK(obj); + CHECK(js::gc::IsInsideNursery(obj)); + + // Do not start with an ID. + CHECK(!obj->zone()->hasUniqueId(obj)); + + // Ensure we can get a new UID. + CHECK(obj->zone()->getUniqueId(obj, &uid)); + CHECK(uid > js::gc::LargestTaggedNullCellPointer); + + // We should now have an id. + CHECK(obj->zone()->hasUniqueId(obj)); + + // Calling again should get us the same thing. + CHECK(obj->zone()->getUniqueId(obj, &tmp)); + CHECK(uid == tmp); + + // Tenure the thing and check that the UID moved with it. + MinimizeHeap(rt); + uintptr_t tenuredAddr = uintptr_t(obj.get()); + CHECK(tenuredAddr != nurseryAddr); + CHECK(!js::gc::IsInsideNursery(obj)); + CHECK(obj->zone()->hasUniqueId(obj)); + CHECK(obj->zone()->getUniqueId(obj, &tmp)); + CHECK(uid == tmp); + + // Allocate a new nursery thing in the same location and check that we + // removed the prior uid that was attached to the location. + obj = JS_NewPlainObject(cx); + CHECK(obj); + CHECK(uintptr_t(obj.get()) == nurseryAddr); + CHECK(!obj->zone()->hasUniqueId(obj)); + + // Try to get another tenured object in the same location and check that + // the uid was removed correctly. + obj = nullptr; + MinimizeHeap(rt); + obj = JS_NewPlainObject(cx); + MinimizeHeap(rt); + CHECK(uintptr_t(obj.get()) == tenuredAddr); + CHECK(!obj->zone()->hasUniqueId(obj)); + CHECK(obj->zone()->getUniqueId(obj, &tmp)); + CHECK(uid != tmp); + uid = tmp; + + // Allocate a few arenas worth of objects to ensure we get some compaction. + const static size_t N = 2049; + using ObjectVector = js::TraceableVector; + JS::Rooted vec(cx, ObjectVector(cx)); + for (size_t i = 0; i < N; ++i) { + obj = JS_NewPlainObject(cx); + CHECK(obj); + CHECK(vec.append(obj)); + } + + // Transfer our vector to tenured if it isn't there already. + MinimizeHeap(rt); + + // Tear holes in the heap by unrooting the even objects and collecting. + JS::Rooted vec2(cx, ObjectVector(cx)); + for (size_t i = 0; i < N; ++i) { + if (i % 2 == 1) + vec2.append(vec[i]); + } + vec.clear(); + MinimizeHeap(rt); + + // Grab the last object in the vector as our object of interest. + obj = vec2.back(); + CHECK(obj); + tenuredAddr = uintptr_t(obj.get()); + CHECK(obj->zone()->getUniqueId(obj, &uid)); + + // Force a compaction to move the object and check that the uid moved to + // the new tenured heap location. + JS::PrepareForFullGC(rt); + JS::GCForReason(rt, GC_SHRINK, JS::gcreason::API); + MinimizeHeap(rt); + CHECK(uintptr_t(obj.get()) != tenuredAddr); + CHECK(obj->zone()->hasUniqueId(obj)); + CHECK(obj->zone()->getUniqueId(obj, &tmp)); + CHECK(uid == tmp); + + return true; +} +END_TEST(testGCUID) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 2d785f4141ac..71204205abf3 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -833,9 +833,7 @@ Chunk::init(JSRuntime* rt) /* Initialize the chunk info. */ info.init(); - info.trailer.storeBuffer = nullptr; - info.trailer.location = ChunkLocationBitTenuredHeap; - info.trailer.runtime = rt; + new (&info.trailer) ChunkTrailer(rt); /* The rest of info fields are initialized in pickChunk. */ } @@ -1110,6 +1108,7 @@ GCRuntime::GCRuntime(JSRuntime* rt) : usage(nullptr), mMemProfiler(rt), maxMallocBytes(0), + nextCellUniqueId_(LargestTaggedNullCellPointer + 1), // Ensure disjoint from null tagged pointers. numArenasFreeCommitted(0), verifyPreData(nullptr), chunkAllocationSinceLastGC(false), @@ -2042,6 +2041,9 @@ RelocateCell(Zone* zone, TenuredCell* src, AllocKind thingKind, size_t thingSize // Copy source cell contents to destination. memcpy(dst, src, thingSize); + // Move any uid attached to the object. + src->zone()->transferUniqueId(dst, src); + if (IsObjectAllocKind(thingKind)) { JSObject* srcObj = static_cast(static_cast(src)); JSObject* dstObj = static_cast(static_cast(dst)); @@ -2173,7 +2175,6 @@ bool ArenaLists::relocateArenas(Zone* zone, ArenaHeader*& relocatedListOut, JS::gcreason::Reason reason, SliceBudget& sliceBudget, gcstats::Statistics& stats) { - // This is only called from the main thread while we are doing a GC, so // there is no need to lock. MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_)); @@ -3588,6 +3589,29 @@ GCRuntime::shouldReleaseObservedTypes() return releaseTypes; } +struct IsAboutToBeFinalizedFunctor { + template bool operator()(Cell** t) { + mozilla::DebugOnly prior = *t; + bool result = IsAboutToBeFinalizedUnbarriered(reinterpret_cast(t)); + // Sweep should not have to deal with moved pointers, since moving GC + // handles updating the UID table manually. + MOZ_ASSERT(*t == prior); + return result; + } +}; + +void +JS::Zone::sweepUniqueIds(js::FreeOp* fop) +{ + for (UniqueIdMap::Enum e(uniqueIds_); !e.empty(); e.popFront()) { + if (DispatchTraceKindTyped(IsAboutToBeFinalizedFunctor(), e.front().key()->getTraceKind(), + &e.front().mutableKey())) + { + e.removeFront(); + } + } +} + /* * It's simpler if we preserve the invariant that every zone has at least one * compartment. If we know we're deleting the entire zone, then @@ -5058,6 +5082,12 @@ GCRuntime::beginSweepingZoneGroup() zone->sweepBreakpoints(&fop); } } + + { + gcstats::AutoPhase ap(stats, gcstats::PHASE_SWEEP_BREAKPOINT); + for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + zone->sweepUniqueIds(&fop); + } } if (sweepingAtoms) { @@ -7150,6 +7180,9 @@ js::gc::CheckHashTablesAfterMovingGC(JSRuntime* rt) * Check that internal hash tables no longer have any pointers to things * that have been moved. */ + for (ZonesIter zone(rt, SkipAtoms); !zone.done(); zone.next()) { + zone->checkUniqueIdTableAfterMovingGC(); + } for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) { c->objectGroups.checkTablesAfterMovingGC(); c->checkInitialShapesTableAfterMovingGC(); @@ -7375,6 +7408,12 @@ JS::IsGenerationalGCEnabled(JSRuntime* rt) return rt->gc.isGenerationalGCEnabled(); } +uint64_t +js::gc::NextCellUniqueId(JSRuntime* rt) +{ + return rt->gc.nextCellUniqueId(); +} + namespace js { namespace gc { namespace MemInfo { diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index f4fba5d4aa1e..8b81d5acf6ae 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -76,6 +76,7 @@ JSObject::finalize(js::FreeOp* fop) MOZ_ASSERT(CurrentThreadCanAccessRuntime(fop->runtime())); } #endif + const js::Class* clasp = getClass(); if (clasp->finalize) clasp->finalize(fop, this); From 0c90745b801b17c48f05ed6508dd35788e9ef5e1 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Wed, 26 Aug 2015 14:51:35 -0700 Subject: [PATCH 129/247] Bug 1196847 - Part 2: Implement a cell hasher that uses unique id based hashes; r=jonco --HG-- extra : rebase_source : e1464d566ec7dbf85b1b9d861450906945057e23 --- js/public/HashTable.h | 11 +++++++++ js/src/gc/Barrier.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++ js/src/gc/Barrier.h | 25 ++++++++++++++++++++ 3 files changed, 91 insertions(+) diff --git a/js/public/HashTable.h b/js/public/HashTable.h index a251886ecbd0..16693bbed38d 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -740,6 +740,7 @@ class HashTableEntry } T& get() { MOZ_ASSERT(isLive()); return *mem.addr(); } + NonConstT& getMutable() { MOZ_ASSERT(isLive()); return *mem.addr(); } bool isFree() const { return keyHash == sFreeKey; } void clearLive() { MOZ_ASSERT(isLive()); keyHash = sFreeKey; mem.addr()->~T(); } @@ -979,6 +980,16 @@ class HashTable : private AllocPolicy #endif } + NonConstT& mutableFront() { + MOZ_ASSERT(!this->empty()); +#ifdef JS_DEBUG + MOZ_ASSERT(this->validEntry); + MOZ_ASSERT(this->generation == this->Range::table_->generation()); + MOZ_ASSERT(this->mutationCount == this->Range::table_->mutationCount); +#endif + return this->cur->getMutable(); + } + // Removes the |front()| element and re-inserts it into the table with // a new key at the new Lookup position. |front()| is invalid after // this operation until the next call to |popFront()|. diff --git a/js/src/gc/Barrier.cpp b/js/src/gc/Barrier.cpp index c361d97f7dae..4014f4a8e6fc 100644 --- a/js/src/gc/Barrier.cpp +++ b/js/src/gc/Barrier.cpp @@ -10,7 +10,9 @@ #include "jsobj.h" #include "gc/Zone.h" +#include "js/HashTable.h" #include "js/Value.h" +#include "vm/ScopeObject.h" #include "vm/Symbol.h" #ifdef DEBUG @@ -102,3 +104,56 @@ JS::HeapValuePostBarrier(JS::Value* valuep, const Value& prev, const Value& next MOZ_ASSERT(valuep); js::InternalGCMethods::postBarrier(valuep, prev, next); } + +template +/* static */ js::HashNumber +js::MovableCellHasher::hash(const Lookup& l) +{ + if (!l) + return 0; + + // We have to access the zone from-any-thread here: a worker thread may be + // cloning a self-hosted object from the main-thread-runtime-owned self- + // hosting zone into the off-main-thread runtime. The zone's uid lock will + // protect against multiple workers doing this simultaneously. + MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) || + l->zoneFromAnyThread()->isSelfHostingZone()); + + js::HashNumber hn; + if (!l->zoneFromAnyThread()->getHashCode(l, &hn)) + js::CrashAtUnhandlableOOM("failed to get a stable hash code"); + return hn; +} + +template +/* static */ bool +js::MovableCellHasher::match(const Key& k, const Lookup& l) +{ + // Return true if both are null or false if only one is null. + if (!k) + return !l; + if (!l) + return false; + + MOZ_ASSERT(k); + MOZ_ASSERT(l); + MOZ_ASSERT(CurrentThreadCanAccessZone(l->zoneFromAnyThread()) || + l->zoneFromAnyThread()->isSelfHostingZone()); + + Zone* zone = k->zoneFromAnyThread(); + if (zone != l->zoneFromAnyThread()) + return false; + MOZ_ASSERT(zone->hasUniqueId(k)); + MOZ_ASSERT(zone->hasUniqueId(l)); + + // Since both already have a uid (from hash), the get is infallible. + uint64_t uidK, uidL; + MOZ_ALWAYS_TRUE(zone->getUniqueId(k, &uidK)); + MOZ_ALWAYS_TRUE(zone->getUniqueId(l, &uidL)); + return uidK == uidL; +} + +template struct js::MovableCellHasher; +template struct js::MovableCellHasher; +template struct js::MovableCellHasher; +template struct js::MovableCellHasher; diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index ec8c00debaff..f80a918e4465 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -693,6 +693,31 @@ class ImmutableTenuredPtr const T* address() { return &value; } }; +// Provide hash codes for Cell kinds that may be relocated and, thus, not have +// a stable address to use as the base for a hash code. Instead of the address, +// this hasher uses Cell::getUniqueId to provide exact matches and as a base +// for generating hash codes. +// +// Note: this hasher, like PointerHasher can "hash" a nullptr. While a nullptr +// would not likely be a useful key, there are some cases where being able to +// hash a nullptr is useful, either on purpose or because of bugs: +// (1) existence checks where the key may happen to be null and (2) some +// aggregate Lookup kinds embed a JSObject* that is frequently null and do not +// null test before dispatching to the hasher. +template +struct MovableCellHasher +{ + static_assert(mozilla::IsBaseOf::Type>::value, + "MovableCellHasher's T must be a Cell type that may move"); + + using Key = T; + using Lookup = T; + + static HashNumber hash(const Lookup& l); + static bool match(const Key& k, const Lookup& l); + static void rekey(Key& k, const Key& newKey) { k = newKey; } +}; + /* Useful for hashtables with a HeapPtr as key. */ template struct HeapPtrHasher From 34f8bce0ceb94292247be143bd215ac747130689 Mon Sep 17 00:00:00 2001 From: Zachary Carter Date: Fri, 25 Sep 2015 14:02:30 -0700 Subject: [PATCH 130/247] Bug 1197323 - prevent profile images from being overwritten by an async onload callback r=markh --- browser/base/content/browser-fxaccounts.js | 15 +++++++++++---- .../components/preferences/in-content/sync.js | 16 ++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/browser/base/content/browser-fxaccounts.js b/browser/base/content/browser-fxaccounts.js index a519afab5d5f..e197dee23c6f 100644 --- a/browser/base/content/browser-fxaccounts.js +++ b/browser/base/content/browser-fxaccounts.js @@ -313,11 +313,18 @@ var gFxAccounts = { this.panelUILabel.setAttribute("label", profile.displayName); } if (profile.avatar) { + this.panelUIFooter.setAttribute("fxaprofileimage", "set"); + let bgImage = "url(\"" + profile.avatar + "\")"; + this.panelUIAvatar.style.listStyleImage = bgImage; + let img = new Image(); - // Make sure the image is available before attempting to display it - img.onload = () => { - this.panelUIFooter.setAttribute("fxaprofileimage", "set"); - this.panelUIAvatar.style.listStyleImage = "url('" + profile.avatar + "')"; + img.onerror = () => { + // Clear the image if it has trouble loading. Since this callback is asynchronous + // we check to make sure the image is still the same before we clear it. + if (this.panelUIAvatar.style.listStyleImage === bgImage) { + this.panelUIFooter.removeAttribute("fxaprofileimage"); + this.panelUIAvatar.style.removeProperty("list-style-image"); + } }; img.src = profile.avatar; } diff --git a/browser/components/preferences/in-content/sync.js b/browser/components/preferences/in-content/sync.js index bbb5c2798bb9..d1b1e465b459 100644 --- a/browser/components/preferences/in-content/sync.js +++ b/browser/components/preferences/in-content/sync.js @@ -406,13 +406,17 @@ var gSyncPane = { displayNameLabel.textContent = data.displayName; } if (data.avatar) { - // Make sure the image is available before displaying it, - // as we don't want to overwrite the default profile image - // with a broken/unavailable image + let bgImage = "url(\"" + data.avatar + "\")"; + let profileImageElement = document.getElementById("fxaProfileImage"); + profileImageElement.style.listStyleImage = bgImage; + let img = new Image(); - img.onload = () => { - let bgImage = "url('" + data.avatar + "')"; - document.getElementById("fxaProfileImage").style.listStyleImage = bgImage; + img.onerror = () => { + // Clear the image if it has trouble loading. Since this callback is asynchronous + // we check to make sure the image is still the same before we clear it. + if (profileImageElement.style.listStyleImage === bgImage) { + profileImageElement.style.removeProperty("list-style-image"); + } }; img.src = data.avatar; } From c95264033aa0a7f6a1e50da991608ad5a1f999fa Mon Sep 17 00:00:00 2001 From: Chris Manchester Date: Fri, 25 Sep 2015 07:33:11 -0700 Subject: [PATCH 131/247] Bug 1184405 - Add a test to fail the build if file patterns are present in test dependency annotations that don't correspond to any files on disk. r=gps --HG-- extra : commitid : HuJebAX8Bwj --- config/tests/test_mozbuild_reading.py | 43 +++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/config/tests/test_mozbuild_reading.py b/config/tests/test_mozbuild_reading.py index 6256d11fa83e..c8d478ccdcce 100644 --- a/config/tests/test_mozbuild_reading.py +++ b/config/tests/test_mozbuild_reading.py @@ -5,11 +5,14 @@ from __future__ import unicode_literals import os +import sys import unittest from mozunit import main from mozbuild.base import MozbuildObject +from mozpack.files import FileFinder +from mozbuild.frontend.context import Files from mozbuild.frontend.reader import ( BuildReader, EmptyConfig, @@ -66,5 +69,45 @@ class TestMozbuildReading(unittest.TestCase): self.assertGreaterEqual(len(contexts), len(paths)) + def test_orphan_file_patterns(self): + if sys.platform == 'win32': + raise unittest.SkipTest('failing on windows builds') + + mb = MozbuildObject.from_environment(detect_virtualenv_mozinfo=False) + + try: + config = mb.config_environment + except Exception as e: + if e.message == 'config.status not available. Run configure.': + raise unittest.SkipTest('failing without config.status') + raise + + reader = BuildReader(config) + all_paths = self._mozbuilds(reader) + _, contexts = reader.read_relevant_mozbuilds(all_paths) + + finder = FileFinder(config.topsrcdir, find_executables=False, + ignore=['obj*']) + + def pattern_exists(pat): + return [p for p in finder.find(pat)] != [] + + for ctx in contexts: + if not isinstance(ctx, Files): + continue + relsrcdir = ctx.relsrcdir + if not pattern_exists(os.path.join(relsrcdir, ctx.pattern)): + self.fail("The pattern '%s' in a Files() entry in " + "'%s' corresponds to no files in the tree.\n" + "Please update this entry." % + (ctx.pattern, ctx.main_path)) + test_files = ctx['IMPACTED_TESTS'].files + for p in test_files: + if not pattern_exists(os.path.relpath(p.full_path, config.topsrcdir)): + self.fail("The pattern '%s' in a dependent tests entry " + "in '%s' corresponds to no files in the tree.\n" + "Please update this entry." % + (p, ctx.main_path)) + if __name__ == '__main__': main() From dab2db0590f0b7c8af0af69ef1c3f559e8a5a111 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 25 Sep 2015 14:46:03 -0700 Subject: [PATCH 132/247] Backed out 2 changesets (bug 1207556) for leaks in various mochitests Backed out changeset bd1eed74e2ec (bug 1207556) Backed out changeset 3260a147595a (bug 1207556) --- .../beacon/beacon-preflight-handler.sjs | 39 ------------- dom/tests/mochitest/beacon/mochitest.ini | 2 - .../beacon/test_beaconPreflight.html | 26 +-------- .../beacon/test_beaconPreflightFailure.html | 56 ------------------- netwerk/base/LoadInfo.cpp | 11 ---- netwerk/base/LoadInfo.h | 3 - netwerk/protocol/http/nsCORSListenerProxy.cpp | 10 +--- 7 files changed, 6 insertions(+), 141 deletions(-) delete mode 100644 dom/tests/mochitest/beacon/beacon-preflight-handler.sjs delete mode 100644 dom/tests/mochitest/beacon/test_beaconPreflightFailure.html diff --git a/dom/tests/mochitest/beacon/beacon-preflight-handler.sjs b/dom/tests/mochitest/beacon/beacon-preflight-handler.sjs deleted file mode 100644 index 6a760cb84ce0..000000000000 --- a/dom/tests/mochitest/beacon/beacon-preflight-handler.sjs +++ /dev/null @@ -1,39 +0,0 @@ -function handleRequest(request, response) -{ - response.setHeader("Cache-Control", "no-cache, must-revalidate", false); - - if (request.queryString === "verify") { - var preflightState = getState("preflight"); - response.write(preflightState === "done" ? "green" : "red"); - return; - } - - var originHeader = request.getHeader("origin"); - response.setHeader("Access-Control-Allow-Headers", "content-type", false); - response.setHeader("Access-Control-Allow-Methods", "POST, GET", false); - response.setHeader("Access-Control-Allow-Origin", originHeader, false); - response.setHeader("Access-Control-Allow-Credentials", "true", false); - - if (request.queryString === "beacon") { - if (request.method == "OPTIONS") { - setState("preflight", "done"); - response.setStatusLine(null, 200, "OK"); - return; - } - response.setStatusLine(null, 200, "OK"); - response.write("DONE"); - return; - } - - if (request.queryString === "fail") { - if (request.method == "OPTIONS") { - setState("preflight", "done"); - response.setStatusLine(null, 400, "Bad Request"); - return; - } - setState("preflight", "oops"); - response.setStatusLine(null, 200, "OK"); - response.write("DONE"); - return; - } -} diff --git a/dom/tests/mochitest/beacon/mochitest.ini b/dom/tests/mochitest/beacon/mochitest.ini index c15c52461a02..07c08dd43c72 100644 --- a/dom/tests/mochitest/beacon/mochitest.ini +++ b/dom/tests/mochitest/beacon/mochitest.ini @@ -2,14 +2,12 @@ skip-if = buildapp == 'b2g' support-files = beacon-frame.html beacon-handler.sjs - beacon-preflight-handler.sjs beacon-originheader-handler.sjs beacon-cors-redirect-handler.sjs [test_beacon.html] [test_beaconFrame.html] [test_beaconPreflight.html] -[test_beaconPreflightFailure.html] [test_beaconContentPolicy.html] [test_beaconOriginHeader.html] [test_beaconCORSRedirect.html] diff --git a/dom/tests/mochitest/beacon/test_beaconPreflight.html b/dom/tests/mochitest/beacon/test_beaconPreflight.html index cec5df84a185..63f4d7857047 100644 --- a/dom/tests/mochitest/beacon/test_beaconPreflight.html +++ b/dom/tests/mochitest/beacon/test_beaconPreflight.html @@ -17,24 +17,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=936340
 
diff --git a/dom/tests/mochitest/beacon/test_beaconPreflightFailure.html b/dom/tests/mochitest/beacon/test_beaconPreflightFailure.html
deleted file mode 100644
index 11879222f1ef..000000000000
--- a/dom/tests/mochitest/beacon/test_beaconPreflightFailure.html
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-  Test for Bug 1207556
-  
-  
-
-
-Mozilla Bug 1207556
-

- -
-
-
- - diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index ec7d82951230..9b7747dbc340 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -117,17 +117,6 @@ LoadInfo::~LoadInfo() NS_IMPL_ISUPPORTS(LoadInfo, nsILoadInfo) -already_AddRefed -LoadInfo::Clone() const -{ - nsRefPtr copy(new LoadInfo(*this)); - // Reset the fields that should be cleared out. - copy->mEnforceSecurity = false; - copy->mInitialSecurityCheckDone = false; - copy->mRedirectChain.Clear(); - return copy.forget(); -} - NS_IMETHODIMP LoadInfo::GetLoadingPrincipal(nsIPrincipal** aLoadingPrincipal) { diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index e0b9909950cb..799e8f144b72 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -50,8 +50,6 @@ public: nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType); - already_AddRefed Clone() const; - private: // private constructor that is only allowed to be called from within // HttpChannelParent and FTPChannelParent declared as friends undeneath. @@ -68,7 +66,6 @@ private: bool aEnforceSecurity, bool aInitialSecurityCheckDone, nsTArray>& aRedirectChain); - LoadInfo(const LoadInfo& rhs) = default; friend nsresult mozilla::ipc::LoadInfoArgsToLoadInfo( diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index 8bf4f132d5d1..6b154a90fe36 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -41,7 +41,6 @@ #include "nsINetworkInterceptController.h" #include "nsNullPrincipal.h" #include "nsICorsPreflightCallback.h" -#include "mozilla/LoadInfo.h" #include using namespace mozilla; @@ -1311,15 +1310,12 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel, nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr originalLoadInfo = aRequestChannel->GetLoadInfo(); - MOZ_ASSERT(originalLoadInfo, "can not perform CORS preflight without a loadInfo"); - if (!originalLoadInfo) { + nsCOMPtr loadInfo = aRequestChannel->GetLoadInfo(); + MOZ_ASSERT(loadInfo, "can not perform CORS preflight without a loadInfo"); + if (!loadInfo) { return NS_ERROR_FAILURE; } - nsCOMPtr loadInfo = static_cast - (originalLoadInfo.get())->Clone(); - nsSecurityFlags securityMode = loadInfo->GetSecurityMode(); MOZ_ASSERT(securityMode == 0 || From 91ee1fd4d402f029eaebce1ef4176b23df7ed25d Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Fri, 25 Sep 2015 11:22:28 -0700 Subject: [PATCH 133/247] Bug 1101561 - Move ensuring classes needed by parsing into a single method, and assert all needed prototypes are created as delegates. r=jandem --HG-- extra : rebase_source : 4232e19fd44e4f6d213cb1142179ff4ca5fa6000 --- js/src/jsarray.cpp | 1 + js/src/vm/GeneratorObject.cpp | 8 ++-- js/src/vm/HelperThreads.cpp | 76 ++++++++++++++++++++--------------- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index e8566ecf0189..a947a54c9c84 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -3247,6 +3247,7 @@ CreateArrayPrototype(JSContext* cx, JSProtoKey key) metadata)); if (!arrayProto || !JSObject::setSingleton(cx, arrayProto) || + !arrayProto->setDelegate(cx) || !AddLengthProperty(cx, arrayProto)) { return nullptr; diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp index 41da53d3d1ce..e3c48faaf4c9 100644 --- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -291,20 +291,22 @@ GlobalObject::initGeneratorClasses(JSContext* cx, Handle global) { if (global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).isUndefined()) { RootedObject proto(cx, NewSingletonObjectWithObjectPrototype(cx, global)); - if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods)) + if (!proto || !proto->setDelegate(cx)) + return false; + if (!DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods)) return false; global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto)); } if (global->getSlot(STAR_GENERATOR_OBJECT_PROTO).isUndefined()) { RootedObject genObjectProto(cx, NewSingletonObjectWithObjectPrototype(cx, global)); - if (!genObjectProto) + if (!genObjectProto || !genObjectProto->setDelegate(cx)) return false; if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods)) return false; RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global)); - if (!genFunctionProto) + if (!genFunctionProto || !genFunctionProto->setDelegate(cx)) return false; if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto)) return false; diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index af27347a7653..ae8c10c4294c 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -313,6 +313,45 @@ js::OffThreadParsingMustWaitForGC(JSRuntime* rt) return rt->activeGCInAtomsZone(); } +static bool +EnsureConstructor(JSContext* cx, Handle global, JSProtoKey key) +{ + if (!GlobalObject::ensureConstructor(cx, global, key)) + return false; + + MOZ_ASSERT(global->getPrototype(key).toObject().isDelegate(), + "standard class prototype wasn't a delegate from birth"); + return true; +} + +// Initialize all classes potentially created during parsing for use in parser +// data structures, template objects, &c. +static bool +EnsureParserCreatedClasses(JSContext* cx) +{ + Handle global = cx->global(); + + if (!EnsureConstructor(cx, global, JSProto_Object)) + return false; // needed by object literals + + if (!EnsureConstructor(cx, global, JSProto_Array)) + return false; // needed by array literals + + if (!EnsureConstructor(cx, global, JSProto_Function)) + return false; // needed by functions + + if (!EnsureConstructor(cx, global, JSProto_RegExp)) + return false; // needed by regular expression literals + + if (!EnsureConstructor(cx, global, JSProto_Iterator)) + return false; // needed by ??? + + if (!EnsureConstructor(cx, global, JSProto_GeneratorFunction)) + return false; // needed by function*() {} and generator comprehensions + + return true; +} + bool js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& options, const char16_t* chars, size_t length, @@ -337,27 +376,15 @@ js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& optio JS_SetCompartmentPrincipals(global->compartment(), cx->compartment()->principals()); - RootedObject obj(cx); - - // Initialize all classes needed for parsing while we are still on the main - // thread. Do this for both the target and the new global so that prototype + // Initialize all classes required for parsing while still on the main + // thread, for both the target and the new global so that prototype // pointers can be changed infallibly after parsing finishes. - if (!GetBuiltinConstructor(cx, JSProto_Function, &obj) || - !GetBuiltinConstructor(cx, JSProto_Array, &obj) || - !GetBuiltinConstructor(cx, JSProto_RegExp, &obj) || - !GetBuiltinConstructor(cx, JSProto_Iterator, &obj)) - { + if (!EnsureParserCreatedClasses(cx)) return false; - } { AutoCompartment ac(cx, global); - if (!GetBuiltinConstructor(cx, JSProto_Function, &obj) || - !GetBuiltinConstructor(cx, JSProto_Array, &obj) || - !GetBuiltinConstructor(cx, JSProto_RegExp, &obj) || - !GetBuiltinConstructor(cx, JSProto_Iterator, &obj)) - { + if (!EnsureParserCreatedClasses(cx)) return false; - } } ScopedJSDeletePtr helpercx( @@ -884,15 +911,6 @@ LeaveParseTaskZone(JSRuntime* rt, ParseTask* task) rt->clearUsedByExclusiveThread(task->cx->zone()); } -static bool -EnsureConstructor(JSContext* cx, Handle global, JSProtoKey key) -{ - if (!GlobalObject::ensureConstructor(cx, global, key)) - return false; - - return global->getPrototype(key).toObject().setDelegate(cx); -} - JSScript* GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void* token) { @@ -924,13 +942,7 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void // Make sure we have all the constructors we need for the prototype // remapping below, since we can't GC while that's happening. Rooted global(cx, &cx->global()->as()); - if (!EnsureConstructor(cx, global, JSProto_Object) || - !EnsureConstructor(cx, global, JSProto_Array) || - !EnsureConstructor(cx, global, JSProto_Function) || - !EnsureConstructor(cx, global, JSProto_RegExp) || - !EnsureConstructor(cx, global, JSProto_Iterator) || - !EnsureConstructor(cx, global, JSProto_GeneratorFunction)) - { + if (!EnsureParserCreatedClasses(cx)) { LeaveParseTaskZone(rt, parseTask); return nullptr; } From 137cd223565ea594715f9ffedb4862cacea77da5 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Thu, 24 Sep 2015 12:51:55 -0700 Subject: [PATCH 134/247] Bug 1101561 - Fix StopIteration class initialization to be OOM-safe. r=jandem --HG-- extra : rebase_source : 15606a30fdff42d358977a793e1f4ff24dbe3fd3 --- js/src/jsiter.cpp | 28 ++++++++++++++-------------- js/src/jsiter.h | 3 +++ js/src/jsprototypes.h | 2 +- js/src/vm/GlobalObject.cpp | 2 +- js/src/vm/GlobalObject.h | 1 - 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 10055aafadbb..af3fc24b2a30 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1424,26 +1424,26 @@ GlobalObject::initIteratorClasses(JSContext* cx, Handle global) global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto)); } - return GlobalObject::initStopIterationClass(cx, global); + return true; } -/* static */ bool -GlobalObject::initStopIterationClass(JSContext* cx, Handle global) +JSObject* +js::InitStopIterationClass(JSContext* cx, HandleObject obj) { - if (!global->getPrototype(JSProto_StopIteration).isUndefined()) - return true; + Handle global = obj.as(); + if (!global->getPrototype(JSProto_StopIteration).isObject()) { + RootedObject proto(cx, global->createBlankPrototype(cx, &StopIterationObject::class_)); + if (!proto || !FreezeObject(cx, proto)) + return nullptr; - RootedObject proto(cx, global->createBlankPrototype(cx, &StopIterationObject::class_)); - if (!proto || !FreezeObject(cx, proto)) - return false; + // This should use a non-JSProtoKey'd slot, but this is easier for now. + if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_StopIteration, proto, proto)) + return nullptr; - // This should use a non-JSProtoKey'd slot, but this is easier for now. - if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_StopIteration, proto, proto)) - return false; + global->setConstructor(JSProto_StopIteration, ObjectValue(*proto)); + } - global->setConstructor(JSProto_StopIteration, ObjectValue(*proto)); - - return true; + return &global->getPrototype(JSProto_StopIteration).toObject(); } JSObject* diff --git a/js/src/jsiter.h b/js/src/jsiter.h index 1ed88bbc1efc..7faba9eed18e 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -207,6 +207,9 @@ ThrowStopIteration(JSContext* cx); extern JSObject* CreateItrResultObject(JSContext* cx, HandleValue value, bool done); +extern JSObject* +InitStopIterationClass(JSContext* cx, HandleObject obj); + extern JSObject* InitIteratorClasses(JSContext* cx, HandleObject obj); diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index 26ae92e6061c..8bd07994aa66 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -77,7 +77,7 @@ real(TypeError, 17, InitViaClassSpec, ERROR_CLASP(JSEXN_TYPEERR)) \ real(URIError, 18, InitViaClassSpec, ERROR_CLASP(JSEXN_URIERR)) \ real(Iterator, 19, InitIteratorClasses, OCLASP(PropertyIterator)) \ - real(StopIteration, 20, InitIteratorClasses, OCLASP(StopIteration)) \ + real(StopIteration, 20, InitStopIterationClass, OCLASP(StopIteration)) \ real(ArrayBuffer, 21, InitArrayBufferClass, &js::ArrayBufferObject::protoClass) \ real(Int8Array, 22, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \ real(Uint8Array, 23, InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8)) \ diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 54af37add1b9..3abcc76dc402 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -406,7 +406,7 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle globa InitBareBuiltinCtor(cx, global, JSProto_Uint8Array) && InitBareBuiltinCtor(cx, global, JSProto_Uint32Array) && InitBareWeakMapCtor(cx, global) && - initStopIterationClass(cx, global) && + InitStopIterationClass(cx, global) && InitSelfHostingCollectionIteratorFunctions(cx, global) && JS_DefineFunctions(cx, global, builtins); } diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index e67d36e9b7e5..c594a4c0b0ae 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -708,7 +708,6 @@ class GlobalObject : public NativeObject // Implemented in jsiter.cpp. static bool initIteratorClasses(JSContext* cx, Handle global); - static bool initStopIterationClass(JSContext* cx, Handle global); // Implemented in vm/GeneratorObject.cpp. static bool initGeneratorClasses(JSContext* cx, Handle global); From e815f375b1c4d4d6efb89be9e370582906af7cc2 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Thu, 24 Sep 2015 12:51:55 -0700 Subject: [PATCH 135/247] Bug 1101561 - Fix %ArrayIteratorPrototype% initialization to be OOM-safe. r=jandem --HG-- extra : rebase_source : 1b01d8f6fc9d5c95036c161b8ac241adfe39dca3 --- js/src/jsiter.cpp | 27 +++++++++++++++++++-------- js/src/vm/GlobalObject.h | 8 +++----- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index af3fc24b2a30..e3dbb7da8a60 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1372,6 +1372,25 @@ const Class StopIterationObject::class_ = { stopiter_hasInstance }; +/* static */ bool +GlobalObject::initArrayIteratorProto(JSContext* cx, Handle global) +{ + if (global->getReservedSlot(ARRAY_ITERATOR_PROTO).isObject()) + return true; + + RootedObject iteratorProto(cx, GlobalObject::getOrCreateIteratorPrototype(cx, global)); + if (!iteratorProto) + return false; + + const Class* cls = &ArrayIteratorPrototypeClass; + RootedObject proto(cx, global->createBlankPrototypeInheriting(cx, cls, iteratorProto)); + if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, array_iterator_methods)) + return false; + + global->setReservedSlot(ARRAY_ITERATOR_PROTO, ObjectValue(*proto)); + return true; +} + /* static */ bool GlobalObject::initIteratorClasses(JSContext* cx, Handle global) { @@ -1408,14 +1427,6 @@ GlobalObject::initIteratorClasses(JSContext* cx, Handle global) } RootedObject proto(cx); - if (global->getSlot(ARRAY_ITERATOR_PROTO).isUndefined()) { - const Class* cls = &ArrayIteratorPrototypeClass; - proto = global->createBlankPrototypeInheriting(cx, cls, iteratorProto); - if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, array_iterator_methods)) - return false; - global->setReservedSlot(ARRAY_ITERATOR_PROTO, ObjectValue(*proto)); - } - if (global->getSlot(STRING_ITERATOR_PROTO).isUndefined()) { const Class* cls = &StringIteratorPrototypeClass; proto = global->createBlankPrototype(cx, cls); diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index c594a4c0b0ae..089b06b1ce06 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -534,12 +534,9 @@ class GlobalObject : public NativeObject return &global->getSlot(slot).toObject().as(); } - static NativeObject* getOrCreateArrayIteratorPrototype(JSContext* cx, - Handle global) + static NativeObject* getOrCreateArrayIteratorPrototype(JSContext* cx, Handle global) { - if (!ensureConstructor(cx, global, JSProto_Iterator)) - return nullptr; - return &global->getSlot(ARRAY_ITERATOR_PROTO).toObject().as(); + return MaybeNativeObject(global->getOrCreateObject(cx, ARRAY_ITERATOR_PROTO, initArrayIteratorProto)); } static NativeObject* getOrCreateStringIteratorPrototype(JSContext* cx, @@ -707,6 +704,7 @@ class GlobalObject : public NativeObject bool valueIsEval(Value val); // Implemented in jsiter.cpp. + static bool initArrayIteratorProto(JSContext* cx, Handle global); static bool initIteratorClasses(JSContext* cx, Handle global); // Implemented in vm/GeneratorObject.cpp. From bd623be2ad61490483647fa107417902ff6ba13a Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Thu, 24 Sep 2015 12:51:55 -0700 Subject: [PATCH 136/247] Bug 1101561 - Fix %StringIteratorPrototype% initialization to be OOM-safe. r=jandem --HG-- extra : rebase_source : 536f5a139a86b7749bf9f868e0e7604c0937db98 --- js/src/jsiter.cpp | 24 +++++++++++++++--------- js/src/vm/GlobalObject.h | 5 ++--- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index e3dbb7da8a60..bb44314b4326 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1391,6 +1391,21 @@ GlobalObject::initArrayIteratorProto(JSContext* cx, Handle global return true; } +/* static */ bool +GlobalObject::initStringIteratorProto(JSContext* cx, Handle global) +{ + if (global->getReservedSlot(STRING_ITERATOR_PROTO).isObject()) + return true; + + const Class* cls = &StringIteratorPrototypeClass; + RootedObject proto(cx, global->createBlankPrototype(cx, cls)); + if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods)) + return false; + + global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto)); + return true; +} + /* static */ bool GlobalObject::initIteratorClasses(JSContext* cx, Handle global) { @@ -1426,15 +1441,6 @@ GlobalObject::initIteratorClasses(JSContext* cx, Handle global) } } - RootedObject proto(cx); - if (global->getSlot(STRING_ITERATOR_PROTO).isUndefined()) { - const Class* cls = &StringIteratorPrototypeClass; - proto = global->createBlankPrototype(cx, cls); - if (!proto || !DefinePropertiesAndFunctions(cx, proto, nullptr, string_iterator_methods)) - return false; - global->setReservedSlot(STRING_ITERATOR_PROTO, ObjectValue(*proto)); - } - return true; } diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 089b06b1ce06..1eaab50c03e4 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -542,9 +542,7 @@ class GlobalObject : public NativeObject static NativeObject* getOrCreateStringIteratorPrototype(JSContext* cx, Handle global) { - if (!ensureConstructor(cx, global, JSProto_Iterator)) - return nullptr; - return &global->getSlot(STRING_ITERATOR_PROTO).toObject().as(); + return MaybeNativeObject(global->getOrCreateObject(cx, STRING_ITERATOR_PROTO, initStringIteratorProto)); } static NativeObject* getOrCreateLegacyGeneratorObjectPrototype(JSContext* cx, @@ -705,6 +703,7 @@ class GlobalObject : public NativeObject // Implemented in jsiter.cpp. static bool initArrayIteratorProto(JSContext* cx, Handle global); + static bool initStringIteratorProto(JSContext* cx, Handle global); static bool initIteratorClasses(JSContext* cx, Handle global); // Implemented in vm/GeneratorObject.cpp. From 5cda3c1e752a87f72addb36734802ec3097fa299 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Thu, 24 Sep 2015 12:51:55 -0700 Subject: [PATCH 137/247] Bug 1101561 - Fix %IteratorPrototype% initialization to be OOM-safe. r=jandem --HG-- extra : rebase_source : dc72bcf441d9ee39b893df3ba78cbb6e61c5336f --- js/src/jsiter.cpp | 60 ++++++++++++++++++------------------- js/src/jsiter.h | 3 ++ js/src/jsprototypes.h | 2 +- js/src/vm/GlobalObject.h | 1 - js/src/vm/HelperThreads.cpp | 9 ++---- 5 files changed, 37 insertions(+), 38 deletions(-) diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index bb44314b4326..a87b8ecfaeb2 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1406,42 +1406,42 @@ GlobalObject::initStringIteratorProto(JSContext* cx, Handle globa return true; } -/* static */ bool -GlobalObject::initIteratorClasses(JSContext* cx, Handle global) +JSObject* +js::InitIteratorClass(JSContext* cx, HandleObject obj) { + Handle global = obj.as(); + + if (global->getPrototype(JSProto_Iterator).isObject()) + return &global->getPrototype(JSProto_Iterator).toObject(); + RootedObject iteratorProto(cx); - Value iteratorProtoVal = global->getPrototype(JSProto_Iterator); - if (iteratorProtoVal.isObject()) { - iteratorProto = &iteratorProtoVal.toObject(); - } else { - iteratorProto = global->createBlankPrototype(cx, &PropertyIteratorObject::class_); - if (!iteratorProto) - return false; + iteratorProto = global->createBlankPrototype(cx, &PropertyIteratorObject::class_); + if (!iteratorProto) + return nullptr; - AutoIdVector blank(cx); - NativeIterator* ni = NativeIterator::allocateIterator(cx, 0, blank); - if (!ni) - return false; - ni->init(nullptr, nullptr, 0 /* flags */, 0, 0); + AutoIdVector blank(cx); + NativeIterator* ni = NativeIterator::allocateIterator(cx, 0, blank); + if (!ni) + return nullptr; + ni->init(nullptr, nullptr, 0 /* flags */, 0, 0); - iteratorProto->as().setNativeIterator(ni); + iteratorProto->as().setNativeIterator(ni); - Rooted ctor(cx); - ctor = global->createConstructor(cx, IteratorConstructor, cx->names().Iterator, 2); - if (!ctor) - return false; - if (!LinkConstructorAndPrototype(cx, ctor, iteratorProto)) - return false; - if (!DefinePropertiesAndFunctions(cx, iteratorProto, nullptr, iterator_methods)) - return false; - if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Iterator, - ctor, iteratorProto)) - { - return false; - } + Rooted ctor(cx); + ctor = global->createConstructor(cx, IteratorConstructor, cx->names().Iterator, 2); + if (!ctor) + return nullptr; + if (!LinkConstructorAndPrototype(cx, ctor, iteratorProto)) + return nullptr; + if (!DefinePropertiesAndFunctions(cx, iteratorProto, nullptr, iterator_methods)) + return nullptr; + if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_Iterator, + ctor, iteratorProto)) + { + return nullptr; } - return true; + return &global->getPrototype(JSProto_Iterator).toObject(); } JSObject* @@ -1467,7 +1467,7 @@ JSObject* js::InitIteratorClasses(JSContext* cx, HandleObject obj) { Rooted global(cx, &obj->as()); - if (!GlobalObject::initIteratorClasses(cx, global)) + if (!InitIteratorClass(cx, global)) return nullptr; if (!GlobalObject::initGeneratorClasses(cx, global)) return nullptr; diff --git a/js/src/jsiter.h b/js/src/jsiter.h index 7faba9eed18e..a1b50ee5af58 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -207,6 +207,9 @@ ThrowStopIteration(JSContext* cx); extern JSObject* CreateItrResultObject(JSContext* cx, HandleValue value, bool done); +extern JSObject* +InitIteratorClass(JSContext* cx, HandleObject obj); + extern JSObject* InitStopIterationClass(JSContext* cx, HandleObject obj); diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index 8bd07994aa66..f4fab680d00f 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -76,7 +76,7 @@ real(SyntaxError, 16, InitViaClassSpec, ERROR_CLASP(JSEXN_SYNTAXERR)) \ real(TypeError, 17, InitViaClassSpec, ERROR_CLASP(JSEXN_TYPEERR)) \ real(URIError, 18, InitViaClassSpec, ERROR_CLASP(JSEXN_URIERR)) \ - real(Iterator, 19, InitIteratorClasses, OCLASP(PropertyIterator)) \ + real(Iterator, 19, InitIteratorClass, OCLASP(PropertyIterator)) \ real(StopIteration, 20, InitStopIterationClass, OCLASP(StopIteration)) \ real(ArrayBuffer, 21, InitArrayBufferClass, &js::ArrayBufferObject::protoClass) \ real(Int8Array, 22, InitViaClassSpec, TYPED_ARRAY_CLASP(Int8)) \ diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 1eaab50c03e4..3a5cc425db61 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -704,7 +704,6 @@ class GlobalObject : public NativeObject // Implemented in jsiter.cpp. static bool initArrayIteratorProto(JSContext* cx, Handle global); static bool initStringIteratorProto(JSContext* cx, Handle global); - static bool initIteratorClasses(JSContext* cx, Handle global); // Implemented in vm/GeneratorObject.cpp. static bool initGeneratorClasses(JSContext* cx, Handle global); diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index ae8c10c4294c..7472f3b7d532 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -331,22 +331,19 @@ EnsureParserCreatedClasses(JSContext* cx) { Handle global = cx->global(); - if (!EnsureConstructor(cx, global, JSProto_Object)) - return false; // needed by object literals + if (!EnsureConstructor(cx, global, JSProto_Function)) + return false; // needed by functions, also adds object literals' proto if (!EnsureConstructor(cx, global, JSProto_Array)) return false; // needed by array literals - if (!EnsureConstructor(cx, global, JSProto_Function)) - return false; // needed by functions - if (!EnsureConstructor(cx, global, JSProto_RegExp)) return false; // needed by regular expression literals if (!EnsureConstructor(cx, global, JSProto_Iterator)) return false; // needed by ??? - if (!EnsureConstructor(cx, global, JSProto_GeneratorFunction)) + if (!GlobalObject::initGeneratorClasses(cx, global)) return false; // needed by function*() {} and generator comprehensions return true; From 780b2875a9230c8c6f1d391484bcc6293046e78f Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Thu, 24 Sep 2015 12:51:56 -0700 Subject: [PATCH 138/247] Bug 1101561 - Fix generator bootstrapping (for legacy and star generators both) to be OOM-safe. r=jandem --HG-- extra : rebase_source : a80a7ad7bbac563e489c8c110d9df40a26a161ca --- js/public/Class.h | 2 +- js/src/jsiter.cpp | 11 ----- js/src/jsiter.h | 3 -- js/src/jsprototypes.h | 9 ++-- js/src/vm/CommonPropertyNames.h | 1 + js/src/vm/GeneratorObject.cpp | 85 ++++++++++++++++++--------------- js/src/vm/GlobalObject.h | 28 +++++------ js/src/vm/HelperThreads.cpp | 71 ++++++++++++++++----------- 8 files changed, 109 insertions(+), 101 deletions(-) diff --git a/js/public/Class.h b/js/public/Class.h index 4d9eeaa37ecd..4104dd6bf04f 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -704,7 +704,7 @@ struct JSClass { // application. #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5 #define JSCLASS_GLOBAL_SLOT_COUNT \ - (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 33) + (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 35) #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) #define JSCLASS_GLOBAL_FLAGS \ diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index a87b8ecfaeb2..0c6b6519a174 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -1462,14 +1462,3 @@ js::InitStopIterationClass(JSContext* cx, HandleObject obj) return &global->getPrototype(JSProto_StopIteration).toObject(); } - -JSObject* -js::InitIteratorClasses(JSContext* cx, HandleObject obj) -{ - Rooted global(cx, &obj->as()); - if (!InitIteratorClass(cx, global)) - return nullptr; - if (!GlobalObject::initGeneratorClasses(cx, global)) - return nullptr; - return global->getIteratorPrototype(); -} diff --git a/js/src/jsiter.h b/js/src/jsiter.h index a1b50ee5af58..7fbbbc619b3e 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -213,9 +213,6 @@ InitIteratorClass(JSContext* cx, HandleObject obj); extern JSObject* InitStopIterationClass(JSContext* cx, HandleObject obj); -extern JSObject* -InitIteratorClasses(JSContext* cx, HandleObject obj); - } /* namespace js */ #endif /* jsiter_h */ diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index f4fab680d00f..e9e413ebef10 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -97,7 +97,7 @@ IF_SAB(real,imaginary)(SharedArrayBuffer, 37, InitSharedArrayBufferClass, &js::SharedArrayBufferObject::protoClass) \ IF_INTL(real,imaginary) (Intl, 38, InitIntlClass, CLASP(Intl)) \ IF_BDATA(real,imaginary)(TypedObject, 39, InitTypedObjectModuleObject, OCLASP(TypedObjectModule)) \ - imaginary(GeneratorFunction, 40, InitIteratorClasses, dummy) \ + real(Reflect, 40, InitReflect, nullptr) \ IF_BDATA(real,imaginary)(SIMD, 41, InitSIMDClass, OCLASP(SIMD)) \ real(WeakSet, 42, InitWeakSetClass, OCLASP(WeakSet)) \ IF_SAB(real,imaginary)(SharedInt8Array, 43, InitViaClassSpec, SHARED_TYPED_ARRAY_CLASP(Int8)) \ @@ -112,10 +112,9 @@ IF_SAB(real,imaginary)(SharedUint8ClampedArray, 51, InitViaClassSpec, real(TypedArray, 52, InitViaClassSpec, &js::TypedArrayObject::sharedTypedArrayPrototypeClass) \ IF_SAB(real,imaginary)(Atomics, 53, InitAtomicsClass, OCLASP(Atomics)) \ real(SavedFrame, 54, InitViaClassSpec, &js::SavedFrame::class_) \ - real(Reflect, 55, InitReflect, nullptr) \ - real(Module, 56, InitModuleClass, OCLASP(Module)) \ - real(ImportEntry, 57, InitImportEntryClass, OCLASP(ImportEntry)) \ - real(ExportEntry, 58, InitExportEntryClass, OCLASP(ExportEntry)) \ + real(Module, 55, InitModuleClass, OCLASP(Module)) \ + real(ImportEntry, 56, InitImportEntryClass, OCLASP(ImportEntry)) \ + real(ExportEntry, 57, InitExportEntryClass, OCLASP(ExportEntry)) \ #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro) diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 23b7ba8ce5c4..16276f406fa7 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -93,6 +93,7 @@ macro(frame, frame, "frame") \ macro(from, from, "from") \ macro(gcCycleNumber, gcCycleNumber, "gcCycleNumber") \ + macro(GeneratorFunction, GeneratorFunction, "GeneratorFunction") \ macro(get, get, "get") \ macro(getInternals, getInternals, "getInternals") \ macro(getOwnPropertyDescriptor, getOwnPropertyDescriptor, "getOwnPropertyDescriptor") \ diff --git a/js/src/vm/GeneratorObject.cpp b/js/src/vm/GeneratorObject.cpp index e3c48faaf4c9..557d5b641b32 100644 --- a/js/src/vm/GeneratorObject.cpp +++ b/js/src/vm/GeneratorObject.cpp @@ -287,47 +287,54 @@ NewSingletonObjectWithFunctionPrototype(JSContext* cx, Handle glo } /* static */ bool -GlobalObject::initGeneratorClasses(JSContext* cx, Handle global) +GlobalObject::initLegacyGeneratorProto(JSContext* cx, Handle global) { - if (global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).isUndefined()) { - RootedObject proto(cx, NewSingletonObjectWithObjectPrototype(cx, global)); - if (!proto || !proto->setDelegate(cx)) - return false; - if (!DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods)) - return false; - global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto)); - } + if (global->getReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO).isObject()) + return true; - if (global->getSlot(STAR_GENERATOR_OBJECT_PROTO).isUndefined()) { - RootedObject genObjectProto(cx, NewSingletonObjectWithObjectPrototype(cx, global)); - if (!genObjectProto || !genObjectProto->setDelegate(cx)) - return false; - if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods)) - return false; - - RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global)); - if (!genFunctionProto || !genFunctionProto->setDelegate(cx)) - return false; - if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto)) - return false; - - RootedValue function(cx, global->getConstructor(JSProto_Function)); - if (!function.toObjectOrNull()) - return false; - RootedObject proto(cx, &function.toObject()); - RootedAtom name(cx, cx->names().GeneratorFunction); - RootedObject genFunction(cx, NewFunctionWithProto(cx, Generator, 1, - JSFunction::NATIVE_CTOR, nullptr, name, - proto)); - if (!genFunction) - return false; - if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto)) - return false; - - global->setSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto)); - global->setConstructor(JSProto_GeneratorFunction, ObjectValue(*genFunction)); - global->setPrototype(JSProto_GeneratorFunction, ObjectValue(*genFunctionProto)); - } + RootedObject proto(cx, NewSingletonObjectWithObjectPrototype(cx, global)); + if (!proto || !proto->setDelegate(cx)) + return false; + if (!DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods)) + return false; + global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto)); + return true; +} + +/* static */ bool +GlobalObject::initStarGenerators(JSContext* cx, Handle global) +{ + if (global->getReservedSlot(STAR_GENERATOR_OBJECT_PROTO).isObject()) + return true; + + RootedObject genObjectProto(cx, NewSingletonObjectWithObjectPrototype(cx, global)); + if (!genObjectProto || !genObjectProto->setDelegate(cx)) + return false; + if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods)) + return false; + + RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global)); + if (!genFunctionProto || !genFunctionProto->setDelegate(cx)) + return false; + if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto)) + return false; + + RootedValue function(cx, global->getConstructor(JSProto_Function)); + if (!function.toObjectOrNull()) + return false; + RootedObject proto(cx, &function.toObject()); + RootedAtom name(cx, cx->names().GeneratorFunction); + RootedObject genFunction(cx, NewFunctionWithProto(cx, Generator, 1, + JSFunction::NATIVE_CTOR, nullptr, name, + proto)); + if (!genFunction) + return false; + if (!LinkConstructorAndPrototype(cx, genFunction, genFunctionProto)) + return false; + + global->setReservedSlot(STAR_GENERATOR_OBJECT_PROTO, ObjectValue(*genObjectProto)); + global->setReservedSlot(STAR_GENERATOR_FUNCTION, ObjectValue(*genFunction)); + global->setReservedSlot(STAR_GENERATOR_FUNCTION_PROTO, ObjectValue(*genFunctionProto)); return true; } diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index 3a5cc425db61..68a9e621ebe4 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -95,6 +95,8 @@ class GlobalObject : public NativeObject STRING_ITERATOR_PROTO, LEGACY_GENERATOR_OBJECT_PROTO, STAR_GENERATOR_OBJECT_PROTO, + STAR_GENERATOR_FUNCTION_PROTO, + STAR_GENERATOR_FUNCTION, MAP_ITERATOR_PROTO, SET_ITERATOR_PROTO, COLLATOR_PROTO, @@ -548,34 +550,26 @@ class GlobalObject : public NativeObject static NativeObject* getOrCreateLegacyGeneratorObjectPrototype(JSContext* cx, Handle global) { - if (!ensureConstructor(cx, global, JSProto_Iterator)) - return nullptr; - return &global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).toObject().as(); + return MaybeNativeObject(global->getOrCreateObject(cx, LEGACY_GENERATOR_OBJECT_PROTO, + initLegacyGeneratorProto)); } static NativeObject* getOrCreateStarGeneratorObjectPrototype(JSContext* cx, Handle global) { - if (!ensureConstructor(cx, global, JSProto_Iterator)) - return nullptr; - return &global->getSlot(STAR_GENERATOR_OBJECT_PROTO).toObject().as(); + return MaybeNativeObject(global->getOrCreateObject(cx, STAR_GENERATOR_OBJECT_PROTO, initStarGenerators)); } static NativeObject* getOrCreateStarGeneratorFunctionPrototype(JSContext* cx, Handle global) { - if (!ensureConstructor(cx, global, JSProto_Iterator)) - return nullptr; - size_t slot = APPLICATION_SLOTS + JSProto_LIMIT + JSProto_GeneratorFunction; - return &global->getSlot(slot).toObject().as(); + return MaybeNativeObject(global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION_PROTO, initStarGenerators)); } static JSObject* getOrCreateStarGeneratorFunction(JSContext* cx, Handle global) { - if (!ensureConstructor(cx, global, JSProto_Iterator)) - return nullptr; - return &global->getSlot(APPLICATION_SLOTS + JSProto_GeneratorFunction).toObject(); + return global->getOrCreateObject(cx, STAR_GENERATOR_FUNCTION, initStarGenerators); } static JSObject* getOrCreateMapIteratorPrototype(JSContext* cx, @@ -706,7 +700,8 @@ class GlobalObject : public NativeObject static bool initStringIteratorProto(JSContext* cx, Handle global); // Implemented in vm/GeneratorObject.cpp. - static bool initGeneratorClasses(JSContext* cx, Handle global); + static bool initLegacyGeneratorProto(JSContext* cx, Handle global); + static bool initStarGenerators(JSContext* cx, Handle global); // Implemented in builtin/MapObject.cpp. static bool initMapIteratorProto(JSContext* cx, Handle global); @@ -759,6 +754,11 @@ class GlobalObject : public NativeObject return &value.toObject().as(); } + + // Returns either this global's star-generator function prototype, or null + // if that object was never created. Dodgy; for use only in also-dodgy + // GlobalHelperThreadState::mergeParseTaskCompartment(). + JSObject* getStarGeneratorFunctionPrototype(); }; template<> diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 7472f3b7d532..079f3240026e 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -343,7 +343,7 @@ EnsureParserCreatedClasses(JSContext* cx) if (!EnsureConstructor(cx, global, JSProto_Iterator)) return false; // needed by ??? - if (!GlobalObject::initGeneratorClasses(cx, global)) + if (!GlobalObject::initStarGenerators(cx, global)) return false; // needed by function*() {} and generator comprehensions return true; @@ -974,6 +974,13 @@ GlobalHelperThreadState::finishParseTask(JSContext* maybecx, JSRuntime* rt, void return script; } +JSObject* +GlobalObject::getStarGeneratorFunctionPrototype() +{ + const Value& v = getReservedSlot(STAR_GENERATOR_FUNCTION_PROTO); + return v.isObject() ? &v.toObject() : nullptr; +} + void GlobalHelperThreadState::mergeParseTaskCompartment(JSRuntime* rt, ParseTask* parseTask, Handle global, @@ -988,37 +995,45 @@ GlobalHelperThreadState::mergeParseTaskCompartment(JSRuntime* rt, ParseTask* par LeaveParseTaskZone(rt, parseTask); - // Point the prototypes of any objects in the script's compartment to refer - // to the corresponding prototype in the new compartment. This will briefly - // create cross compartment pointers, which will be fixed by the - // MergeCompartments call below. - for (gc::ZoneCellIter iter(parseTask->cx->zone(), gc::AllocKind::OBJECT_GROUP); - !iter.done(); - iter.next()) { - ObjectGroup* group = iter.get(); - TaggedProto proto(group->proto()); - if (!proto.isObject()) - continue; + gc::ZoneCellIter iter(parseTask->cx->zone(), gc::AllocKind::OBJECT_GROUP); - JSProtoKey key = JS::IdentifyStandardPrototype(proto.toObject()); - if (key == JSProto_Null) { - // Generator functions don't have Function.prototype as prototype - // but a different function object, so IdentifyStandardPrototype - // doesn't work. Just special-case it here. - if (IsStandardPrototype(proto.toObject(), JSProto_GeneratorFunction)) - key = JSProto_GeneratorFunction; - else + // Generator functions don't have Function.prototype as prototype but a + // different function object, so the IdentifyStandardPrototype trick + // below won't work. Just special-case it. + JSObject* parseTaskStarGenFunctionProto = + parseTask->exclusiveContextGlobal->as().getStarGeneratorFunctionPrototype(); + + // Point the prototypes of any objects in the script's compartment to refer + // to the corresponding prototype in the new compartment. This will briefly + // create cross compartment pointers, which will be fixed by the + // MergeCompartments call below. + for (; !iter.done(); iter.next()) { + ObjectGroup* group = iter.get(); + TaggedProto proto(group->proto()); + if (!proto.isObject()) continue; + + JSObject* protoObj = proto.toObject(); + + JSObject* newProto; + if (protoObj == parseTaskStarGenFunctionProto) { + newProto = global->getStarGeneratorFunctionPrototype(); + } else { + JSProtoKey key = JS::IdentifyStandardPrototype(protoObj); + if (key == JSProto_Null) + continue; + + MOZ_ASSERT(key == JSProto_Object || key == JSProto_Array || + key == JSProto_Function || key == JSProto_RegExp || + key == JSProto_Iterator); + + newProto = GetBuiltinPrototypePure(global, key); + } + + MOZ_ASSERT(newProto); + group->setProtoUnchecked(TaggedProto(newProto)); } - MOZ_ASSERT(key == JSProto_Object || key == JSProto_Array || - key == JSProto_Function || key == JSProto_RegExp || - key == JSProto_Iterator || key == JSProto_GeneratorFunction); - - JSObject* newProto = GetBuiltinPrototypePure(global, key); - MOZ_ASSERT(newProto); - - group->setProtoUnchecked(TaggedProto(newProto)); } // Move the parsed script and all its contents into the desired compartment. From 895856cf29856cb511fb48951d5c4d48d42c7704 Mon Sep 17 00:00:00 2001 From: Neil Deakin Date: Fri, 25 Sep 2015 21:14:43 -0400 Subject: [PATCH 139/247] Bug 1199239, remove cpow usage from bookmark this page, r=mak --- browser/base/content/browser-places.js | 57 +++++++++++-------- browser/base/content/content.js | 8 +++ .../test/general/browser_bookmark_titles.js | 55 +++++++++++------- .../content/test/general/browser_star_hsts.js | 31 +--------- browser/base/content/test/general/head.js | 31 ++++++++++ browser/components/feeds/FeedConverter.js | 3 +- 6 files changed, 111 insertions(+), 74 deletions(-) diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js index aba7ca6298bc..3b2d17a1b3cf 100644 --- a/browser/base/content/browser-places.js +++ b/browser/base/content/browser-places.js @@ -334,13 +334,14 @@ var PlacesCommandHook = { var title; var description; var charset; + + let docInfo = yield this._getPageDetails(aBrowser); + try { - let isErrorPage = /^about:(neterror|certerror|blocked)/ - .test(aBrowser.contentDocumentAsCPOW.documentURI); - title = isErrorPage ? PlacesUtils.history.getPageTitle(uri) - : aBrowser.contentTitle; + title = docInfo.isErrorPage ? PlacesUtils.history.getPageTitle(uri) + : aBrowser.contentTitle; title = title || uri.spec; - description = PlacesUIUtils.getDescriptionFromDocument(aBrowser.contentDocumentAsCPOW); + description = docInfo.description; charset = aBrowser.characterSet; } catch (e) { } @@ -405,14 +406,15 @@ var PlacesCommandHook = { // Bug 1148838 - Make this code work for full page plugins. let description = null; let charset = null; + + let docInfo = yield this._getPageDetails(aBrowser); + try { - let isErrorPage = /^about:(neterror|certerror|blocked)/ - .test(aBrowser.contentDocumentAsCPOW.documentURI); - info.title = isErrorPage ? + info.title = docInfo.isErrorPage ? (yield PlacesUtils.promisePlaceInfo(aBrowser.currentURI)).title : aBrowser.contentTitle; info.title = info.title || url.href; - description = PlacesUIUtils.getDescriptionFromDocument(aBrowser.contentDocumentAsCPOW); + description = docInfo.description; charset = aBrowser.characterSet; } catch (e) { @@ -467,6 +469,18 @@ var PlacesCommandHook = { } }), + _getPageDetails(browser) { + return new Promise(resolve => { + let mm = browser.messageManager; + mm.addMessageListener("Bookmarks:GetPageDetails:Result", function listener(msg) { + mm.removeMessageListener("Bookmarks:GetPageDetails:Result", listener); + resolve(msg.data); + }); + + mm.sendAsyncMessage("Bookmarks:GetPageDetails", { }) + }); + }, + /** * Adds a bookmark to the page loaded in the current tab. */ @@ -568,21 +582,18 @@ var PlacesCommandHook = { * @subtitle subtitle * A short description of the feed. Optional. */ - addLiveBookmark: function PCH_addLiveBookmark(url, feedTitle, feedSubtitle) { - var feedURI = makeURI(url); - - var doc = gBrowser.contentDocumentAsCPOW; - var title = (arguments.length > 1) ? feedTitle : doc.title; - - var description; - if (arguments.length > 2) - description = feedSubtitle; - else - description = PlacesUIUtils.getDescriptionFromDocument(doc); - - var toolbarIP = new InsertionPoint(PlacesUtils.toolbarFolderId, + addLiveBookmark: Task.async(function *(url, feedTitle, feedSubtitle) { + let toolbarIP = new InsertionPoint(PlacesUtils.toolbarFolderId, PlacesUtils.bookmarks.DEFAULT_INDEX, Components.interfaces.nsITreeView.DROP_ON); + + let feedURI = makeURI(url); + let title = feedTitle || gBrowser.contentTitle; + let description = feedSubtitle; + if (!description) { + description = (yield this._getPageDetails(gBrowser.selectedBrowser)).description; + } + PlacesUIUtils.showBookmarkDialog({ action: "add" , type: "livemark" , feedURI: feedURI @@ -594,7 +605,7 @@ var PlacesCommandHook = { , "siteLocation" , "description" ] }, window); - }, + }), /** * Opens the Places Organizer. diff --git a/browser/base/content/content.js b/browser/base/content/content.js index 1ee74f279e0e..769fdce42e4e 100644 --- a/browser/base/content/content.js +++ b/browser/base/content/content.js @@ -753,6 +753,14 @@ addMessageListener("ContextMenu:SearchFieldBookmarkData", (message) => { { spec, title, description, postData, charset }); }); +addMessageListener("Bookmarks:GetPageDetails", (message) => { + let doc = content.document; + let isErrorPage = /^about:(neterror|certerror|blocked)/.test(doc.documentURI); + sendAsyncMessage("Bookmarks:GetPageDetails:Result", + { isErrorPage: isErrorPage, + description: PlacesUIUtils.getDescriptionFromDocument(doc) }); +}); + var LightWeightThemeWebInstallListener = { _previewWindow: null, diff --git a/browser/base/content/test/general/browser_bookmark_titles.js b/browser/base/content/test/general/browser_bookmark_titles.js index 98f624c03509..b962337508ad 100644 --- a/browser/base/content/test/general/browser_bookmark_titles.js +++ b/browser/base/content/test/general/browser_bookmark_titles.js @@ -19,30 +19,19 @@ var tests = [ 'https://untrusted.example.com/somepage.html'] ]; -function generatorTest() { +add_task(function* () { gBrowser.selectedTab = gBrowser.addTab(); let browser = gBrowser.selectedBrowser; browser.stop(); // stop the about:blank load. - browser.addEventListener("DOMContentLoaded", event => { - if (event.originalTarget != browser.contentDocument || - event.target.location.href == "about:blank") { - info("skipping spurious load event"); - return; - } - nextStep(); - }, true); - registerCleanupFunction(function () { - browser.removeEventListener("DOMContentLoaded", nextStep, true); - gBrowser.removeCurrentTab(); - }); - // Test that a bookmark of each URI gets the corresponding default title. for (let i = 0; i < tests.length; ++i) { let [uri, title] = tests[i]; + + let promiseLoaded = promisePageLoaded(browser); content.location = uri; - yield undefined; - checkBookmark(uri, title); + yield promiseLoaded; + yield checkBookmark(uri, title); } // Network failure test: now that dummy_page.html is in history, bookmarking @@ -62,20 +51,28 @@ function generatorTest() { Services.cache2.clear(); let [uri, title] = tests[0]; + + let promiseLoaded = promisePageLoaded(browser); content.location = uri; - yield undefined; + yield promiseLoaded; + // The offline mode test is only good if the page failed to load. is(content.document.documentURI.substring(0, 14), 'about:neterror', "Offline mode successfully simulated network outage."); - checkBookmark(uri, title); -} + yield checkBookmark(uri, title); + + gBrowser.removeCurrentTab(); +}); // Bookmark the current page and confirm that the new bookmark has the expected // title. (Then delete the bookmark.) -function checkBookmark(uri, expected_title) { +function* checkBookmark(uri, expected_title) { is(gBrowser.selectedBrowser.currentURI.spec, uri, "Trying to bookmark the expected uri"); + + let promiseBookmark = promiseOnBookmarkItemAdded(gBrowser.selectedBrowser.currentURI); PlacesCommandHook.bookmarkCurrentPage(false); + yield promiseBookmark; let id = PlacesUtils.getMostRecentBookmarkForURI(PlacesUtils._uri(uri)); ok(id > 0, "Found the expected bookmark"); @@ -84,3 +81,21 @@ function checkBookmark(uri, expected_title) { PlacesUtils.bookmarks.removeItem(id); } + +// BrowserTestUtils.browserLoaded doesn't work for the about pages, so use a +// custom page load listener. +function promisePageLoaded(browser) +{ + return new Promise(resolve => { + browser.addEventListener("DOMContentLoaded", function pageLoaded(event) { + browser.removeEventListener("DOMContentLoaded", pageLoaded, true); + + if (event.originalTarget != browser.contentDocument || + event.target.location.href == "about:blank") { + info("skipping spurious load event"); + return; + } + resolve(); + }, true); + }); +} diff --git a/browser/base/content/test/general/browser_star_hsts.js b/browser/base/content/test/general/browser_star_hsts.js index eee6a28aa622..c52e563bc661 100644 --- a/browser/base/content/test/general/browser_star_hsts.js +++ b/browser/base/content/test/general/browser_star_hsts.js @@ -24,7 +24,7 @@ add_task(function* test_star_redirect() { yield promiseStarState(BookmarkingUI.STATUS_UNSTARRED); - let promiseBookmark = promiseOnItemAdded(gBrowser.currentURI); + let promiseBookmark = promiseOnBookmarkItemAdded(gBrowser.currentURI); BookmarkingUI.star.click(); // This resolves on the next tick, so the star should have already been // updated at that point. @@ -83,32 +83,3 @@ function promiseTabLoadEvent(aTab, aURL, aFinalURL) aTab.linkedBrowser.loadURI(aURL); return deferred.promise; } - -/** - * Waits for a bookmark to be added for the given uri. - */ -function promiseOnItemAdded(aExpectedURI) { - let defer = Promise.defer(); - let bookmarksObserver = { - onItemAdded: function (aItemId, aFolderId, aIndex, aItemType, aURI) { - info("Added a bookmark to " + aURI.spec); - PlacesUtils.bookmarks.removeObserver(bookmarksObserver); - if (aURI.equals(aExpectedURI)) - defer.resolve(); - else - defer.reject(new Error("Added an unexpected bookmark")); - }, - onBeginUpdateBatch: function () {}, - onEndUpdateBatch: function () {}, - onItemRemoved: function () {}, - onItemChanged: function () {}, - onItemVisited: function () {}, - onItemMoved: function () {}, - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsINavBookmarkObserver, - ]) - }; - info("Waiting for a bookmark to be added"); - PlacesUtils.bookmarks.addObserver(bookmarksObserver, false); - return defer.promise; -} diff --git a/browser/base/content/test/general/head.js b/browser/base/content/test/general/head.js index 4388969d55b9..1d9b0258024d 100644 --- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -1072,3 +1072,34 @@ function isSecurityState(expectedState) { is(expectedState, actualState, "Expected state " + expectedState + " and the actual state is " + actualState + "."); } + +/** + * Resolves when a bookmark with the given uri is added. + */ +function promiseOnBookmarkItemAdded(aExpectedURI) { + return new Promise((resolve, reject) => { + let bookmarksObserver = { + onItemAdded: function (aItemId, aFolderId, aIndex, aItemType, aURI) { + info("Added a bookmark to " + aURI.spec); + PlacesUtils.bookmarks.removeObserver(bookmarksObserver); + if (aURI.equals(aExpectedURI)) { + resolve(); + } + else { + reject(new Error("Added an unexpected bookmark")); + } + }, + onBeginUpdateBatch: function () {}, + onEndUpdateBatch: function () {}, + onItemRemoved: function () {}, + onItemChanged: function () {}, + onItemVisited: function () {}, + onItemMoved: function () {}, + QueryInterface: XPCOMUtils.generateQI([ + Ci.nsINavBookmarkObserver, + ]) + }; + info("Waiting for a bookmark to be added"); + PlacesUtils.bookmarks.addObserver(bookmarksObserver, false); + }); +} diff --git a/browser/components/feeds/FeedConverter.js b/browser/components/feeds/FeedConverter.js index a6ecfb4575db..742bbcca57d0 100644 --- a/browser/components/feeds/FeedConverter.js +++ b/browser/components/feeds/FeedConverter.js @@ -424,7 +424,8 @@ FeedResultService.prototype = { Cc["@mozilla.org/appshell/window-mediator;1"]. getService(Ci.nsIWindowMediator); var topWindow = wm.getMostRecentWindow("navigator:browser"); - topWindow.PlacesCommandHook.addLiveBookmark(spec, title, subtitle); + topWindow.PlacesCommandHook.addLiveBookmark(spec, title, subtitle) + .catch(Components.utils.reportError); break; } }, From 04e5ed4966b0c02e5a329ac3368ba24bb3c85ede Mon Sep 17 00:00:00 2001 From: Francois Marier Date: Fri, 25 Sep 2015 20:39:49 -0700 Subject: [PATCH 140/247] Bug 1208285 - Improve TP debug logging. r=gcp --- netwerk/base/nsChannelClassifier.cpp | 112 +++++++++++++-------------- 1 file changed, 54 insertions(+), 58 deletions(-) diff --git a/netwerk/base/nsChannelClassifier.cpp b/netwerk/base/nsChannelClassifier.cpp index 02adbe609f87..9b8e35a1e098 100644 --- a/netwerk/base/nsChannelClassifier.cpp +++ b/netwerk/base/nsChannelClassifier.cpp @@ -30,9 +30,9 @@ #include "nsPIDOMWindow.h" #include "nsXULAppAPI.h" -#include "mozilla/Preferences.h" - +#include "mozilla/ErrorNames.h" #include "mozilla/Logging.h" +#include "mozilla/Preferences.h" using mozilla::ArrayLength; using mozilla::Preferences; @@ -43,6 +43,7 @@ using mozilla::Preferences; static PRLogModuleInfo *gChannelClassifierLog; #undef LOG #define LOG(args) MOZ_LOG(gChannelClassifierLog, mozilla::LogLevel::Debug, args) +#define LOG_ENABLED() MOZ_LOG_TEST(gChannelClassifierLog, mozilla::LogLevel::Debug) NS_IMPL_ISUPPORTS(nsChannelClassifier, nsIURIClassifierCallback) @@ -104,15 +105,15 @@ nsChannelClassifier::ShouldEnableTrackingProtection(nsIChannel *aChannel, thirdPartyUtil->IsThirdPartyURI(chanURI, topWinURI, &isThirdPartyWindow); thirdPartyUtil->IsThirdPartyChannel(aChannel, nullptr, &isThirdPartyChannel); if (!isThirdPartyWindow || !isThirdPartyChannel) { - *result = false; -#ifdef DEBUG - nsCString spec; + *result = false; + if (LOG_ENABLED()) { + nsAutoCString spec; chanURI->GetSpec(spec); - LOG(("nsChannelClassifier[%p]: Skipping tracking protection checks for " - "first party or top-level load channel[%p] with uri %s", this, aChannel, - spec.get())); -#endif - return NS_OK; + LOG(("nsChannelClassifier[%p]: Skipping tracking protection checks " + "for first party or top-level load channel[%p] with uri %s", + this, aChannel, spec.get())); + } + return NS_OK; } nsCOMPtr ios = do_GetService(NS_IOSERVICE_CONTRACTID, &rv); @@ -152,14 +153,9 @@ nsChannelClassifier::ShouldEnableTrackingProtection(nsIChannel *aChannel, rv = permMgr->TestPermission(topWinURI, "trackingprotection", &permissions); NS_ENSURE_SUCCESS(rv, rv); -#ifdef DEBUG - if (permissions == nsIPermissionManager::ALLOW_ACTION) { - LOG(("nsChannelClassifier[%p]: Allowlisting channel[%p] for %s", this, - aChannel, escaped.get())); - } -#endif - if (permissions == nsIPermissionManager::ALLOW_ACTION) { + LOG(("nsChannelClassifier[%p]: Allowlisting channel[%p] for %s", this, + aChannel, escaped.get())); mIsAllowListed = true; *result = false; } else { @@ -189,15 +185,14 @@ nsChannelClassifier::ShouldEnableTrackingProtection(nsIChannel *aChannel, // the security state. If any channels are subsequently cancelled // (page elements blocked) the state will be then updated. if (*result) { -#ifdef DEBUG - nsCString topspec; - nsCString spec; - topWinURI->GetSpec(topspec); - chanURI->GetSpec(spec); - LOG(("nsChannelClassifier[%p]: Enabling tracking protection checks on channel[%p] " - "with uri %s for toplevel window %s", this, aChannel, spec.get(), - topspec.get())); -#endif + if (LOG_ENABLED()) { + nsAutoCString topspec, spec; + topWinURI->GetSpec(topspec); + chanURI->GetSpec(spec); + LOG(("nsChannelClassifier[%p]: Enabling tracking protection checks on " + "channel[%p] with uri %s for toplevel window %s", this, aChannel, + spec.get(), topspec.get())); + } return NS_OK; } @@ -341,18 +336,15 @@ nsChannelClassifier::StartInternal() bool trackingProtectionEnabled = false; (void)ShouldEnableTrackingProtection(mChannel, &trackingProtectionEnabled); -#ifdef DEBUG - { - nsCString uriSpec; + if (LOG_ENABLED()) { + nsAutoCString uriSpec, principalSpec; uri->GetSpec(uriSpec); nsCOMPtr principalURI; principal->GetURI(getter_AddRefs(principalURI)); - nsCString principalSpec; principalURI->GetSpec(principalSpec); - LOG(("nsChannelClassifier: Classifying principal %s on channel with uri %s " - "[this=%p]", principalSpec.get(), uriSpec.get(), this)); + LOG(("nsChannelClassifier[%p]: Classifying principal %s on channel with " + "uri %s", this, principalSpec.get(), uriSpec.get())); } -#endif rv = uriClassifier->Classify(principal, trackingProtectionEnabled, this, &expectCallback); if (NS_FAILED(rv)) { @@ -623,33 +615,37 @@ nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode) } if (mSuspendedChannel) { - LOG(("nsChannelClassifier[%p]:OnClassifyComplete %d (suspended channel)", - this, aErrorCode)); - MarkEntryClassified(aErrorCode); + nsAutoCString errorName; + if (LOG_ENABLED()) { + mozilla::GetErrorName(aErrorCode, errorName); + LOG(("nsChannelClassifier[%p]:OnClassifyComplete %s (suspended channel)", + this, errorName.get())); + } + MarkEntryClassified(aErrorCode); - if (NS_FAILED(aErrorCode)) { -#ifdef DEBUG - nsCOMPtr uri; - mChannel->GetURI(getter_AddRefs(uri)); - nsCString spec; - uri->GetSpec(spec); - LOG(("nsChannelClassifier[%p]: cancelling channel %p for %s " - "with error code: %x", this, mChannel.get(), - spec.get(), aErrorCode)); -#endif - - // Channel will be cancelled (page element blocked) due to tracking. - // Do update the security state of the document and fire a security - // change event. - if (aErrorCode == NS_ERROR_TRACKING_URI) { - SetBlockedTrackingContent(mChannel); - } - - mChannel->Cancel(aErrorCode); + if (NS_FAILED(aErrorCode)) { + if (LOG_ENABLED()) { + nsCOMPtr uri; + mChannel->GetURI(getter_AddRefs(uri)); + nsAutoCString spec; + uri->GetSpec(spec); + LOG(("nsChannelClassifier[%p]: cancelling channel %p for %s " + "with error code %s", this, mChannel.get(), + spec.get(), errorName.get())); } - LOG(("nsChannelClassifier[%p]: resuming channel %p from " - "OnClassifyComplete", this, mChannel.get())); - mChannel->Resume(); + + // Channel will be cancelled (page element blocked) due to tracking. + // Do update the security state of the document and fire a security + // change event. + if (aErrorCode == NS_ERROR_TRACKING_URI) { + SetBlockedTrackingContent(mChannel); + } + + mChannel->Cancel(aErrorCode); + } + LOG(("nsChannelClassifier[%p]: resuming channel %p from " + "OnClassifyComplete", this, mChannel.get())); + mChannel->Resume(); } mChannel = nullptr; From 627b3ff6cae4dae851719a235e24efad2b7582c8 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Sat, 26 Sep 2015 00:30:02 -0700 Subject: [PATCH 141/247] Bug 1208517 - Use the legacy opt-out in CanAccessNativeAnon for now to avoid crashes. r=me --- dom/base/nsContentUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 66e4bd13b395..32b6be7c9f5f 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -6098,7 +6098,7 @@ nsContentTypeParser::GetParameter(const char* aParameterName, nsAString& aResult bool nsContentUtils::CanAccessNativeAnon() { - return IsCallerChrome() || IsCallerContentXBL(); + return LegacyIsCallerChromeOrNativeCode() || IsCallerContentXBL(); } /* static */ nsresult From 2648aa62519fd39535baf39ea80d1397063cbf86 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Mon, 21 Sep 2015 23:39:00 -0700 Subject: [PATCH 142/247] Bug 1208353 - Fix -Wshadow warnings in dom/audiochannel. r=padenot --HG-- extra : rebase_source : 0eb4688dc114e21a9b1607c14453439b3aff8ab0 --- dom/audiochannel/AudioChannelService.cpp | 12 ++++++------ dom/audiochannel/moz.build | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/dom/audiochannel/AudioChannelService.cpp b/dom/audiochannel/AudioChannelService.cpp index 634a27a7a10a..9ec4005a7dda 100644 --- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -359,9 +359,9 @@ AudioChannelService::GetState(nsPIDOMWindow* aWindow, uint32_t aAudioChannel, bool AudioChannelService::TelephonyChannelIsActive() { - nsTObserverArray>::ForwardIterator iter(mWindows); - while (iter.HasMore()) { - AudioChannelWindow* next = iter.GetNext(); + nsTObserverArray>::ForwardIterator windowsIter(mWindows); + while (windowsIter.HasMore()) { + AudioChannelWindow* next = windowsIter.GetNext(); if (next->mChannels[(uint32_t)AudioChannel::Telephony].mNumberOfAgents != 0 && !next->mChannels[(uint32_t)AudioChannel::Telephony].mMuted) { return true; @@ -370,9 +370,9 @@ AudioChannelService::TelephonyChannelIsActive() if (IsParentProcess()) { nsTObserverArray>::ForwardIterator - iter(mPlayingChildren); - while (iter.HasMore()) { - AudioChannelChildStatus* child = iter.GetNext(); + childrenIter(mPlayingChildren); + while (childrenIter.HasMore()) { + AudioChannelChildStatus* child = childrenIter.GetNext(); if (child->mActiveTelephonyChannel) { return true; } diff --git a/dom/audiochannel/moz.build b/dom/audiochannel/moz.build index 0c6a489a2ddf..f8bf7c25f7d6 100644 --- a/dom/audiochannel/moz.build +++ b/dom/audiochannel/moz.build @@ -24,3 +24,6 @@ UNIFIED_SOURCES += [ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' + +if CONFIG['GNU_CXX']: + CXXFLAGS += ['-Wshadow'] From ba99adc235c50571f78c448814d19f9c3f5ea4a4 Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Sat, 26 Sep 2015 01:36:19 -0700 Subject: [PATCH 143/247] Bug 1207378 (Part 1) - Add support for a frame rect to Downscaler. r=tn --- image/Downscaler.cpp | 35 +++++++++++++++++++++++++++++++- image/Downscaler.h | 13 ++++++++++-- image/decoders/nsBMPDecoder.cpp | 3 ++- image/decoders/nsGIFDecoder2.cpp | 2 +- image/decoders/nsICODecoder.cpp | 2 +- image/decoders/nsIconDecoder.cpp | 2 +- image/decoders/nsJPEGDecoder.cpp | 2 +- image/decoders/nsPNGDecoder.cpp | 3 ++- 8 files changed, 53 insertions(+), 9 deletions(-) diff --git a/image/Downscaler.cpp b/image/Downscaler.cpp index 0700eeb32295..a01b67c3a391 100644 --- a/image/Downscaler.cpp +++ b/image/Downscaler.cpp @@ -57,6 +57,7 @@ Downscaler::ReleaseWindow() nsresult Downscaler::BeginFrame(const nsIntSize& aOriginalSize, + const Maybe& aFrameRect, uint8_t* aOutputBuffer, bool aHasAlpha, bool aFlipVertically /* = false */) @@ -71,6 +72,17 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize, MOZ_ASSERT(aOriginalSize.width > 0 && aOriginalSize.height > 0, "Invalid original size"); + mFrameRect = aFrameRect.valueOr(nsIntRect(nsIntPoint(), aOriginalSize)); + MOZ_ASSERT(mFrameRect.x >= 0 && mFrameRect.y >= 0 && + mFrameRect.width > 0 && mFrameRect.height > 0, + "Frame rect must have positive components"); + MOZ_ASSERT(nsIntRect(0, 0, aOriginalSize.width, aOriginalSize.height) + .Contains(mFrameRect), + "Frame rect must fit inside image"); + MOZ_ASSERT_IF(!nsIntRect(0, 0, aOriginalSize.width, aOriginalSize.height) + .IsEqualEdges(mFrameRect), + aHasAlpha); + mOriginalSize = aOriginalSize; mScale = gfxSize(double(mOriginalSize.width) / mTargetSize.width, double(mOriginalSize.height) / mTargetSize.height); @@ -78,7 +90,6 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize, mHasAlpha = aHasAlpha; mFlipVertically = aFlipVertically; - ResetForNextProgressivePass(); ReleaseWindow(); auto resizeMethod = skia::ImageOperations::RESIZE_LANCZOS3; @@ -124,9 +135,22 @@ Downscaler::BeginFrame(const nsIntSize& aOriginalSize, return NS_ERROR_OUT_OF_MEMORY; } + ResetForNextProgressivePass(); + return NS_OK; } +void +Downscaler::SkipToRow(int32_t aRow) +{ + if (mCurrentInLine < aRow) { + ClearRow(); + do { + CommitRow(); + } while (mCurrentInLine < aRow); + } +} + void Downscaler::ResetForNextProgressivePass() { @@ -134,6 +158,9 @@ Downscaler::ResetForNextProgressivePass() mCurrentOutLine = 0; mCurrentInLine = 0; mLinesInBuffer = 0; + + // If we have a vertical offset, commit rows to shift us past it. + SkipToRow(mFrameRect.y); } static void @@ -193,6 +220,12 @@ Downscaler::CommitRow() } mCurrentInLine += 1; + + // If we're at the end of the part of the original image that has data, commit + // rows to shift us to the end. + if (mCurrentInLine == (mFrameRect.y + mFrameRect.height)) { + SkipToRow(mOriginalSize.height - 1); + } } bool diff --git a/image/Downscaler.h b/image/Downscaler.h index c883d952895b..4083e83df96e 100644 --- a/image/Downscaler.h +++ b/image/Downscaler.h @@ -12,10 +12,10 @@ #ifndef mozilla_image_Downscaler_h #define mozilla_image_Downscaler_h +#include "mozilla/Maybe.h" #include "mozilla/UniquePtr.h" #include "nsRect.h" - namespace skia { class ConvolutionFilter1D; } // namespace skia @@ -64,6 +64,9 @@ public: * Begins a new frame and reinitializes the Downscaler. * * @param aOriginalSize The original size of this frame, before scaling. + * @param aFrameRect The region of the original image which has data. + * Every pixel outside @aFrameRect is considered blank and + * has zero alpha. * @param aOutputBuffer The buffer to which the Downscaler should write its * output; this is the same buffer where the Decoder * would write its output when not downscaling during @@ -75,12 +78,16 @@ public: * the way they are stored in some image formats. */ nsresult BeginFrame(const nsIntSize& aOriginalSize, + const Maybe& aFrameRect, uint8_t* aOutputBuffer, bool aHasAlpha, bool aFlipVertically = false); /// Retrieves the buffer into which the Decoder should write each row. - uint8_t* RowBuffer() { return mRowBuffer.get(); } + uint8_t* RowBuffer() + { + return mRowBuffer.get() + mFrameRect.x * sizeof(uint32_t); + } /// Clears the current row buffer (optionally starting at @aStartingAtCol). void ClearRow(uint32_t aStartingAtCol = 0); @@ -104,9 +111,11 @@ public: private: void DownscaleInputLine(); void ReleaseWindow(); + void SkipToRow(int32_t aRow); nsIntSize mOriginalSize; nsIntSize mTargetSize; + nsIntRect mFrameRect; gfxSize mScale; uint8_t* mOutputBuffer; diff --git a/image/decoders/nsBMPDecoder.cpp b/image/decoders/nsBMPDecoder.cpp index c9c23296247c..b973b3d4eefa 100644 --- a/image/decoders/nsBMPDecoder.cpp +++ b/image/decoders/nsBMPDecoder.cpp @@ -461,7 +461,8 @@ nsBMPDecoder::WriteInternal(const char* aBuffer, uint32_t aCount) if (mDownscaler) { // BMPs store their rows in reverse order, so the downscaler needs to // reverse them again when writing its output. - rv = mDownscaler->BeginFrame(GetSize(), mImageData, hasTransparency, + rv = mDownscaler->BeginFrame(GetSize(), Nothing(), + mImageData, hasTransparency, /* aFlipVertically = */ true); if (NS_FAILED(rv)) { return; diff --git a/image/decoders/nsGIFDecoder2.cpp b/image/decoders/nsGIFDecoder2.cpp index 2a64a34bcf6e..93c92bc5b0cb 100644 --- a/image/decoders/nsGIFDecoder2.cpp +++ b/image/decoders/nsGIFDecoder2.cpp @@ -279,7 +279,7 @@ nsGIFDecoder2::BeginImageFrame(uint16_t aDepth) } if (mDownscaler) { - rv = mDownscaler->BeginFrame(frameRect.Size(), mImageData, + rv = mDownscaler->BeginFrame(frameRect.Size(), Nothing(), mImageData, mGIFStruct.is_transparent); } diff --git a/image/decoders/nsICODecoder.cpp b/image/decoders/nsICODecoder.cpp index 1f8cf9439795..dadb6fa7489f 100644 --- a/image/decoders/nsICODecoder.cpp +++ b/image/decoders/nsICODecoder.cpp @@ -553,7 +553,7 @@ nsICODecoder::PrepareForMask() mDownscaler->TargetSize().height * sizeof(uint32_t)); mMaskBuffer = MakeUnique(bmpDecoder->GetImageDataLength()); - nsresult rv = mDownscaler->BeginFrame(GetRealSize(), + nsresult rv = mDownscaler->BeginFrame(GetRealSize(), Nothing(), mMaskBuffer.get(), /* aHasAlpha = */ true, /* aFlipVertically = */ true); diff --git a/image/decoders/nsIconDecoder.cpp b/image/decoders/nsIconDecoder.cpp index 55666f67dd4c..72df5913d3f7 100644 --- a/image/decoders/nsIconDecoder.cpp +++ b/image/decoders/nsIconDecoder.cpp @@ -93,7 +93,7 @@ nsIconDecoder::WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_ASSERT(mImageData, "Should have a buffer now"); if (mDownscaler) { - nsresult rv = mDownscaler->BeginFrame(GetSize(), + nsresult rv = mDownscaler->BeginFrame(GetSize(), Nothing(), mImageData, /* aHasAlpha = */ true); if (NS_FAILED(rv)) { diff --git a/image/decoders/nsJPEGDecoder.cpp b/image/decoders/nsJPEGDecoder.cpp index 61d32c0d53fc..b9d8619a742f 100644 --- a/image/decoders/nsJPEGDecoder.cpp +++ b/image/decoders/nsJPEGDecoder.cpp @@ -398,7 +398,7 @@ nsJPEGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount) MOZ_ASSERT(mImageData, "Should have a buffer now"); if (mDownscaler) { - nsresult rv = mDownscaler->BeginFrame(GetSize(), + nsresult rv = mDownscaler->BeginFrame(GetSize(), Nothing(), mImageData, /* aHasAlpha = */ false); if (NS_FAILED(rv)) { diff --git a/image/decoders/nsPNGDecoder.cpp b/image/decoders/nsPNGDecoder.cpp index 74119178b0b8..6b60a9b914ab 100644 --- a/image/decoders/nsPNGDecoder.cpp +++ b/image/decoders/nsPNGDecoder.cpp @@ -209,7 +209,8 @@ nsPNGDecoder::CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset, if (mDownscaler) { bool hasAlpha = aFormat != SurfaceFormat::B8G8R8X8; - rv = mDownscaler->BeginFrame(frameRect.Size(), mImageData, hasAlpha); + rv = mDownscaler->BeginFrame(frameRect.Size(), Nothing(), + mImageData, hasAlpha); if (NS_FAILED(rv)) { return rv; } From ae6de3f01a7ac8b02c242ce2d91f031713ac5f4c Mon Sep 17 00:00:00 2001 From: Seth Fowler Date: Sat, 26 Sep 2015 01:36:23 -0700 Subject: [PATCH 144/247] Bug 1207378 (Part 2) - Use Downscaler to remove first-frame padding when downscaling GIFs. r=tn --- image/decoders/nsGIFDecoder2.cpp | 40 ++++++++++++++------------------ image/decoders/nsGIFDecoder2.h | 2 +- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/image/decoders/nsGIFDecoder2.cpp b/image/decoders/nsGIFDecoder2.cpp index 93c92bc5b0cb..5dd8e6ebd447 100644 --- a/image/decoders/nsGIFDecoder2.cpp +++ b/image/decoders/nsGIFDecoder2.cpp @@ -206,17 +206,17 @@ nsGIFDecoder2::BeginGIF() PostSize(mGIFStruct.screen_width, mGIFStruct.screen_height); } -void +bool nsGIFDecoder2::CheckForTransparency(IntRect aFrameRect) { // Check if the image has a transparent color in its palette. if (mGIFStruct.is_transparent) { PostHasTransparency(); - return; + return true; } if (mGIFStruct.images_decoded > 0) { - return; // We only care about first frame padding below. + return false; // We only care about first frame padding below. } // If we need padding on the first frame, that means we don't draw into part @@ -224,7 +224,11 @@ nsGIFDecoder2::CheckForTransparency(IntRect aFrameRect) IntRect imageRect(0, 0, mGIFStruct.screen_width, mGIFStruct.screen_height); if (!imageRect.IsEqualEdges(aFrameRect)) { PostHasTransparency(); + mSawTransparency = true; // Make sure we don't optimize it away. + return true; } + + return false; } //****************************************************************************** @@ -233,31 +237,23 @@ nsGIFDecoder2::BeginImageFrame(uint16_t aDepth) { MOZ_ASSERT(HasSize()); - gfx::SurfaceFormat format; - if (mGIFStruct.is_transparent) { - format = gfx::SurfaceFormat::B8G8R8A8; - } else { - format = gfx::SurfaceFormat::B8G8R8X8; - } - IntRect frameRect(mGIFStruct.x_offset, mGIFStruct.y_offset, mGIFStruct.width, mGIFStruct.height); - CheckForTransparency(frameRect); + bool hasTransparency = CheckForTransparency(frameRect); + gfx::SurfaceFormat format = hasTransparency ? SurfaceFormat::B8G8R8A8 + : SurfaceFormat::B8G8R8X8; // Make sure there's no animation if we're downscaling. MOZ_ASSERT_IF(mDownscaler, !GetImageMetadata().HasAnimation()); + // Compute the target size and target frame rect. If we're downscaling, + // Downscaler will automatically strip out first-frame padding, so the target + // frame rect takes up the entire frame regardless. IntSize targetSize = mDownscaler ? mDownscaler->TargetSize() : GetSize(); - - // Rescale the frame rect for the target size. - IntRect targetFrameRect = frameRect; - if (mDownscaler) { - IntSize originalSize = GetSize(); - targetFrameRect.ScaleRoundOut(double(targetSize.width) / originalSize.width, - double(targetSize.height) / originalSize.height); - } + IntRect targetFrameRect = mDownscaler ? IntRect(IntPoint(), targetSize) + : frameRect; // Use correct format, RGB for first frame, PAL for following frames // and include transparency to allow for optimization of opaque images @@ -279,8 +275,8 @@ nsGIFDecoder2::BeginImageFrame(uint16_t aDepth) } if (mDownscaler) { - rv = mDownscaler->BeginFrame(frameRect.Size(), Nothing(), mImageData, - mGIFStruct.is_transparent); + rv = mDownscaler->BeginFrame(GetSize(), Some(frameRect), mImageData, + hasTransparency); } return rv; @@ -318,7 +314,7 @@ nsGIFDecoder2::EndImageFrame() // should fix that. We can also mark it opaque unconditionally if we didn't // actually see any transparent pixels - this test is only valid for the // first frame. - if (!mGIFStruct.is_transparent || !mSawTransparency) { + if (!mGIFStruct.is_transparent && !mSawTransparency) { opacity = Opacity::OPAQUE; } } diff --git a/image/decoders/nsGIFDecoder2.h b/image/decoders/nsGIFDecoder2.h index 52b551f73a58..76ddf1ac2230 100644 --- a/image/decoders/nsGIFDecoder2.h +++ b/image/decoders/nsGIFDecoder2.h @@ -50,7 +50,7 @@ private: bool DoLzw(const uint8_t* q); bool SetHold(const uint8_t* buf, uint32_t count, const uint8_t* buf2 = nullptr, uint32_t count2 = 0); - void CheckForTransparency(gfx::IntRect aFrameRect); + bool CheckForTransparency(gfx::IntRect aFrameRect); inline int ClearCode() const { return 1 << mGIFStruct.datasize; } From 83feb843ff23f28178c9235d4941ad168b788421 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Sat, 26 Sep 2015 14:45:43 +0200 Subject: [PATCH 145/247] Bug 1208457 - Fuzz bg-fixed-child-mask.html reftest failure. r=kats --HG-- extra : commitid : 1Lg7cSngbcc --- layout/reftests/async-scrolling/reftest.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/reftests/async-scrolling/reftest.list b/layout/reftests/async-scrolling/reftest.list index e9907a0dacb9..16bad50d9478 100644 --- a/layout/reftests/async-scrolling/reftest.list +++ b/layout/reftests/async-scrolling/reftest.list @@ -5,7 +5,7 @@ skip-if(!asyncPan) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html skip-if(!asyncPan) == bg-fixed-child.html bg-fixed-child-ref.html skip-if(!asyncPan) == bg-fixed-child-clip-1.html bg-fixed-child-clip-ref.html skip-if(!asyncPan) == bg-fixed-child-clip-2.html bg-fixed-child-clip-ref.html -skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html +fuzzy(1,246) skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html skip-if(!asyncPan) == element-1.html element-1-ref.html pref(layers.force-active,true) skip-if(!asyncPan) == iframe-1.html iframe-1-ref.html skip-if(!asyncPan) == nested-1.html nested-1-ref.html From e21bd1df786e5c64767add3f44d9ed5f4dd49373 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Fri, 25 Sep 2015 15:47:41 +0200 Subject: [PATCH 146/247] Bug 1208438 - Don't allow layers with scrolling clips to occlusion-cull layers behind them. r=mattwoodrow --HG-- extra : commitid : LZhXvCVgeyn --- layout/base/FrameLayerBuilder.cpp | 5 +++++ .../bg-fixed-child-no-culling-ref.html | 11 +++++++++++ .../async-scrolling/bg-fixed-child-no-culling.html | 14 ++++++++++++++ layout/reftests/async-scrolling/reftest.list | 1 + 4 files changed, 31 insertions(+) create mode 100644 layout/reftests/async-scrolling/bg-fixed-child-no-culling-ref.html create mode 100644 layout/reftests/async-scrolling/bg-fixed-child-no-culling.html diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 1d7677601851..4875c9d4c4fd 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -4863,6 +4863,11 @@ ContainerState::PostprocessRetainedLayers(nsIntRegion* aOpaqueRegionForContainer if (clipRect) { clippedOpaque.AndWith(ParentLayerIntRect::ToUntyped(*clipRect)); } + if (e->mLayer->GetIsFixedPosition() && !e->mLayer->IsClipFixed()) { + // The clip can move asynchronously, so we can't rely on opaque parts + // staying in the same place. + clippedOpaque.SetEmpty(); + } data->mOpaqueRegion.Or(data->mOpaqueRegion, clippedOpaque); if (e->mHideAllLayersBelow) { hideAll = true; diff --git a/layout/reftests/async-scrolling/bg-fixed-child-no-culling-ref.html b/layout/reftests/async-scrolling/bg-fixed-child-no-culling-ref.html new file mode 100644 index 000000000000..8f647b7c9e14 --- /dev/null +++ b/layout/reftests/async-scrolling/bg-fixed-child-no-culling-ref.html @@ -0,0 +1,11 @@ + + + +
+
+ + diff --git a/layout/reftests/async-scrolling/bg-fixed-child-no-culling.html b/layout/reftests/async-scrolling/bg-fixed-child-no-culling.html new file mode 100644 index 000000000000..9c385c20c8ec --- /dev/null +++ b/layout/reftests/async-scrolling/bg-fixed-child-no-culling.html @@ -0,0 +1,14 @@ + + + +
+
+
+
+ + diff --git a/layout/reftests/async-scrolling/reftest.list b/layout/reftests/async-scrolling/reftest.list index 16bad50d9478..773ae1e4fa38 100644 --- a/layout/reftests/async-scrolling/reftest.list +++ b/layout/reftests/async-scrolling/reftest.list @@ -6,6 +6,7 @@ skip-if(!asyncPan) == bg-fixed-child.html bg-fixed-child-ref.html skip-if(!asyncPan) == bg-fixed-child-clip-1.html bg-fixed-child-clip-ref.html skip-if(!asyncPan) == bg-fixed-child-clip-2.html bg-fixed-child-clip-ref.html fuzzy(1,246) skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html +skip-if(!asyncPan) == bg-fixed-child-no-culling.html bg-fixed-child-no-culling-ref.html skip-if(!asyncPan) == element-1.html element-1-ref.html pref(layers.force-active,true) skip-if(!asyncPan) == iframe-1.html iframe-1-ref.html skip-if(!asyncPan) == nested-1.html nested-1-ref.html From 3414ffd7581e8a2fea54c9d34aa053ebd6869315 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 24 Sep 2015 16:42:02 -0400 Subject: [PATCH 147/247] Bug 1207556 - Part 1: Stop reusing the loadinfo in StartCORSPreflight; r=sicking --- netwerk/base/LoadInfo.cpp | 22 +++++++++++++++++++ netwerk/base/LoadInfo.h | 3 +++ netwerk/protocol/http/nsCORSListenerProxy.cpp | 10 ++++++--- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index 9b7747dbc340..80be5951f468 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -83,6 +83,21 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, } } +LoadInfo::LoadInfo(const LoadInfo& rhs) + : mLoadingPrincipal(rhs.mLoadingPrincipal) + , mTriggeringPrincipal(rhs.mTriggeringPrincipal) + , mLoadingContext(rhs.mLoadingContext) + , mSecurityFlags(rhs.mSecurityFlags) + , mContentPolicyType(rhs.mContentPolicyType) + , mUpgradeInsecureRequests(rhs.mUpgradeInsecureRequests) + , mInnerWindowID(rhs.mInnerWindowID) + , mOuterWindowID(rhs.mOuterWindowID) + , mParentOuterWindowID(rhs.mParentOuterWindowID) + , mEnforceSecurity(false) + , mInitialSecurityCheckDone(false) +{ +} + LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags, @@ -117,6 +132,13 @@ LoadInfo::~LoadInfo() NS_IMPL_ISUPPORTS(LoadInfo, nsILoadInfo) +already_AddRefed +LoadInfo::Clone() const +{ + nsRefPtr copy(new LoadInfo(*this)); + return copy.forget(); +} + NS_IMETHODIMP LoadInfo::GetLoadingPrincipal(nsIPrincipal** aLoadingPrincipal) { diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index 799e8f144b72..cad67a47f8d2 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -50,6 +50,8 @@ public: nsSecurityFlags aSecurityFlags, nsContentPolicyType aContentPolicyType); + already_AddRefed Clone() const; + private: // private constructor that is only allowed to be called from within // HttpChannelParent and FTPChannelParent declared as friends undeneath. @@ -66,6 +68,7 @@ private: bool aEnforceSecurity, bool aInitialSecurityCheckDone, nsTArray>& aRedirectChain); + LoadInfo(const LoadInfo& rhs); friend nsresult mozilla::ipc::LoadInfoArgsToLoadInfo( diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index 6b154a90fe36..8bf4f132d5d1 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -41,6 +41,7 @@ #include "nsINetworkInterceptController.h" #include "nsNullPrincipal.h" #include "nsICorsPreflightCallback.h" +#include "mozilla/LoadInfo.h" #include using namespace mozilla; @@ -1310,12 +1311,15 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel, nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(uri)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr loadInfo = aRequestChannel->GetLoadInfo(); - MOZ_ASSERT(loadInfo, "can not perform CORS preflight without a loadInfo"); - if (!loadInfo) { + nsCOMPtr originalLoadInfo = aRequestChannel->GetLoadInfo(); + MOZ_ASSERT(originalLoadInfo, "can not perform CORS preflight without a loadInfo"); + if (!originalLoadInfo) { return NS_ERROR_FAILURE; } + nsCOMPtr loadInfo = static_cast + (originalLoadInfo.get())->Clone(); + nsSecurityFlags securityMode = loadInfo->GetSecurityMode(); MOZ_ASSERT(securityMode == 0 || From 596a32d9eb16b7199aebf968a8796c90900eb016 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 24 Sep 2015 16:45:26 -0400 Subject: [PATCH 148/247] Bug 1207556 - Part 2: Fix the beacon CORS preflight tests; r=sicking --- .../beacon/beacon-preflight-handler.sjs | 39 +++++++++++++ dom/tests/mochitest/beacon/mochitest.ini | 2 + .../beacon/test_beaconPreflight.html | 26 ++++++++- .../beacon/test_beaconPreflightFailure.html | 56 +++++++++++++++++++ 4 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 dom/tests/mochitest/beacon/beacon-preflight-handler.sjs create mode 100644 dom/tests/mochitest/beacon/test_beaconPreflightFailure.html diff --git a/dom/tests/mochitest/beacon/beacon-preflight-handler.sjs b/dom/tests/mochitest/beacon/beacon-preflight-handler.sjs new file mode 100644 index 000000000000..6a760cb84ce0 --- /dev/null +++ b/dom/tests/mochitest/beacon/beacon-preflight-handler.sjs @@ -0,0 +1,39 @@ +function handleRequest(request, response) +{ + response.setHeader("Cache-Control", "no-cache, must-revalidate", false); + + if (request.queryString === "verify") { + var preflightState = getState("preflight"); + response.write(preflightState === "done" ? "green" : "red"); + return; + } + + var originHeader = request.getHeader("origin"); + response.setHeader("Access-Control-Allow-Headers", "content-type", false); + response.setHeader("Access-Control-Allow-Methods", "POST, GET", false); + response.setHeader("Access-Control-Allow-Origin", originHeader, false); + response.setHeader("Access-Control-Allow-Credentials", "true", false); + + if (request.queryString === "beacon") { + if (request.method == "OPTIONS") { + setState("preflight", "done"); + response.setStatusLine(null, 200, "OK"); + return; + } + response.setStatusLine(null, 200, "OK"); + response.write("DONE"); + return; + } + + if (request.queryString === "fail") { + if (request.method == "OPTIONS") { + setState("preflight", "done"); + response.setStatusLine(null, 400, "Bad Request"); + return; + } + setState("preflight", "oops"); + response.setStatusLine(null, 200, "OK"); + response.write("DONE"); + return; + } +} diff --git a/dom/tests/mochitest/beacon/mochitest.ini b/dom/tests/mochitest/beacon/mochitest.ini index 07c08dd43c72..c15c52461a02 100644 --- a/dom/tests/mochitest/beacon/mochitest.ini +++ b/dom/tests/mochitest/beacon/mochitest.ini @@ -2,12 +2,14 @@ skip-if = buildapp == 'b2g' support-files = beacon-frame.html beacon-handler.sjs + beacon-preflight-handler.sjs beacon-originheader-handler.sjs beacon-cors-redirect-handler.sjs [test_beacon.html] [test_beaconFrame.html] [test_beaconPreflight.html] +[test_beaconPreflightFailure.html] [test_beaconContentPolicy.html] [test_beaconOriginHeader.html] [test_beaconCORSRedirect.html] diff --git a/dom/tests/mochitest/beacon/test_beaconPreflight.html b/dom/tests/mochitest/beacon/test_beaconPreflight.html index 63f4d7857047..cec5df84a185 100644 --- a/dom/tests/mochitest/beacon/test_beaconPreflight.html +++ b/dom/tests/mochitest/beacon/test_beaconPreflight.html @@ -17,7 +17,24 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=936340
 
diff --git a/dom/tests/mochitest/beacon/test_beaconPreflightFailure.html b/dom/tests/mochitest/beacon/test_beaconPreflightFailure.html
new file mode 100644
index 000000000000..11879222f1ef
--- /dev/null
+++ b/dom/tests/mochitest/beacon/test_beaconPreflightFailure.html
@@ -0,0 +1,56 @@
+
+
+
+
+  Test for Bug 1207556
+  
+  
+
+
+Mozilla Bug 1207556
+

+ +
+
+
+ + From 6311eaf83c64cee06babcfc5dc5a3e2416370502 Mon Sep 17 00:00:00 2001 From: Neil Rashbrook Date: Sat, 26 Sep 2015 19:22:06 +0100 Subject: [PATCH 149/247] Bug 1012397 Add support for ignoreBlurWhileSearching r=mak --- toolkit/content/widgets/autocomplete.xml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/toolkit/content/widgets/autocomplete.xml b/toolkit/content/widgets/autocomplete.xml index 711df7e8fbdb..e42a0b4e4edf 100644 --- a/toolkit/content/widgets/autocomplete.xml +++ b/toolkit/content/widgets/autocomplete.xml @@ -219,6 +219,11 @@ else this.removeAttribute("nomatch"); + if (this.ignoreBlurWhileSearching && !this.focused) { + this.handleEnter(); + this.detachController(); + } + if (this._searchCompleteHandler) this._searchCompleteHandler(); ]]> @@ -311,6 +316,12 @@ onset="this.setAttribute('tabscrolling', val); return val;" onget="return this.getAttribute('tabscrolling') == 'true';"/> + + + @@ -633,7 +645,8 @@ } this.mController.handleEnter(false); } - this.detachController(); + if (!this.ignoreBlurWhileSearching) + this.detachController(); } ]]> From 3bd1951671e64ab3a438264324d58294d8bdea58 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Sun, 27 Sep 2015 00:52:26 +0300 Subject: [PATCH 150/247] bug 1072150, backout the release assertion which changed the ancient requirements of nsContentUtils::IsCallerChrome(), a=backout --- dom/base/nsContentUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 32b6be7c9f5f..886169c32cdf 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -2710,7 +2710,7 @@ nsContentUtils::SubjectPrincipal() MOZ_ASSERT(NS_IsMainThread()); JSContext* cx = GetCurrentJSContext(); if (!cx) { - MOZ_CRASH("Accessing the Subject Principal without an AutoJSAPI on the stack is forbidden"); + return GetSystemPrincipal(); } JSCompartment *compartment = js::GetContextCompartment(cx); From abc4fb69661e6d60ea87451c418414a8ac6db38f Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Fri, 25 Sep 2015 11:15:19 +1000 Subject: [PATCH 151/247] Bug 1207119: [mp3] Properly read channels count. r=esawin The channel count is stored on bit 6 & 7 of byte at offset 3. --- dom/media/MP3Demuxer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dom/media/MP3Demuxer.cpp b/dom/media/MP3Demuxer.cpp index d12aca3af7fa..0ce291370481 100644 --- a/dom/media/MP3Demuxer.cpp +++ b/dom/media/MP3Demuxer.cpp @@ -688,7 +688,7 @@ FrameParser::FrameHeader::Private() const { uint8_t FrameParser::FrameHeader::RawChannelMode() const { - return 0xF & mRaw[frame_header::CHANNELMODE_MODEEXT_COPY_ORIG_EMPH] >> 4; + return 0x3 & mRaw[frame_header::CHANNELMODE_MODEEXT_COPY_ORIG_EMPH] >> 6; } int32_t From e071e8739267405d62dc61dfe982d866df7151f1 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Fri, 25 Sep 2015 16:37:53 +1000 Subject: [PATCH 152/247] Bug 1207429: P1. remove media.fragmented-mp4.exposed pref. r=kentuckyfriedtakahe --- dom/media/DecoderTraits.cpp | 3 +-- dom/media/test/eme.js | 1 - dom/media/test/test_can_play_type_mpeg.html | 3 +-- mobile/android/app/mobile.js | 1 - modules/libpref/init/all.js | 6 ------ 5 files changed, 2 insertions(+), 12 deletions(-) diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp index a7efa7ae0178..a4ee3c2f72b4 100644 --- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -349,8 +349,7 @@ IsMP4SupportedType(const nsACString& aType, { // MP4Decoder/Reader is currently used for MSE and mp4 files local playback. bool haveAAC, haveMP3, haveH264; - return Preferences::GetBool("media.fragmented-mp4.exposed", false) && - MP4Decoder::CanHandleMediaType(aType, aCodecs, haveAAC, haveH264, haveMP3); + return MP4Decoder::CanHandleMediaType(aType, aCodecs, haveAAC, haveH264, haveMP3); } #endif diff --git a/dom/media/test/eme.js b/dom/media/test/eme.js index 9f218734b083..913cf2966a60 100644 --- a/dom/media/test/eme.js +++ b/dom/media/test/eme.js @@ -399,7 +399,6 @@ function SetupEME(test, token, params) function SetupEMEPref(callback) { var prefs = [ [ "media.mediasource.enabled", true ], - [ "media.fragmented-mp4.exposed", true ], [ "media.eme.apiVisible", true ], ]; diff --git a/dom/media/test/test_can_play_type_mpeg.html b/dom/media/test/test_can_play_type_mpeg.html index 8b822644fc9d..79a2f3f4b1fc 100644 --- a/dom/media/test/test_can_play_type_mpeg.html +++ b/dom/media/test/test_can_play_type_mpeg.html @@ -131,8 +131,7 @@ function IsJellyBeanOrLater() { // Check whether we should expect the new MP4Reader-based support to work. function IsMP4ReaderAvailable() { - var prefs = getPref("media.fragmented-mp4.enabled") && - getPref("media.fragmented-mp4.exposed"); + var prefs = getPref("media.fragmented-mp4.enabled"); return prefs && (IsWindowsVistaOrLater() || IsMacOSSnowLeopardOrLater() || IsJellyBeanOrLater()); } diff --git a/mobile/android/app/mobile.js b/mobile/android/app/mobile.js index dea3ff662579..e54f43cf673f 100644 --- a/mobile/android/app/mobile.js +++ b/mobile/android/app/mobile.js @@ -589,7 +589,6 @@ pref("media.cache_readahead_limit", 30); pref("media.video-queue.default-size", 3); // Enable the MediaCodec PlatformDecoderModule by default. -pref("media.fragmented-mp4.exposed", true); pref("media.fragmented-mp4.enabled", true); pref("media.fragmented-mp4.android-media-codec.enabled", true); pref("media.fragmented-mp4.android-media-codec.preferred", true); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 11ff561b4ec2..ce98815ff4c2 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -314,12 +314,6 @@ pref("media.directshow.enabled", true); pref("media.fragmented-mp4.enabled", true); pref("media.fragmented-mp4.ffmpeg.enabled", false); pref("media.fragmented-mp4.gmp.enabled", false); -#if defined(XP_WIN) && defined(MOZ_WMF) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GONK) -// Denotes that the fragmented MP4 parser can be created by