From 702f1619f7ce2b53fc14bd779462c0f3ad09a9b1 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Mon, 28 Dec 2015 00:11:26 -0700 Subject: [PATCH 01/36] Bug 1235503 - Fix -Wunreachable-code warnings in dom/media/. r=jya dom/media/DecoderTraits.cpp:314:10 [-Wunreachable-code-return] 'return' will never be executed dom/media/DecoderTraits.cpp:324:10 [-Wunreachable-code-return] 'return' will never be executed --- dom/media/DecoderTraits.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp index 5093be06c1be..bf181bd7e4ea 100644 --- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -310,8 +310,9 @@ DecoderTraits::IsMP4TypeAndEnabled(const nsACString& aType) { #ifdef MOZ_FMP4 return IsMP4SupportedType(aType); -#endif +#else return false; +#endif } static bool @@ -320,8 +321,9 @@ IsMP3SupportedType(const nsACString& aType, { #ifdef MOZ_OMX_DECODER return false; -#endif +#else return MP3Decoder::CanHandleMediaType(aType, aCodecs); +#endif } static bool From 96dd413273bccdf42b4340ef551dd21a300e6a50 Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Tue, 29 Dec 2015 10:55:38 +0100 Subject: [PATCH 02/36] Bug 1230005: Delay buffer flushing in asm.js until the last minute; r=luke --HG-- extra : commitid : 6ar03ADOWzM extra : rebase_source : 5e1b25850ca8390d54b545314e543ad2d14f781a extra : amend_source : 097590cf5a6f98cb74b0af0e9c811c84c932ed53 --- js/src/jit/CodeGenerator.cpp | 6 ------ js/src/jit/MacroAssembler.cpp | 2 +- js/src/jit/MacroAssembler.h | 2 +- js/src/jit/arm/Assembler-arm.cpp | 3 ++- js/src/jit/arm/Assembler-arm.h | 2 +- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 326e50093b2b..8707bfa92cac 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -7896,7 +7896,6 @@ CodeGenerator::generateAsmJS(wasm::FuncOffsets* offsets) target); } - if (!generateBody()) return false; @@ -7912,7 +7911,6 @@ CodeGenerator::generateAsmJS(wasm::FuncOffsets* offsets) masm.jump(masm.asmStackOverflowLabel()); } - #if defined(JS_ION_PERF) // Note the end of the inline code and start of the OOL code. gen->perfSpewer().noteEndInlineCode(masm); @@ -7921,10 +7919,6 @@ CodeGenerator::generateAsmJS(wasm::FuncOffsets* offsets) if (!generateOutOfLineCode()) return false; - // Flush constant pools now so that pool hints encoded in the code stream - // get converted into actual instructions. - masm.flushBuffer(); - offsets->end = masm.currentOffset(); MOZ_ASSERT(!masm.failureLabel()->used()); diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 8751c2df27c8..59f6ebadc570 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -2007,7 +2007,7 @@ MacroAssembler::convertTypedOrValueToInt(TypedOrValueRegister src, FloatRegister } bool -MacroAssembler::asmMergeWith(const MacroAssembler& other) +MacroAssembler::asmMergeWith(MacroAssembler& other) { size_t sizeBeforeMerge = size(); diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index 0d9a982b2ecc..12945265e906 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -1427,7 +1427,7 @@ class MacroAssembler : public MacroAssemblerSpecific return &asmOnConversionErrorLabel_; } - bool asmMergeWith(const MacroAssembler& masm); + bool asmMergeWith(MacroAssembler& masm); void finish(); void link(JitCode* code); diff --git a/js/src/jit/arm/Assembler-arm.cpp b/js/src/jit/arm/Assembler-arm.cpp index 8732f8ca65e1..1f1b8dd3ca38 100644 --- a/js/src/jit/arm/Assembler-arm.cpp +++ b/js/src/jit/arm/Assembler-arm.cpp @@ -634,9 +634,10 @@ Assembler::finish() } bool -Assembler::asmMergeWith(const Assembler& other) +Assembler::asmMergeWith(Assembler& other) { flush(); + other.flush(); if (!AssemblerShared::asmMergeWith(size(), other)) return false; return m_buffer.appendBuffer(other.m_buffer); diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h index 34088121d47a..a0f40303eb83 100644 --- a/js/src/jit/arm/Assembler-arm.h +++ b/js/src/jit/arm/Assembler-arm.h @@ -1396,7 +1396,7 @@ class Assembler : public AssemblerShared bool isFinished; public: void finish(); - bool asmMergeWith(const Assembler& other); + bool asmMergeWith(Assembler& other); void executableCopy(void* buffer); void copyJumpRelocationTable(uint8_t* dest); void copyDataRelocationTable(uint8_t* dest); From e234f69eff058dd907d0cb9dfaf57fc59ec0cea6 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 30 Dec 2015 08:53:20 +0000 Subject: [PATCH 03/36] Bug 1234192 - part 1 - FileSystemBase should not be thread-safe, r=smaug --- dom/filesystem/FileSystemBase.h | 2 +- dom/filesystem/FileSystemTaskBase.cpp | 30 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/dom/filesystem/FileSystemBase.h b/dom/filesystem/FileSystemBase.h index fbd0f18be240..0301a4e7d577 100644 --- a/dom/filesystem/FileSystemBase.h +++ b/dom/filesystem/FileSystemBase.h @@ -20,7 +20,7 @@ class Directory; class FileSystemBase { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileSystemBase) + NS_INLINE_DECL_REFCOUNTING(FileSystemBase) public: // Create file system object from its string representation. diff --git a/dom/filesystem/FileSystemTaskBase.cpp b/dom/filesystem/FileSystemTaskBase.cpp index 36ac33211eed..e77cf251262a 100644 --- a/dom/filesystem/FileSystemTaskBase.cpp +++ b/dom/filesystem/FileSystemTaskBase.cpp @@ -16,10 +16,34 @@ #include "mozilla/dom/PContent.h" #include "mozilla/dom/ipc/BlobParent.h" #include "mozilla/unused.h" +#include "nsProxyRelease.h" namespace mozilla { namespace dom { +namespace { + +class FileSystemReleaseRunnable : public nsRunnable +{ +public: + explicit FileSystemReleaseRunnable(RefPtr& aDoomed) + : mDoomed(nullptr) + { + aDoomed.swap(mDoomed); + } + + NS_IMETHOD Run() + { + mDoomed->Release(); + return NS_OK; + } + +private: + FileSystemBase* MOZ_OWNING_REF mDoomed; +}; + +} // anonymous namespace + FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem) : mErrorValue(NS_OK) , mFileSystem(aFileSystem) @@ -43,6 +67,12 @@ FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem, FileSystemTaskBase::~FileSystemTaskBase() { + if (!NS_IsMainThread()) { + RefPtr runnable = + new FileSystemReleaseRunnable(mFileSystem); + MOZ_ASSERT(!mFileSystem); + NS_DispatchToMainThread(runnable); + } } FileSystemBase* From 748bf4398331e5c87f1ffe592d4016520d34f8fd Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 30 Dec 2015 08:53:38 +0000 Subject: [PATCH 04/36] Bug 1234192 - part 2 - Directory should unlink/traverse the OSFileSystem in order to unlink/traverse the window, r=smaug --- dom/filesystem/Directory.cpp | 15 ++++++++++++++- dom/filesystem/FileSystemBase.h | 5 +++++ dom/filesystem/OSFileSystem.cpp | 13 +++++++++++++ dom/filesystem/OSFileSystem.h | 6 +++++- 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/dom/filesystem/Directory.cpp b/dom/filesystem/Directory.cpp index cbc70cd88434..1cdf78a9fafa 100644 --- a/dom/filesystem/Directory.cpp +++ b/dom/filesystem/Directory.cpp @@ -34,7 +34,20 @@ namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(Directory) +NS_IMPL_CYCLE_COLLECTION_CLASS(Directory) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Directory) + tmp->mFileSystem->Unlink(); + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Directory) + tmp->mFileSystem->Traverse(cb); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(Directory) + NS_IMPL_CYCLE_COLLECTING_ADDREF(Directory) NS_IMPL_CYCLE_COLLECTING_RELEASE(Directory) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Directory) diff --git a/dom/filesystem/FileSystemBase.h b/dom/filesystem/FileSystemBase.h index 0301a4e7d577..f304410cd134 100644 --- a/dom/filesystem/FileSystemBase.h +++ b/dom/filesystem/FileSystemBase.h @@ -95,6 +95,11 @@ public: { return mRequiresPermissionChecks; } + + // CC methods + virtual void Unlink() {} + virtual void Traverse(nsCycleCollectionTraversalCallback &cb) {} + protected: virtual ~FileSystemBase(); diff --git a/dom/filesystem/OSFileSystem.cpp b/dom/filesystem/OSFileSystem.cpp index 164709ec701c..9937357ebf7e 100644 --- a/dom/filesystem/OSFileSystem.cpp +++ b/dom/filesystem/OSFileSystem.cpp @@ -76,5 +76,18 @@ OSFileSystem::IsSafeDirectory(Directory* aDir) const return true; } +void +OSFileSystem::Unlink() +{ + mWindow = nullptr; +} + +void +OSFileSystem::Traverse(nsCycleCollectionTraversalCallback &cb) +{ + OSFileSystem* tmp = this; + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow); +} + } // namespace dom } // namespace mozilla diff --git a/dom/filesystem/OSFileSystem.h b/dom/filesystem/OSFileSystem.h index f82800a980f4..039a7e13b052 100644 --- a/dom/filesystem/OSFileSystem.h +++ b/dom/filesystem/OSFileSystem.h @@ -12,7 +12,7 @@ namespace mozilla { namespace dom { -class OSFileSystem : public FileSystemBase +class OSFileSystem final : public FileSystemBase { public: explicit OSFileSystem(const nsAString& aRootDir); @@ -34,6 +34,10 @@ public: virtual bool IsSafeDirectory(Directory* aDir) const override; + // CC methods + virtual void Unlink() override; + virtual void Traverse(nsCycleCollectionTraversalCallback &cb) override; + private: virtual ~OSFileSystem() {} From 3345f3b6d90ea802addb1cdb3ffb42f5cc1683b5 Mon Sep 17 00:00:00 2001 From: Arthur Edelstein Date: Tue, 29 Dec 2015 13:56:00 +0100 Subject: [PATCH 05/36] Bug 867501 - Pref allows JS locale to be set to US English/C. r=khuey --- js/xpconnect/src/XPCLocale.cpp | 10 ++++++++++ toolkit/xre/nsAppRunner.cpp | 15 +++++++++++++++ toolkit/xre/nsAppRunner.h | 3 +++ toolkit/xre/nsEmbedFunctions.cpp | 2 ++ 4 files changed, 30 insertions(+) diff --git a/js/xpconnect/src/XPCLocale.cpp b/js/xpconnect/src/XPCLocale.cpp index 220d76fbd5dd..4fa6bc80acd9 100644 --- a/js/xpconnect/src/XPCLocale.cpp +++ b/js/xpconnect/src/XPCLocale.cpp @@ -17,6 +17,7 @@ #include "nsComponentManagerUtils.h" #include "nsServiceManagerUtils.h" #include "mozilla/dom/EncodingUtils.h" +#include "mozilla/Preferences.h" #include "nsIUnicodeDecoder.h" #include "xpcpublic.h" @@ -252,6 +253,15 @@ xpc_LocalizeRuntime(JSRuntime* rt) JS_SetLocaleCallbacks(rt, new XPCLocaleCallbacks()); // Set the default locale. + + // Check a pref to see if we should use US English locale regardless + // of the system locale. + if (Preferences::GetBool("javascript.use_us_english_locale", false)) { + return JS_SetDefaultLocale(rt, "en-US"); + } + + // No pref has been found, so get the default locale from the + // application's locale. nsCOMPtr localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID); if (!localeService) diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 6e18ea6084ba..a46b06ba182f 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -145,6 +145,7 @@ #include "mozilla/LateWriteChecks.h" #include +#include #ifdef XP_UNIX #include @@ -4150,6 +4151,8 @@ XREMain::XRE_mainRun() mDirProvider.DoStartup(); + OverrideDefaultLocaleIfNeeded(); + #ifdef MOZ_CRASHREPORTER nsCString userAgentLocale; // Try a localized string first. This pref is always a localized string in @@ -4808,3 +4811,15 @@ SetupErrorHandling(const char* progname) // Unbuffer stdout, needed for tinderbox tests. setbuf(stdout, 0); } + +void +OverrideDefaultLocaleIfNeeded() { + // Read pref to decide whether to override default locale with US English. + if (mozilla::Preferences::GetBool("javascript.use_us_english_locale", false)) { + // Set the application-wide C-locale. Needed to resist fingerprinting + // of Date.toLocaleFormat(). We use the locale to "C.UTF-8" if possible, + // to avoid interfering with non-ASCII keyboard input on some Linux desktops. + // Otherwise fall back to the "C" locale, which is available on all platforms. + setlocale(LC_ALL, "C.UTF-8") || setlocale(LC_ALL, "C"); + } +} diff --git a/toolkit/xre/nsAppRunner.h b/toolkit/xre/nsAppRunner.h index 9b2cb135b3a7..c7048e0c87bf 100644 --- a/toolkit/xre/nsAppRunner.h +++ b/toolkit/xre/nsAppRunner.h @@ -93,6 +93,9 @@ NS_LockProfilePath(nsIFile* aPath, nsIFile* aTempPath, void WriteConsoleLog(); +void +OverrideDefaultLocaleIfNeeded(); + #ifdef XP_WIN void UseParentConsole(); diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index e735bf626208..70015dfa1e7a 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -619,6 +619,8 @@ XRE_InitChildProcess(int aArgc, mozilla::sandboxing::InitLoggingIfRequired(); #endif + OverrideDefaultLocaleIfNeeded(); + // Run the UI event loop on the main thread. uiMessageLoop.MessageLoop::Run(); From 5428ba382d5b788494547bda1b2e40785c54e20f Mon Sep 17 00:00:00 2001 From: Marco Castelluccio Date: Thu, 24 Dec 2015 16:49:00 +0100 Subject: [PATCH 06/36] Bug 1235101 - Add script to create test receipts to the tree. r=ferjm --- dom/apps/tests/create_test_receipts.py | 163 +++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100755 dom/apps/tests/create_test_receipts.py diff --git a/dom/apps/tests/create_test_receipts.py b/dom/apps/tests/create_test_receipts.py new file mode 100755 index 000000000000..e8774edec6e6 --- /dev/null +++ b/dom/apps/tests/create_test_receipts.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python + +import jwt + +receipt1 = { + "typ": "purchase-receipt", + "product": { + "url": "https://www.mozilla.org", + "storedata": "5169314356" + }, + "user": { + "type": "directed-identifier", + "value": "4fb35151-2b9b-4ba2-8283-c49d381640bd" + }, + "iss": "http://mochi.test:8888", + "nbf": 131360185, + "iat": 131360188, + "detail": "http://mochi.test:8888/receipt/5169314356", + "verify": "http://mochi.test:8888/verify/5169314356", + "reissue": "http://mochi.test:8888/reissue/5169314356" +} + +receipt2 = { + "typ": "purchase-receipt", + "product": { + "url": "https://www.mozilla.org", + "storedata": "5169314357" + }, + "user": { + "type": "directed-identifier", + "value": "4fb35151-2b9b-4ba2-8283-c49d381640bd" + }, + "iss": "http://mochi.test:8888", + "nbf": 131360185, + "iat": 131360188, + "detail": "http://mochi.test:8888/receipt/5169314356", + "verify": "http://mochi.test:8888/verify/5169314356", + "reissue": "http://mochi.test:8888/reissue/5169314356" +} + +receipt_without_typ = { + "product": { + "url": "https://www.mozilla.org", + "storedata": "5169314358" + }, + "user": { + "type": "directed-identifier", + "value": "4fb35151-2b9b-4ba2-8283-c49d381640bd" + }, + "iss": "http://mochi.test:8888", + "nbf": 131360185, + "iat": 131360188, + "detail": "http://mochi.test:8888/receipt/5169314356", + "verify": "http://mochi.test:8888/verify/5169314356", + "reissue": "http://mochi.test:8888/reissue/5169314356" +} + +receipt_without_product = { + "typ": "purchase-receipt", + "user": { + "type": "directed-identifier", + "value": "4fb35151-2b9b-4ba2-8283-c49d381640bd" + }, + "iss": "http://mochi.test:8888", + "nbf": 131360185, + "iat": 131360188, + "detail": "http://mochi.test:8888/receipt/5169314356", + "verify": "http://mochi.test:8888/verify/5169314356", + "reissue": "http://mochi.test:8888/reissue/5169314356" +} + +receipt_without_user = { + "typ": "purchase-receipt", + "product": { + "url": "https://www.mozilla.org", + "storedata": "5169314358" + }, + "iss": "http://mochi.test:8888", + "nbf": 131360185, + "iat": 131360188, + "detail": "http://mochi.test:8888/receipt/5169314356", + "verify": "http://mochi.test:8888/verify/5169314356", + "reissue": "http://mochi.test:8888/reissue/5169314356" +} + +receipt_without_iss = { + "typ": "purchase-receipt", + "product": { + "url": "https://www.mozilla.org", + "storedata": "5169314358" + }, + "user": { + "type": "directed-identifier", + "value": "4fb35151-2b9b-4ba2-8283-c49d381640bd" + }, + "nbf": 131360185, + "iat": 131360188, + "detail": "http://mochi.test:8888/receipt/5169314356", + "verify": "http://mochi.test:8888/verify/5169314356", + "reissue": "http://mochi.test:8888/reissue/5169314356" +} + +receipt_without_nbf = { + "typ": "purchase-receipt", + "product": { + "url": "https://www.mozilla.org", + "storedata": "5169314358" + }, + "user": { + "type": "directed-identifier", + "value": "4fb35151-2b9b-4ba2-8283-c49d381640bd" + }, + "iss": "http://mochi.test:8888", + "iat": 131360188, + "detail": "http://mochi.test:8888/receipt/5169314356", + "verify": "http://mochi.test:8888/verify/5169314356", + "reissue": "http://mochi.test:8888/reissue/5169314356" +} + +receipt_without_iat = { + "typ": "purchase-receipt", + "product": { + "url": "https://www.mozilla.org", + "storedata": "5169314358" + }, + "user": { + "type": "directed-identifier", + "value": "4fb35151-2b9b-4ba2-8283-c49d381640bd" + }, + "iss": "http://mochi.test:8888", + "nbf": 131360185, + "detail": "http://mochi.test:8888/receipt/5169314356", + "verify": "http://mochi.test:8888/verify/5169314356", + "reissue": "http://mochi.test:8888/reissue/5169314356" +} + +receipt_with_wrong_typ = { + "typ": "fake", + "product": { + "url": "https://www.mozilla.org", + "storedata": "5169314358" + }, + "user": { + "type": "directed-identifier", + "value": "4fb35151-2b9b-4ba2-8283-c49d381640bd" + }, + "iss": "http://mochi.test:8888", + "nbf": 131360185, + "iat": 131360188, + "detail": "http://mochi.test:8888/receipt/5169314356", + "verify": "http://mochi.test:8888/verify/5169314356", + "reissue": "http://mochi.test:8888/reissue/5169314356" +} + +print("let valid_receipt1 = \"" + jwt.encode(receipt1, "") + "\";\n") +print("let valid_receipt2 = \"" + jwt.encode(receipt2, "") + "\";\n") +print("let receipt_without_typ = \"" + jwt.encode(receipt_without_typ, "") + "\";\n") +print("let receipt_without_product = \"" + jwt.encode(receipt_without_product, "") + "\";\n") +print("let receipt_without_user = \"" + jwt.encode(receipt_without_user, "") + "\";\n") +print("let receipt_without_iss = \"" + jwt.encode(receipt_without_iss, "") + "\";\n") +print("let receipt_without_nbf = \"" + jwt.encode(receipt_without_nbf, "") + "\";\n") +print("let receipt_without_iat = \"" + jwt.encode(receipt_without_iat, "") + "\";\n") +print("let receipt_with_wrong_typ = \"" + jwt.encode(receipt_with_wrong_typ, "") + "\";\n") From 016ec296bf6819b61b23dbe83569efbefc7377a2 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 16 Dec 2015 14:56:22 -0500 Subject: [PATCH 07/36] Bug 1229932 - check that offsets to canvas fillText() are finite. r=jmuizelaar --- dom/canvas/CanvasRenderingContext2D.cpp | 4 ++++ dom/canvas/crashtests/1229932-1.html | 16 ++++++++++++++++ dom/canvas/crashtests/crashtests.list | 1 + 3 files changed, 21 insertions(+) create mode 100644 dom/canvas/crashtests/1229932-1.html diff --git a/dom/canvas/CanvasRenderingContext2D.cpp b/dom/canvas/CanvasRenderingContext2D.cpp index 0e480db623e7..339a899baa2a 100644 --- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -3811,6 +3811,10 @@ CanvasRenderingContext2D::DrawOrMeasureText(const nsAString& aRawText, return NS_OK; } + if (!IsFinite(aX) || !IsFinite(aY)) { + return NS_OK; + } + const ContextState &state = CurrentState(); // This is only needed to know if we can know the drawing bounding box easily. diff --git a/dom/canvas/crashtests/1229932-1.html b/dom/canvas/crashtests/1229932-1.html new file mode 100644 index 000000000000..b5f06ff85c39 --- /dev/null +++ b/dom/canvas/crashtests/1229932-1.html @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list index a8dcd51fa853..34c602d51d7b 100644 --- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -25,4 +25,5 @@ load 1183363.html load 1190705.html load 1223740-1.html load 1225381-1.html +load 1229932-1.html load texImage2D.html From cafcefe18316629392de9716c003f1ab87929447 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 16 Dec 2015 17:53:11 -0500 Subject: [PATCH 08/36] Bug 1229983 - verify that paths are finite in DrawTargetSkia::Stroke/Fill to handle Canvas paths containing infs. r=jmuizelaar --- dom/canvas/crashtests/1229983-1.html | 24 ++++++++++++++++++++++++ dom/canvas/crashtests/crashtests.list | 1 + gfx/2d/DrawTargetSkia.cpp | 8 ++++++++ gfx/2d/PathSkia.cpp | 8 ++++++++ 4 files changed, 41 insertions(+) create mode 100644 dom/canvas/crashtests/1229983-1.html diff --git a/dom/canvas/crashtests/1229983-1.html b/dom/canvas/crashtests/1229983-1.html new file mode 100644 index 000000000000..a865c569e478 --- /dev/null +++ b/dom/canvas/crashtests/1229983-1.html @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list index 34c602d51d7b..bb7db4a51dde 100644 --- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -25,5 +25,6 @@ load 1183363.html load 1190705.html load 1223740-1.html load 1225381-1.html +load 1229983-1.html load 1229932-1.html load texImage2D.html diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 0f752b25e9eb..7402a4dfd554 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -493,6 +493,10 @@ DrawTargetSkia::Stroke(const Path *aPath, return; } + if (!skiaPath->GetPath().isFinite()) { + return; + } + mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint); } @@ -543,6 +547,10 @@ DrawTargetSkia::Fill(const Path *aPath, AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); + if (!skiaPath->GetPath().isFinite()) { + return; + } + mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint); } diff --git a/gfx/2d/PathSkia.cpp b/gfx/2d/PathSkia.cpp index dc3980bbf405..3726439b66f1 100644 --- a/gfx/2d/PathSkia.cpp +++ b/gfx/2d/PathSkia.cpp @@ -201,6 +201,10 @@ PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, Rect PathSkia::GetBounds(const Matrix &aTransform) const { + if (!mPath.isFinite()) { + return Rect(); + } + Rect bounds = SkRectToRect(mPath.getBounds()); return aTransform.TransformBounds(bounds); } @@ -209,6 +213,10 @@ Rect PathSkia::GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform) const { + if (!mPath.isFinite()) { + return Rect(); + } + SkPaint paint; StrokeOptionsToPaint(paint, aStrokeOptions); From 8eff629f46edf8095e4abe17d0e4ae6458fb4c5e Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Sat, 5 Dec 2015 01:09:13 -0500 Subject: [PATCH 09/36] Bug 1230639 - Propagate the namespace ID to AttributeRuleProcessorData on attribute changes. r=dbaron --- layout/base/RestyleManager.cpp | 2 ++ layout/style/nsCSSRuleProcessor.cpp | 3 ++- layout/style/nsRuleProcessorData.h | 3 +++ layout/style/nsStyleSet.cpp | 12 +++++++----- layout/style/nsStyleSet.h | 1 + 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp index 501b85bc5b94..5250a09b42ce 100644 --- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -1235,6 +1235,7 @@ RestyleManager::AttributeWillChange(Element* aElement, RestyleHintData rsdata; nsRestyleHint rshint = mPresContext->StyleSet()->HasAttributeDependentStyle(aElement, + aNameSpaceID, aAttribute, aModType, false, @@ -1326,6 +1327,7 @@ RestyleManager::AttributeChanged(Element* aElement, RestyleHintData rsdata; nsRestyleHint rshint = mPresContext->StyleSet()->HasAttributeDependentStyle(aElement, + aNameSpaceID, aAttribute, aModType, true, diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index db9209ed9827..057c38f68fd7 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -3010,7 +3010,8 @@ nsCSSRuleProcessor::HasAttributeDependentStyle( EnumerateSelectors(cascade->mPossiblyNegatedIDSelectors, &data); } - if (aData->mAttribute == nsGkAtoms::_class) { + if (aData->mAttribute == nsGkAtoms::_class && + aData->mNameSpaceID == kNameSpaceID_None) { const nsAttrValue* otherClasses = aData->mOtherValue; NS_ASSERTION(otherClasses || aData->mModType == nsIDOMMutationEvent::REMOVAL, diff --git a/layout/style/nsRuleProcessorData.h b/layout/style/nsRuleProcessorData.h index 0e84d96b7310..35a5d11e2950 100644 --- a/layout/style/nsRuleProcessorData.h +++ b/layout/style/nsRuleProcessorData.h @@ -572,6 +572,7 @@ struct MOZ_STACK_CLASS AttributeRuleProcessorData : public ElementDependentRuleProcessorData { AttributeRuleProcessorData(nsPresContext* aPresContext, mozilla::dom::Element* aElement, + int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType, bool aAttrHasChanged, @@ -579,6 +580,7 @@ struct MOZ_STACK_CLASS AttributeRuleProcessorData : TreeMatchContext& aTreeMatchContext) : ElementDependentRuleProcessorData(aPresContext, aElement, nullptr, aTreeMatchContext), + mNameSpaceID(aNameSpaceID), mAttribute(aAttribute), mOtherValue(aOtherValue), mModType(aModType), @@ -586,6 +588,7 @@ struct MOZ_STACK_CLASS AttributeRuleProcessorData : { NS_PRECONDITION(!aTreeMatchContext.mForStyling, "Not styling here!"); } + int32_t mNameSpaceID; // Namespace of the attribute involved. nsIAtom* mAttribute; // |HasAttributeDependentStyle| for which attribute? // non-null if we have the value. const nsAttrValue* mOtherValue; diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index ca2ad0a63e66..80361bbbbb91 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -2388,12 +2388,13 @@ nsStyleSet::HasStateDependentStyle(Element* aElement, } struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData { - AttributeData(nsPresContext* aPresContext, - Element* aElement, nsIAtom* aAttribute, int32_t aModType, + AttributeData(nsPresContext* aPresContext, Element* aElement, + int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType, bool aAttrHasChanged, const nsAttrValue* aOtherValue, TreeMatchContext& aTreeMatchContext) - : AttributeRuleProcessorData(aPresContext, aElement, aAttribute, aModType, - aAttrHasChanged, aOtherValue, aTreeMatchContext), + : AttributeRuleProcessorData(aPresContext, aElement, aNameSpaceID, + aAttribute, aModType, aAttrHasChanged, + aOtherValue, aTreeMatchContext), mHint(nsRestyleHint(0)) {} nsRestyleHint mHint; @@ -2413,6 +2414,7 @@ SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData) // Test if style is dependent on content state nsRestyleHint nsStyleSet::HasAttributeDependentStyle(Element* aElement, + int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType, bool aAttrHasChanged, @@ -2423,7 +2425,7 @@ nsStyleSet::HasAttributeDependentStyle(Element* aElement, TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited, aElement->OwnerDoc()); InitStyleScopes(treeContext, aElement); - AttributeData data(PresContext(), aElement, aAttribute, + AttributeData data(PresContext(), aElement, aNameSpaceID, aAttribute, aModType, aAttrHasChanged, aOtherValue, treeContext); WalkRuleProcessors(SheetHasAttributeStyle, &data, false); if (!(data.mHint & eRestyle_Subtree)) { diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index a1bd602b2fcb..deaebb333f7d 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -289,6 +289,7 @@ class nsStyleSet final // Test if style is dependent on the presence of an attribute. nsRestyleHint HasAttributeDependentStyle(mozilla::dom::Element* aElement, + int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType, bool aAttrHasChanged, From 69278658e468a8e10101ef12d44ed97a6cf15743 Mon Sep 17 00:00:00 2001 From: Bas Schouten Date: Thu, 26 Nov 2015 15:51:49 +0100 Subject: [PATCH 10/36] Bug 1227210: Ensure the mask and the surface are in the right space when being blended. r=mattwoodrow --- gfx/layers/basic/BasicLayerManager.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/gfx/layers/basic/BasicLayerManager.cpp b/gfx/layers/basic/BasicLayerManager.cpp index 94007abd4984..5133b634b76f 100644 --- a/gfx/layers/basic/BasicLayerManager.cpp +++ b/gfx/layers/basic/BasicLayerManager.cpp @@ -128,6 +128,16 @@ BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer, const Matrix maskTransform; RefPtr maskSurf = GetMaskForLayer(aLayer, &maskTransform); + if (maskSurf) { + // The returned transform will transform the mask to device space on the + // destination. Since the User->Device space transform will be applied + // to the mask by PopGroupAndBlend we need to adjust the transform to + // transform the mask to user space. + Matrix currentTransform = ToMatrix(group.mFinalTarget->CurrentMatrix()); + currentTransform.Invert(); + maskTransform = maskTransform * currentTransform; + } + if (aLayer->CanUseOpaqueSurface() && ((didCompleteClip && aRegion.GetNumRects() == 1) || !aContext->CurrentMatrix().HasNonIntegerTranslation())) { @@ -172,8 +182,12 @@ BasicLayerManager::PopGroupForLayer(PushedGroup &group) RefPtr src = sourceDT->Snapshot(); if (group.mMaskSurface) { - dt->SetTransform(group.mMaskTransform * Matrix::Translation(-group.mFinalTarget->GetDeviceOffset())); - dt->MaskSurface(SurfacePattern(src, ExtendMode::CLAMP, Matrix::Translation(group.mGroupOffset.x, group.mGroupOffset.y)), + Point finalOffset = group.mFinalTarget->GetDeviceOffset(); + dt->SetTransform(group.mMaskTransform * Matrix::Translation(-finalOffset)); + Matrix surfTransform = group.mMaskTransform; + surfTransform.Invert(); + dt->MaskSurface(SurfacePattern(src, ExtendMode::CLAMP, surfTransform * + Matrix::Translation(group.mGroupOffset.x, group.mGroupOffset.y)), group.mMaskSurface, Point(0, 0), DrawOptions(group.mOpacity, group.mOperator)); } else { // For now this is required since our group offset is in device space of the final target, From d861b1e8125c7a8d0469afaa6d3d58f983a4cd22 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 30 Dec 2015 13:23:01 +0100 Subject: [PATCH 11/36] Bug 1176024 - Have TextureClient::Lock check that it can expose a DrawTarget when it makes sense. r=Bas --- gfx/layers/client/TextureClient.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index 3e2646111d61..13fb9b377898 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -363,6 +363,24 @@ TextureClient::Lock(OpenMode aMode) mIsLocked = mData->Lock(aMode, mReleaseFenceHandle.IsValid() ? &mReleaseFenceHandle : nullptr); mOpenMode = aMode; + auto format = GetFormat(); + if (mIsLocked && CanExposeDrawTarget() && + aMode == OpenMode::OPEN_READ_WRITE && + NS_IsMainThread() && + // the formats that we apparently expect, in the cairo backend. Any other + // format will trigger an assertion in GfxFormatToCairoFormat. + (format == SurfaceFormat::A8R8G8B8_UINT32 || + format == SurfaceFormat::X8R8G8B8_UINT32 || + format == SurfaceFormat::A8 || + format == SurfaceFormat::R5G6B5_UINT16)) { + if (!BorrowDrawTarget()) { + // Failed to get a DrawTarget, means we won't be able to write into the + // texture, might as well fail now. + Unlock(); + return false; + } + } + return mIsLocked; } @@ -427,6 +445,9 @@ TextureClient::UpdateFromSurface(gfx::SourceSurface* aSurface) MOZ_ASSERT(IsValid()); MOZ_ASSERT(mIsLocked); MOZ_ASSERT(aSurface); + // If you run into this assertion, make sure the texture was locked write-only + // rather than read-write. + MOZ_ASSERT(!mBorrowedDrawTarget); // XXX - It would be better to first try the DrawTarget approach and fallback // to the backend-specific implementation because the latter will usually do From c31028f3b18867b87ca46c39f2404e0ba85c3a4d Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 30 Dec 2015 13:27:09 +0100 Subject: [PATCH 12/36] Bug 1221385 - Handle OOM during JitRuntime initialization a bit better. r=bhackett --- js/src/jscompartment.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index be157444ae7a..749d8e94b83c 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -168,19 +168,12 @@ JSRuntime::createJitRuntime(JSContext* cx) JitRuntime::AutoPreventBackedgePatching apbp(cx->runtime(), jrt); jitRuntime_ = jrt; + AutoEnterOOMUnsafeRegion noOOM; if (!jitRuntime_->initialize(cx)) { - ReportOutOfMemory(cx); - - js_delete(jitRuntime_); - jitRuntime_ = nullptr; - - JSCompartment* comp = cx->runtime()->atomsCompartment(); - if (comp->jitCompartment_) { - js_delete(comp->jitCompartment_); - comp->jitCompartment_ = nullptr; - } - - return nullptr; + // Handling OOM here is complicated: if we delete jitRuntime_ now, we + // will destroy the ExecutableAllocator, even though there may still be + // JitCode instances holding references to ExecutablePools. + noOOM.crash("OOM in createJitRuntime"); } return jitRuntime_; From aa7429333ca733eacc2e0e93b205be219add7720 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 30 Dec 2015 13:28:13 +0100 Subject: [PATCH 13/36] Bug 1233152 - Use PersistentRooted for ParseTask script and sourceObject. r=terrence --- js/src/vm/HelperThreads.cpp | 5 +++-- js/src/vm/HelperThreads.h | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index e1b063085094..a31a8e90b36c 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -202,7 +202,8 @@ ParseTask::ParseTask(ExclusiveContext* cx, JSObject* exclusiveContextGlobal, JSC alloc(JSRuntime::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), exclusiveContextGlobal(initCx->runtime(), exclusiveContextGlobal), callback(callback), callbackData(callbackData), - script(nullptr), sourceObject(nullptr), errors(cx), overRecursed(false) + script(initCx->runtime()), sourceObject(initCx->runtime()), + errors(cx), overRecursed(false) { } @@ -1384,7 +1385,7 @@ HelperThread::handleParseWorkload() task->options, srcBuf, /* source_ = */ nullptr, /* extraSct = */ nullptr, - /* sourceObjectOut = */ &(task->sourceObject)); + /* sourceObjectOut = */ task->sourceObject.address()); } // The callback is invoked while we are still off the main thread. diff --git a/js/src/vm/HelperThreads.h b/js/src/vm/HelperThreads.h index 10f1471fad48..aae3c152ddfa 100644 --- a/js/src/vm/HelperThreads.h +++ b/js/src/vm/HelperThreads.h @@ -479,10 +479,10 @@ struct ParseTask // Holds the final script between the invocation of the callback and the // point where FinishOffThreadScript is called, which will destroy the // ParseTask. - JSScript* script; + PersistentRootedScript script; // Holds the ScriptSourceObject generated for the script compilation. - ScriptSourceObject* sourceObject; + PersistentRooted sourceObject; // Any errors or warnings produced during compilation. These are reported // when finishing the script. From eb979d623f36b02ba8b1518a57ce02fd7075b815 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 30 Dec 2015 15:13:19 +1100 Subject: [PATCH 14/36] Bug 1223193: P1. Make ImageBridgeChild::mShuttingDown atomic. r=nical --- gfx/layers/ipc/ImageBridgeChild.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index 37f25fef0d30..b3aa34dc3cc4 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -9,6 +9,7 @@ #include // for size_t #include // for uint32_t, uint64_t #include "mozilla/Attributes.h" // for override +#include "mozilla/Atomics.h" #include "mozilla/RefPtr.h" // for already_AddRefed #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTrackerHolder @@ -316,7 +317,7 @@ protected: bool aUnsafe); CompositableTransaction* mTxn; - bool mShuttingDown; + Atomic mShuttingDown; }; } // namespace layers From 647eadb92b91c9be0888b1a89f6832023f63b3f9 Mon Sep 17 00:00:00 2001 From: Jean-Yves Avenard Date: Wed, 30 Dec 2015 16:52:41 +1100 Subject: [PATCH 15/36] Bug 1223193: P2. Cancel ImageBridge proxy functions if shutdown has started. r=nical --- gfx/layers/ipc/ImageBridgeChild.cpp | 16 +++++++++++----- gfx/layers/ipc/ImageBridgeChild.h | 10 ++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index f352fdca7264..100270205356 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -108,6 +108,9 @@ struct AutoEndTransaction { CompositableTransaction* mTxn; }; +/* static */ +Atomic ImageBridgeChild::sIsShutDown(false); + void ImageBridgeChild::UseTextures(CompositableClient* aCompositable, const nsTArray& aTextures) @@ -371,7 +374,7 @@ static void ReleaseImageClientNow(ImageClient* aClient, if (aClient) { aClient->Release(); } - if (aChild && ImageBridgeChild::IsCreated()) { + if (aChild && ImageBridgeChild::IsCreated() && !ImageBridgeChild::IsShutDown()) { aChild->SendAsyncDelete(); } } @@ -463,7 +466,7 @@ void ImageBridgeChild::DispatchReleaseTextureClient(TextureClient* aClient) static void UpdateImageClientNow(ImageClient* aClient, RefPtr&& aContainer) { - if (!ImageBridgeChild::IsCreated()) { + if (!ImageBridgeChild::IsCreated() || ImageBridgeChild::IsShutDown()) { NS_WARNING("Something is holding on to graphics resources after the shutdown" "of the graphics subsystem!"); return; @@ -479,7 +482,7 @@ static void UpdateImageClientNow(ImageClient* aClient, RefPtr&& void ImageBridgeChild::DispatchImageClientUpdate(ImageClient* aClient, ImageContainer* aContainer) { - if (!ImageBridgeChild::IsCreated()) { + if (!ImageBridgeChild::IsCreated() || ImageBridgeChild::IsShutDown()) { NS_WARNING("Something is holding on to graphics resources after the shutdown" "of the graphics subsystem!"); return; @@ -545,7 +548,7 @@ void ImageBridgeChild::UpdateAsyncCanvasRendererNow(AsyncCanvasRenderer* aWrappe static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, RefPtr&& aWaiter) { - if (!ImageBridgeChild::IsCreated()) { + if (!ImageBridgeChild::IsCreated() || ImageBridgeChild::IsShutDown()) { // How sad. If we get into this branch it means that the ImageBridge // got destroyed between the time we ImageBridgeChild::FlushAllImage // was called on some thread, and the time this function was proxied @@ -574,7 +577,7 @@ static void FlushAllImagesSync(ImageClient* aClient, ImageContainer* aContainer, void ImageBridgeChild::FlushAllImages(ImageClient* aClient, ImageContainer* aContainer) { - if (!IsCreated()) { + if (!IsCreated() || IsShutDown()) { return; } MOZ_ASSERT(aClient); @@ -705,6 +708,9 @@ ImageBridgeChild::StartUpInChildProcess(Transport* aTransport, void ImageBridgeChild::ShutDown() { MOZ_ASSERT(NS_IsMainThread()); + + sIsShutDown = true; + if (ImageBridgeChild::IsCreated()) { MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown); diff --git a/gfx/layers/ipc/ImageBridgeChild.h b/gfx/layers/ipc/ImageBridgeChild.h index b3aa34dc3cc4..5f830153bbd7 100644 --- a/gfx/layers/ipc/ImageBridgeChild.h +++ b/gfx/layers/ipc/ImageBridgeChild.h @@ -141,6 +141,15 @@ public: * Can be called from any thread. */ static bool IsCreated(); + /** + * Returns true if the singleton's ShutDown() was called. + * + * Can be called from any thread. + */ + static bool IsShutDown() + { + return sIsShutDown; + } /** * returns the singleton instance. @@ -318,6 +327,7 @@ protected: CompositableTransaction* mTxn; Atomic mShuttingDown; + static Atomic sIsShutDown; }; } // namespace layers From 5fb86d302cea1fa0f39124633e9553a7a9a65d83 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Wed, 30 Dec 2015 15:00:44 +0100 Subject: [PATCH 16/36] Backed out changeset 21607399e25e (bug 1229983) for failing own R(C) test. r=backout --- dom/canvas/crashtests/1229983-1.html | 24 ------------------------ dom/canvas/crashtests/crashtests.list | 1 - gfx/2d/DrawTargetSkia.cpp | 8 -------- gfx/2d/PathSkia.cpp | 8 -------- 4 files changed, 41 deletions(-) delete mode 100644 dom/canvas/crashtests/1229983-1.html diff --git a/dom/canvas/crashtests/1229983-1.html b/dom/canvas/crashtests/1229983-1.html deleted file mode 100644 index a865c569e478..000000000000 --- a/dom/canvas/crashtests/1229983-1.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list index bb7db4a51dde..34c602d51d7b 100644 --- a/dom/canvas/crashtests/crashtests.list +++ b/dom/canvas/crashtests/crashtests.list @@ -25,6 +25,5 @@ load 1183363.html load 1190705.html load 1223740-1.html load 1225381-1.html -load 1229983-1.html load 1229932-1.html load texImage2D.html diff --git a/gfx/2d/DrawTargetSkia.cpp b/gfx/2d/DrawTargetSkia.cpp index 7402a4dfd554..0f752b25e9eb 100644 --- a/gfx/2d/DrawTargetSkia.cpp +++ b/gfx/2d/DrawTargetSkia.cpp @@ -493,10 +493,6 @@ DrawTargetSkia::Stroke(const Path *aPath, return; } - if (!skiaPath->GetPath().isFinite()) { - return; - } - mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint); } @@ -547,10 +543,6 @@ DrawTargetSkia::Fill(const Path *aPath, AutoPaintSetup paint(mCanvas.get(), aOptions, aPattern); - if (!skiaPath->GetPath().isFinite()) { - return; - } - mCanvas->drawPath(skiaPath->GetPath(), paint.mPaint); } diff --git a/gfx/2d/PathSkia.cpp b/gfx/2d/PathSkia.cpp index 3726439b66f1..dc3980bbf405 100644 --- a/gfx/2d/PathSkia.cpp +++ b/gfx/2d/PathSkia.cpp @@ -201,10 +201,6 @@ PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, Rect PathSkia::GetBounds(const Matrix &aTransform) const { - if (!mPath.isFinite()) { - return Rect(); - } - Rect bounds = SkRectToRect(mPath.getBounds()); return aTransform.TransformBounds(bounds); } @@ -213,10 +209,6 @@ Rect PathSkia::GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform) const { - if (!mPath.isFinite()) { - return Rect(); - } - SkPaint paint; StrokeOptionsToPaint(paint, aStrokeOptions); From 913ef0d5c0e76d8ef71b90813cfa70cfd21be7ac Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Thu, 10 Dec 2015 15:42:24 -0500 Subject: [PATCH 17/36] Bug 1210170: Add RID header extension send/receive/query support r=pkerr --- media/webrtc/trunk/webrtc/common_types.cc | 4 +- media/webrtc/trunk/webrtc/common_types.h | 10 ++- .../modules/rtp_rtcp/interface/rtp_receiver.h | 2 + .../modules/rtp_rtcp/interface/rtp_rtcp.h | 5 ++ .../rtp_rtcp/interface/rtp_rtcp_defines.h | 1 + .../rtp_rtcp/source/rtp_header_extension.h | 5 ++ .../rtp_rtcp/source/rtp_receiver_impl.cc | 18 +++++- .../rtp_rtcp/source/rtp_receiver_impl.h | 3 + .../modules/rtp_rtcp/source/rtp_rtcp_impl.cc | 5 ++ .../modules/rtp_rtcp/source/rtp_rtcp_impl.h | 2 + .../modules/rtp_rtcp/source/rtp_sender.cc | 40 ++++++++++++ .../modules/rtp_rtcp/source/rtp_sender.h | 3 + .../modules/rtp_rtcp/source/rtp_utility.cc | 23 ++++++- .../video_engine/include/vie_rtp_rtcp.h | 14 +++++ .../trunk/webrtc/video_engine/vie_channel.cc | 62 ++++++++++++++++++- .../trunk/webrtc/video_engine/vie_channel.h | 6 ++ .../trunk/webrtc/video_engine/vie_receiver.cc | 23 +++++++ .../trunk/webrtc/video_engine/vie_receiver.h | 3 + .../webrtc/video_engine/vie_rtp_rtcp_impl.cc | 53 ++++++++++++++++ .../webrtc/video_engine/vie_rtp_rtcp_impl.h | 9 +++ 20 files changed, 285 insertions(+), 6 deletions(-) diff --git a/media/webrtc/trunk/webrtc/common_types.cc b/media/webrtc/trunk/webrtc/common_types.cc index b67c18c986d4..3ed9a1970292 100644 --- a/media/webrtc/trunk/webrtc/common_types.cc +++ b/media/webrtc/trunk/webrtc/common_types.cc @@ -30,7 +30,9 @@ RTPHeaderExtension::RTPHeaderExtension() hasAudioLevel(false), audioLevel(0), hasVideoRotation(false), - videoRotation(0) { + videoRotation(0), + hasRID(false), + rid(NULL) { } RTPHeader::RTPHeader() diff --git a/media/webrtc/trunk/webrtc/common_types.h b/media/webrtc/trunk/webrtc/common_types.h index 42502d1254e6..0c11be01d88f 100644 --- a/media/webrtc/trunk/webrtc/common_types.h +++ b/media/webrtc/trunk/webrtc/common_types.h @@ -572,6 +572,7 @@ enum { kConfigParameterSize = 128}; enum { kPayloadNameSize = 32}; enum { kMaxSimulcastStreams = 4}; enum { kMaxTemporalStreams = 4}; +enum { kRIDSize = 32}; enum VideoCodecComplexity { @@ -685,6 +686,7 @@ struct SimulcastStream { unsigned int targetBitrate; // kilobits/sec. unsigned int minBitrate; // kilobits/sec. unsigned int qpMax; // minimum quality + char rid[kRIDSize]; bool operator==(const SimulcastStream& other) const { return width == other.width && @@ -693,7 +695,8 @@ struct SimulcastStream { maxBitrate == other.maxBitrate && targetBitrate == other.targetBitrate && minBitrate == other.minBitrate && - qpMax == other.qpMax; + qpMax == other.qpMax && + strcmp(rid, other.rid) == 0; } bool operator!=(const SimulcastStream& other) const { @@ -728,6 +731,7 @@ struct VideoCodec { unsigned int qpMax; unsigned char numberOfSimulcastStreams; + unsigned char ridId; SimulcastStream simulcastStream[kMaxSimulcastStreams]; VideoCodecMode mode; @@ -848,6 +852,10 @@ struct RTPHeaderExtension { // ts_126114v120700p.pdf bool hasVideoRotation; uint8_t videoRotation; + + // RID values for simulcast; see draft-roach-avtext-rid + bool hasRID; + char *rid; // UTF8 string }; struct RTPHeader { diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_receiver.h b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_receiver.h index 62835667df09..e383923c7fd6 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_receiver.h +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_receiver.h @@ -95,6 +95,8 @@ class RtpReceiver { // Returns the current remote CSRCs. virtual int32_t CSRCs(uint32_t array_of_csrc[kRtpCsrcSize]) const = 0; + virtual void GetRID(char rid[256]) const = 0; + // Returns the current energy of the RTP stream received. virtual int32_t Energy(uint8_t array_of_energy[kRtpCsrcSize]) const = 0; }; diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h index 4696be4b4bc6..01a515b0fd18 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h @@ -217,6 +217,11 @@ class RtpRtcp : public Module { */ virtual void SetCsrcs(const std::vector& csrcs) = 0; + /* + * Set RID value for the RID header extension or RTCP SDES + */ + virtual int32_t SetRID(const char *rid) = 0; + /* * Turn on/off sending RTX (RFC 4588). The modes can be set as a combination * of values of the enumerator RtxMode. diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h index 8431fe3b5089..ac35670f4de3 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h @@ -81,6 +81,7 @@ enum RTPExtensionType { kRtpExtensionAbsoluteSendTime, kRtpExtensionVideoRotation, kRtpExtensionTransportSequenceNumber, + kRtpExtensionRID, }; enum RTCPAppSubTypes diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h index 7be3c2e5c4fa..74a9ed5c078a 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_header_extension.h @@ -26,6 +26,8 @@ const size_t kAudioLevelLength = 2; const size_t kAbsoluteSendTimeLength = 4; const size_t kVideoRotationLength = 2; const size_t kTransportSequenceNumberLength = 3; +// kRIDLength is variable +const size_t kRIDLength = 4; // max 1-byte header extension length struct HeaderExtension { HeaderExtension(RTPExtensionType extension_type) @@ -58,6 +60,9 @@ struct HeaderExtension { case kRtpExtensionTransportSequenceNumber: length = kTransportSequenceNumberLength; break; + case kRtpExtensionRID: + length = kRIDLength; + break; default: assert(false); } diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc index 3640933324b5..1c14ec365cb2 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.cc @@ -81,6 +81,7 @@ RtpReceiverImpl::RtpReceiverImpl(int32_t id, last_received_timestamp_(0), last_received_frame_time_ms_(-1), last_received_sequence_number_(0), + rid_(NULL), nack_method_(kNackOff) { assert(incoming_audio_messages_callback); assert(incoming_messages_callback); @@ -155,6 +156,15 @@ int32_t RtpReceiverImpl::CSRCs(uint32_t array_of_csrcs[kRtpCsrcSize]) const { return num_csrcs_; } +void RtpReceiverImpl::GetRID(char rid[256]) const { + CriticalSectionScoped lock(critical_section_rtp_receiver_.get()); + if (rid_) { + strncpy(rid, rid_, 256); + } else { + rid[0] = '\0'; + } +} + int32_t RtpReceiverImpl::Energy( uint8_t array_of_energy[kRtpCsrcSize]) const { return rtp_media_receiver_->Energy(array_of_energy); @@ -222,7 +232,13 @@ bool RtpReceiverImpl::IncomingRtpPacket( last_receive_time_ = clock_->TimeInMilliseconds(); last_received_payload_length_ = payload_data_length; - + // RID rarely if ever changes + if (rtp_header.extension.hasRID && + (!rid_ || strcmp(rtp_header.extension.rid, rid_) != 0)) { + delete [] rid_; + rid_ = new char[strlen(rtp_header.extension.rid)+1]; + strcpy(rid_, rtp_header.extension.rid); + } if (in_order) { if (last_received_timestamp_ != rtp_header.timestamp) { last_received_timestamp_ = rtp_header.timestamp; diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h index 539c22676db9..33c7fdad47f9 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_receiver_impl.h @@ -61,6 +61,8 @@ class RtpReceiverImpl : public RtpReceiver { int32_t CSRCs(uint32_t array_of_csrc[kRtpCsrcSize]) const override; + void GetRID(char rid[256]) const override; + int32_t Energy(uint8_t array_of_energy[kRtpCsrcSize]) const override; TelephoneEventHandler* GetTelephoneEventHandler() override; @@ -96,6 +98,7 @@ class RtpReceiverImpl : public RtpReceiver { uint32_t last_received_timestamp_; int64_t last_received_frame_time_ms_; uint16_t last_received_sequence_number_; + char *rid_; // scope NACKMethod nack_method_; }; diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc index 7b48bbbb0adf..cb661f1d8b79 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -317,6 +317,11 @@ void ModuleRtpRtcpImpl::SetCsrcs(const std::vector& csrcs) { rtp_sender_.SetCsrcs(csrcs); } +int32_t ModuleRtpRtcpImpl::SetRID(const char *rid) { + //XXX rtcp_sender_.SetRID(rid); + return rtp_sender_.SetRID(rid); +} + // TODO(pbos): Handle media and RTX streams separately (separate RTCP // feedbacks). RTCPSender::FeedbackState ModuleRtpRtcpImpl::GetFeedbackState() { diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h index 2288f061bbaa..e946860d9adb 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -79,6 +79,8 @@ class ModuleRtpRtcpImpl : public RtpRtcp { void SetCsrcs(const std::vector& csrcs) override; + int32_t SetRID(const char *rid) override; + RTCPSender::FeedbackState GetFeedbackState(); int CurrentSendFrequencyHz() const; diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index cb0c6dc0c2b5..72aa476d8d12 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -131,6 +131,7 @@ RTPSender::RTPSender(int32_t id, rotation_(kVideoRotation_0), cvo_mode_(kCVONone), transport_sequence_number_(0), + rid_(NULL), // NACK. nack_byte_count_times_(), nack_byte_count_(), @@ -264,6 +265,18 @@ int32_t RTPSender::SetTransportSequenceNumber(uint16_t sequence_number) { return 0; } +int32_t RTPSender::SetRID(const char* rid) { + CriticalSectionScoped cs(send_critsect_.get()); + // TODO(jesup) avoid allocations + if (!rid_ || strlen(rid_) < strlen(rid)) { + // rid rarely changes length.... + delete [] rid_; + rid_ = new char[strlen(rid)+1]; + } + strcpy(rid_, rid); + return 0; +} + int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id) { CriticalSectionScoped cs(send_critsect_.get()); @@ -1221,6 +1234,9 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer, case kRtpExtensionTransportSequenceNumber: block_length = BuildTransportSequenceNumberExtension(extension_data); break; + case kRtpExtensionRID: + block_length = BuildRIDExtension(extension_data); + break; default: assert(false); } @@ -1396,6 +1412,30 @@ uint8_t RTPSender::BuildTransportSequenceNumberExtension( return kTransportSequenceNumberLength; } +uint8_t RTPSender::BuildRIDExtension( + uint8_t* data_buffer) const { + // 0 1 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | L=? |UTF-8 RID value...... |... + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // Get id defined by user. + uint8_t id; + if (rtp_header_extension_map_.GetId(kRtpExtensionRID, + &id) != 0) { + // Not registered. + return 0; + } + size_t pos = 0; + // RID value is not null-terminated in header, so no +1 + const uint8_t len = strlen(rid_); + data_buffer[pos++] = (id << 4) + len; + memcpy(data_buffer + pos, rid_, len); + pos += len; + return pos; +} + bool RTPSender::FindHeaderExtensionPosition(RTPExtensionType type, const uint8_t* rtp_packet, size_t rtp_packet_length, diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h index 61d835d06d90..3d766d7781ea 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -163,6 +163,7 @@ class RTPSender : public RTPSenderInterface { int32_t SetAbsoluteSendTime(uint32_t absolute_send_time); void SetVideoRotation(VideoRotation rotation); int32_t SetTransportSequenceNumber(uint16_t sequence_number); + int32_t SetRID(const char* rid); int32_t RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id); virtual bool IsRtpHeaderExtensionRegistered(RTPExtensionType type) override; @@ -177,6 +178,7 @@ class RTPSender : public RTPSenderInterface { uint8_t BuildAbsoluteSendTimeExtension(uint8_t* data_buffer) const; uint8_t BuildVideoRotationExtension(uint8_t* data_buffer) const; uint8_t BuildTransportSequenceNumberExtension(uint8_t* data_buffer) const; + uint8_t BuildRIDExtension(uint8_t* data_buffer) const; bool UpdateAudioLevel(uint8_t* rtp_packet, size_t rtp_packet_length, @@ -390,6 +392,7 @@ class RTPSender : public RTPSenderInterface { VideoRotation rotation_; CVOMode cvo_mode_; uint16_t transport_sequence_number_; + char* rid_; // NACK uint32_t nack_byte_count_times_[NACK_BYTECOUNT_SIZE]; diff --git a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc index 22e10747f16f..05da63c3b486 100644 --- a/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc +++ b/media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtp_utility.cc @@ -291,7 +291,7 @@ bool RtpHeaderParser::Parse(RTPHeader& header, header.headerLength = 12 + (CC * 4); // not a full validation, just safety against underflow. Padding must // start after the header. We can have 0 payload bytes left, note. - if (header.paddingLength + header.headerLength > length) { + if (header.paddingLength + header.headerLength > (ptrdiff_t) length) { return false; } @@ -300,7 +300,7 @@ bool RtpHeaderParser::Parse(RTPHeader& header, ptr += 4; header.arrOfCSRCs[i] = CSRC; } - assert((ptr - _ptrRTPDataBegin) == header.headerLength); + assert((ptr - _ptrRTPDataBegin) == (ptrdiff_t) header.headerLength); // If in effect, MAY be omitted for those packets for which the offset // is zero. @@ -319,6 +319,10 @@ bool RtpHeaderParser::Parse(RTPHeader& header, header.extension.hasVideoRotation = false; header.extension.videoRotation = 0; + // May not be present in packet. + header.extension.hasRID = false; + header.extension.rid = NULL; + if (X) { /* RTP header extension, RFC 3550. 0 1 2 3 @@ -483,6 +487,21 @@ void RtpHeaderParser::ParseOneByteExtensionHeader( header.extension.hasTransportSequenceNumber = true; break; } + case kRtpExtensionRID: { + // 0 1 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | ID | L=? |UTF-8 RID value...... |... + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // TODO(jesup) - avoid allocating on each packet - high watermark the RID buffer? + char* ptrRID = new char[len+1]; + memcpy(ptrRID, ptr, len); + ptrRID[len] = '\0'; + header.extension.rid = ptrRID; + header.extension.hasRID = true; + break; + } default: { LOG(LS_WARNING) << "Extension type not implemented: " << type; return; diff --git a/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h b/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h index 3898d5b1fe9f..94eb5083d86b 100644 --- a/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h +++ b/media/webrtc/trunk/webrtc/video_engine/include/vie_rtp_rtcp.h @@ -113,6 +113,11 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP { virtual int GetRemoteCSRCs(const int video_channel, unsigned int CSRCs[kRtpCsrcSize]) const = 0; + // This function gets the RID value (if any) for the incoming RTP stream + // for the specified channel. + virtual int GetRemoteRID(const int video_channel, + char rid[256]) const = 0; + // This sets a specific payload type for the RTX stream. Note that this // doesn't enable RTX, SetLocalSSRC must still be called to enable RTX. virtual int SetRtxSendPayloadType(const int video_channel, @@ -265,6 +270,15 @@ class WEBRTC_DLLEXPORT ViERTP_RTCP { bool enable, int id) = 0; + virtual int SetSendRIDStatus(int video_channel, + bool enable, + int id, + const char *rid) = 0; + + virtual int SetReceiveRIDStatus(int video_channel, + bool enable, + int id) = 0; + // Enables/disables RTCP Receiver Reference Time Report Block extension/ // DLRR Report Block extension (RFC 3611). virtual int SetRtcpXrRrtrStatus(int video_channel, bool enable) = 0; diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc b/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc index 514b793db274..ef4fefbe61a6 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc +++ b/media/webrtc/trunk/webrtc/video_engine/vie_channel.cc @@ -123,6 +123,7 @@ ViEChannel::ViEChannel(int32_t channel_id, send_timestamp_extension_id_(kInvalidRtpExtensionId), absolute_send_time_extension_id_(kInvalidRtpExtensionId), video_rotation_extension_id_(kInvalidRtpExtensionId), + rid_extension_id_(kInvalidRtpExtensionId), external_transport_(NULL), decoder_reset_(true), wait_for_key_frame_(false), @@ -370,10 +371,19 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, if (rtp_rtcp_->Sending() && new_stream) { restart_rtp = true; rtp_rtcp_->SetSendingStatus(false); + int i = 0; for (std::list::iterator it = simulcast_rtp_rtcp_.begin(); - it != simulcast_rtp_rtcp_.end(); ++it) { + it != simulcast_rtp_rtcp_.end(); ++it, ++i) { (*it)->SetSendingStatus(false); (*it)->SetSendingMediaStatus(false); + if (video_codec.simulcastStream[i].rid[0] != 0) { + (*it)->RegisterSendRtpHeaderExtension( + kRtpExtensionRID, video_codec.ridId); + (*it)->SetRID(video_codec.simulcastStream[i].rid); + } else { + (*it)->DeregisterSendRtpHeaderExtension( + kRtpExtensionRID); + } } } @@ -503,6 +513,19 @@ int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, rtp_rtcp->DeregisterSendRtpHeaderExtension( kRtpExtensionVideoRotation); } + if (rid_extension_id_ != kInvalidRtpExtensionId) { + // Deregister in case the extension was previously enabled. + rtp_rtcp->DeregisterSendRtpHeaderExtension( + kRtpExtensionRID); + if (rtp_rtcp->RegisterSendRtpHeaderExtension( + kRtpExtensionRID, + rid_extension_id_) != 0) { + LOG(LS_WARNING) << "Register RID extension failed"; + } + } else { + rtp_rtcp->DeregisterSendRtpHeaderExtension( + kRtpExtensionRID); + } rtp_rtcp->RegisterRtcpStatisticsCallback( rtp_rtcp_->GetRtcpStatisticsCallback()); rtp_rtcp->RegisterSendChannelRtpStatisticsCallback( @@ -966,6 +989,37 @@ int ViEChannel::SetReceiveVideoRotationStatus(bool enable, int id) { return vie_receiver_.SetReceiveVideoRotationStatus(enable, id) ? 0 : -1; } +int ViEChannel::SetSendRIDStatus(bool enable, int id, const char *rid) { + CriticalSectionScoped cs(rtp_rtcp_cs_.get()); + int error = 0; + if (enable) { + // Enable the extension, but disable possible old id to avoid errors. + rid_extension_id_ = id; + rtp_rtcp_->DeregisterSendRtpHeaderExtension( + kRtpExtensionRID); + error = rtp_rtcp_->RegisterSendRtpHeaderExtension( + kRtpExtensionRID, id); + rtp_rtcp_->SetRID(rid); + // NOTE: simulcast streams must be set via the SetSendCodec() API + } else { + // Disable the extension. + rid_extension_id_ = kInvalidRtpExtensionId; + rtp_rtcp_->DeregisterSendRtpHeaderExtension( + kRtpExtensionRID); + // This may be overkill... + for (std::list::iterator it = simulcast_rtp_rtcp_.begin(); + it != simulcast_rtp_rtcp_.end(); it++) { + (*it)->DeregisterSendRtpHeaderExtension( + kRtpExtensionRID); + } + } + return error; +} + +int ViEChannel::SetReceiveRIDStatus(bool enable, int id) { + return vie_receiver_.SetReceiveRIDStatus(enable, id) ? 0 : -1; +} + void ViEChannel::SetRtcpXrRrtrStatus(bool enable) { CriticalSectionScoped cs(rtp_rtcp_cs_.get()); rtp_rtcp_->SetRtcpXrRrtrStatus(enable); @@ -1037,6 +1091,12 @@ int32_t ViEChannel::GetRemoteCSRC(uint32_t CSRCs[kRtpCsrcSize]) { return 0; } +int32_t ViEChannel::GetRemoteRID(char rid[256]) +{ + vie_receiver_.GetRID(rid); + return 0; +} + int ViEChannel::SetRtxSendPayloadType(int payload_type) { rtp_rtcp_->SetRtxSendPayloadType(payload_type); for (std::list::iterator it = simulcast_rtp_rtcp_.begin(); diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_channel.h b/media/webrtc/trunk/webrtc/video_engine/vie_channel.h index 1197115e2807..9658b209cde7 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_channel.h +++ b/media/webrtc/trunk/webrtc/video_engine/vie_channel.h @@ -138,6 +138,8 @@ class ViEChannel bool GetReceiveAbsoluteSendTimeStatus() const; int SetSendVideoRotationStatus(bool enable, int id); int SetReceiveVideoRotationStatus(bool enable, int id); + int SetSendRIDStatus(bool enable, int id, const char *rid); + int SetReceiveRIDStatus(bool enable, int id); void SetRtcpXrRrtrStatus(bool enable); void SetTransmissionSmoothingStatus(bool enable); void EnableTMMBR(bool enable); @@ -157,6 +159,9 @@ class ViEChannel // Gets the CSRC for the incoming stream. int32_t GetRemoteCSRC(uint32_t CSRCs[kRtpCsrcSize]); + // Gets the RID (if any) for the incoming stream. + int32_t GetRemoteRID(char rid[256]); + int SetRtxSendPayloadType(int payload_type); void SetRtxReceivePayloadType(int payload_type); @@ -554,6 +559,7 @@ class ViEChannel int send_timestamp_extension_id_; int absolute_send_time_extension_id_; int video_rotation_extension_id_; + int rid_extension_id_; Transport* external_transport_; diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_receiver.cc b/media/webrtc/trunk/webrtc/video_engine/vie_receiver.cc index daac6b93c4c5..d4989777db67 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_receiver.cc +++ b/media/webrtc/trunk/webrtc/video_engine/vie_receiver.cc @@ -61,6 +61,7 @@ ViEReceiver::ViEReceiver(const int32_t channel_id, restored_packet_in_use_(false), receiving_ast_enabled_(false), receiving_cvo_enabled_(false), + receiving_rid_enabled_(false), last_packet_log_ms_(-1) { assert(remote_bitrate_estimator); } @@ -144,6 +145,10 @@ int ViEReceiver::GetCsrcs(uint32_t* csrcs) const { return rtp_receiver_->CSRCs(csrcs); } +void ViEReceiver::GetRID(char rid[256]) const { + rtp_receiver_->GetRID(rid); +} + void ViEReceiver::SetRtpRtcpModule(RtpRtcp* module) { rtp_rtcp_ = module; } @@ -206,6 +211,22 @@ bool ViEReceiver::SetReceiveVideoRotationStatus(bool enable, int id) { } } +bool ViEReceiver::SetReceiveRIDStatus(bool enable, int id) { + if (enable) { + if (rtp_header_parser_->RegisterRtpHeaderExtension( + kRtpExtensionRID, id)) { + receiving_rid_enabled_ = true; + return true; + } else { + return false; + } + } else { + receiving_rid_enabled_ = false; + return rtp_header_parser_->DeregisterRtpHeaderExtension( + kRtpExtensionRID); + } +} + int ViEReceiver::ReceivedRTPPacket(const void* rtp_packet, size_t rtp_packet_length, const PacketTime& packet_time) { @@ -295,6 +316,8 @@ int ViEReceiver::InsertRTPPacket(const uint8_t* rtp_packet, ss << ", toffset: " << header.extension.transmissionTimeOffset; if (header.extension.hasAbsoluteSendTime) ss << ", abs send time: " << header.extension.absoluteSendTime; + if (header.extension.hasRID) + ss << ", rid: " << header.extension.rid; LOG(LS_INFO) << ss.str(); last_packet_log_ms_ = now_ms; } diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_receiver.h b/media/webrtc/trunk/webrtc/video_engine/vie_receiver.h index 1002f6416536..4b064767901c 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_receiver.h +++ b/media/webrtc/trunk/webrtc/video_engine/vie_receiver.h @@ -55,6 +55,7 @@ class ViEReceiver : public RtpData { uint32_t GetRemoteSsrc() const; int GetCsrcs(uint32_t* csrcs) const; + void GetRID(char rid[256]) const; void SetRtpRtcpModule(RtpRtcp* module); @@ -65,6 +66,7 @@ class ViEReceiver : public RtpData { bool SetReceiveTimestampOffsetStatus(bool enable, int id); bool SetReceiveAbsoluteSendTimeStatus(bool enable, int id); bool SetReceiveVideoRotationStatus(bool enable, int id); + bool SetReceiveRIDStatus(bool enable, int id); void StartReceive(); void StopReceive(); @@ -129,6 +131,7 @@ class ViEReceiver : public RtpData { bool restored_packet_in_use_; bool receiving_ast_enabled_; bool receiving_cvo_enabled_; + bool receiving_rid_enabled_; int64_t last_packet_log_ms_; }; diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc index b8f8bd33a210..236d6771469f 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc +++ b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.cc @@ -191,6 +191,21 @@ int ViERTP_RTCPImpl::GetRemoteCSRCs(const int video_channel, return 0; } +int ViERTP_RTCPImpl::GetRemoteRID(const int video_channel, + char rid[256]) const { + ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); + ViEChannel* vie_channel = cs.Channel(video_channel); + if (!vie_channel) { + shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (vie_channel->GetRemoteRID(rid) != 0) { + shared_data_->SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + int ViERTP_RTCPImpl::SetRtxSendPayloadType(const int video_channel, const uint8_t payload_type) { LOG_F(LS_INFO) << "channel: " << video_channel @@ -683,6 +698,44 @@ int ViERTP_RTCPImpl::SetReceiveVideoRotationStatus(int video_channel, return 0; } +int ViERTP_RTCPImpl::SetSendRIDStatus(int video_channel, + bool enable, + int id, + const char *rid) { + LOG_F(LS_INFO) << "channel: " << video_channel + << " enable: " << (enable ? "on" : "off") << " id: " << id << " RID: " << rid; + + ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); + ViEChannel* vie_channel = cs.Channel(video_channel); + if (!vie_channel) { + shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (vie_channel->SetSendRIDStatus(enable, id, rid) != 0) { + shared_data_->SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + +int ViERTP_RTCPImpl::SetReceiveRIDStatus(int video_channel, + bool enable, + int id) { + LOG_F(LS_INFO) << "channel: " << video_channel + << " enable: " << (enable ? "on" : "off") << " id: " << id; + ViEChannelManagerScoped cs(*(shared_data_->channel_manager())); + ViEChannel* vie_channel = cs.Channel(video_channel); + if (!vie_channel) { + shared_data_->SetLastError(kViERtpRtcpInvalidChannelId); + return -1; + } + if (vie_channel->SetReceiveRIDStatus(enable, id) != 0) { + shared_data_->SetLastError(kViERtpRtcpUnknownError); + return -1; + } + return 0; +} + int ViERTP_RTCPImpl::SetRtcpXrRrtrStatus(int video_channel, bool enable) { LOG_F(LS_INFO) << "channel: " << video_channel << " enable: " << (enable ? "on" : "off"); diff --git a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h index 8f92a72525cf..e1ac4f8cbc41 100644 --- a/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h +++ b/media/webrtc/trunk/webrtc/video_engine/vie_rtp_rtcp_impl.h @@ -39,6 +39,8 @@ class ViERTP_RTCPImpl unsigned int& SSRC) const; // NOLINT virtual int GetRemoteCSRCs(const int video_channel, unsigned int CSRCs[kRtpCsrcSize]) const; + virtual int GetRemoteRID(const int video_channel, + char rid[256]) const; virtual int SetRtxSendPayloadType(const int video_channel, const uint8_t payload_type); virtual int SetRtxReceivePayloadType(const int video_channel, @@ -105,6 +107,13 @@ class ViERTP_RTCPImpl virtual int SetReceiveVideoRotationStatus(int video_channel, bool enable, int id); + virtual int SetSendRIDStatus(int video_channel, + bool enable, + int id, + const char *rid); + virtual int SetReceiveRIDStatus(int video_channel, + bool enable, + int id); virtual int SetRtcpXrRrtrStatus(int video_channel, bool enable); virtual int SetTransmissionSmoothingStatus(int video_channel, bool enable); virtual int SetMinTransmitBitrate(int video_channel, From 39d98db02b461992528e8fb2a2b4a7020e469aec Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Wed, 30 Dec 2015 10:13:13 -0700 Subject: [PATCH 18/36] Bug 1234281 - Use new Android x86 avd; r=me --- .../config/tooltool-manifests/androidx86/releng.manifest | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/testing/config/tooltool-manifests/androidx86/releng.manifest b/testing/config/tooltool-manifests/androidx86/releng.manifest index 2bc23050057d..70258982ab4f 100644 --- a/testing/config/tooltool-manifests/androidx86/releng.manifest +++ b/testing/config/tooltool-manifests/androidx86/releng.manifest @@ -1,7 +1,8 @@ [{ -"size": 561274118, -"digest": "3b2d18eb0194d82c70c5ee17487ccbac309f9b2e9839fe7ca4a27a9a06f6338bb24394476da78559685d99151fccc85fdde03297aa73ee2f7fb3183e11925c4d", +"size": 560988557, +"visibility": "public", +"digest": "9c09e2084e1640dbf95d37ca198803064afea9d7ce5455e2860aa3a8a738976a9e56464a6d829ba05fa13978305a9ddd2eaec6e482de8974af8523e523556631", "algorithm": "sha512", -"filename": "AVDs-x86-android-4.2_r1-build-2013-11-13-ubuntu.tar.gz", +"filename": "AVDs-x86-android-4.2_r1-build-2015-12-29-ubuntu.tar.gz", "unpack": true }] From f72ad5d158971947a4a5495572bb352a1c1e9981 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 30 Dec 2015 12:17:06 -0500 Subject: [PATCH 19/36] Bug 1234494 - part 2 - disable Skia GPU support by default on certain *BSDs, r=glandium --- configure.in | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/configure.in b/configure.in index 7289fcf019d7..263c3ce4559a 100644 --- a/configure.in +++ b/configure.in @@ -7991,6 +7991,15 @@ MOZ_ARG_ENABLE_BOOL(skia, MOZ_ENABLE_SKIA=1, MOZ_ENABLE_SKIA=) +dnl Skia GPU support may not reliably build on certain *BSDs (see bug 1234494). +if test "${OS_TARGET}" = "OpenBSD" -o \ + "${OS_TARGET}" = "NetBSD" -o \ + "${OS_ARCH}" = "SunOS"; then + MOZ_DISABLE_SKIA_GPU=1 +else + MOZ_DISABLE_SKIA_GPU= +fi + MOZ_ARG_DISABLE_BOOL(skia-gpu, [ --disable-skia-gpu Disable use of Skia-GPU], MOZ_DISABLE_SKIA_GPU=1, From 08826ed9762ac07b333997b570eb840d33602caf Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 30 Dec 2015 12:17:32 -0500 Subject: [PATCH 20/36] Bug 1234494 - part 1 - don't build in Skia GPU code if support is disabled, r=jrmuizel --- gfx/skia/generate_mozbuild.py | 11 +- gfx/skia/moz.build | 372 +++++++++++++++++----------------- 2 files changed, 200 insertions(+), 183 deletions(-) diff --git a/gfx/skia/generate_mozbuild.py b/gfx/skia/generate_mozbuild.py index f882c7eac5a7..0a3a75bcf071 100755 --- a/gfx/skia/generate_mozbuild.py +++ b/gfx/skia/generate_mozbuild.py @@ -102,6 +102,9 @@ elif CONFIG['CLANG_CL']: DEFINES['SKIA_IMPLEMENTATION'] = 1 +if not CONFIG['MOZ_ENABLE_SKIA_GPU']: + DEFINES['SK_SUPPORT_GPU'] = 0 + if CONFIG['GNU_CXX']: CXXFLAGS += [ '-Wno-deprecated-declarations', @@ -227,7 +230,8 @@ def generate_separated_sources(platform_sources): 'skia/src/opts/SkOpts_neon.cpp', 'skia/src/opts/SkBitmapProcState_arm_neon.cpp', }, - 'none': set() + 'none': set(), + 'gpu': set() }) for plat in platform_sources.keys(): @@ -248,6 +252,8 @@ def generate_separated_sources(platform_sources): key = 'arm' elif '_none' in value: key = 'none' + elif 'gpu' in value or 'Gpu' in value: + key = 'gpu' elif all(value in platform_sources.get(p, {}) for p in platforms if p != plat): key = 'common' @@ -358,6 +364,9 @@ def write_mozbuild(sources): write_sources(f, sources['common'], 0) + f.write("if CONFIG['MOZ_ENABLE_SKIA_GPU']:\n") + write_sources(f, sources['gpu'], 4) + f.write("if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):\n") write_sources(f, sources['android'], 4) diff --git a/gfx/skia/moz.build b/gfx/skia/moz.build index da3a99b6ce11..d5ff0f8dc491 100644 --- a/gfx/skia/moz.build +++ b/gfx/skia/moz.build @@ -181,7 +181,6 @@ UNIFIED_SOURCES += [ 'skia/src/effects/gradients/SkRadialGradient.cpp', 'skia/src/effects/gradients/SkSweepGradient.cpp', 'skia/src/effects/gradients/SkTwoPointConicalGradient.cpp', - 'skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp', 'skia/src/effects/GrCircleBlurFragmentProcessor.cpp', 'skia/src/effects/Sk1DPathEffect.cpp', 'skia/src/effects/Sk2DPathEffect.cpp', @@ -205,7 +204,6 @@ UNIFIED_SOURCES += [ 'skia/src/effects/SkDropShadowImageFilter.cpp', 'skia/src/effects/SkEmbossMask.cpp', 'skia/src/effects/SkEmbossMaskFilter.cpp', - 'skia/src/effects/SkGpuBlurUtils.cpp', 'skia/src/effects/SkImageSource.cpp', 'skia/src/effects/SkLayerDrawLooper.cpp', 'skia/src/effects/SkLayerRasterizer.cpp', @@ -232,133 +230,11 @@ UNIFIED_SOURCES += [ 'skia/src/fonts/SkRandomScalerContext.cpp', 'skia/src/fonts/SkRemotableFontMgr.cpp', 'skia/src/fonts/SkTestScalerContext.cpp', - 'skia/src/gpu/batches/GrAtlasTextBatch.cpp', - 'skia/src/gpu/batches/GrBatch.cpp', - 'skia/src/gpu/batches/GrCopySurfaceBatch.cpp', - 'skia/src/gpu/batches/GrDashLinePathRenderer.cpp', - 'skia/src/gpu/batches/GrDefaultPathRenderer.cpp', - 'skia/src/gpu/batches/GrDrawAtlasBatch.cpp', - 'skia/src/gpu/batches/GrDrawBatch.cpp', - 'skia/src/gpu/batches/GrDrawPathBatch.cpp', - 'skia/src/gpu/batches/GrDrawVerticesBatch.cpp', - 'skia/src/gpu/batches/GrNinePatch.cpp', - 'skia/src/gpu/batches/GrNonAAFillRectBatch.cpp', - 'skia/src/gpu/batches/GrNonAAStrokeRectBatch.cpp', - 'skia/src/gpu/batches/GrRectBatchFactory.cpp', - 'skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp', - 'skia/src/gpu/batches/GrTessellatingPathRenderer.cpp', - 'skia/src/gpu/batches/GrVertexBatch.cpp', - 'skia/src/gpu/effects/GrBezierEffect.cpp', - 'skia/src/gpu/effects/GrBicubicEffect.cpp', - 'skia/src/gpu/effects/GrBitmapTextGeoProc.cpp', - 'skia/src/gpu/effects/GrConfigConversionEffect.cpp', - 'skia/src/gpu/effects/GrConstColorProcessor.cpp', - 'skia/src/gpu/effects/GrConvexPolyEffect.cpp', - 'skia/src/gpu/effects/GrConvolutionEffect.cpp', - 'skia/src/gpu/effects/GrCoverageSetOpXP.cpp', - 'skia/src/gpu/effects/GrCustomXfermode.cpp', - 'skia/src/gpu/effects/GrDashingEffect.cpp', - 'skia/src/gpu/effects/GrDisableColorXP.cpp', - 'skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp', - 'skia/src/gpu/effects/GrDitherEffect.cpp', - 'skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp', - 'skia/src/gpu/effects/GrOvalEffect.cpp', - 'skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp', - 'skia/src/gpu/effects/GrRRectEffect.cpp', - 'skia/src/gpu/effects/GrSimpleTextureEffect.cpp', - 'skia/src/gpu/effects/GrSingleTextureEffect.cpp', - 'skia/src/gpu/effects/GrTextureDomain.cpp', - 'skia/src/gpu/effects/GrTextureStripAtlas.cpp', - 'skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp', - 'skia/src/gpu/effects/GrYUVtoRGBEffect.cpp', - 'skia/src/gpu/gl/debug/GrBufferObj.cpp', - 'skia/src/gpu/gl/debug/GrDebugGL.cpp', - 'skia/src/gpu/gl/debug/GrFrameBufferObj.cpp', - 'skia/src/gpu/gl/debug/GrProgramObj.cpp', - 'skia/src/gpu/gl/debug/GrShaderObj.cpp', - 'skia/src/gpu/gl/debug/GrTextureObj.cpp', - 'skia/src/gpu/gl/debug/GrTextureUnitObj.cpp', - 'skia/src/gpu/gl/debug/SkDebugGLContext.cpp', - 'skia/src/gpu/gl/SkGLContext.cpp', - 'skia/src/gpu/gl/SkNullGLContext.cpp', - 'skia/src/gpu/GrAtlasTextBlob.cpp', - 'skia/src/gpu/GrAtlasTextContext.cpp', - 'skia/src/gpu/GrBatchFlushState.cpp', - 'skia/src/gpu/GrBatchFontCache.cpp', - 'skia/src/gpu/GrBatchTest.cpp', - 'skia/src/gpu/GrBlend.cpp', - 'skia/src/gpu/GrBlurUtils.cpp', - 'skia/src/gpu/GrBufferAllocPool.cpp', - 'skia/src/gpu/GrCaps.cpp', - 'skia/src/gpu/GrClip.cpp', - 'skia/src/gpu/GrClipMaskManager.cpp', - 'skia/src/gpu/GrContext.cpp', - 'skia/src/gpu/GrCoordTransform.cpp', - 'skia/src/gpu/GrDefaultGeoProcFactory.cpp', - 'skia/src/gpu/GrDrawingManager.cpp', - 'skia/src/gpu/GrDrawTarget.cpp', - 'skia/src/gpu/GrFontScaler.cpp', - 'skia/src/gpu/GrFragmentProcessor.cpp', - 'skia/src/gpu/GrGpu.cpp', - 'skia/src/gpu/GrGpuFactory.cpp', - 'skia/src/gpu/GrGpuResource.cpp', - 'skia/src/gpu/GrGpuResourceRef.cpp', - 'skia/src/gpu/GrImageIDTextureAdjuster.cpp', - 'skia/src/gpu/GrInvariantOutput.cpp', - 'skia/src/gpu/GrLayerAtlas.cpp', - 'skia/src/gpu/GrLayerCache.cpp', - 'skia/src/gpu/GrLayerHoister.cpp', - 'skia/src/gpu/GrMemoryPool.cpp', - 'skia/src/gpu/GrOvalRenderer.cpp', - 'skia/src/gpu/GrPaint.cpp', - 'skia/src/gpu/GrPath.cpp', - 'skia/src/gpu/GrPathProcessor.cpp', - 'skia/src/gpu/GrPathRange.cpp', - 'skia/src/gpu/GrPathRenderer.cpp', - 'skia/src/gpu/GrPathRendererChain.cpp', - 'skia/src/gpu/GrPathRendering.cpp', - 'skia/src/gpu/GrPathUtils.cpp', - 'skia/src/gpu/GrPipeline.cpp', - 'skia/src/gpu/GrPipelineBuilder.cpp', - 'skia/src/gpu/GrPrimitiveProcessor.cpp', - 'skia/src/gpu/GrProcessor.cpp', - 'skia/src/gpu/GrProcessorUnitTest.cpp', - 'skia/src/gpu/GrProcOptInfo.cpp', - 'skia/src/gpu/GrProgramElement.cpp', - 'skia/src/gpu/GrRecordReplaceDraw.cpp', - 'skia/src/gpu/GrRectanizer_pow2.cpp', - 'skia/src/gpu/GrRectanizer_skyline.cpp', - 'skia/src/gpu/GrReducedClip.cpp', - 'skia/src/gpu/GrRenderTarget.cpp', - 'skia/src/gpu/GrResourceProvider.cpp', - 'skia/src/gpu/GrSoftwarePathRenderer.cpp', - 'skia/src/gpu/GrStencil.cpp', - 'skia/src/gpu/GrStencilAndCoverTextContext.cpp', - 'skia/src/gpu/GrStencilAttachment.cpp', - 'skia/src/gpu/GrStrokeInfo.cpp', - 'skia/src/gpu/GrSurface.cpp', - 'skia/src/gpu/GrSWMaskHelper.cpp', - 'skia/src/gpu/GrTestUtils.cpp', - 'skia/src/gpu/GrTextBlobCache.cpp', - 'skia/src/gpu/GrTextContext.cpp', - 'skia/src/gpu/GrTexture.cpp', - 'skia/src/gpu/GrTextureAccess.cpp', - 'skia/src/gpu/GrTextureParamsAdjuster.cpp', - 'skia/src/gpu/GrTextureProvider.cpp', - 'skia/src/gpu/GrTraceMarker.cpp', - 'skia/src/gpu/GrXferProcessor.cpp', - 'skia/src/gpu/GrYUVProvider.cpp', - 'skia/src/gpu/SkGpuDevice.cpp', - 'skia/src/gpu/SkGpuDevice_drawTexture.cpp', - 'skia/src/gpu/SkGr.cpp', - 'skia/src/gpu/SkGrPixelRef.cpp', - 'skia/src/gpu/SkGrTexturePixelRef.cpp', 'skia/src/image/SkImage.cpp', 'skia/src/image/SkImage_Generator.cpp', 'skia/src/image/SkImage_Raster.cpp', 'skia/src/image/SkImageShader.cpp', 'skia/src/image/SkSurface.cpp', - 'skia/src/image/SkSurface_Gpu.cpp', 'skia/src/image/SkSurface_Raster.cpp', 'skia/src/images/bmpdecoderhelper.cpp', 'skia/src/images/SkDecodingImageGenerator.cpp', @@ -455,71 +331,200 @@ SOURCES += [ 'skia/src/core/SkPictureData.cpp', 'skia/src/core/SkRecorder.cpp', 'skia/src/core/SkScan_Antihair.cpp', - 'skia/src/effects/SkArithmeticMode_gpu.cpp', - 'skia/src/gpu/batches/GrAAConvexPathRenderer.cpp', - 'skia/src/gpu/batches/GrAAConvexTessellator.cpp', - 'skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp', - 'skia/src/gpu/batches/GrAAFillRectBatch.cpp', - 'skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp', - 'skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp', - 'skia/src/gpu/batches/GrAAStrokeRectBatch.cpp', - 'skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp', - 'skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp', - 'skia/src/gpu/gl/builders/GrGLSLPrettyPrint.cpp', - 'skia/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp', - 'skia/src/gpu/gl/GrGLAssembleInterface.cpp', - 'skia/src/gpu/gl/GrGLBufferImpl.cpp', - 'skia/src/gpu/gl/GrGLCaps.cpp', - 'skia/src/gpu/gl/GrGLContext.cpp', 'skia/src/gpu/gl/GrGLCreateNativeInterface_none.cpp', - 'skia/src/gpu/gl/GrGLCreateNullInterface.cpp', - 'skia/src/gpu/gl/GrGLDefaultInterface_native.cpp', - 'skia/src/gpu/gl/GrGLExtensions.cpp', - 'skia/src/gpu/gl/GrGLGLSL.cpp', - 'skia/src/gpu/gl/GrGLGpu.cpp', - 'skia/src/gpu/gl/GrGLGpuProgramCache.cpp', - 'skia/src/gpu/gl/GrGLIndexBuffer.cpp', - 'skia/src/gpu/gl/GrGLInterface.cpp', - 'skia/src/gpu/gl/GrGLNameAllocator.cpp', - 'skia/src/gpu/gl/GrGLNoOpInterface.cpp', - 'skia/src/gpu/gl/GrGLPath.cpp', - 'skia/src/gpu/gl/GrGLPathRange.cpp', - 'skia/src/gpu/gl/GrGLPathRendering.cpp', - 'skia/src/gpu/gl/GrGLProgram.cpp', - 'skia/src/gpu/gl/GrGLProgramDataManager.cpp', - 'skia/src/gpu/gl/GrGLProgramDesc.cpp', - 'skia/src/gpu/gl/GrGLRenderTarget.cpp', - 'skia/src/gpu/gl/GrGLStencilAttachment.cpp', - 'skia/src/gpu/gl/GrGLTexture.cpp', - 'skia/src/gpu/gl/GrGLTextureRenderTarget.cpp', - 'skia/src/gpu/gl/GrGLUtil.cpp', - 'skia/src/gpu/gl/GrGLVaryingHandler.cpp', - 'skia/src/gpu/gl/GrGLVertexArray.cpp', - 'skia/src/gpu/gl/GrGLVertexBuffer.cpp', - 'skia/src/gpu/glsl/GrGLSL.cpp', - 'skia/src/gpu/glsl/GrGLSLBlend.cpp', - 'skia/src/gpu/glsl/GrGLSLCaps.cpp', - 'skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp', - 'skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp', - 'skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp', - 'skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp', - 'skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp', - 'skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp', - 'skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp', - 'skia/src/gpu/glsl/GrGLSLUtil.cpp', - 'skia/src/gpu/glsl/GrGLSLVarying.cpp', - 'skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp', - 'skia/src/gpu/glsl/GrGLSLXferProcessor.cpp', - 'skia/src/gpu/GrBatchAtlas.cpp', - 'skia/src/gpu/GrDrawContext.cpp', - 'skia/src/gpu/GrResourceCache.cpp', - 'skia/src/image/SkImage_Gpu.cpp', 'skia/src/pathops/SkPathOpsDebug.cpp', 'skia/src/utils/SkMD5.cpp', 'skia/src/utils/SkParse.cpp', 'skia/src/utils/SkParsePath.cpp', 'skia/src/utils/SkSHA1.cpp', ] +if CONFIG['MOZ_ENABLE_SKIA_GPU']: + UNIFIED_SOURCES += [ + 'skia/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp', + 'skia/src/effects/SkGpuBlurUtils.cpp', + 'skia/src/gpu/batches/GrAtlasTextBatch.cpp', + 'skia/src/gpu/batches/GrBatch.cpp', + 'skia/src/gpu/batches/GrCopySurfaceBatch.cpp', + 'skia/src/gpu/batches/GrDashLinePathRenderer.cpp', + 'skia/src/gpu/batches/GrDefaultPathRenderer.cpp', + 'skia/src/gpu/batches/GrDrawAtlasBatch.cpp', + 'skia/src/gpu/batches/GrDrawBatch.cpp', + 'skia/src/gpu/batches/GrDrawPathBatch.cpp', + 'skia/src/gpu/batches/GrDrawVerticesBatch.cpp', + 'skia/src/gpu/batches/GrNinePatch.cpp', + 'skia/src/gpu/batches/GrNonAAFillRectBatch.cpp', + 'skia/src/gpu/batches/GrNonAAStrokeRectBatch.cpp', + 'skia/src/gpu/batches/GrRectBatchFactory.cpp', + 'skia/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp', + 'skia/src/gpu/batches/GrTessellatingPathRenderer.cpp', + 'skia/src/gpu/batches/GrVertexBatch.cpp', + 'skia/src/gpu/effects/GrBezierEffect.cpp', + 'skia/src/gpu/effects/GrBicubicEffect.cpp', + 'skia/src/gpu/effects/GrBitmapTextGeoProc.cpp', + 'skia/src/gpu/effects/GrConfigConversionEffect.cpp', + 'skia/src/gpu/effects/GrConstColorProcessor.cpp', + 'skia/src/gpu/effects/GrConvexPolyEffect.cpp', + 'skia/src/gpu/effects/GrConvolutionEffect.cpp', + 'skia/src/gpu/effects/GrCoverageSetOpXP.cpp', + 'skia/src/gpu/effects/GrCustomXfermode.cpp', + 'skia/src/gpu/effects/GrDashingEffect.cpp', + 'skia/src/gpu/effects/GrDisableColorXP.cpp', + 'skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp', + 'skia/src/gpu/effects/GrDitherEffect.cpp', + 'skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp', + 'skia/src/gpu/effects/GrOvalEffect.cpp', + 'skia/src/gpu/effects/GrPorterDuffXferProcessor.cpp', + 'skia/src/gpu/effects/GrRRectEffect.cpp', + 'skia/src/gpu/effects/GrSimpleTextureEffect.cpp', + 'skia/src/gpu/effects/GrSingleTextureEffect.cpp', + 'skia/src/gpu/effects/GrTextureDomain.cpp', + 'skia/src/gpu/effects/GrTextureStripAtlas.cpp', + 'skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp', + 'skia/src/gpu/effects/GrYUVtoRGBEffect.cpp', + 'skia/src/gpu/gl/debug/GrBufferObj.cpp', + 'skia/src/gpu/gl/debug/GrDebugGL.cpp', + 'skia/src/gpu/gl/debug/GrFrameBufferObj.cpp', + 'skia/src/gpu/gl/debug/GrProgramObj.cpp', + 'skia/src/gpu/gl/debug/GrShaderObj.cpp', + 'skia/src/gpu/gl/debug/GrTextureObj.cpp', + 'skia/src/gpu/gl/debug/GrTextureUnitObj.cpp', + 'skia/src/gpu/gl/debug/SkDebugGLContext.cpp', + 'skia/src/gpu/gl/SkGLContext.cpp', + 'skia/src/gpu/gl/SkNullGLContext.cpp', + 'skia/src/gpu/GrAtlasTextBlob.cpp', + 'skia/src/gpu/GrAtlasTextContext.cpp', + 'skia/src/gpu/GrBatchFlushState.cpp', + 'skia/src/gpu/GrBatchFontCache.cpp', + 'skia/src/gpu/GrBatchTest.cpp', + 'skia/src/gpu/GrBlend.cpp', + 'skia/src/gpu/GrBlurUtils.cpp', + 'skia/src/gpu/GrBufferAllocPool.cpp', + 'skia/src/gpu/GrCaps.cpp', + 'skia/src/gpu/GrClip.cpp', + 'skia/src/gpu/GrClipMaskManager.cpp', + 'skia/src/gpu/GrContext.cpp', + 'skia/src/gpu/GrCoordTransform.cpp', + 'skia/src/gpu/GrDefaultGeoProcFactory.cpp', + 'skia/src/gpu/GrDrawingManager.cpp', + 'skia/src/gpu/GrDrawTarget.cpp', + 'skia/src/gpu/GrFontScaler.cpp', + 'skia/src/gpu/GrFragmentProcessor.cpp', + 'skia/src/gpu/GrGpu.cpp', + 'skia/src/gpu/GrGpuFactory.cpp', + 'skia/src/gpu/GrGpuResource.cpp', + 'skia/src/gpu/GrGpuResourceRef.cpp', + 'skia/src/gpu/GrImageIDTextureAdjuster.cpp', + 'skia/src/gpu/GrInvariantOutput.cpp', + 'skia/src/gpu/GrLayerAtlas.cpp', + 'skia/src/gpu/GrLayerCache.cpp', + 'skia/src/gpu/GrLayerHoister.cpp', + 'skia/src/gpu/GrMemoryPool.cpp', + 'skia/src/gpu/GrOvalRenderer.cpp', + 'skia/src/gpu/GrPaint.cpp', + 'skia/src/gpu/GrPath.cpp', + 'skia/src/gpu/GrPathProcessor.cpp', + 'skia/src/gpu/GrPathRange.cpp', + 'skia/src/gpu/GrPathRenderer.cpp', + 'skia/src/gpu/GrPathRendererChain.cpp', + 'skia/src/gpu/GrPathRendering.cpp', + 'skia/src/gpu/GrPathUtils.cpp', + 'skia/src/gpu/GrPipeline.cpp', + 'skia/src/gpu/GrPipelineBuilder.cpp', + 'skia/src/gpu/GrPrimitiveProcessor.cpp', + 'skia/src/gpu/GrProcessor.cpp', + 'skia/src/gpu/GrProcessorUnitTest.cpp', + 'skia/src/gpu/GrProcOptInfo.cpp', + 'skia/src/gpu/GrProgramElement.cpp', + 'skia/src/gpu/GrRecordReplaceDraw.cpp', + 'skia/src/gpu/GrRectanizer_pow2.cpp', + 'skia/src/gpu/GrRectanizer_skyline.cpp', + 'skia/src/gpu/GrReducedClip.cpp', + 'skia/src/gpu/GrRenderTarget.cpp', + 'skia/src/gpu/GrResourceProvider.cpp', + 'skia/src/gpu/GrSoftwarePathRenderer.cpp', + 'skia/src/gpu/GrStencil.cpp', + 'skia/src/gpu/GrStencilAndCoverTextContext.cpp', + 'skia/src/gpu/GrStencilAttachment.cpp', + 'skia/src/gpu/GrStrokeInfo.cpp', + 'skia/src/gpu/GrSurface.cpp', + 'skia/src/gpu/GrSWMaskHelper.cpp', + 'skia/src/gpu/GrTestUtils.cpp', + 'skia/src/gpu/GrTextBlobCache.cpp', + 'skia/src/gpu/GrTextContext.cpp', + 'skia/src/gpu/GrTexture.cpp', + 'skia/src/gpu/GrTextureAccess.cpp', + 'skia/src/gpu/GrTextureParamsAdjuster.cpp', + 'skia/src/gpu/GrTextureProvider.cpp', + 'skia/src/gpu/GrTraceMarker.cpp', + 'skia/src/gpu/GrXferProcessor.cpp', + 'skia/src/gpu/GrYUVProvider.cpp', + 'skia/src/gpu/SkGpuDevice.cpp', + 'skia/src/gpu/SkGpuDevice_drawTexture.cpp', + 'skia/src/gpu/SkGr.cpp', + 'skia/src/gpu/SkGrPixelRef.cpp', + 'skia/src/gpu/SkGrTexturePixelRef.cpp', + 'skia/src/image/SkSurface_Gpu.cpp', + ] + SOURCES += [ + 'skia/src/effects/SkArithmeticMode_gpu.cpp', + 'skia/src/gpu/batches/GrAAConvexPathRenderer.cpp', + 'skia/src/gpu/batches/GrAAConvexTessellator.cpp', + 'skia/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp', + 'skia/src/gpu/batches/GrAAFillRectBatch.cpp', + 'skia/src/gpu/batches/GrAAHairLinePathRenderer.cpp', + 'skia/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp', + 'skia/src/gpu/batches/GrAAStrokeRectBatch.cpp', + 'skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp', + 'skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp', + 'skia/src/gpu/gl/builders/GrGLSLPrettyPrint.cpp', + 'skia/src/gpu/gl/debug/GrGLCreateDebugInterface.cpp', + 'skia/src/gpu/gl/GrGLAssembleInterface.cpp', + 'skia/src/gpu/gl/GrGLBufferImpl.cpp', + 'skia/src/gpu/gl/GrGLCaps.cpp', + 'skia/src/gpu/gl/GrGLContext.cpp', + 'skia/src/gpu/gl/GrGLCreateNullInterface.cpp', + 'skia/src/gpu/gl/GrGLDefaultInterface_native.cpp', + 'skia/src/gpu/gl/GrGLExtensions.cpp', + 'skia/src/gpu/gl/GrGLGLSL.cpp', + 'skia/src/gpu/gl/GrGLGpu.cpp', + 'skia/src/gpu/gl/GrGLGpuProgramCache.cpp', + 'skia/src/gpu/gl/GrGLIndexBuffer.cpp', + 'skia/src/gpu/gl/GrGLInterface.cpp', + 'skia/src/gpu/gl/GrGLNameAllocator.cpp', + 'skia/src/gpu/gl/GrGLNoOpInterface.cpp', + 'skia/src/gpu/gl/GrGLPath.cpp', + 'skia/src/gpu/gl/GrGLPathRange.cpp', + 'skia/src/gpu/gl/GrGLPathRendering.cpp', + 'skia/src/gpu/gl/GrGLProgram.cpp', + 'skia/src/gpu/gl/GrGLProgramDataManager.cpp', + 'skia/src/gpu/gl/GrGLProgramDesc.cpp', + 'skia/src/gpu/gl/GrGLRenderTarget.cpp', + 'skia/src/gpu/gl/GrGLStencilAttachment.cpp', + 'skia/src/gpu/gl/GrGLTexture.cpp', + 'skia/src/gpu/gl/GrGLTextureRenderTarget.cpp', + 'skia/src/gpu/gl/GrGLUtil.cpp', + 'skia/src/gpu/gl/GrGLVaryingHandler.cpp', + 'skia/src/gpu/gl/GrGLVertexArray.cpp', + 'skia/src/gpu/gl/GrGLVertexBuffer.cpp', + 'skia/src/gpu/glsl/GrGLSL.cpp', + 'skia/src/gpu/glsl/GrGLSLBlend.cpp', + 'skia/src/gpu/glsl/GrGLSLCaps.cpp', + 'skia/src/gpu/glsl/GrGLSLFragmentProcessor.cpp', + 'skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp', + 'skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp', + 'skia/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp', + 'skia/src/gpu/glsl/GrGLSLPrimitiveProcessor.cpp', + 'skia/src/gpu/glsl/GrGLSLProgramBuilder.cpp', + 'skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp', + 'skia/src/gpu/glsl/GrGLSLUtil.cpp', + 'skia/src/gpu/glsl/GrGLSLVarying.cpp', + 'skia/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp', + 'skia/src/gpu/glsl/GrGLSLXferProcessor.cpp', + 'skia/src/gpu/GrBatchAtlas.cpp', + 'skia/src/gpu/GrDrawContext.cpp', + 'skia/src/gpu/GrResourceCache.cpp', + 'skia/src/image/SkImage_Gpu.cpp', + ] if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'): UNIFIED_SOURCES += [ 'skia/src/ports/SkDebug_android.cpp', @@ -713,6 +718,9 @@ elif CONFIG['CLANG_CL']: DEFINES['SKIA_IMPLEMENTATION'] = 1 +if not CONFIG['MOZ_ENABLE_SKIA_GPU']: + DEFINES['SK_SUPPORT_GPU'] = 0 + if CONFIG['GNU_CXX']: CXXFLAGS += [ '-Wno-deprecated-declarations', From ad5a13c938ff86c4ae66e37c9b1d5537e56d0944 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Wed, 30 Dec 2015 12:42:52 -0500 Subject: [PATCH 21/36] Bug 1178298 - Enable APZ on the trains. r=botond --HG-- extra : commitid : 2f7yxWS17pI --- browser/app/profile/firefox.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index f607f700b266..833f4f8cfbe0 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1573,11 +1573,9 @@ pref("browser.tabs.crashReporting.includeURL", false); pref("browser.tabs.crashReporting.emailMe", false); pref("browser.tabs.crashReporting.email", ""); -#ifdef NIGHTLY_BUILD #ifndef MOZ_MULET pref("layers.async-pan-zoom.enabled", true); #endif -#endif #ifdef E10S_TESTING_ONLY // Enable e10s add-on interposition by default. From 656cb779c35cc878a87fb24bdba2e7c8f6558f88 Mon Sep 17 00:00:00 2001 From: Daniel Holbert Date: Wed, 30 Dec 2015 10:38:40 -0800 Subject: [PATCH 22/36] Bug 1221919: Disable resizing of textarea in test_bug582181-1.html, since we don't use it and it causes intermittent orange due to inconsistent rendering. r=jfkthame --- layout/base/tests/test_bug582181-1.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/base/tests/test_bug582181-1.html b/layout/base/tests/test_bug582181-1.html index d9cd0cd06a7e..c2cd399bddb4 100644 --- a/layout/base/tests/test_bug582181-1.html +++ b/layout/base/tests/test_bug582181-1.html @@ -15,7 +15,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=582181 Mozilla Bug 582181

-

From add7a54a344daa7a684d28b5f2ccabafb58cbea8 Mon Sep 17 00:00:00 2001
From: Terrence Cole 
Date: Tue, 17 Nov 2015 13:40:55 -0800
Subject: [PATCH 23/36] Bug 1225650 - Use stable hashing for
 JSObject2WrappedJSMap; r=jonco

---
 js/xpconnect/src/XPCMaps.cpp |  5 ++---
 js/xpconnect/src/XPCMaps.h   | 18 ++++--------------
 2 files changed, 6 insertions(+), 17 deletions(-)

diff --git a/js/xpconnect/src/XPCMaps.cpp b/js/xpconnect/src/XPCMaps.cpp
index 297e9776ce73..45876a9138d7 100644
--- a/js/xpconnect/src/XPCMaps.cpp
+++ b/js/xpconnect/src/XPCMaps.cpp
@@ -119,12 +119,11 @@ JSObject2WrappedJSMap::UpdateWeakPointersAfterGC(XPCJSRuntime* runtime)
 
         // Remove or update the JSObject key in the table if necessary.
         JSObject* obj = e.front().key();
-        JSObject* prior = obj;
         JS_UpdateWeakPointerAfterGCUnbarriered(&obj);
         if (!obj)
             e.removeFront();
-        else if (obj != prior)
-            e.rekeyFront(obj);
+        else
+            e.front().mutableKey() = obj;
     }
 }
 
diff --git a/js/xpconnect/src/XPCMaps.h b/js/xpconnect/src/XPCMaps.h
index 15f10b6a3602..7d585e93ea7e 100644
--- a/js/xpconnect/src/XPCMaps.h
+++ b/js/xpconnect/src/XPCMaps.h
@@ -27,8 +27,10 @@
 
 class JSObject2WrappedJSMap
 {
-    typedef js::HashMap,
-                        js::SystemAllocPolicy> Map;
+    using Map = js::HashMap,
+                            nsXPCWrappedJS*,
+                            js::MovableCellHasher>,
+                            js::SystemAllocPolicy>;
 
 public:
     static JSObject2WrappedJSMap* newMap(int length) {
@@ -66,7 +68,6 @@ public:
             return p->value();
         if (!mTable.add(p, obj, wrapper))
             return nullptr;
-        JS_StoreObjectPostBarrierCallback(cx, KeyMarkCallback, obj, this);
         return wrapper;
     }
 
@@ -95,17 +96,6 @@ public:
 private:
     JSObject2WrappedJSMap() {}
 
-    /*
-     * This function is called during minor GCs for each key in the HashMap that
-     * has been moved.
-     */
-    static void KeyMarkCallback(JSTracer* trc, JSObject* key, void* data) {
-        JSObject2WrappedJSMap* self = static_cast(data);
-        JSObject* prior = key;
-        JS_CallUnbarrieredObjectTracer(trc, &key, "XPCJSRuntime::mWrappedJSMap key");
-        self->mTable.rekeyIfMoved(prior, key);
-    }
-
     Map mTable;
 };
 

From 67ecabbdda64e8f706bcaf2a0b65ab6a8015467f Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 30 Dec 2015 12:32:47 -0600
Subject: [PATCH 24/36] Bug 1235631 - Odin: remove change-heap support
 (r=bbouvier)

--HG--
extra : commitid : 4s3rKVYz3Wr
extra : rebase_source : fb76a99fa15b5814b024926ccffc80bb0777ecba
---
 js/src/asmjs/AsmJS.cpp                        | 569 ++----------------
 js/src/asmjs/AsmJS.h                          |   3 -
 js/src/asmjs/WasmGenerator.cpp                |  11 +-
 js/src/asmjs/WasmGenerator.h                  |   5 +-
 js/src/asmjs/WasmModule.cpp                   | 135 +----
 js/src/asmjs/WasmModule.h                     |  48 +-
 js/src/asmjs/WasmSignalHandlers.cpp           |  34 +-
 js/src/asmjs/WasmStubs.cpp                    | 105 +---
 js/src/asmjs/WasmStubs.h                      |   2 +-
 js/src/asmjs/WasmTypes.cpp                    |  40 +-
 js/src/asmjs/WasmTypes.h                      |   1 -
 js/src/builtin/AtomicsObject.cpp              |   2 +-
 .../jit-test/tests/asm.js/testBug1100237.js   |  33 -
 js/src/jit-test/tests/asm.js/testNeuter.js    |  78 +--
 js/src/jit-test/tests/asm.js/testProfiling.js |  10 -
 js/src/jit-test/tests/asm.js/testResize.js    | 366 -----------
 .../tests/asm.js/testTimeout7-nosignals.js    |  29 -
 js/src/jit-test/tests/asm.js/testTimeout7.js  |  27 -
 .../tests/basic/testArrayBufferTransfer.js    | 123 ----
 js/src/jsfun.h                                |   4 +-
 .../js1_8_5/extensions/clone-transferables.js |  14 +-
 js/src/tests/js1_8_5/extensions/shell.js      |  14 -
 js/src/vm/ArrayBufferObject.cpp               | 251 +-------
 js/src/vm/Runtime.cpp                         |   1 -
 js/src/vm/Runtime.h                           |   3 -
 25 files changed, 187 insertions(+), 1721 deletions(-)
 delete mode 100644 js/src/jit-test/tests/asm.js/testBug1100237.js
 delete mode 100644 js/src/jit-test/tests/asm.js/testResize.js
 delete mode 100644 js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js
 delete mode 100644 js/src/jit-test/tests/asm.js/testTimeout7.js
 delete mode 100644 js/src/jit-test/tests/basic/testArrayBufferTransfer.js

diff --git a/js/src/asmjs/AsmJS.cpp b/js/src/asmjs/AsmJS.cpp
index 1a7413febf93..b50d1688cf6d 100644
--- a/js/src/asmjs/AsmJS.cpp
+++ b/js/src/asmjs/AsmJS.cpp
@@ -132,7 +132,7 @@ class js::AsmJSModule
     {
       public:
         enum Which { Variable, FFI, ArrayView, ArrayViewCtor, MathBuiltinFunction,
-                     AtomicsBuiltinFunction, Constant, SimdCtor, SimdOperation, ByteLength };
+                     AtomicsBuiltinFunction, Constant, SimdCtor, SimdOperation };
         enum VarInitKind { InitConstant, InitImport };
         enum ConstantKind { GlobalConstant, MathConstant };
 
@@ -301,21 +301,19 @@ class js::AsmJSModule
         PropertyName* name_;
         PropertyName* maybeFieldName_;
         struct CacheablePod {
-            uint32_t wasmIndex_;
             uint32_t startOffsetInModule_;  // Store module-start-relative offsets
             uint32_t endOffsetInModule_;    // so preserved by serialization.
         } pod;
 
       public:
         Export() {}
-        Export(PropertyName* name, PropertyName* maybeFieldName, uint32_t wasmIndex,
+        Export(PropertyName* name, PropertyName* maybeFieldName,
                uint32_t startOffsetInModule, uint32_t endOffsetInModule)
           : name_(name),
             maybeFieldName_(maybeFieldName)
         {
             MOZ_ASSERT(name_->isTenured());
             MOZ_ASSERT_IF(maybeFieldName_, maybeFieldName_->isTenured());
-            pod.wasmIndex_ = wasmIndex;
             pod.startOffsetInModule_ = startOffsetInModule;
             pod.endOffsetInModule_ = endOffsetInModule;
         }
@@ -338,14 +336,6 @@ class js::AsmJSModule
         uint32_t endOffsetInModule() const {
             return pod.endOffsetInModule_;
         }
-        static const uint32_t ChangeHeap = UINT32_MAX;
-        bool isChangeHeap() const {
-            return pod.wasmIndex_ == ChangeHeap;
-        }
-        uint32_t wasmIndex() const {
-            MOZ_ASSERT(!isChangeHeap());
-            return pod.wasmIndex_;
-        }
 
         WASM_DECLARE_SERIALIZABLE(Export)
     };
@@ -359,15 +349,12 @@ class js::AsmJSModule
     wasm::UniqueStaticLinkData  linkData_;
     struct CacheablePod {
         uint32_t                minHeapLength_;
-        uint32_t                maxHeapLength_;
-        uint32_t                heapLengthMask_;
         uint32_t                numFFIs_;
         uint32_t                srcLength_;
         uint32_t                srcLengthWithRightBrace_;
         bool                    strict_;
         bool                    hasArrayView_;
         bool                    isSharedView_;
-        bool                    hasFixedMinHeapLength_;
     } pod;
     const ScriptSourceHolder    scriptSource_;
     const uint32_t              srcStart_;
@@ -391,7 +378,6 @@ class js::AsmJSModule
     {
         mozilla::PodZero(&pod);
         pod.minHeapLength_ = RoundUpToNextValidAsmJSHeapLength(0);
-        pod.maxHeapLength_ = 0x80000000;
         pod.strict_ = strict;
 
         MOZ_ASSERT(srcStart_ <= srcBodyStart_);
@@ -446,13 +432,6 @@ class js::AsmJSModule
     uint32_t minHeapLength() const {
         return pod.minHeapLength_;
     }
-    uint32_t maxHeapLength() const {
-        return pod.maxHeapLength_;
-    }
-    uint32_t heapLengthMask() const {
-        MOZ_ASSERT(pod.hasFixedMinHeapLength_);
-        return pod.heapLengthMask_;
-    }
 
     void initGlobalArgumentName(PropertyName* n) {
         MOZ_ASSERT(!isFinished());
@@ -520,11 +499,6 @@ class js::AsmJSModule
         g.pod.u.viewType_ = vt;
         return globals_.append(g);
     }
-    bool addByteLength() {
-        MOZ_ASSERT(!isFinished());
-        Global g(Global::ByteLength, nullptr);
-        return globals_.append(g);
-    }
     bool addMathBuiltinFunction(AsmJSMathBuiltinFunction func, PropertyName* field) {
         MOZ_ASSERT(!isFinished());
         Global g(Global::MathBuiltinFunction, field);
@@ -569,30 +543,16 @@ class js::AsmJSModule
         MOZ_ASSERT(imports_.length() == importIndex);
         return imports_.emplaceBack(ffiIndex);
     }
-    bool addExport(PropertyName* name, PropertyName* maybeFieldName, uint32_t wasmIndex,
-                   uint32_t funcSrcBegin, uint32_t funcSrcEnd)
-    {
-        // NB: funcSrcBegin/funcSrcEnd are given relative to the ScriptSource
-        // (the entire file) and ExportedFunctions store offsets relative to
-        // the beginning of the module (so that they are caching-invariant).
+    bool addExport(PropertyName* name, PropertyName* maybeFieldName, uint32_t begin, uint32_t end) {
+        // The begin/end offsets are given relative to the ScriptSource (the
+        // entire file) and ExportedFunctions store offsets relative to the
+        // beginning of the module (so that they are caching-invariant).
         MOZ_ASSERT(!isFinished());
-        MOZ_ASSERT(srcStart_ < funcSrcBegin);
-        MOZ_ASSERT(funcSrcBegin < funcSrcEnd);
-        return exports_.emplaceBack(name, maybeFieldName, wasmIndex,
-                                    funcSrcBegin - srcStart_, funcSrcEnd - srcStart_);
-    }
-    bool addChangeHeap(uint32_t mask, uint32_t min, uint32_t max) {
-        MOZ_ASSERT(!isFinished());
-        MOZ_ASSERT(!pod.hasFixedMinHeapLength_);
-        MOZ_ASSERT(IsValidAsmJSHeapLength(mask + 1));
-        MOZ_ASSERT(min >= RoundUpToNextValidAsmJSHeapLength(0));
-        MOZ_ASSERT(max <= pod.maxHeapLength_);
-        MOZ_ASSERT(min <= max);
-        pod.heapLengthMask_ = mask;
-        pod.minHeapLength_ = min;
-        pod.maxHeapLength_ = max;
-        pod.hasFixedMinHeapLength_ = true;
-        return true;
+        MOZ_ASSERT(srcStart_ < begin);
+        MOZ_ASSERT(begin < end);
+        uint32_t startOffsetInModule = begin - srcStart_;
+        uint32_t endOffsetInModule = end - srcStart_;
+        return exports_.emplaceBack(name, maybeFieldName, startOffsetInModule, endOffsetInModule);
     }
 
     const GlobalVector& globals() const {
@@ -615,16 +575,11 @@ class js::AsmJSModule
     bool isSharedView() const {
         return pod.isSharedView_;
     }
-    bool tryRequireHeapLengthToBeAtLeast(uint32_t len) {
+    void requireHeapLengthToBeAtLeast(uint32_t len) {
         MOZ_ASSERT(!isFinished());
-        if (pod.hasFixedMinHeapLength_ && len > pod.minHeapLength_)
-            return false;
-        if (len > pod.maxHeapLength_)
-            return false;
         len = RoundUpToNextValidAsmJSHeapLength(len);
         if (len > pod.minHeapLength_)
             pod.minHeapLength_ = len;
-        return true;
     }
 
     /*************************************************************************/
@@ -1720,9 +1675,7 @@ class MOZ_STACK_CLASS ModuleValidator
             MathBuiltinFunction,
             AtomicsBuiltinFunction,
             SimdCtor,
-            SimdOperation,
-            ByteLength,
-            ChangeHeap
+            SimdOperation
         };
 
       private:
@@ -1746,10 +1699,6 @@ class MOZ_STACK_CLASS ModuleValidator
                 AsmJSSimdType type_;
                 AsmJSSimdOperation which_;
             } simdOp;
-            struct {
-                uint32_t srcBegin_;
-                uint32_t srcEnd_;
-            } changeHeap;
         } u;
 
         friend class ModuleValidator;
@@ -1827,14 +1776,6 @@ class MOZ_STACK_CLASS ModuleValidator
             MOZ_ASSERT(which_ == SimdOperation);
             return u.simdOp.type_;
         }
-        uint32_t changeHeapSrcBegin() const {
-            MOZ_ASSERT(which_ == ChangeHeap);
-            return u.changeHeap.srcBegin_;
-        }
-        uint32_t changeHeapSrcEnd() const {
-            MOZ_ASSERT(which_ == ChangeHeap);
-            return u.changeHeap.srcEnd_;
-        }
     };
 
     struct MathBuiltin
@@ -1931,8 +1872,6 @@ class MOZ_STACK_CLASS ModuleValidator
     uint32_t             errorOffset_;
     bool                 errorOverRecursed_;
 
-    bool                 canValidateChangeHeap_;
-    bool                 hasChangeHeap_;
     bool                 supportsSimd_;
     bool                 atomicsPresent_;
 
@@ -1955,8 +1894,6 @@ class MOZ_STACK_CLASS ModuleValidator
         errorString_(nullptr),
         errorOffset_(UINT32_MAX),
         errorOverRecursed_(false),
-        canValidateChangeHeap_(false),
-        hasChangeHeap_(false),
         supportsSimd_(cx->jitSupportsSimd()),
         atomicsPresent_(false)
     {
@@ -2089,8 +2026,12 @@ class MOZ_STACK_CLASS ModuleValidator
         JS_ALWAYS_TRUE(tokenStream().peekTokenPos(&pos, TokenStream::Operand));
         uint32_t endAfterCurly = pos.end;
 
-        auto usesHeap = Module::HeapBool(module_->hasArrayView());
-        auto sharedHeap = Module::SharedBool(module_->isSharedView());
+        HeapUsage heapUsage = module_->hasArrayView()
+                              ? module_->isSharedView()
+                                ? HeapUsage::Shared
+                                : HeapUsage::Unshared
+                              : HeapUsage::None;
+
         auto mutedErrors = Module::MutedBool(parser_.ss->mutedErrors());
 
         CacheableChars filename = make_string_copy(parser_.ss->filename());
@@ -2107,8 +2048,7 @@ class MOZ_STACK_CLASS ModuleValidator
         }
 
         UniqueStaticLinkData linkData;
-        Module* wasm = mg_.finish(usesHeap, sharedHeap, mutedErrors,
-                                  Move(filename), Move(displayURL),
+        Module* wasm = mg_.finish(heapUsage, mutedErrors, Move(filename), Move(displayURL),
                                   &linkData, slowFuncs);
         if (!wasm)
             return false;
@@ -2219,23 +2159,6 @@ class MOZ_STACK_CLASS ModuleValidator
         return globals_.putNew(var, global) &&
                module().addSimdOperation(type, op, opName);
     }
-    bool addByteLength(PropertyName* name) {
-        canValidateChangeHeap_ = true;
-        Global* global = validationLifo_.new_(Global::ByteLength);
-        return global &&
-               globals_.putNew(name, global) &&
-               module().addByteLength();
-    }
-    bool addChangeHeap(PropertyName* name, ParseNode* fn, uint32_t mask, uint32_t min, uint32_t max) {
-        hasChangeHeap_ = true;
-        Global* global = validationLifo_.new_(Global::ChangeHeap);
-        if (!global)
-            return false;
-        global->u.changeHeap.srcBegin_ = fn->pn_pos.begin;
-        global->u.changeHeap.srcEnd_ = fn->pn_pos.end;
-        return globals_.putNew(name, global) &&
-               module().addChangeHeap(mask, min, max);
-    }
     bool addArrayViewCtor(PropertyName* var, Scalar::Type vt, PropertyName* field) {
         Global* global = validationLifo_.new_(Global::ArrayViewCtor);
         if (!global)
@@ -2259,17 +2182,8 @@ class MOZ_STACK_CLASS ModuleValidator
         if (!args.appendAll(func.sig().args()))
             return false;
         MallocSig sig(Move(args), func.sig().ret());
-        uint32_t wasmIndex;
-        if (!mg_.declareExport(Move(sig), func.index(), &wasmIndex))
-            return false;
-        if (wasmIndex == AsmJSModule::Export::ChangeHeap)
-            return fail(pn, "too many exports");
-        return module().addExport(func.name(), maybeFieldName, wasmIndex,
-                                  func.srcBegin(), func.srcEnd());
-    }
-    bool addChangeHeapExport(PropertyName* name, const Global& g, PropertyName* maybeFieldName) {
-        return module().addExport(name, maybeFieldName, AsmJSModule::Export::ChangeHeap,
-                                  g.changeHeapSrcBegin(), g.changeHeapSrcEnd());
+        return mg_.declareExport(Move(sig), func.index()) &&
+               module().addExport(func.name(), maybeFieldName, func.srcBegin(), func.srcEnd());
     }
   private:
     const LifoSig* getLifoSig(const LifoSig& sig) {
@@ -2338,19 +2252,13 @@ class MOZ_STACK_CLASS ModuleValidator
                module().addImport(ffiIndex, *importIndex);
     }
 
-    bool tryOnceToValidateChangeHeap() {
-        bool ret = canValidateChangeHeap_;
-        canValidateChangeHeap_ = false;
-        return ret;
-    }
-    bool hasChangeHeap() const {
-        return hasChangeHeap_;
-    }
-    bool tryRequireHeapLengthToBeAtLeast(uint32_t len) {
-        return module().tryRequireHeapLengthToBeAtLeast(len);
-    }
-    uint32_t minHeapLength() const {
-        return module().minHeapLength();
+    bool tryConstantAccess(uint64_t start, uint64_t width) {
+        MOZ_ASSERT(UINT64_MAX - start > width);
+        uint64_t end = start + width;
+        if (end > uint64_t(INT32_MAX) + 1)
+            return false;
+        module().requireHeapLengthToBeAtLeast(end);
+        return true;
     }
 
     bool usesSharedMemory() const {
@@ -2822,8 +2730,6 @@ class MOZ_STACK_CLASS FunctionValidator
     LocalMap          locals_;
     LabelMap          labels_;
 
-    unsigned          heapExpressionDepth_;
-
     bool              hasAlreadyReturned_;
     ExprType          ret_;
 
@@ -2833,7 +2739,6 @@ class MOZ_STACK_CLASS FunctionValidator
         fn_(fn),
         locals_(m.cx()),
         labels_(m.cx()),
-        heapExpressionDepth_(0),
         hasAlreadyReturned_(false)
     {}
 
@@ -2887,19 +2792,6 @@ class MOZ_STACK_CLASS FunctionValidator
         return funcIR().addVariable(init.value());
     }
 
-    /*************************************************************************/
-
-    void enterHeapExpression() {
-        heapExpressionDepth_++;
-    }
-    void leaveHeapExpression() {
-        MOZ_ASSERT(heapExpressionDepth_ > 0);
-        heapExpressionDepth_--;
-    }
-    bool canCall() const {
-        return heapExpressionDepth_ == 0 || !m_.hasChangeHeap();
-    }
-
     /****************************** For consistency of returns in a function */
 
     bool hasAlreadyReturned() const {
@@ -3471,8 +3363,6 @@ CheckGlobalDotImport(ModuleValidator& m, PropertyName* varName, ParseNode* initN
             return m.addGlobalConstant(varName, GenericNaN(), field);
         if (field == m.cx()->names().Infinity)
             return m.addGlobalConstant(varName, PositiveInfinity(), field);
-        if (field == m.cx()->names().byteLength)
-            return m.addByteLength(varName);
 
         Scalar::Type type;
         if (IsArrayViewCtorName(m, field, &type))
@@ -3783,8 +3673,6 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
           case ModuleValidator::Global::ArrayViewCtor:
           case ModuleValidator::Global::SimdCtor:
           case ModuleValidator::Global::SimdOperation:
-          case ModuleValidator::Global::ByteLength:
-          case ModuleValidator::Global::ChangeHeap:
             return f.failName(varRef, "'%s' may not be accessed by ordinary expressions", name);
         }
         return true;
@@ -3819,7 +3707,7 @@ FoldMaskedArrayIndex(FunctionValidator& f, ParseNode** indexExpr, int32_t* mask,
         // constraint. The unsigned maximum of a masked index is the mask
         // itself, so check that the mask is not negative and compare the mask
         // to the known minimum heap length.
-        if (int32_t(mask2) >= 0 && mask2 < f.m().minHeapLength())
+        if (int32_t(mask2) >= 0 && mask2 < f.m().module().minHeapLength())
             *needsBoundsCheck = NO_BOUNDS_CHECK;
         *mask &= mask2;
         *indexExpr = indexNode;
@@ -3849,16 +3737,9 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr
     uint32_t index;
     if (IsLiteralOrConstInt(f, indexExpr, &index)) {
         uint64_t byteOffset = uint64_t(index) << TypedArrayShift(*viewType);
-        if (byteOffset > INT32_MAX)
+        if (!f.m().tryConstantAccess(byteOffset, TypedArrayElemSize(*viewType)))
             return f.fail(indexExpr, "constant index out of range");
 
-        unsigned elementSize = TypedArrayElemSize(*viewType);
-        if (!f.m().tryRequireHeapLengthToBeAtLeast(byteOffset + elementSize)) {
-            return f.failf(indexExpr, "constant index outside heap size range declared by the "
-                                      "change-heap function (0x%x - 0x%x)",
-                                      f.m().minHeapLength(), f.m().module().maxHeapLength());
-        }
-
         *mask = NoMask;
         *needsBoundsCheck = NO_BOUNDS_CHECK;
         f.writeInt32Lit(byteOffset);
@@ -3886,14 +3767,10 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr
         if (pointerNode->isKind(PNK_BITAND))
             FoldMaskedArrayIndex(f, &pointerNode, mask, needsBoundsCheck);
 
-        f.enterHeapExpression();
-
         Type pointerType;
         if (!CheckExpr(f, pointerNode, &pointerType))
             return false;
 
-        f.leaveHeapExpression();
-
         if (!pointerType.isIntish())
             return f.failf(pointerNode, "%s is not a subtype of int", pointerType.toChars());
     } else {
@@ -3909,14 +3786,10 @@ CheckArrayAccess(FunctionValidator& f, ParseNode* viewName, ParseNode* indexExpr
         if (pointerNode->isKind(PNK_BITAND))
             folded = FoldMaskedArrayIndex(f, &pointerNode, mask, needsBoundsCheck);
 
-        f.enterHeapExpression();
-
         Type pointerType;
         if (!CheckExpr(f, pointerNode, &pointerType))
             return false;
 
-        f.leaveHeapExpression();
-
         if (folded) {
             if (!pointerType.isIntish())
                 return f.failf(pointerNode, "%s is not a subtype of intish", pointerType.toChars());
@@ -4010,14 +3883,10 @@ CheckStoreArray(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type
     if (!CheckAndPrepareArrayAccess(f, ElemBase(lhs), ElemIndex(lhs), &viewType, &needsBoundsCheck, &mask))
         return false;
 
-    f.enterHeapExpression();
-
     Type rhsType;
     if (!CheckExpr(f, rhs, &rhsType))
         return false;
 
-    f.leaveHeapExpression();
-
     switch (viewType) {
       case Scalar::Int8:
       case Scalar::Int16:
@@ -4657,11 +4526,6 @@ static bool
 CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calleeName,
                   ExprType ret, Type* type)
 {
-    if (!f.canCall()) {
-        return f.fail(callNode, "call expressions may not be nested inside heap expressions "
-                                "when the module contains a change-heap function");
-    }
-
     switch (ret) {
       case ExprType::Void:   f.writeOp(Stmt::CallInternal);  break;
       case ExprType::I32:    f.writeOp(I32::CallInternal);   break;
@@ -4728,11 +4592,6 @@ CheckFuncPtrTableAgainstExisting(ModuleValidator& m, ParseNode* usepn, PropertyN
 static bool
 CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, ExprType ret, Type* type)
 {
-    if (!f.canCall()) {
-        return f.fail(callNode, "function-pointer call expressions may not be nested inside heap "
-                                "expressions when the module contains a change-heap function");
-    }
-
     ParseNode* callee = CallCallee(callNode);
     ParseNode* tableNode = ElemBase(callee);
     ParseNode* indexExpr = ElemIndex(callee);
@@ -4813,11 +4672,6 @@ static bool
 CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, ExprType ret,
              Type* type)
 {
-    if (!f.canCall()) {
-        return f.fail(callNode, "FFI call expressions may not be nested inside heap "
-                                "expressions when the module contains a change-heap function");
-    }
-
     PropertyName* calleeName = CallCallee(callNode)->name();
 
     if (ret == ExprType::F32)
@@ -5504,30 +5358,21 @@ CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, AsmJSSimdType opTy
     ParseNode* indexExpr = NextNode(view);
     uint32_t indexLit;
     if (IsLiteralOrConstInt(f, indexExpr, &indexLit)) {
-        if (indexLit > INT32_MAX)
+        if (!f.m().tryConstantAccess(indexLit, Simd128DataSize))
             return f.fail(indexExpr, "constant index out of range");
 
-        if (!f.m().tryRequireHeapLengthToBeAtLeast(indexLit + Simd128DataSize)) {
-            return f.failf(indexExpr, "constant index outside heap size range declared by the "
-                                      "change-heap function (0x%x - 0x%x)",
-                                      f.m().minHeapLength(), f.m().module().maxHeapLength());
-        }
-
         *needsBoundsCheck = NO_BOUNDS_CHECK;
         f.writeInt32Lit(indexLit);
         return true;
     }
 
-    f.enterHeapExpression();
-
     Type indexType;
     if (!CheckExpr(f, indexExpr, &indexType))
         return false;
+
     if (!indexType.isIntish())
         return f.failf(indexExpr, "%s is not a subtype of intish", indexType.toChars());
 
-    f.leaveHeapExpression();
-
     return true;
 }
 
@@ -5953,8 +5798,6 @@ CheckCoercedCall(FunctionValidator& f, ParseNode* call, ExprType ret, Type* type
           case ModuleValidator::Global::FuncPtrTable:
           case ModuleValidator::Global::ArrayView:
           case ModuleValidator::Global::ArrayViewCtor:
-          case ModuleValidator::Global::ByteLength:
-          case ModuleValidator::Global::ChangeHeap:
             return f.failName(callee, "'%s' is not callable function", callee->name());
           case ModuleValidator::Global::SimdCtor:
           case ModuleValidator::Global::SimdOperation:
@@ -7020,225 +6863,6 @@ CheckStatement(FunctionValidator& f, ParseNode* stmt)
     return f.fail(stmt, "unexpected statement kind");
 }
 
-static bool
-CheckByteLengthCall(ModuleValidator& m, ParseNode* pn, PropertyName* newBufferName)
-{
-    if (!pn->isKind(PNK_CALL) || !CallCallee(pn)->isKind(PNK_NAME))
-        return m.fail(pn, "expecting call to imported byteLength");
-
-    const ModuleValidator::Global* global = m.lookupGlobal(CallCallee(pn)->name());
-    if (!global || global->which() != ModuleValidator::Global::ByteLength)
-        return m.fail(pn, "expecting call to imported byteLength");
-
-    if (CallArgListLength(pn) != 1 || !IsUseOfName(CallArgList(pn), newBufferName))
-        return m.failName(pn, "expecting %s as argument to byteLength call", newBufferName);
-
-    return true;
-}
-
-static bool
-CheckHeapLengthCondition(ModuleValidator& m, ParseNode* cond, PropertyName* newBufferName,
-                         uint32_t* mask, uint32_t* minLength, uint32_t* maxLength)
-{
-    if (!cond->isKind(PNK_OR) || !AndOrLeft(cond)->isKind(PNK_OR))
-        return m.fail(cond, "expecting byteLength & K || byteLength <= L || byteLength > M");
-
-    ParseNode* cond1 = AndOrLeft(AndOrLeft(cond));
-    ParseNode* cond2 = AndOrRight(AndOrLeft(cond));
-    ParseNode* cond3 = AndOrRight(cond);
-
-    if (!cond1->isKind(PNK_BITAND))
-        return m.fail(cond1, "expecting byteLength & K");
-
-    if (!CheckByteLengthCall(m, BitwiseLeft(cond1), newBufferName))
-        return false;
-
-    ParseNode* maskNode = BitwiseRight(cond1);
-    if (!IsLiteralInt(m, maskNode, mask))
-        return m.fail(maskNode, "expecting integer literal mask");
-    if (*mask == UINT32_MAX)
-        return m.fail(maskNode, "invalid mask value");
-    if ((*mask & 0xffffff) != 0xffffff)
-        return m.fail(maskNode, "mask value must have the bits 0xffffff set");
-
-    if (!cond2->isKind(PNK_LE))
-        return m.fail(cond2, "expecting byteLength <= L");
-
-    if (!CheckByteLengthCall(m, RelationalLeft(cond2), newBufferName))
-        return false;
-
-    ParseNode* minLengthNode = RelationalRight(cond2);
-    uint32_t minLengthExclusive;
-    if (!IsLiteralInt(m, minLengthNode, &minLengthExclusive))
-        return m.fail(minLengthNode, "expecting integer literal");
-    if (minLengthExclusive < 0xffffff || minLengthExclusive == UINT32_MAX)
-        return m.fail(minLengthNode, "literal must be >= 0xffffff and < 0xffffffff");
-
-    // Add one to convert from exclusive (the branch rejects if ==) to inclusive.
-    *minLength = minLengthExclusive + 1;
-
-    if (!cond3->isKind(PNK_GT))
-        return m.fail(cond3, "expecting byteLength > M");
-
-    if (!CheckByteLengthCall(m, RelationalLeft(cond3), newBufferName))
-        return false;
-
-    ParseNode* maxLengthNode = RelationalRight(cond3);
-    if (!IsLiteralInt(m, maxLengthNode, maxLength))
-        return m.fail(maxLengthNode, "expecting integer literal");
-    if (*maxLength > 0x80000000)
-        return m.fail(maxLengthNode, "literal must be <= 0x80000000");
-
-    if (*maxLength < *minLength)
-        return m.fail(maxLengthNode, "maximum length must be greater or equal to minimum length");
-
-    return true;
-}
-
-static bool
-CheckReturnBoolLiteral(ModuleValidator& m, ParseNode* stmt, bool retval)
-{
-    if (stmt->isKind(PNK_STATEMENTLIST)) {
-        ParseNode* next = SkipEmptyStatements(ListHead(stmt));
-        if (!next)
-            return m.fail(stmt, "expected return statement");
-        stmt = next;
-        if (NextNonEmptyStatement(stmt))
-            return m.fail(stmt, "expected single return statement");
-    }
-
-    if (!stmt->isKind(PNK_RETURN))
-        return m.fail(stmt, "expected return statement");
-
-    ParseNode* returnExpr = ReturnExpr(stmt);
-    if (!returnExpr || !returnExpr->isKind(retval ? PNK_TRUE : PNK_FALSE))
-        return m.failf(stmt, "expected 'return %s;'", retval ? "true" : "false");
-
-    return true;
-}
-
-static bool
-CheckReassignmentTo(ModuleValidator& m, ParseNode* stmt, PropertyName* lhsName, ParseNode** rhs)
-{
-    if (!stmt->isKind(PNK_SEMI))
-        return m.fail(stmt, "missing reassignment");
-
-    ParseNode* assign = UnaryKid(stmt);
-    if (!assign || !assign->isKind(PNK_ASSIGN))
-        return m.fail(stmt, "missing reassignment");
-
-    ParseNode* lhs = BinaryLeft(assign);
-    if (!IsUseOfName(lhs, lhsName))
-        return m.failName(lhs, "expecting reassignment of %s", lhsName);
-
-    *rhs = BinaryRight(assign);
-    return true;
-}
-
-static bool
-CheckChangeHeap(ModuleValidator& m, ParseNode* fn, bool* validated)
-{
-    MOZ_ASSERT(fn->isKind(PNK_FUNCTION));
-
-    // We don't yet know whether this is a change-heap function.
-    // The point at which we know we have a change-heap function is once we see
-    // whether the argument is coerced according to the normal asm.js rules. If
-    // it is coerced, it's not change-heap and must validate according to normal
-    // rules; otherwise it must validate as a change-heap function.
-    *validated = false;
-
-    PropertyName* changeHeapName = FunctionName(fn);
-    if (!CheckModuleLevelName(m, fn, changeHeapName))
-        return false;
-
-    unsigned numFormals;
-    ParseNode* arg = FunctionArgsList(fn, &numFormals);
-    if (numFormals != 1)
-        return true;
-
-    PropertyName* newBufferName;
-    if (!CheckArgument(m, arg, &newBufferName))
-        return false;
-
-    ParseNode* stmtIter = SkipEmptyStatements(ListHead(FunctionStatementList(fn)));
-    if (!stmtIter || !stmtIter->isKind(PNK_IF))
-        return true;
-
-    // We can now issue validation failures if we see something that isn't a
-    // valid change-heap function.
-    *validated = true;
-
-    PropertyName* bufferName = m.module().bufferArgumentName();
-    if (!bufferName)
-        return m.fail(fn, "to change heaps, the module must have a buffer argument");
-
-    ParseNode* cond = TernaryKid1(stmtIter);
-    ParseNode* thenStmt = TernaryKid2(stmtIter);
-    if (ParseNode* elseStmt = TernaryKid3(stmtIter))
-        return m.fail(elseStmt, "unexpected else statement");
-
-    uint32_t mask, min = 0, max;  // initialize min to silence GCC warning
-    if (!CheckHeapLengthCondition(m, cond, newBufferName, &mask, &min, &max))
-        return false;
-
-    if (!CheckReturnBoolLiteral(m, thenStmt, false))
-        return false;
-
-    ParseNode* next = NextNonEmptyStatement(stmtIter);
-
-    for (unsigned i = 0; i < m.numArrayViews(); i++, next = NextNonEmptyStatement(stmtIter)) {
-        if (!next)
-            return m.failOffset(stmtIter->pn_pos.end, "missing reassignment");
-        stmtIter = next;
-
-        const ModuleValidator::ArrayView& view = m.arrayView(i);
-
-        ParseNode* rhs;
-        if (!CheckReassignmentTo(m, stmtIter, view.name, &rhs))
-            return false;
-
-        if (!rhs->isKind(PNK_NEW))
-            return m.failName(rhs, "expecting assignment of new array view to %s", view.name);
-
-        ParseNode* ctorExpr = ListHead(rhs);
-        if (!ctorExpr->isKind(PNK_NAME))
-            return m.fail(rhs, "expecting name of imported typed array constructor");
-
-        const ModuleValidator::Global* global = m.lookupGlobal(ctorExpr->name());
-        if (!global || global->which() != ModuleValidator::Global::ArrayViewCtor)
-            return m.fail(rhs, "expecting name of imported typed array constructor");
-        if (global->viewType() != view.type)
-            return m.fail(rhs, "can't change the type of a global view variable");
-
-        if (!CheckNewArrayViewArgs(m, ctorExpr, newBufferName))
-            return false;
-    }
-
-    if (!next)
-        return m.failOffset(stmtIter->pn_pos.end, "missing reassignment");
-    stmtIter = next;
-
-    ParseNode* rhs;
-    if (!CheckReassignmentTo(m, stmtIter, bufferName, &rhs))
-        return false;
-    if (!IsUseOfName(rhs, newBufferName))
-        return m.failName(stmtIter, "expecting assignment of new buffer to %s", bufferName);
-
-    next = NextNonEmptyStatement(stmtIter);
-    if (!next)
-        return m.failOffset(stmtIter->pn_pos.end, "expected return statement");
-    stmtIter = next;
-
-    if (!CheckReturnBoolLiteral(m, stmtIter, true))
-        return false;
-
-    stmtIter = NextNonEmptyStatement(stmtIter);
-    if (stmtIter)
-        return m.fail(stmtIter, "expecting end of function");
-
-    return m.addChangeHeap(changeHeapName, fn, mask, min, max);
-}
-
 static bool
 ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line, unsigned* column)
 {
@@ -7319,14 +6943,6 @@ CheckFunction(ModuleValidator& m)
     if (!CheckFunctionHead(m, fn))
         return false;
 
-    if (m.tryOnceToValidateChangeHeap()) {
-        bool validated;
-        if (!CheckChangeHeap(m, fn, &validated))
-            return false;
-        if (validated)
-            return true;
-    }
-
     FunctionValidator f(m, fn);
     if (!f.init(FunctionName(fn), line, column))
         return m.fail(fn, "internal compiler failure (probably out of memory)");
@@ -7493,13 +7109,10 @@ CheckModuleExportFunction(ModuleValidator& m, ParseNode* pn, PropertyName* maybe
     if (!global)
         return m.failName(pn, "exported function name '%s' not found", funcName);
 
-    if (global->which() == ModuleValidator::Global::Function)
-        return m.addExport(pn, m.function(global->funcIndex()), maybeFieldName);
+    if (global->which() != ModuleValidator::Global::Function)
+        return m.failName(pn, "'%s' is not a function", funcName);
 
-    if (global->which() == ModuleValidator::Global::ChangeHeap)
-        return m.addChangeHeapExport(funcName, *global, maybeFieldName);
-
-    return m.failName(pn, "'%s' is not a function", funcName);
+    return m.addExport(pn, m.function(global->funcIndex()), maybeFieldName);
 }
 
 static bool
@@ -7636,13 +7249,13 @@ CheckModule(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* stmtList, Hand
 }
 
 /*****************************************************************************/
-// Runtime calls to asm.js module exports
+// Link-time validation
 
 static AsmJSModuleObject&
 FunctionToModuleObject(JSFunction* fun)
 {
     MOZ_ASSERT(IsAsmJSFunction(fun) || IsAsmJSModule(fun));
-    const Value& v = fun->getExtendedSlot(FunctionExtended::ASM_MODULE_SLOT);
+    const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_MODULE_SLOT);
     return v.toObject().as();
 }
 
@@ -7650,44 +7263,10 @@ static unsigned
 FunctionToExportIndex(JSFunction* fun)
 {
     MOZ_ASSERT(IsAsmJSFunction(fun));
-    const Value& v = fun->getExtendedSlot(FunctionExtended::ASM_EXPORT_INDEX_SLOT);
+    const Value& v = fun->getExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT);
     return v.toInt32();
 }
 
-static bool
-ChangeHeap(JSContext* cx, AsmJSModule& module, const CallArgs& args)
-{
-    HandleValue bufferArg = args.get(0);
-    if (!IsArrayBuffer(bufferArg)) {
-        ReportIncompatible(cx, args);
-        return false;
-    }
-
-    Rooted newBuffer(cx, &bufferArg.toObject().as());
-    uint32_t heapLength = newBuffer->byteLength();
-    if (heapLength & module.heapLengthMask() ||
-        heapLength < module.minHeapLength() ||
-        heapLength > module.maxHeapLength())
-    {
-        args.rval().set(BooleanValue(false));
-        return true;
-    }
-
-    if (!module.hasArrayView()) {
-        args.rval().set(BooleanValue(true));
-        return true;
-    }
-
-    MOZ_ASSERT(IsValidAsmJSHeapLength(heapLength));
-
-    bool useSignalHandlers = module.wasmModule().compileArgs().useSignalHandlersForOOB;
-    if (!ArrayBufferObject::prepareForAsmJS(cx, newBuffer, useSignalHandlers))
-        return false;
-
-    args.rval().set(BooleanValue(module.wasmModule().changeHeap(newBuffer, cx)));
-    return true;
-}
-
 static bool
 CallAsmJS(JSContext* cx, unsigned argc, Value* vp)
 {
@@ -7695,18 +7274,11 @@ CallAsmJS(JSContext* cx, unsigned argc, Value* vp)
     RootedFunction callee(cx, &args.callee().as());
 
     AsmJSModule& module = FunctionToModuleObject(callee).module();
-    const AsmJSModule::Export& exp = module.exports()[FunctionToExportIndex(callee)];
+    uint32_t exportIndex = FunctionToExportIndex(callee);
 
-    // The heap-changing function is a special-case and is implemented by C++.
-    if (exp.isChangeHeap())
-        return ChangeHeap(cx, module, args);
-
-    return module.wasmModule().callExport(cx, exp.wasmIndex(), args);
+    return module.wasmModule().callExport(cx, exportIndex, args);
 }
 
-/*****************************************************************************/
-// Link-time validation
-
 static bool
 LinkFail(JSContext* cx, const char* str)
 {
@@ -7885,30 +7457,6 @@ ValidateArrayView(JSContext* cx, const AsmJSModule::Global& global, HandleValue
     return true;
 }
 
-static bool
-ValidateByteLength(JSContext* cx, HandleValue globalVal)
-{
-    RootedPropertyName field(cx, cx->names().byteLength);
-    RootedValue v(cx);
-    if (!GetDataProperty(cx, globalVal, field, &v))
-        return false;
-
-    if (!v.isObject() || !v.toObject().isBoundFunction())
-        return LinkFail(cx, "byteLength must be a bound function object");
-
-    RootedFunction fun(cx, &v.toObject().as());
-
-    RootedValue boundTarget(cx, ObjectValue(*fun->getBoundFunctionTarget()));
-    if (!IsNativeFunction(boundTarget, fun_call))
-        return LinkFail(cx, "bound target of byteLength must be Function.prototype.call");
-
-    RootedValue boundThis(cx, fun->getBoundFunctionThis());
-    if (!IsNativeFunction(boundThis, ArrayBufferObject::byteLengthGetter))
-        return LinkFail(cx, "bound this value must be ArrayBuffer.protototype.byteLength accessor");
-
-    return true;
-}
-
 static bool
 ValidateMathBuiltinFunction(JSContext* cx, const AsmJSModule::Global& global, HandleValue globalVal)
 {
@@ -8151,20 +7699,12 @@ CheckBuffer(JSContext* cx, AsmJSModule& module, HandleValue bufferVal,
     if (heapLength < module.minHeapLength()) {
         UniqueChars msg(
             JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (the size implied "
-                        "by const heap accesses and/or change-heap minimum-length requirements).",
+                        "by const heap accesses).",
                         heapLength,
                         module.minHeapLength()));
         return LinkFail(cx, msg.get());
     }
 
-    if (heapLength > module.maxHeapLength()) {
-        UniqueChars msg(
-            JS_smprintf("ArrayBuffer byteLength 0x%x is greater than maximum length of 0x%x",
-                        heapLength,
-                        module.maxHeapLength()));
-        return LinkFail(cx, msg.get());
-    }
-
     // Shell builtins may have disabled signal handlers since the module we're
     // cloning was compiled. LookupAsmJSModuleInCache checks for signal handlers
     // as well for the caching case.
@@ -8211,10 +7751,6 @@ DynamicallyLinkModule(JSContext* cx, const CallArgs& args, AsmJSModule& module)
             if (!ValidateArrayView(cx, global, globalVal))
                 return false;
             break;
-          case AsmJSModule::Global::ByteLength:
-            if (!ValidateByteLength(cx, globalVal))
-                return false;
-            break;
           case AsmJSModule::Global::MathBuiltinFunction:
             if (!ValidateMathBuiltinFunction(cx, global, globalVal))
                 return false;
@@ -8251,9 +7787,7 @@ static JSFunction*
 NewExportedFunction(JSContext* cx, const AsmJSModule& module, const AsmJSModule::Export& func,
                     HandleObject moduleObj, unsigned exportIndex)
 {
-    unsigned numArgs = func.isChangeHeap()
-                       ? 1
-                       : module.wasmModule().exports()[func.wasmIndex()].sig().args().length();
+    unsigned numArgs = module.wasmModule().exports()[exportIndex].sig().args().length();
 
     RootedPropertyName name(cx, func.name());
     JSFunction* fun =
@@ -8263,8 +7797,8 @@ NewExportedFunction(JSContext* cx, const AsmJSModule& module, const AsmJSModule:
     if (!fun)
         return nullptr;
 
-    fun->setExtendedSlot(FunctionExtended::ASM_MODULE_SLOT, ObjectValue(*moduleObj));
-    fun->setExtendedSlot(FunctionExtended::ASM_EXPORT_INDEX_SLOT, Int32Value(exportIndex));
+    fun->setExtendedSlot(FunctionExtended::WASM_MODULE_SLOT, ObjectValue(*moduleObj));
+    fun->setExtendedSlot(FunctionExtended::WASM_EXPORT_INDEX_SLOT, Int32Value(exportIndex));
     return fun;
 }
 
@@ -8434,7 +7968,7 @@ NewModuleFunction(ExclusiveContext* cx, JSFunction* origFun, HandleObject module
     if (!moduleFun)
         return nullptr;
 
-    moduleFun->setExtendedSlot(FunctionExtended::ASM_MODULE_SLOT, ObjectValue(*moduleObj));
+    moduleFun->setExtendedSlot(FunctionExtended::WASM_MODULE_SLOT, ObjectValue(*moduleObj));
     return moduleFun;
 }
 
@@ -9390,14 +8924,3 @@ js::RoundUpToNextValidAsmJSHeapLength(uint32_t length)
     MOZ_ASSERT(length <= 0xff000000);
     return (length + 0x00ffffff) & ~0x00ffffff;
 }
-
-bool
-js::OnDetachAsmJSArrayBuffer(JSContext* cx, Handle buffer)
-{
-    for (Module* m = cx->runtime()->linkedWasmModules; m; m = m->nextLinked()) {
-        if (buffer == m->maybeBuffer() && !m->detachHeap(cx))
-            return false;
-    }
-    return true;
-}
-
diff --git a/js/src/asmjs/AsmJS.h b/js/src/asmjs/AsmJS.h
index 2f7902134df3..b3d05b7583f5 100644
--- a/js/src/asmjs/AsmJS.h
+++ b/js/src/asmjs/AsmJS.h
@@ -109,9 +109,6 @@ IsValidAsmJSHeapLength(uint32_t length);
 extern uint32_t
 RoundUpToNextValidAsmJSHeapLength(uint32_t length);
 
-extern bool
-OnDetachAsmJSArrayBuffer(JSContext* cx, Handle buffer);
-
 // The assumed page size; dynamically checked in CompileAsmJS.
 #ifdef _MIPS_ARCH_LOONGSON3A
 static const size_t AsmJSPageSize = 16384;
diff --git a/js/src/asmjs/WasmGenerator.cpp b/js/src/asmjs/WasmGenerator.cpp
index 94f88f3f08ea..a636e442d85d 100644
--- a/js/src/asmjs/WasmGenerator.cpp
+++ b/js/src/asmjs/WasmGenerator.cpp
@@ -312,9 +312,8 @@ ModuleGenerator::defineImport(uint32_t index, ProfilingOffsets interpExit, Profi
 }
 
 bool
-ModuleGenerator::declareExport(MallocSig&& sig, uint32_t funcIndex, uint32_t* index)
+ModuleGenerator::declareExport(MallocSig&& sig, uint32_t funcIndex)
 {
-    *index = exports_.length();
     return exports_.emplaceBack(Move(sig), funcIndex);
 }
 
@@ -499,8 +498,7 @@ ModuleGenerator::defineOutOfBoundsStub(Offsets offsets)
 }
 
 Module*
-ModuleGenerator::finish(Module::HeapBool usesHeap,
-                        Module::SharedBool sharedHeap,
+ModuleGenerator::finish(HeapUsage heapUsage,
                         Module::MutedBool mutedErrors,
                         CacheableChars filename,
                         CacheableTwoByteChars displayURL,
@@ -510,7 +508,7 @@ ModuleGenerator::finish(Module::HeapBool usesHeap,
     MOZ_ASSERT(!activeFunc_);
     MOZ_ASSERT(finishedFuncs_);
 
-    if (!GenerateStubs(*this, usesHeap))
+    if (!GenerateStubs(*this, UsesHeap(heapUsage)))
         return nullptr;
 
     masm_.finish();
@@ -616,8 +614,7 @@ ModuleGenerator::finish(Module::HeapBool usesHeap,
                              funcBytes_,
                              codeBytes,
                              globalBytes_,
-                             usesHeap,
-                             sharedHeap,
+                             heapUsage,
                              mutedErrors,
                              Move(code),
                              Move(imports_),
diff --git a/js/src/asmjs/WasmGenerator.h b/js/src/asmjs/WasmGenerator.h
index 759ff8e79514..f910db0739c0 100644
--- a/js/src/asmjs/WasmGenerator.h
+++ b/js/src/asmjs/WasmGenerator.h
@@ -123,7 +123,7 @@ class MOZ_STACK_CLASS ModuleGenerator
     bool defineImport(uint32_t index, ProfilingOffsets interpExit, ProfilingOffsets jitExit);
 
     // Exports:
-    bool declareExport(MallocSig&& sig, uint32_t funcIndex, uint32_t* index);
+    bool declareExport(MallocSig&& sig, uint32_t funcIndex);
     uint32_t numDeclaredExports() const;
     uint32_t exportFuncIndex(uint32_t index) const;
     const MallocSig& exportSig(uint32_t index) const;
@@ -147,8 +147,7 @@ class MOZ_STACK_CLASS ModuleGenerator
 
     // Null return indicates failure. The caller must immediately root a
     // non-null return value.
-    Module* finish(Module::HeapBool usesHeap,
-                   Module::SharedBool sharedHeap,
+    Module* finish(HeapUsage heapUsage,
                    Module::MutedBool mutedErrors,
                    CacheableChars filename,
                    CacheableTwoByteChars displayURL,
diff --git a/js/src/asmjs/WasmModule.cpp b/js/src/asmjs/WasmModule.cpp
index 71ae3730662c..214c790fe92f 100644
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -511,8 +511,9 @@ Module::activation()
 void
 Module::specializeToHeap(ArrayBufferObjectMaybeShared* heap)
 {
+    MOZ_ASSERT(usesHeap());
     MOZ_ASSERT_IF(heap->is(), heap->as().isAsmJS());
-    MOZ_ASSERT(!maybeHeap_);
+    MOZ_ASSERT(!heap_);
     MOZ_ASSERT(!rawHeapPtr());
 
     uint8_t* ptrBase = heap->dataPointerEither().unwrap(/*safe - protected by Module methods*/);
@@ -550,14 +551,17 @@ Module::specializeToHeap(ArrayBufferObjectMaybeShared* heap)
         Assembler::UpdateBoundsCheck(heapLength, (Instruction*)(access.insnOffset() + code()));
 #endif
 
-    maybeHeap_ = heap;
+    heap_ = heap;
     rawHeapPtr() = ptrBase;
 }
 
 void
 Module::despecializeFromHeap(ArrayBufferObjectMaybeShared* heap)
 {
-    MOZ_ASSERT_IF(maybeHeap_, maybeHeap_ == heap);
+    // heap_/rawHeapPtr can be null if this module holds cloned code from
+    // another dynamically-linked module which we are despecializing from that
+    // module's heap.
+    MOZ_ASSERT_IF(heap_, heap_ == heap);
     MOZ_ASSERT_IF(rawHeapPtr(), rawHeapPtr() == heap->dataPointerEither().unwrap());
 
 #if defined(JS_CODEGEN_X86)
@@ -581,7 +585,7 @@ Module::despecializeFromHeap(ArrayBufferObjectMaybeShared* heap)
     }
 #endif
 
-    maybeHeap_ = nullptr;
+    heap_ = nullptr;
     rawHeapPtr() = nullptr;
 }
 
@@ -700,7 +704,7 @@ Module::importToExit(const Import& import)
 /* static */ Module::CacheablePod
 Module::zeroPod()
 {
-    CacheablePod pod = {0, 0, 0, false, false, false, false, false};
+    CacheablePod pod = {0, 0, 0, HeapUsage::None, false, false, false};
     return pod;
 }
 
@@ -711,9 +715,6 @@ Module::init()
    interrupt_ = nullptr;
    outOfBounds_ = nullptr;
    dynamicallyLinked_ = false;
-   prev_ = nullptr;
-   next_ = nullptr;
-   interrupted_ = false;
 
     *(double*)(globalData() + NaN64GlobalDataOffset) = GenericNaN();
     *(float*)(globalData() + NaN32GlobalDataOffset) = GenericNaN();
@@ -757,8 +758,7 @@ Module::Module(CompileArgs args,
                uint32_t functionBytes,
                uint32_t codeBytes,
                uint32_t globalBytes,
-               HeapBool usesHeap,
-               SharedBool sharedHeap,
+               HeapUsage heapUsage,
                MutedBool mutedErrors,
                UniqueCodePtr code,
                ImportVector&& imports,
@@ -786,20 +786,16 @@ Module::Module(CompileArgs args,
     const_cast(pod.functionBytes_) = functionBytes;
     const_cast(pod.codeBytes_) = codeBytes;
     const_cast(pod.globalBytes_) = globalBytes;
-    const_cast(pod.usesHeap_) = bool(usesHeap);
-    const_cast(pod.sharedHeap_) = bool(sharedHeap);
+    const_cast(pod.heapUsage_) = heapUsage;
     const_cast(pod.mutedErrors_) = bool(mutedErrors);
     const_cast(pod.usesSignalHandlersForOOB_) = args.useSignalHandlersForOOB;
     const_cast(pod.usesSignalHandlersForInterrupt_) = args.useSignalHandlersForInterrupt;
 
-    MOZ_ASSERT_IF(sharedHeap, usesHeap);
     init();
 }
 
 Module::~Module()
 {
-    MOZ_ASSERT(!interrupted_);
-
     if (code_) {
         for (unsigned i = 0; i < imports_.length(); i++) {
             ImportExit& exit = importToExit(imports_[i]);
@@ -807,11 +803,6 @@ Module::~Module()
                 exit.baselineScript->removeDependentWasmModule(*this, i);
         }
     }
-
-    if (prev_)
-        *prev_ = next_;
-    if (next_)
-        next_->prev_ = prev_;
 }
 
 void
@@ -822,8 +813,8 @@ Module::trace(JSTracer* trc)
             TraceEdge(trc, &importToExit(import).fun, "wasm function import");
     }
 
-    if (maybeHeap_)
-        TraceEdge(trc, &maybeHeap_, "wasm buffer");
+    if (heap_)
+        TraceEdge(trc, &heap_, "wasm buffer");
 }
 
 CompileArgs
@@ -982,13 +973,6 @@ Module::dynamicallyLink(JSContext* cx, Handle hea
     MOZ_ASSERT(!dynamicallyLinked_);
     dynamicallyLinked_ = true;
 
-    // Add this module to the JSRuntime-wide list of dynamically-linked modules.
-    next_ = cx->runtime()->linkedWasmModules;
-    prev_ = &cx->runtime()->linkedWasmModules;
-    cx->runtime()->linkedWasmModules = this;
-    if (next_)
-        next_->prev_ = &next_;
-
     // Push a JitContext for benefit of IsCompilingAsmJS and flush the ICache.
     // We've been inhibiting flushing up to this point so flush it all now.
     JitContext jcx(CompileRuntime::get(cx->compartment()->runtimeFromAnyThread()));
@@ -1007,7 +991,7 @@ Module::dynamicallyLink(JSContext* cx, Handle hea
     }
 
     // Specialize code to the actual heap.
-    if (heap)
+    if (usesHeap())
         specializeToHeap(heap);
 
     // See AllocateCode comment above.
@@ -1017,19 +1001,13 @@ Module::dynamicallyLink(JSContext* cx, Handle hea
     return true;
 }
 
-ArrayBufferObjectMaybeShared*
-Module::maybeBuffer() const
-{
-    MOZ_ASSERT(dynamicallyLinked_);
-    return maybeHeap_;
-}
-
 SharedMem
-Module::maybeHeap() const
+Module::heap() const
 {
     MOZ_ASSERT(dynamicallyLinked_);
-    MOZ_ASSERT_IF(!pod.usesHeap_, rawHeapPtr() == nullptr);
-    return pod.sharedHeap_
+    MOZ_ASSERT(usesHeap());
+    MOZ_ASSERT(rawHeapPtr());
+    return hasSharedHeap()
            ? SharedMem::shared(rawHeapPtr())
            : SharedMem::unshared(rawHeapPtr());
 }
@@ -1038,7 +1016,8 @@ size_t
 Module::heapLength() const
 {
     MOZ_ASSERT(dynamicallyLinked_);
-    return maybeHeap_ ? maybeHeap_->byteLength() : 0;
+    MOZ_ASSERT(usesHeap());
+    return heap_->byteLength();
 }
 
 void
@@ -1051,65 +1030,6 @@ Module::deoptimizeImportExit(uint32_t importIndex)
     exit.baselineScript = nullptr;
 }
 
-bool
-Module::changeHeap(Handle newHeap, JSContext* cx)
-{
-    MOZ_ASSERT(dynamicallyLinked_);
-    MOZ_ASSERT(pod.usesHeap_);
-
-    // Content JS should not be able to run (and change heap) from within an
-    // interrupt callback, but in case it does, fail to change heap. Otherwise,
-    // the heap can change at every single instruction which would prevent
-    // future optimizations like heap-base hoisting.
-    if (interrupted_)
-        return false;
-
-    AutoMutateCode amc(cx, *this, "Module::changeHeap");
-    if (maybeHeap_)
-        despecializeFromHeap(maybeHeap_);
-    specializeToHeap(newHeap);
-    return true;
-}
-
-bool
-Module::detachHeap(JSContext* cx)
-{
-    MOZ_ASSERT(dynamicallyLinked_);
-    MOZ_ASSERT(pod.usesHeap_);
-
-    // Content JS should not be able to run (and detach heap) from within an
-    // interrupt callback, but in case it does, fail. Otherwise, the heap can
-    // change at an arbitrary instruction and break the assumption below.
-    if (interrupted_) {
-        JS_ReportError(cx, "attempt to detach from inside interrupt handler");
-        return false;
-    }
-
-    // Even if this->active(), to reach here, the activation must have called
-    // out via an import exit stub. FFI stubs check if heapDatum() is null on
-    // reentry and throw an exception if so.
-    MOZ_ASSERT_IF(activation(), activation()->exitReason() == ExitReason::ImportJit ||
-                                activation()->exitReason() == ExitReason::ImportInterp);
-
-    AutoMutateCode amc(cx, *this, "Module::detachHeap");
-    despecializeFromHeap(maybeHeap_);
-    return true;
-}
-
-void
-Module::setInterrupted(bool interrupted)
-{
-    MOZ_ASSERT(dynamicallyLinked_);
-    interrupted_ = interrupted;
-}
-
-Module*
-Module::nextLinked() const
-{
-    MOZ_ASSERT(dynamicallyLinked_);
-    return next_;
-}
-
 bool
 Module::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
 {
@@ -1179,17 +1099,6 @@ Module::callExport(JSContext* cx, uint32_t exportIndex, CallArgs args)
         }
     }
 
-    // The correct way to handle this situation would be to allocate a new range
-    // of PROT_NONE memory and module.changeHeap to this memory. That would
-    // cause every access to take the out-of-bounds signal-handler path which
-    // does the right thing. For now, just throw an out-of-memory exception
-    // since these can technically pop out anywhere and the full fix may
-    // actually OOM when trying to allocate the PROT_NONE memory.
-    if (usesHeap() && !maybeHeap_) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY);
-        return false;
-    }
-
     {
         // Push a WasmActivation to describe the wasm frames we're about to push
         // when running this module. Additionally, push a JitActivation so that
@@ -1518,8 +1427,8 @@ Module::clone(JSContext* cx, const StaticLinkData& linkData) const
 
     // If the copied machine code has been specialized to the heap, it must be
     // unspecialized in the copy.
-    if (maybeHeap_)
-        out->despecializeFromHeap(maybeHeap_);
+    if (usesHeap())
+        out->despecializeFromHeap(heap_);
 
     if (!out->staticallyLink(cx, linkData))
         return nullptr;
diff --git a/js/src/asmjs/WasmModule.h b/js/src/asmjs/WasmModule.h
index 503e53796f4c..582b2a99ee97 100644
--- a/js/src/asmjs/WasmModule.h
+++ b/js/src/asmjs/WasmModule.h
@@ -325,6 +325,22 @@ typedef JS::UniquePtr UniqueCodePtr;
 UniqueCodePtr
 AllocateCode(ExclusiveContext* cx, size_t bytes);
 
+// A wasm module can either use no heap, a unshared heap (ArrayBuffer) or shared
+// heap (SharedArrayBuffer).
+
+enum class HeapUsage
+{
+    None = false,
+    Unshared = 1,
+    Shared = 2
+};
+
+static inline bool
+UsesHeap(HeapUsage heapUsage)
+{
+    return bool(heapUsage);
+}
+
 // Module represents a compiled WebAssembly module which lives until the last
 // reference to any exported functions is dropped. Modules must be wrapped by a
 // rooted JSObject immediately after creation so that Module::trace() is called
@@ -375,8 +391,7 @@ class Module
         const uint32_t           functionBytes_;
         const uint32_t           codeBytes_;
         const uint32_t           globalBytes_;
-        const bool               usesHeap_;
-        const bool               sharedHeap_;
+        const HeapUsage          heapUsage_;
         const bool               mutedErrors_;
         const bool               usesSignalHandlersForOOB_;
         const bool               usesSignalHandlersForInterrupt_;
@@ -400,14 +415,11 @@ class Module
 
     // Initialized during dynamicallyLink:
     bool                         dynamicallyLinked_;
-    BufferPtr                    maybeHeap_;
-    Module**                     prev_;
-    Module*                      next_;
+    BufferPtr                    heap_;
 
     // Mutated after dynamicallyLink:
     bool                         profilingEnabled_;
     FuncLabelVector              funcLabels_;
-    bool                         interrupted_;
 
     class AutoMutateCode;
 
@@ -448,16 +460,13 @@ class Module
     static const unsigned OffsetOfImportExitFun = offsetof(ImportExit, fun);
     static const unsigned SizeOfEntryArg = sizeof(EntryArg);
 
-    enum HeapBool { DoesntUseHeap = false, UsesHeap = true };
-    enum SharedBool { UnsharedHeap = false, SharedHeap = true };
     enum MutedBool { DontMuteErrors = false, MuteErrors = true };
 
     Module(CompileArgs args,
            uint32_t functionBytes,
            uint32_t codeBytes,
            uint32_t globalBytes,
-           HeapBool usesHeap,
-           SharedBool sharedHeap,
+           HeapUsage heapUsage,
            MutedBool mutedErrors,
            UniqueCodePtr code,
            ImportVector&& imports,
@@ -474,8 +483,9 @@ class Module
     uint8_t* code() const { return code_.get(); }
     uint8_t* globalData() const { return code() + pod.codeBytes_; }
     uint32_t globalBytes() const { return pod.globalBytes_; }
-    bool usesHeap() const { return pod.usesHeap_; }
-    bool sharedHeap() const { return pod.sharedHeap_; }
+    HeapUsage heapUsage() const { return pod.heapUsage_; }
+    bool usesHeap() const { return UsesHeap(pod.heapUsage_); }
+    bool hasSharedHeap() const { return pod.heapUsage_ == HeapUsage::Shared; }
     bool mutedErrors() const { return pod.mutedErrors_; }
     CompileArgs compileArgs() const;
     const ImportVector& imports() const { return imports_; }
@@ -515,21 +525,9 @@ class Module
 
     // The wasm heap, established by dynamicallyLink.
 
-    ArrayBufferObjectMaybeShared* maybeBuffer() const;
-    SharedMem maybeHeap() const;
+    SharedMem heap() const;
     size_t heapLength() const;
 
-    // asm.js may detach and change the heap at any time. As an internal detail,
-    // the heap may not be changed while the module has been asynchronously
-    // interrupted.
-    //
-    // N.B. These methods and asm.js change-heap support will be removed soon.
-
-    bool changeHeap(Handle newBuffer, JSContext* cx);
-    bool detachHeap(JSContext* cx);
-    void setInterrupted(bool interrupted);
-    Module* nextLinked() const;
-
     // The exports of a wasm module are called by preparing an array of
     // arguments (coerced to the corresponding types of the Export signature)
     // and calling the export's entry trampoline.
diff --git a/js/src/asmjs/WasmSignalHandlers.cpp b/js/src/asmjs/WasmSignalHandlers.cpp
index 785f75362ea8..9ba91872d952 100644
--- a/js/src/asmjs/WasmSignalHandlers.cpp
+++ b/js/src/asmjs/WasmSignalHandlers.cpp
@@ -627,7 +627,7 @@ EmulateHeapAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddre
         uintptr_t base;
         StoreValueFromGPReg(SharedMem::unshared(&base), sizeof(uintptr_t),
                             AddressOfGPRegisterSlot(context, address.base()));
-        MOZ_RELEASE_ASSERT(reinterpret_cast(base) == module.maybeHeap());
+        MOZ_RELEASE_ASSERT(reinterpret_cast(base) == module.heap());
     }
     if (address.hasIndex()) {
         uintptr_t index;
@@ -645,11 +645,11 @@ EmulateHeapAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddre
     MOZ_RELEASE_ASSERT(size_t(faultingAddress - accessAddress) < access.size(),
                        "Given faulting address does not appear to be within computed "
                        "faulting address range");
-    MOZ_RELEASE_ASSERT(accessAddress >= module.maybeHeap(),
+    MOZ_RELEASE_ASSERT(accessAddress >= module.heap(),
                        "Access begins outside the asm.js heap");
-    MOZ_RELEASE_ASSERT(accessAddress + access.size() <= module.maybeHeap() + AsmJSMappedSize,
+    MOZ_RELEASE_ASSERT(accessAddress + access.size() <= module.heap() + AsmJSMappedSize,
                        "Access extends beyond the asm.js heap guard region");
-    MOZ_RELEASE_ASSERT(accessAddress + access.size() > module.maybeHeap() + module.heapLength(),
+    MOZ_RELEASE_ASSERT(accessAddress + access.size() > module.heap() + module.heapLength(),
                        "Computed access address is not actually out of bounds");
 
     // The basic sandbox model is that all heap accesses are a heap base
@@ -666,7 +666,7 @@ EmulateHeapAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddre
     //
     // Taking a signal is really slow, but in theory programs really shouldn't
     // be hitting this anyway.
-    intptr_t unwrappedOffset = accessAddress - module.maybeHeap().unwrap(/*safe - for value*/);
+    intptr_t unwrappedOffset = accessAddress - module.heap().unwrap(/*safe - for value*/);
     uint32_t wrappedOffset = uint32_t(unwrappedOffset);
     size_t size = access.size();
     MOZ_RELEASE_ASSERT(wrappedOffset + size > wrappedOffset);
@@ -684,10 +684,10 @@ EmulateHeapAccess(EMULATOR_CONTEXT* context, uint8_t* pc, uint8_t* faultingAddre
         // We now know that this is an access that is actually in bounds when
         // properly wrapped. Complete the load or store with the wrapped
         // address.
-        SharedMem wrappedAddress = module.maybeHeap() + wrappedOffset;
-        MOZ_RELEASE_ASSERT(wrappedAddress >= module.maybeHeap());
+        SharedMem wrappedAddress = module.heap() + wrappedOffset;
+        MOZ_RELEASE_ASSERT(wrappedAddress >= module.heap());
         MOZ_RELEASE_ASSERT(wrappedAddress + size > wrappedAddress);
-        MOZ_RELEASE_ASSERT(wrappedAddress + size <= module.maybeHeap() + module.heapLength());
+        MOZ_RELEASE_ASSERT(wrappedAddress + size <= module.heap() + module.heapLength());
         switch (access.kind()) {
           case Disassembler::HeapAccess::Load:
             SetRegisterToLoadedValue(context, wrappedAddress.cast(), size, access.otherOperand());
@@ -762,9 +762,9 @@ HandleFault(PEXCEPTION_POINTERS exception)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     uint8_t* faultingAddress = reinterpret_cast(record->ExceptionInformation[1]);
-    if (!module.maybeHeap() ||
-        faultingAddress < module.maybeHeap() ||
-        faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
+    if (!module.usesHeap() ||
+        faultingAddress < module.heap() ||
+        faultingAddress >= module.heap() + AsmJSMappedSize)
     {
         return false;
     }
@@ -907,9 +907,9 @@ HandleMachException(JSRuntime* rt, const ExceptionRequest& request)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     uint8_t* faultingAddress = reinterpret_cast(request.body.code[1]);
-    if (!module.maybeHeap() ||
-        faultingAddress < module.maybeHeap() ||
-        faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
+    if (!module.usesHeap() ||
+        faultingAddress < module.heap() ||
+        faultingAddress >= module.heap() + AsmJSMappedSize)
     {
         return false;
     }
@@ -1117,9 +1117,9 @@ HandleFault(int signum, siginfo_t* info, void* ctx)
     // These checks aren't necessary, but, since we can, check anyway to make
     // sure we aren't covering up a real bug.
     uint8_t* faultingAddress = reinterpret_cast(info->si_addr);
-    if (!module.maybeHeap() ||
-        faultingAddress < module.maybeHeap() ||
-        faultingAddress >= module.maybeHeap() + AsmJSMappedSize)
+    if (!module.usesHeap() ||
+        faultingAddress < module.heap() ||
+        faultingAddress >= module.heap() + AsmJSMappedSize)
     {
         return false;
     }
diff --git a/js/src/asmjs/WasmStubs.cpp b/js/src/asmjs/WasmStubs.cpp
index 170140598f5d..05635d4b4089 100644
--- a/js/src/asmjs/WasmStubs.cpp
+++ b/js/src/asmjs/WasmStubs.cpp
@@ -99,7 +99,7 @@ static const unsigned FramePushedForEntrySP = FramePushedAfterSave + sizeof(void
 // function has an ABI derived from its specific signature, so this function
 // must map from the ABI of CodePtr to the export's signature's ABI.
 static bool
-GenerateEntry(ModuleGenerator& mg, unsigned exportIndex, Module::HeapBool usesHeap)
+GenerateEntry(ModuleGenerator& mg, unsigned exportIndex, bool usesHeap)
 {
     MacroAssembler& masm = mg.masm();
     const MallocSig& sig = mg.exportSig(exportIndex);
@@ -332,30 +332,12 @@ FillArgumentArray(MacroAssembler& masm, const MallocSig::ArgVector& args, unsign
     }
 }
 
-// If an import call detaches its heap (viz., via ArrayBuffer.transfer), it must
-// call change-heap to another heap (viz., the new heap returned by transfer)
-// before returning to asm.js code. If the application fails to do this (if the
-// heap pointer is null), jump to a stub.
-static void
-CheckForHeapDetachment(MacroAssembler& masm, Register scratch, Label* onDetached)
-{
-    MOZ_ASSERT(int(masm.framePushed()) >= int(ShadowStackSpace));
-    AssertStackAlignment(masm, ABIStackAlignment);
-#if defined(JS_CODEGEN_X86)
-    CodeOffset offset = masm.movlWithPatch(PatchedAbsoluteAddress(), scratch);
-    masm.append(AsmJSGlobalAccess(offset, HeapGlobalDataOffset));
-    masm.branchTestPtr(Assembler::Zero, scratch, scratch, onDetached);
-#else
-    masm.branchTestPtr(Assembler::Zero, HeapReg, HeapReg, onDetached);
-#endif
-}
-
 // Generate a stub that is called via the internal ABI derived from the
 // signature of the import and calls into an appropriate InvokeImport C++
 // function, having boxed all the ABI arguments into a homogeneous Value array.
 static bool
-GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, Module::HeapBool usesHeap,
-                       Label* throwLabel, Label* onDetached, ProfilingOffsets* offsets)
+GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, Label* throwLabel,
+                       ProfilingOffsets* offsets)
 {
     MacroAssembler& masm = mg.masm();
     const MallocSig& sig = mg.importSig(importIndex);
@@ -440,13 +422,6 @@ GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, Module::HeapBo
         MOZ_CRASH("SIMD types shouldn't be returned from a FFI");
     }
 
-    // The heap pointer may have changed during the FFI, so reload it and test
-    // for detachment.
-    if (usesHeap) {
-        masm.loadAsmJSHeapRegisterFromGlobalData();
-        CheckForHeapDetachment(masm, ABIArgGenerator::NonReturn_VolatileReg0, onDetached);
-    }
-
     GenerateExitEpilogue(masm, framePushed, ExitReason::ImportInterp, offsets);
 
     if (masm.oom())
@@ -466,8 +441,8 @@ static const unsigned MaybeSavedGlobalReg = 0;
 // signature of the import and calls into a compatible JIT function,
 // having boxed all the ABI arguments into the JIT stack frame layout.
 static bool
-GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, Module::HeapBool usesHeap,
-                    Label* throwLabel, Label* onDetached, ProfilingOffsets* offsets)
+GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, bool usesHeap,
+                    Label* throwLabel, ProfilingOffsets* offsets)
 {
     MacroAssembler& masm = mg.masm();
     const MallocSig& sig = mg.importSig(importIndex);
@@ -540,8 +515,7 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, Module::HeapBool
     //    HeapReg are removed from the general register set for asm.js code, so
     //    these will not have been saved by the caller like all other registers,
     //    so they must be explicitly preserved. Only save GlobalReg since
-    //    HeapReg must be reloaded (from global data) after the call since the
-    //    heap may change during the FFI call.
+    //    HeapReg can be reloaded (from global data) after the call.
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     static_assert(MaybeSavedGlobalReg == sizeof(void*), "stack frame accounting");
     masm.storePtr(GlobalReg, Address(masm.getStackPointer(), jitFrameBytes));
@@ -698,12 +672,10 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, Module::HeapBool
     Label done;
     masm.bind(&done);
 
-    // The heap pointer has to be reloaded anyway since JIT code could have
-    // clobbered it. Additionally, the import may have detached the heap buffer.
-    if (usesHeap) {
+    // Ion code does not respect system callee-saved register conventions so
+    // reload the heap register.
+    if (usesHeap)
         masm.loadAsmJSHeapRegisterFromGlobalData();
-        CheckForHeapDetachment(masm, ABIArgGenerator::NonReturn_VolatileReg0, onDetached);
-    }
 
     GenerateExitEpilogue(masm, masm.framePushed(), ExitReason::ImportJit, offsets);
 
@@ -764,32 +736,6 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, Module::HeapBool
     return true;
 }
 
-// Generate a stub that is called when returning from an exit where the module's
-// buffer has been detached. This stub first calls a C++ function to report an
-// exception and then jumps to the generic throw stub to pop everything off the
-// stack.
-static bool
-GenerateOnDetachedStub(ModuleGenerator& mg, Label* onDetached, Label* throwLabel)
-{
-    MacroAssembler& masm = mg.masm();
-
-    masm.haltingAlign(CodeAlignment);
-    Offsets offsets;
-    offsets.begin = masm.currentOffset();
-    masm.bind(onDetached);
-
-    // For now, OnDetached always throws (see OnDetached comment).
-    masm.assertStackAlignment(ABIStackAlignment);
-    masm.call(SymbolicAddress::OnDetached);
-    masm.jump(throwLabel);
-
-    if (masm.oom())
-        return false;
-
-    offsets.end = masm.currentOffset();
-    return mg.defineInlineStub(offsets);
-}
-
 // Generate a stub that is called immediately after the prologue when there is a
 // stack overflow. This stub calls a C++ function to report the error and then
 // jumps to the throw stub to pop the activation.
@@ -929,7 +875,7 @@ static const LiveRegisterSet AllRegsExceptSP(
 // after restoring all registers. To hack around this, push the resumePC on the
 // stack so that it can be popped directly into PC.
 static bool
-GenerateAsyncInterruptStub(ModuleGenerator& mg, Module::HeapBool usesHeap, Label* throwLabel)
+GenerateAsyncInterruptStub(ModuleGenerator& mg, Label* throwLabel)
 {
     MacroAssembler& masm = mg.masm();
 
@@ -1126,7 +1072,7 @@ GenerateThrowStub(ModuleGenerator& mg, Label* throwLabel)
 }
 
 bool
-wasm::GenerateStubs(ModuleGenerator& mg, Module::HeapBool usesHeap)
+wasm::GenerateStubs(ModuleGenerator& mg, bool usesHeap)
 {
     for (unsigned i = 0; i < mg.numDeclaredExports(); i++) {
         if (!GenerateEntry(mg, i, usesHeap))
@@ -1135,26 +1081,17 @@ wasm::GenerateStubs(ModuleGenerator& mg, Module::HeapBool usesHeap)
 
     Label onThrow;
 
-    {
-        Label onDetached;
+    for (size_t i = 0; i < mg.numDeclaredImports(); i++) {
+        ProfilingOffsets interp;
+        if (!GenerateInterpExitStub(mg, i, &onThrow, &interp))
+            return false;
 
-        for (size_t i = 0; i < mg.numDeclaredImports(); i++) {
-            ProfilingOffsets interp;
-            if (!GenerateInterpExitStub(mg, i, usesHeap, &onThrow, &onDetached, &interp))
-                return false;
+        ProfilingOffsets jit;
+        if (!GenerateJitExitStub(mg, i, usesHeap, &onThrow, &jit))
+            return false;
 
-            ProfilingOffsets jit;
-            if (!GenerateJitExitStub(mg, i, usesHeap, &onThrow, &onDetached, &jit))
-                return false;
-
-            if (!mg.defineImport(i, interp, jit))
-                return false;
-        }
-
-        if (onDetached.used()) {
-            if (!GenerateOnDetachedStub(mg, &onDetached, &onThrow))
-                return false;
-        }
+        if (!mg.defineImport(i, interp, jit))
+            return false;
     }
 
     if (mg.masm().asmStackOverflowLabel()->used()) {
@@ -1178,7 +1115,7 @@ wasm::GenerateStubs(ModuleGenerator& mg, Module::HeapBool usesHeap)
         return false;
 
     // Generate unconditionally: the async interrupt may be taken at any time.
-    if (!GenerateAsyncInterruptStub(mg, usesHeap, &onThrow))
+    if (!GenerateAsyncInterruptStub(mg, &onThrow))
         return false;
 
     if (onThrow.used()) {
diff --git a/js/src/asmjs/WasmStubs.h b/js/src/asmjs/WasmStubs.h
index ae947f496472..72dbc59a6b5c 100644
--- a/js/src/asmjs/WasmStubs.h
+++ b/js/src/asmjs/WasmStubs.h
@@ -25,7 +25,7 @@ namespace js {
 namespace wasm {
 
 bool
-GenerateStubs(ModuleGenerator& mg, Module::HeapBool usesHeap);
+GenerateStubs(ModuleGenerator& mg, bool usesHeap);
 
 } // namespace wasm
 } // namespace js
diff --git a/js/src/asmjs/WasmTypes.cpp b/js/src/asmjs/WasmTypes.cpp
index 08c72af05595..e51a185a1da0 100644
--- a/js/src/asmjs/WasmTypes.cpp
+++ b/js/src/asmjs/WasmTypes.cpp
@@ -43,34 +43,16 @@ __aeabi_uidivmod(int, int);
 }
 #endif
 
-namespace js {
-namespace wasm {
-
-void
-ReportOverRecursed()
-{
-    JSContext* cx = JSRuntime::innermostWasmActivation()->cx();
-    ReportOverRecursed(cx);
-}
-
-bool
-HandleExecutionInterrupt()
-{
-    WasmActivation* act = JSRuntime::innermostWasmActivation();
-    act->module().setInterrupted(true);
-    bool ret = CheckForInterrupt(act->cx());
-    act->module().setInterrupted(false);
-    return ret;
-}
-
-} // namespace wasm
-} // namespace js
-
 static void
-OnDetached()
+WasmReportOverRecursed()
 {
-    JSContext* cx = JSRuntime::innermostWasmActivation()->cx();
-    JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY);
+    ReportOverRecursed(JSRuntime::innermostWasmActivation()->cx());
+}
+
+static bool
+WasmHandleExecutionInterrupt()
+{
+    return CheckForInterrupt(JSRuntime::innermostWasmActivation()->cx());
 }
 
 static void
@@ -187,15 +169,13 @@ wasm::AddressOf(SymbolicAddress imm, ExclusiveContext* cx)
       case SymbolicAddress::StackLimit:
         return cx->stackLimitAddressForJitCode(StackForUntrustedScript);
       case SymbolicAddress::ReportOverRecursed:
-        return FuncCast(wasm::ReportOverRecursed, Args_General0);
-      case SymbolicAddress::OnDetached:
-        return FuncCast(OnDetached, Args_General0);
+        return FuncCast(WasmReportOverRecursed, Args_General0);
       case SymbolicAddress::OnOutOfBounds:
         return FuncCast(OnOutOfBounds, Args_General0);
       case SymbolicAddress::OnImpreciseConversion:
         return FuncCast(OnImpreciseConversion, Args_General0);
       case SymbolicAddress::HandleExecutionInterrupt:
-        return FuncCast(wasm::HandleExecutionInterrupt, Args_General0);
+        return FuncCast(WasmHandleExecutionInterrupt, Args_General0);
       case SymbolicAddress::InvokeImport_Void:
         return FuncCast(InvokeImport_Void, Args_General3);
       case SymbolicAddress::InvokeImport_I32:
diff --git a/js/src/asmjs/WasmTypes.h b/js/src/asmjs/WasmTypes.h
index 1bf56a337575..45eec15815d2 100644
--- a/js/src/asmjs/WasmTypes.h
+++ b/js/src/asmjs/WasmTypes.h
@@ -557,7 +557,6 @@ enum class SymbolicAddress
     RuntimeInterruptUint32,
     StackLimit,
     ReportOverRecursed,
-    OnDetached,
     OnOutOfBounds,
     OnImpreciseConversion,
     HandleExecutionInterrupt,
diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp
index e6033997c591..1d9b56987c0c 100644
--- a/js/src/builtin/AtomicsObject.cpp
+++ b/js/src/builtin/AtomicsObject.cpp
@@ -524,7 +524,7 @@ GetCurrentAsmJSHeap(SharedMem* heap, size_t* length)
 {
     JSRuntime* rt = js::TlsPerThreadData.get()->runtimeFromMainThread();
     wasm::Module& module = rt->wasmActivationStack()->module();
-    *heap = module.maybeHeap().cast();
+    *heap = module.heap().cast();
     *length = module.heapLength();
 }
 
diff --git a/js/src/jit-test/tests/asm.js/testBug1100237.js b/js/src/jit-test/tests/asm.js/testBug1100237.js
deleted file mode 100644
index f9c780256b82..000000000000
--- a/js/src/jit-test/tests/asm.js/testBug1100237.js
+++ /dev/null
@@ -1,33 +0,0 @@
-load(libdir + "asm.js");
-
-var byteLength = Function.prototype.call.bind(
-    Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, "byteLength").get
-);
-var m = asmCompile("glob", "s", "b", `
-    "use asm";
-    var I32 = glob.Int32Array;
-    var i32 = new I32(b);
-    var len = glob.byteLength;
-    function ch(b2) {
-        if (len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 80000000) {
-            return false;
-        }
-        i32 = new I32(b2);
-        b = b2;
-        return true
-    }
-    function get(i) {
-        i = i | 0;
-        return i32[i >> 2] | 0
-    }
-    return {
-        get: get,
-        changeHeap: ch
-    }
-`);
-var buf1 = new ArrayBuffer(16777216)
-var { get, changeHeap } = asmLink(m, this, null, buf1)
-assertEq(changeHeap(new ArrayBuffer(33554432)), true)
-assertEq(get(), 0)
-assertEq(changeHeap(buf1), true);
-get();
diff --git a/js/src/jit-test/tests/asm.js/testNeuter.js b/js/src/jit-test/tests/asm.js/testNeuter.js
index a9c505066897..4000adab71e5 100644
--- a/js/src/jit-test/tests/asm.js/testNeuter.js
+++ b/js/src/jit-test/tests/asm.js/testNeuter.js
@@ -23,19 +23,8 @@ var buffer = new ArrayBuffer(BUF_MIN);
 var {get, set} = asmLink(m, this, null, buffer);
 set(4, 42);
 assertEq(get(4), 42);
-neuter(buffer, "change-data");
-neuter(buffer, "same-data");
-assertThrowsInstanceOf(() => get(4), InternalError);
-
-var buf1 = new ArrayBuffer(BUF_MIN);
-var buf2 = new ArrayBuffer(BUF_MIN);
-var {get:get1, set:set1} = asmLink(m, this, null, buf1);
-var {get:get2, set:set2} = asmLink(m, this, null, buf2);
-set1(0, 13);
-set2(0, 42);
-neuter(buf1, "change-data");
-assertThrowsInstanceOf(() => get1(0), InternalError);
-assertEq(get2(0), 42);
+assertThrowsInstanceOf(() => neuter(buffer, "change-data"), InternalError);
+assertThrowsInstanceOf(() => neuter(buffer, "same-data"), InternalError);
 
 var m = asmCompile('stdlib', 'foreign', 'buffer',
                   `"use asm";
@@ -49,66 +38,5 @@ var m = asmCompile('stdlib', 'foreign', 'buffer',
                    return inner`);
 
 var buffer = new ArrayBuffer(BUF_MIN);
-function ffi1() { neuter(buffer, "change-data"); }
+function ffi1() { assertThrowsInstanceOf(() => neuter(buffer, "change-data"), InternalError) }
 var inner = asmLink(m, this, {ffi:ffi1}, buffer);
-assertThrowsInstanceOf(() => inner(8), InternalError);
-
-var byteLength = Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get);
-var m = asmCompile('stdlib', 'foreign', 'buffer',
-                  `"use asm";
-                   var ffi = foreign.ffi;
-                   var I32 = stdlib.Int32Array;
-                   var i32 = new I32(buffer);
-                   var len = stdlib.byteLength;
-                   function changeHeap(newBuffer) {
-                       if (len(newBuffer) & 0xffffff || len(newBuffer) <= 0xffffff || len(newBuffer) > 0x80000000)
-                           return false;
-                       i32 = new I32(newBuffer);
-                       buffer = newBuffer;
-                       return true;
-                   }
-                   function get(i) {
-                       i=i|0;
-                       return i32[i>>2]|0;
-                   }
-                   function inner(i) {
-                       i=i|0;
-                       ffi();
-                       return get(i)|0;
-                   }
-                   return {changeHeap:changeHeap, get:get, inner:inner}`);
-
-var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
-var buf2 = new ArrayBuffer(BUF_CHANGE_MIN);
-var buf3 = new ArrayBuffer(BUF_CHANGE_MIN);
-var buf4 = new ArrayBuffer(BUF_CHANGE_MIN);
-new Int32Array(buf2)[13] = 42;
-new Int32Array(buf3)[13] = 1024;
-new Int32Array(buf4)[13] = 1337;
-
-function ffi2() { neuter(buf1, "change-data"); assertEq(changeHeap(buf2), true); }
-var {changeHeap, get:get2, inner} = asmLink(m, this, {ffi:ffi2}, buf1);
-assertEq(inner(13*4), 42);
-
-function ffi3() {
-    assertEq(get2(13*4), 42);
-    assertEq(get2(BUF_CHANGE_MIN), 0)
-    assertEq(get3(13*4), 42);
-    assertEq(get3(BUF_CHANGE_MIN), 0)
-    neuter(buf2, "change-data");
-    assertThrowsInstanceOf(()=>get2(13*4), InternalError);
-    assertThrowsInstanceOf(()=>get2(BUF_CHANGE_MIN), InternalError);
-    assertThrowsInstanceOf(()=>get3(13*4), InternalError);
-    assertThrowsInstanceOf(()=>get3(BUF_CHANGE_MIN), InternalError);
-    assertEq(changeHeap(buf3), true);
-    assertThrowsInstanceOf(()=>get2(13*4), InternalError);
-    assertThrowsInstanceOf(()=>get2(BUF_CHANGE_MIN), InternalError);
-    assertEq(get3(13*4), 1024);
-    assertEq(get3(BUF_CHANGE_MIN), 0);
-    assertEq(changeHeap(buf4), true);
-}
-var {changeHeap, get:get3, inner} = asmLink(m, this, {ffi:ffi3}, buf2);
-assertEq(inner(13*4), 1337);
-assertThrowsInstanceOf(()=>get2(0), InternalError);
-assertEq(get3(BUF_CHANGE_MIN), 0);
-assertEq(get3(13*4), 1337);
diff --git a/js/src/jit-test/tests/asm.js/testProfiling.js b/js/src/jit-test/tests/asm.js/testProfiling.js
index 8dc41080c4ce..69d99467925d 100644
--- a/js/src/jit-test/tests/asm.js/testProfiling.js
+++ b/js/src/jit-test/tests/asm.js/testProfiling.js
@@ -202,16 +202,6 @@ var stacks = disableSingleStepProfiling();
 assertStackContainsSeq(stacks, ">,f1,>,<,f1,>,>,<,f1,>,f2,>,<,f1,>,<,f2,>,<,f1,>,f2,>,<,f1,>,>,<,f1,>,<,f1,>,f1,>,>");
 
 
-// Detachment exit
-var buf = new ArrayBuffer(BUF_CHANGE_MIN);
-var ffi = function() { neuter(buf, 'change-data') }
-var f = asmLink(asmCompile('g','ffis','buf', USE_ASM + 'var ffi = ffis.ffi; var i32 = new g.Int32Array(buf); function f() { ffi() } return f'), this, {ffi:ffi}, buf);
-enableSingleStepProfiling();
-assertThrowsInstanceOf(f, InternalError);
-var stacks = disableSingleStepProfiling();
-assertStackContainsSeq(stacks, ">,f,>,<,f,>,inline stub,f,>,<,f,>,inline stub,f,>");
-
-
 if (isSimdAvailable() && typeof SIMD !== 'undefined') {
     // SIMD out-of-bounds exit
     var buf = new ArrayBuffer(0x10000);
diff --git a/js/src/jit-test/tests/asm.js/testResize.js b/js/src/jit-test/tests/asm.js/testResize.js
deleted file mode 100644
index c529a9f5f55f..000000000000
--- a/js/src/jit-test/tests/asm.js/testResize.js
+++ /dev/null
@@ -1,366 +0,0 @@
-// |jit-test| test-also-noasmjs
-load(libdir + "asm.js");
-load(libdir + "asserts.js");
-
-// Tests for importing typed array view constructors
-
-assertAsmTypeFail('glob', USE_ASM + "var I32=glob.Int32Arra; function f() {} return f");
-var m = asmCompile('glob', USE_ASM + "var I32=glob.Int32Array; function f() {} return f");
-assertAsmLinkFail(m, {});
-assertAsmLinkFail(m, {Int32Array:null});
-assertAsmLinkFail(m, {Int32Array:{}});
-assertAsmLinkFail(m, {Int32Array:Uint32Array});
-assertEq(asmLink(m, {Int32Array:Int32Array})(), undefined);
-var m = asmCompile('glob', 'ffis', 'buf', USE_ASM + "var I32=glob.Int32Array; function f() {} return f");
-assertEq(asmLink(m, this)(), undefined);
-assertEq(asmLink(m, this, null, BUF_64KB)(), undefined);
-
-assertAsmTypeFail('glob', 'ffis', 'buf', USE_ASM + 'var I32=glob.Int32Array; var i32=new I3(buf); function f() {} return f');
-assertAsmTypeFail('glob', 'ffis', 'buf', USE_ASM + 'var I32=0; var i32=new I32(buf); function f() {} return f');
-var m = asmCompile('glob', 'ffis', 'buf', USE_ASM + 'var I32=glob.Int32Array; var i32=new I32(buf); function f() {} return f');
-assertAsmLinkFail(m, this, null, {});
-assertAsmLinkAlwaysFail(m, this, null, null);
-assertAsmLinkFail(m, this, null, new ArrayBuffer(100));
-assertEq(asmLink(m, this, null, BUF_64KB)(), undefined);
-
-var m = asmCompile('glob', 'ffis', 'buf', USE_ASM + 'var I32=glob.Int32Array; var i32=new glob.Int32Array(buf); function f() {} return f');
-assertAsmLinkFail(m, this, null, {});
-assertAsmLinkAlwaysFail(m, this, null, null);
-assertAsmLinkFail(m, this, null, new ArrayBuffer(100));
-assertEq(asmLink(m, this, null, BUF_64KB)(), undefined);
-
-var m = asmCompile('glob', 'ffis', 'buf', USE_ASM + 'var F32=glob.Float32Array; var i32=new glob.Int32Array(buf); function f() {} return f');
-assertAsmLinkFail(m, this, null, {});
-assertAsmLinkAlwaysFail(m, this, null, null);
-assertAsmLinkFail(m, this, null, new ArrayBuffer(100));
-assertEq(asmLink(m, this, null, BUF_64KB)(), undefined);
-
-// Tests for link-time validation of byteLength import
-
-assertAsmTypeFail('glob', 'ffis', 'buf', USE_ASM + 'var byteLength=glob.byteLength; function f() { return byteLength(1)|0 } return f');
-
-var m = asmCompile('glob', 'ffis', 'buf', USE_ASM + 'var byteLength=glob.byteLength; function f() { return 42 } return f');
-assertEq('byteLength' in this, false);
-assertAsmLinkFail(m, this);
-this['byteLength'] = null;
-assertAsmLinkFail(m, this);
-this['byteLength'] = {};
-assertAsmLinkFail(m, this);
-this['byteLength'] = function(){}
-assertAsmLinkFail(m, this);
-this['byteLength'] = (function(){}).bind(null);
-assertAsmLinkFail(m, this);
-this['byteLength'] = Function.prototype.call.bind();
-assertAsmLinkFail(m, this);
-this['byteLength'] = Function.prototype.call.bind({});
-assertAsmLinkFail(m, this);
-this['byteLength'] = Function.prototype.call.bind(function f() {});
-assertAsmLinkFail(m, this);
-this['byteLength'] = Function.prototype.call.bind(Math.sin);
-assertAsmLinkFail(m, this);
-this['byteLength'] =
-  Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get);
-assertEq(asmLink(m, this)(), 42);
-
-var m = asmCompile('glob', 'ffis', 'buf', USE_ASM + 'var b1=glob.byteLength, b2=glob.byteLength; function f() { return 43 } return f');
-assertEq(asmLink(m, this)(), 43);
-
-// Tests for validation of change-heap function
-
-const BYTELENGTH_IMPORT = "var len = glob.byteLength; ";
-const IMPORT0 = BYTELENGTH_IMPORT;
-const IMPORT1 = "var I8=glob.Int8Array; var i8=new I8(b); " + BYTELENGTH_IMPORT;
-const IMPORT2 = "var I8=glob.Int8Array; var i8=new I8(b); var I32=glob.Int32Array; var i32=new I32(b); var II32=glob.Int32Array; " + BYTELENGTH_IMPORT;
-
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f() { return 42 } function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function b(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function f(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2=1) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,xyz) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2,...r) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch({b2}) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { ;if((len((b2))) & (0xffffff) || (len((b2)) <= (0xffffff)) || len(b2) > 0x80000000) {;;return false;;} ; i8=new I8(b2);; b=b2;; return true;; } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function ch2(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { 3; if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { b2=b2|0; if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || 1 || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(1 & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || 1 || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(i8(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(xyz) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff && len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) | 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) == 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xfffffe || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0x1ffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0x7fffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) < 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xfffffe || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000 || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || 1) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) < 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || 1 > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0.0) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0xffffff) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x1000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffffff || len(b2) > 0x1000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000 || len(b2) > 0x1000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1000000 || len(b2) > 0x1000001) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000001) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) ; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) {} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) {return false} i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return true; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT0 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i7=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=1; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new 1; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I7(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new b(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8; b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(1); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2,1); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); xyz=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=1; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; 1; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return 1 } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return false } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; if (0) return true; 1 } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true } function f() { return 42 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I32(b2); i32=new I8(b2); b=b2; return true } function f() { return 42 } return f');
-       asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new II32(b2); b=b2; return true } function f() { return 42 } return f');
-
-// Tests for no calls in heap index expressions
-
-const CHANGE_FUN = 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); i32=new I32(b2); b=b2; return true }';
-const SETUP = USE_ASM + IMPORT2 + 'var imul=glob.Math.imul; var ffi=ffis.ffi;' + CHANGE_FUN;
-
-       asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { i32[0] } return f');
-       asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { i32[0] = 0 } return f');
-       asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] } return f');
-       asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = 0 } return f');
-       asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(imul(i,i)|0) >> 2] = 0 } return f');
-       asmCompile('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = (imul(i,i)|0) } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(ffi()|0) >> 2] } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(g()|0) >> 2] } function g() { return 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(TBL[i&0]()|0) >> 2] } function g() { return 0 } var TBL=[g]; return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[(g()|0) >> 2] = 0 } function g() { return 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = g()|0 } function g() { return 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i32[(g()|0)>>2] >> 2] } function g() { return 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i32[(g()|0)>>2] >> 2] = 0 } function g() { return 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = i32[(g()|0)>>2] } function g() { return 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[((i32[i>>2]|0) + (g()|0)) >> 2] } function g() { return 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[((i32[i>>2]|0) + (g()|0)) >> 2] = 0 } function g() { return 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', SETUP + 'function f() { var i = 0; i32[i >> 2] = (i32[i>>2]|0) + (g()|0) } function g() { return 0 } return f');
-if (isSimdAvailable() && typeof SIMD !== 'undefined')
-    asmCompile('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'var i4 = glob.SIMD.Int32x4; var ext = i4.extractLane; var add = i4.add;' + CHANGE_FUN + 'function f(i) { i=i|0; i32[ext(i4(i,1,2,i),0) >> 2]; i32[ext(add(i4(0,0,0,0),i4(1,1,1,1)),0) >> 2]; } return f');
-
-// Tests for constant heap accesses when change-heap is used
-
-const HEADER = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= MIN || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } ';
-assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { i8[0x1000000] = 0 } return f');
-       asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { i8[0xffffff] = 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { i8[0x1000001] = 0 } return f');
-       asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { i8[0x1000000] = 0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { return i8[0x1000000]|0 } return f');
-       asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0xffffff') + 'function f() { return i8[0xffffff]|0 } return f');
-assertAsmTypeFail('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { return i8[0x1000001]|0 } return f');
-       asmCompile('glob', 'ffis', 'b', HEADER.replace('MIN', '0x1000000') + 'function f() { return i8[0x1000000]|0 } return f');
-
-// Tests for validation of heap length
-
-var body = USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0x1ffffff || len(b2) > 0x4000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return ch';
-var m = asmCompile('glob', 'ffis', 'b', body);
-assertAsmLinkFail(m, this, null, new ArrayBuffer(BUF_CHANGE_MIN));
-assertAsmLinkFail(m, this, null, new ArrayBuffer(0x1000000));
-var changeHeap = asmLink(m, this, null, new ArrayBuffer(0x2000000));
-assertEq(changeHeap(new ArrayBuffer(0x1000000)), false);
-assertEq(changeHeap(new ArrayBuffer(0x2000000)), true);
-assertEq(changeHeap(new ArrayBuffer(0x2000001)), false);
-assertEq(changeHeap(new ArrayBuffer(0x4000000)), true);
-assertEq(changeHeap(new ArrayBuffer(0x5000000)), false);
-assertThrowsInstanceOf(() => changeHeap(null), TypeError);
-assertThrowsInstanceOf(() => changeHeap({}), TypeError);
-assertThrowsInstanceOf(() => changeHeap(new Int32Array(100)), TypeError);
-
-var detached = new ArrayBuffer(BUF_CHANGE_MIN);
-neuter(detached, "change-data");
-assertEq(changeHeap(detached), false);
-
-// Tests for runtime changing heap
-
-const CHANGE_HEAP = 'var changeHeap = glob.byteLength;';
-
-var changeHeapSource = `function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true }`;
-var body = `var I32=glob.Int32Array; var i32=new I32(b);
-            var len=glob.byteLength;` +
-            changeHeapSource +
-           `function get(i) { i=i|0; return i32[i>>2]|0 }
-            function set(i, v) { i=i|0; v=v|0; i32[i>>2] = v }
-            return {get:get, set:set, changeHeap:ch}`;
-
-var m = asmCompile('glob', 'ffis', 'b', USE_ASM + body);
-var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
-var {get, set, changeHeap} = asmLink(m, this, null, buf1);
-
-assertEq(m.toString(), "function anonymous(glob, ffis, b) {\n" + USE_ASM + body + "\n}");
-assertEq(m.toSource(), "(function anonymous(glob, ffis, b) {\n" + USE_ASM + body + "\n})");
-assertEq(changeHeap.toString(), changeHeapSource);
-assertEq(changeHeap.toSource(), changeHeapSource);
-
-set(0, 42);
-set(4, 13);
-set(4, 13);
-assertEq(get(0), 42);
-assertEq(get(4), 13);
-set(BUF_CHANGE_MIN, 262);
-assertEq(get(BUF_CHANGE_MIN), 0);
-var buf2 = new ArrayBuffer(2*BUF_CHANGE_MIN);
-assertEq(changeHeap(buf2), true);
-assertEq(get(0), 0);
-assertEq(get(4), 0);
-set(BUF_CHANGE_MIN, 262);
-assertEq(get(BUF_CHANGE_MIN), 262);
-set(2*BUF_CHANGE_MIN, 262);
-assertEq(get(2*BUF_CHANGE_MIN), 0);
-changeHeap(buf1);
-assertEq(get(0), 42);
-assertEq(get(4), 13);
-set(BUF_CHANGE_MIN, 262);
-assertEq(get(BUF_CHANGE_MIN), 0);
-
-if (ArrayBuffer.transfer) {
-    var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
-    var {get, set, changeHeap} = asmLink(m, this, null, buf1);
-    set(0, 100);
-    set(BUF_CHANGE_MIN - 4, 101);
-    set(BUF_CHANGE_MIN, 102);
-    var buf2 = ArrayBuffer.transfer(buf1);
-    assertEq(changeHeap(buf2), true);
-    assertEq(buf1.byteLength, 0);
-    assertEq(buf2.byteLength, BUF_CHANGE_MIN);
-    assertEq(get(0), 100);
-    assertEq(get(BUF_CHANGE_MIN-4), 101);
-    assertEq(get(BUF_CHANGE_MIN), 0);
-    assertEq(get(2*BUF_CHANGE_MIN-4), 0);
-    var buf3 = ArrayBuffer.transfer(buf2, 3*BUF_CHANGE_MIN);
-    assertEq(changeHeap(buf3), true);
-    assertEq(buf2.byteLength, 0);
-    assertEq(buf3.byteLength, 3*BUF_CHANGE_MIN);
-    assertEq(get(0), 100);
-    assertEq(get(BUF_CHANGE_MIN-4), 101);
-    assertEq(get(BUF_CHANGE_MIN), 0);
-    assertEq(get(2*BUF_CHANGE_MIN), 0);
-    set(BUF_CHANGE_MIN, 102);
-    set(2*BUF_CHANGE_MIN, 103);
-    assertEq(get(BUF_CHANGE_MIN), 102);
-    assertEq(get(2*BUF_CHANGE_MIN), 103);
-    var buf4 = ArrayBuffer.transfer(buf3, 2*BUF_CHANGE_MIN);
-    assertEq(changeHeap(buf4), true);
-    assertEq(buf3.byteLength, 0);
-    assertEq(buf4.byteLength, 2*BUF_CHANGE_MIN);
-    assertEq(get(0), 100);
-    assertEq(get(BUF_CHANGE_MIN-4), 101);
-    assertEq(get(BUF_CHANGE_MIN), 102);
-    assertEq(get(2*BUF_CHANGE_MIN), 0);
-    var buf5 = ArrayBuffer.transfer(buf4, 3*BUF_CHANGE_MIN);
-    assertEq(changeHeap(buf5), true);
-    assertEq(buf4.byteLength, 0);
-    assertEq(buf5.byteLength, 3*BUF_CHANGE_MIN);
-    assertEq(get(0), 100);
-    assertEq(get(BUF_CHANGE_MIN-4), 101);
-    assertEq(get(BUF_CHANGE_MIN), 102);
-    assertEq(get(2*BUF_CHANGE_MIN), 0);
-    var buf6 = ArrayBuffer.transfer(buf5, 0);
-    assertEq(buf5.byteLength, 0);
-    assertEq(buf6.byteLength, 0);
-    assertEq(changeHeap(buf6), false);
-}
-
-var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
-var buf2 = new ArrayBuffer(BUF_CHANGE_MIN);
-var m = asmCompile('glob', 'ffis', 'b', USE_ASM +
-                   `var len=glob.byteLength;
-                    function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; b=b2; return true }
-                    return ch`);
-var changeHeap = asmLink(m, this, null, buf1);
-assertEq(changeHeap(buf2), true);
-neuter(buf2, "change-data");
-assertEq(changeHeap(buf1), true);
-neuter(buf1, "change-data");
-
-var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
-new Int32Array(buf1)[0] = 13;
-var buf2 = new ArrayBuffer(BUF_CHANGE_MIN);
-new Int32Array(buf2)[0] = 42;
-
-// Tests for changing heap during an FFI:
-
-// Set the warmup to '2' so we can hit both interp and ion FFI exits
-setJitCompilerOption("ion.warmup.trigger", 2);
-setJitCompilerOption("baseline.warmup.trigger", 0);
-setJitCompilerOption("offthread-compilation.enable", 0);
-
-var changeToBuf = null;
-var m = asmCompile('glob', 'ffis', 'b', USE_ASM +
-                   `var ffi=ffis.ffi;
-                    var I32=glob.Int32Array; var i32=new I32(b);
-                    var len=glob.byteLength;
-                    function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true }
-                    function test(i) { i=i|0; var sum=0; sum = i32[i>>2]|0; sum = (sum + (ffi()|0))|0; sum = (sum + (i32[i>>2]|0))|0; return sum|0 }
-                    return {test:test, changeHeap:ch}`);
-var ffi = function() { changeHeap(changeToBuf); return 1 }
-var {test, changeHeap} = asmLink(m, this, {ffi:ffi}, buf1);
-changeToBuf = buf1;
-assertEq(test(0), 27);
-changeToBuf = buf2;
-assertEq(test(0), 56);
-changeToBuf = buf2;
-assertEq(test(0), 85);
-changeToBuf = buf1;
-assertEq(test(0), 56);
-changeToBuf = buf1;
-assertEq(test(0), 27);
-
-var ffi = function() { return { valueOf:function() { changeHeap(changeToBuf); return 100 } } };
-var {test, changeHeap} = asmLink(m, this, {ffi:ffi}, buf1);
-changeToBuf = buf1;
-assertEq(test(0), 126);
-changeToBuf = buf2;
-assertEq(test(0), 155);
-changeToBuf = buf2;
-assertEq(test(0), 184);
-changeToBuf = buf1;
-assertEq(test(0), 155);
-changeToBuf = buf1;
-assertEq(test(0), 126);
-
-if (ArrayBuffer.transfer) {
-    var buf = new ArrayBuffer(BUF_CHANGE_MIN);
-    new Int32Array(buf)[0] = 3;
-    var ffi = function() {
-        var buf2 = ArrayBuffer.transfer(buf, 2*BUF_CHANGE_MIN);
-        new Int32Array(buf2)[BUF_CHANGE_MIN/4] = 13;
-        assertEq(changeHeap(buf2), true);
-        return 1
-    }
-    var {test, changeHeap} = asmLink(m, this, {ffi:ffi}, buf);
-    assertEq(test(BUF_CHANGE_MIN), 14);
-}
diff --git a/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js b/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js
deleted file mode 100644
index bde496899cc1..000000000000
--- a/js/src/jit-test/tests/asm.js/testTimeout7-nosignals.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// |jit-test| exitstatus: 6;
-load(libdir + "asm.js");
-
-// This test may iloop for valid reasons if not compiled with asm.js (namely,
-// inlining may allow the heap load to be hoisted out of the loop).
-if (!isAsmJSCompilationAvailable())
-    quit(6);
-
-setJitCompilerOption("signals.enable", 0);
-
-var byteLength =
-  Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get);
-
-var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
-new Int32Array(buf1)[0] = 13;
-var buf2 = new ArrayBuffer(BUF_CHANGE_MIN);
-new Int32Array(buf2)[0] = 42;
-
-// Test changeHeap from interrupt (as if that could ever happen...)
-var m = asmCompile('glob', 'ffis', 'b', USE_ASM +
-                   `var I32=glob.Int32Array; var i32=new I32(b);
-                    var len=glob.byteLength;
-                    function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true }
-                    function f() {}
-                    function loop(i) { i=i|0; while((i32[i>>2]|0) == 13) { f() } }
-                    return {loop:loop, changeHeap:changeHeap}`);
-var { loop, changeHeap } = asmLink(m, this, null, buf1);
-timeout(1, function() { assertEq(changeHeap(buf2), false); return false });
-loop(0);
diff --git a/js/src/jit-test/tests/asm.js/testTimeout7.js b/js/src/jit-test/tests/asm.js/testTimeout7.js
deleted file mode 100644
index ce85cebb09c9..000000000000
--- a/js/src/jit-test/tests/asm.js/testTimeout7.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// |jit-test| exitstatus: 6;
-load(libdir + "asm.js");
-
-// This test may iloop for valid reasons if not compiled with asm.js (namely,
-// inlining may allow the heap load to be hoisted out of the loop).
-if (!isAsmJSCompilationAvailable())
-    quit(6);
-
-var byteLength =
-  Function.prototype.call.bind(Object.getOwnPropertyDescriptor(ArrayBuffer.prototype, 'byteLength').get);
-
-var buf1 = new ArrayBuffer(BUF_CHANGE_MIN);
-new Int32Array(buf1)[0] = 13;
-var buf2 = new ArrayBuffer(BUF_CHANGE_MIN);
-new Int32Array(buf2)[0] = 42;
-
-// Test changeHeap from interrupt (as if that could ever happen...)
-var m = asmCompile('glob', 'ffis', 'b', USE_ASM +
-                   `var I32=glob.Int32Array; var i32=new I32(b);
-                    var len=glob.byteLength;
-                    function changeHeap(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true }
-                    function f() {}
-                    function loop(i) { i=i|0; while((i32[i>>2]|0) == 13) { f() } }
-                    return {loop:loop, changeHeap:changeHeap}`);
-var { loop, changeHeap } = asmLink(m, this, null, buf1);
-timeout(1, function() { assertEq(changeHeap(buf2), false); return false });
-loop(0);
diff --git a/js/src/jit-test/tests/basic/testArrayBufferTransfer.js b/js/src/jit-test/tests/basic/testArrayBufferTransfer.js
deleted file mode 100644
index 9a68ed75153a..000000000000
--- a/js/src/jit-test/tests/basic/testArrayBufferTransfer.js
+++ /dev/null
@@ -1,123 +0,0 @@
-load(libdir + "asserts.js");
-load(libdir + "asm.js");
-
-// Currently, ArrayBuffer.transfer is #ifdef NIGHTLY_BUILD. When
-// ArrayBuffer.transfer is enabled on release, this test should be removed.
-if (!ArrayBuffer.transfer)
-    quit();
-
-var XF = ArrayBuffer.transfer;
-
-assertEq(typeof XF, "function");
-assertEq(XF.length, 2);
-
-// arg 1 errors
-assertThrowsInstanceOf(()=>XF(), Error);
-assertThrowsInstanceOf(()=>XF(undefined), Error);
-assertThrowsInstanceOf(()=>XF(null), Error);
-assertThrowsInstanceOf(()=>XF({}), Error);
-assertThrowsInstanceOf(()=>XF(new Int32Array(1)), Error);
-var buf = new ArrayBuffer(1);
-neuter(buf, 'change-data');
-assertThrowsInstanceOf(()=>XF(buf), TypeError);
-
-// arg 2 errors
-var buf = new ArrayBuffer(1);
-assertThrowsInstanceOf(()=>XF(buf, -1), Error);
-assertThrowsInstanceOf(()=>XF(buf, {valueOf() { return -1 }}), Error);
-assertThrowsInstanceOf(()=>XF(buf, {toString() { return "-1" }}), Error);
-assertThrowsValue(()=>XF(buf, {valueOf() { throw "wee" }}), "wee");
-
-// arg 2 is coerced via ToInt32
-var buf = new ArrayBuffer(1);
-assertThrowsInstanceOf(()=>XF(buf, Math.pow(2,31)), Error);
-buf = XF(buf, Math.pow(2,32));
-assertEq(buf.byteLength, 0);
-buf = XF(buf, Math.pow(2,32) + 10);
-assertEq(buf.byteLength, 10);
-
-assertThrowsInstanceOf(()=>XF(buf, {valueOf() { neuter(buf, "change-data"); return 10; }}), TypeError);
-var buf = new ArrayBuffer(100);
-assertThrowsInstanceOf(()=>XF(buf, {valueOf() { ArrayBuffer.transfer(buf, 0); return 100; }}), TypeError);
-
-// on undefined second argument, stay the same size:
-var buf1 = new ArrayBuffer(0);
-var buf2 = XF(buf1);
-assertEq(buf1.byteLength, 0);
-assertEq(buf2.byteLength, 0);
-assertThrowsInstanceOf(()=>XF(buf1), TypeError);
-
-var buf1 = new ArrayBuffer(3);
-var buf2 = XF(buf1);
-assertEq(buf1.byteLength, 0);
-assertEq(buf2.byteLength, 3);
-assertThrowsInstanceOf(()=>XF(buf1), TypeError);
-
-var buf1 = new ArrayBuffer(9);
-var buf2 = XF(buf1, undefined);
-assertEq(buf1.byteLength, 0);
-assertEq(buf2.byteLength, 9);
-assertThrowsInstanceOf(()=>XF(buf1), TypeError);
-
-// cross-compartment wrapper
-var buf3 = newGlobal().eval("new ArrayBuffer(10)");
-var buf4 = XF(buf3, 20);
-assertEq(buf4.byteLength, 20);
-assertThrowsInstanceOf(()=>XF(buf3), TypeError);
-
-// test going to from various sizes
-function test(N1, N2) {
-    var buf1 = new ArrayBuffer(N1);
-    var i32 = new Int32Array(buf1);
-    for (var i = 0; i < i32.length; i++)
-        i32[i] = i;
-
-    var buf2 = XF(buf1, N2);
-
-    assertEq(buf1.byteLength, 0);
-    assertEq(i32.length, 0);
-    assertEq(buf2.byteLength, N2);
-    var i32 = new Int32Array(buf2);
-    for (var i = 0; i < Math.min(N1, N2)/4; i++)
-        assertEq(i32[i], i);
-    for (var i = Math.min(N1, N2)/4; i < i32.length; i++) {
-        assertEq(i32[i], 0);
-        i32[i] = -i;
-    }
-}
-test(0, 0);
-test(0, 4);
-test(4, 0);
-test(4, 4);
-test(0, 1000);
-test(4, 1000);
-test(1000, 0);
-test(1000, 4);
-test(1000, 1000);
-
-// asm.js:
-function testAsmJS(N1, N2) {
-    var buf1 = new ArrayBuffer(N1);
-    asmLink(asmCompile('stdlib', 'ffis', 'buf', USE_ASM + "var i32=new stdlib.Int32Array(buf); function f() {} return f"), this, null, buf1);
-    var i32 = new Int32Array(buf1);
-    for (var i = 0; i < i32.length; i+=100)
-        i32[i] = i;
-
-    var buf2 = XF(buf1, N2);
-
-    assertEq(buf1.byteLength, 0);
-    assertEq(i32.length, 0);
-    assertEq(buf2.byteLength, N2);
-    var i32 = new Int32Array(buf2);
-    var i = 0;
-    for (; i < Math.min(N1, N2)/4; i+=100)
-        assertEq(i32[i], i);
-    for (; i < i32.length; i+=100) {
-        assertEq(i32[i], 0);
-        i32[i] = -i;
-    }
-}
-testAsmJS(BUF_MIN, 0);
-testAsmJS(BUF_MIN, BUF_MIN);
-testAsmJS(BUF_MIN, 2*BUF_MIN);
-testAsmJS(2*BUF_MIN, BUF_MIN);
diff --git a/js/src/jsfun.h b/js/src/jsfun.h
index 82c4182749f5..979b728b8fc4 100644
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -699,13 +699,13 @@ class FunctionExtended : public JSFunction
      * All asm.js/wasm functions store their compiled module (either
      * WasmModuleObject or AsmJSModuleObject) in the first extended slot.
      */
-    static const unsigned ASM_MODULE_SLOT = 0;
+    static const unsigned WASM_MODULE_SLOT = 0;
 
     /*
      * wasm/asm.js exported functions store the index of the export in the
      * module's export vector in the second slot.
      */
-    static const unsigned ASM_EXPORT_INDEX_SLOT = 1;
+    static const unsigned WASM_EXPORT_INDEX_SLOT = 1;
 
     static inline size_t offsetOfExtendedSlot(unsigned which) {
         MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
diff --git a/js/src/tests/js1_8_5/extensions/clone-transferables.js b/js/src/tests/js1_8_5/extensions/clone-transferables.js
index 13657e5513d7..38cf84daee13 100644
--- a/js/src/tests/js1_8_5/extensions/clone-transferables.js
+++ b/js/src/tests/js1_8_5/extensions/clone-transferables.js
@@ -3,14 +3,10 @@
 // http://creativecommons.org/licenses/publicdomain/
 
 function test() {
-    // Note: -8 and -200 will trigger asm.js link failures because 8 and 200
-    // bytes are below the minimum allowed size, and the buffer will not
-    // actually be converted to an asm.js buffer.
     for (var size of [0, 8, 16, 200, 1000, 4096, -8, -200, -8192, -65536]) {
-        var buffer_ctor = (size < 0) ? AsmJSArrayBuffer : ArrayBuffer;
         size = Math.abs(size);
 
-        var old = new buffer_ctor(size);
+        var old = new ArrayBuffer(size);
         var copy = deserialize(serialize(old, [old]));
         assertEq(old.byteLength, 0);
         assertEq(copy.byteLength, size);
@@ -29,7 +25,7 @@ function test() {
         for (var ctor of constructors) {
             var dataview = (ctor === DataView);
 
-            var buf = new buffer_ctor(size);
+            var buf = new ArrayBuffer(size);
             var old_arr = new ctor(buf);
             assertEq(buf.byteLength, size);
             assertEq(buf, old_arr.buffer);
@@ -52,7 +48,7 @@ function test() {
         for (var ctor of constructors) {
             var dataview = (ctor === DataView);
 
-            var buf = new buffer_ctor(size);
+            var buf = new ArrayBuffer(size);
             var old_arr = new ctor(buf);
             var dv = new DataView(buf); // Second view
             var copy_arr = deserialize(serialize(old_arr, [ buf ]));
@@ -69,7 +65,7 @@ function test() {
 
         // Mutate the buffer during the clone operation. The modifications should be visible.
         if (size >= 4) {
-            old = new buffer_ctor(size);
+            old = new ArrayBuffer(size);
             var view = new Int32Array(old);
             view[0] = 1;
             var mutator = { get foo() { view[0] = 2; } };
@@ -81,7 +77,7 @@ function test() {
 
         // Neuter the buffer during the clone operation. Should throw an exception.
         if (size >= 4) {
-            old = new buffer_ctor(size);
+            old = new ArrayBuffer(size);
             var mutator = {
                 get foo() {
                     deserialize(serialize(old, [old]));
diff --git a/js/src/tests/js1_8_5/extensions/shell.js b/js/src/tests/js1_8_5/extensions/shell.js
index dff2e842f153..05e47cb78073 100644
--- a/js/src/tests/js1_8_5/extensions/shell.js
+++ b/js/src/tests/js1_8_5/extensions/shell.js
@@ -16,17 +16,3 @@ if (typeof version != 'undefined')
 {
   version(185);
 }
-
-
-// Note that AsmJS ArrayBuffers have a minimum size, currently 4096 bytes. If a
-// smaller size is given, a regular ArrayBuffer will be returned instead.
-function AsmJSArrayBuffer(size) {
-    var ab = new ArrayBuffer(size);
-    (new Function('global', 'foreign', 'buffer', '' +
-'        "use asm";' +
-'        var i32 = new global.Int32Array(buffer);' +
-'        function g() {};' +
-'        return g;' +
-''))(Function("return this")(),null,ab);
-    return ab;
-}
diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp
index 87b077e40cf2..69a266c2c957 100644
--- a/js/src/vm/ArrayBufferObject.cpp
+++ b/js/src/vm/ArrayBufferObject.cpp
@@ -130,9 +130,6 @@ const JSFunctionSpec ArrayBufferObject::jsfuncs[] = {
 
 const JSFunctionSpec ArrayBufferObject::jsstaticfuncs[] = {
     JS_FN("isView", ArrayBufferObject::fun_isView, 1, 0),
-#ifdef NIGHTLY_BUILD
-    JS_FN("transfer", ArrayBufferObject::fun_transfer, 2, 0),
-#endif
     JS_FS_END
 };
 
@@ -233,223 +230,6 @@ ArrayBufferObject::fun_isView(JSContext* cx, unsigned argc, Value* vp)
     return true;
 }
 
-#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
-static void
-ReleaseAsmJSMappedData(void* base)
-{
-    MOZ_ASSERT(uintptr_t(base) % AsmJSPageSize == 0);
-#  ifdef XP_WIN
-    VirtualFree(base, 0, MEM_RELEASE);
-#  else
-    munmap(base, AsmJSMappedSize);
-#   if defined(MOZ_VALGRIND) && defined(VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE)
-    // Tell Valgrind/Memcheck to recommence reporting accesses in the
-    // previously-inaccessible region.
-    if (AsmJSMappedSize > 0) {
-        VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(base, AsmJSMappedSize);
-    }
-#   endif
-#  endif
-    MemProfiler::RemoveNative(base);
-}
-#else
-static void
-ReleaseAsmJSMappedData(void* base)
-{
-    MOZ_CRASH("asm.js only uses mapped buffers when using signal-handler OOB checking");
-}
-#endif
-
-#ifdef NIGHTLY_BUILD
-# if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
-static bool
-TransferAsmJSMappedBuffer(JSContext* cx, const CallArgs& args,
-                          Handle oldBuffer, size_t newByteLength)
-{
-    size_t oldByteLength = oldBuffer->byteLength();
-    MOZ_ASSERT(oldByteLength % AsmJSPageSize == 0);
-    MOZ_ASSERT(newByteLength % AsmJSPageSize == 0);
-
-    ArrayBufferObject::BufferContents stolen =
-        ArrayBufferObject::stealContents(cx, oldBuffer, /* hasStealableContents = */ true);
-    if (!stolen)
-        return false;
-
-    MOZ_ASSERT(stolen.kind() == ArrayBufferObject::ASMJS_MAPPED);
-    uint8_t* data = stolen.data();
-
-    if (newByteLength > oldByteLength) {
-        void* diffStart = data + oldByteLength;
-        size_t diffLength = newByteLength - oldByteLength;
-#  ifdef XP_WIN
-        if (!VirtualAlloc(diffStart, diffLength, MEM_COMMIT, PAGE_READWRITE)) {
-            ReleaseAsmJSMappedData(data);
-            ReportOutOfMemory(cx);
-            return false;
-        }
-#  else
-        // To avoid memset, use MAP_FIXED to clobber the newly-accessible pages
-        // with zero pages.
-        int flags = MAP_FIXED | MAP_PRIVATE | MAP_ANON;
-        if (mmap(diffStart, diffLength, PROT_READ | PROT_WRITE, flags, -1, 0) == MAP_FAILED) {
-            ReleaseAsmJSMappedData(data);
-            ReportOutOfMemory(cx);
-            return false;
-        }
-#  endif
-        MemProfiler::SampleNative(diffStart, diffLength);
-    } else if (newByteLength < oldByteLength) {
-        void* diffStart = data + newByteLength;
-        size_t diffLength = oldByteLength - newByteLength;
-#  ifdef XP_WIN
-        if (!VirtualFree(diffStart, diffLength, MEM_DECOMMIT)) {
-            ReleaseAsmJSMappedData(data);
-            ReportOutOfMemory(cx);
-            return false;
-        }
-#  else
-        if (madvise(diffStart, diffLength, MADV_DONTNEED) ||
-            mprotect(diffStart, diffLength, PROT_NONE))
-        {
-            ReleaseAsmJSMappedData(data);
-            ReportOutOfMemory(cx);
-            return false;
-        }
-#  endif
-    }
-
-    ArrayBufferObject::BufferContents newContents =
-        ArrayBufferObject::BufferContents::create(data);
-
-    RootedObject newBuffer(cx, ArrayBufferObject::create(cx, newByteLength, newContents));
-    if (!newBuffer) {
-        ReleaseAsmJSMappedData(data);
-        return false;
-    }
-
-    args.rval().setObject(*newBuffer);
-    return true;
-}
-# endif  // defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
-
-/*
- * Experimental implementation of ArrayBuffer.transfer:
- *   https://gist.github.com/andhow/95fb9e49996615764eff
- * which is currently in the early stages of proposal for ES7.
- */
-bool
-ArrayBufferObject::fun_transfer(JSContext* cx, unsigned argc, Value* vp)
-{
-    CallArgs args = CallArgsFromVp(argc, vp);
-    HandleValue oldBufferArg = args.get(0);
-    HandleValue newByteLengthArg = args.get(1);
-
-    if (!oldBufferArg.isObject()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
-        return false;
-    }
-
-    RootedObject oldBufferObj(cx, &oldBufferArg.toObject());
-    ESClassValue cls;
-    if (!GetBuiltinClass(cx, oldBufferObj, &cls))
-        return false;
-    if (cls != ESClass_ArrayBuffer) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
-        return false;
-    }
-
-    // Beware: oldBuffer can point across compartment boundaries. ArrayBuffer
-    // contents are not compartment-specific so this is safe.
-    Rooted oldBuffer(cx);
-    if (oldBufferObj->is()) {
-        oldBuffer = &oldBufferObj->as();
-    } else {
-        JSObject* unwrapped = CheckedUnwrap(oldBufferObj);
-        if (!unwrapped || !unwrapped->is()) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
-            return false;
-        }
-        oldBuffer = &unwrapped->as();
-    }
-
-    size_t oldByteLength = oldBuffer->byteLength();
-    size_t newByteLength;
-    if (newByteLengthArg.isUndefined()) {
-        newByteLength = oldByteLength;
-    } else {
-        int32_t i32;
-        if (!ToInt32(cx, newByteLengthArg, &i32))
-            return false;
-        if (i32 < 0) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
-            return false;
-        }
-        newByteLength = size_t(i32);
-    }
-
-    if (oldBuffer->isNeutered()) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED);
-        return false;
-    }
-
-    UniquePtr newData;
-    if (!newByteLength) {
-        if (!ArrayBufferObject::neuter(cx, oldBuffer, oldBuffer->contents()))
-            return false;
-    } else {
-# if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
-        // With a 4gb mapped asm.js buffer, we can simply enable/disable access
-        // to the delta as long as the requested length is page-sized.
-        if (oldBuffer->isAsmJSMapped() && (newByteLength % AsmJSPageSize) == 0)
-            return TransferAsmJSMappedBuffer(cx, args, oldBuffer, newByteLength);
-# endif
-
-        // Since we try to realloc below, only allow stealing malloc'd buffers.
-        // If !hasMallocedContents, stealContents will malloc a copy which we
-        // can then realloc.
-        bool steal = oldBuffer->hasMallocedContents();
-        auto stolenContents = ArrayBufferObject::stealContents(cx, oldBuffer, steal);
-        if (!stolenContents)
-            return false;
-
-        UniquePtr oldData(stolenContents.data());
-        if (newByteLength > oldByteLength) {
-            // In theory, realloc+memset(0) can be optimized to avoid touching
-            // any pages (by using OS page mapping tricks). However, in
-            // practice, we don't seem to get this optimization in Firefox with
-            // jemalloc so calloc+memcpy are faster.
-            newData.reset(cx->runtime()->pod_callocCanGC(newByteLength));
-            if (newData) {
-                memcpy(newData.get(), oldData.get(), oldByteLength);
-            } else {
-                // Try malloc before giving up since it might be able to succed
-                // by resizing oldData in-place.
-                newData.reset(cx->pod_realloc(oldData.get(), oldByteLength, newByteLength));
-                if (!newData)
-                    return false;
-                oldData.release();
-                memset(newData.get() + oldByteLength, 0, newByteLength - oldByteLength);
-            }
-        } else if (newByteLength < oldByteLength) {
-            newData.reset(cx->pod_realloc(oldData.get(), oldByteLength, newByteLength));
-            if (!newData)
-                return false;
-            oldData.release();
-        } else {
-            newData = Move(oldData);
-        }
-    }
-
-    RootedObject newBuffer(cx, JS_NewArrayBufferWithContents(cx, newByteLength, newData.get()));
-    if (!newBuffer)
-        return false;
-    newData.release();
-
-    args.rval().setObject(*newBuffer);
-    return true;
-}
-#endif  // defined(NIGHTLY_BUILD)
-
 /*
  * new ArrayBuffer(byteLength)
  */
@@ -511,8 +291,10 @@ ArrayBufferObject::neuterView(JSContext* cx, ArrayBufferViewObject* view,
 ArrayBufferObject::neuter(JSContext* cx, Handle buffer,
                           BufferContents newContents)
 {
-    if (buffer->isAsmJS() && !OnDetachAsmJSArrayBuffer(cx, buffer))
+    if (buffer->isAsmJS()) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_OUT_OF_MEMORY);
         return false;
+    }
 
     // When neutering buffers where we don't know all views, the new data must
     // match the old data. All missing views are typed objects, which do not
@@ -742,6 +524,33 @@ ArrayBufferObject::dataPointerShared() const
     return SharedMem::unshared(getSlot(DATA_SLOT).toPrivate());
 }
 
+#if defined(ASMJS_MAY_USE_SIGNAL_HANDLERS_FOR_OOB)
+static void
+ReleaseAsmJSMappedData(void* base)
+{
+    MOZ_ASSERT(uintptr_t(base) % AsmJSPageSize == 0);
+#  ifdef XP_WIN
+    VirtualFree(base, 0, MEM_RELEASE);
+#  else
+    munmap(base, AsmJSMappedSize);
+#   if defined(MOZ_VALGRIND) && defined(VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE)
+    // Tell Valgrind/Memcheck to recommence reporting accesses in the
+    // previously-inaccessible region.
+    if (AsmJSMappedSize > 0) {
+        VALGRIND_ENABLE_ADDR_ERROR_REPORTING_IN_RANGE(base, AsmJSMappedSize);
+    }
+#   endif
+#  endif
+    MemProfiler::RemoveNative(base);
+}
+#else
+static void
+ReleaseAsmJSMappedData(void* base)
+{
+    MOZ_CRASH("asm.js only uses mapped buffers when using signal-handler OOB checking");
+}
+#endif
+
 void
 ArrayBufferObject::releaseData(FreeOp* fop)
 {
diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
index 87214f80b50a..78be8809414f 100644
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -202,7 +202,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
     destroyPrincipals(nullptr),
     readPrincipals(nullptr),
     errorReporter(nullptr),
-    linkedWasmModules(nullptr),
     propertyRemovals(0),
 #if !EXPOSE_INTL_API
     thousandsSeparator(0),
diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
index 9061201e9b7c..2334baba8795 100644
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -1190,9 +1190,6 @@ struct JSRuntime : public JS::shadow::Runtime,
     /* AsmJSCache callbacks are runtime-wide. */
     JS::AsmJSCacheOps   asmJSCacheOps;
 
-    /* Head of the linked list of linked wasm modules. */
-    js::wasm::Module*   linkedWasmModules;
-
     /*
      * The propertyRemovals counter is incremented for every JSObject::clear,
      * and for each JSObject::remove method call that frees a slot in the given

From 1a55f25e5b67fe012a36c3770c59774dfddb25a2 Mon Sep 17 00:00:00 2001
From: Timothy Nikkel 
Date: Wed, 30 Dec 2015 13:21:10 -0600
Subject: [PATCH 25/36] Bug 1235678. Fix printing animated geometry roots of
 display items. r=dholbert

---
 layout/base/nsLayoutDebugger.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/layout/base/nsLayoutDebugger.cpp b/layout/base/nsLayoutDebugger.cpp
index 75b70f26e577..73714df26d72 100644
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -190,7 +190,7 @@ PrintDisplayItemTo(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem,
           clip.ToString().get(),
           DisplayItemScrollClip::ToString(aItem->ScrollClip()).get(),
           aItem->IsUniform(aBuilder, &color) ? " uniform" : "",
-          aItem->ReferenceFrame(), aItem->GetAnimatedGeometryRoot());
+          aItem->ReferenceFrame(), aItem->GetAnimatedGeometryRoot()->mFrame);
 
   nsRegionRectIterator iter(opaque);
   for (const nsRect* r = iter.Next(); r; r = iter.Next()) {

From eddfe6b602a78666e206ce48ee32dc402ab9b643 Mon Sep 17 00:00:00 2001
From: Timothy Nikkel 
Date: Wed, 30 Dec 2015 13:21:10 -0600
Subject: [PATCH 26/36] Bug 1235467. If the root reference frame is transformed
 don't use an ancestor of the root reference frame as the local reference
 frame. r=mattwoodrow

When painting a -moz-element the root reference frame is the refered-to frame, so it can be transformed. In normal painting root reference frames are root frames which can't be transformed so this doesn't come up.
---
 layout/base/crashtests/1235467-1.html  | 8 ++++++++
 layout/base/crashtests/crashtests.list | 1 +
 layout/generic/nsFrame.cpp             | 7 +++++--
 3 files changed, 14 insertions(+), 2 deletions(-)
 create mode 100644 layout/base/crashtests/1235467-1.html

diff --git a/layout/base/crashtests/1235467-1.html b/layout/base/crashtests/1235467-1.html
new file mode 100644
index 000000000000..39a374b00377
--- /dev/null
+++ b/layout/base/crashtests/1235467-1.html
@@ -0,0 +1,8 @@
+
+
+
+
+
Q
+
+ + diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list index 2cfa45e3b521..11e317f3ea96 100644 --- a/layout/base/crashtests/crashtests.list +++ b/layout/base/crashtests/crashtests.list @@ -477,3 +477,4 @@ load 1140198.html pref(layout.css.grid.enabled,true) load 1156588.html load 1162813.xul load 1163583.html +load 1235467-1.html diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index c3ab2df210f2..887baa776e62 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -2249,8 +2249,11 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder, // Revert to the outer reference frame and offset because all display // items we create from now on are outside the transform. nsPoint toOuterReferenceFrame; - const nsIFrame* outerReferenceFrame = - aBuilder->FindReferenceFrameFor(GetParent(), &toOuterReferenceFrame); + const nsIFrame* outerReferenceFrame = this; + if (this != aBuilder->RootReferenceFrame()) { + outerReferenceFrame = + aBuilder->FindReferenceFrameFor(GetParent(), &toOuterReferenceFrame); + } buildingDisplayList.SetReferenceFrameAndCurrentOffset(outerReferenceFrame, GetOffsetToCrossDoc(outerReferenceFrame)); From d8552b26808ef6455d1e9cc88d69a4d6832f20ac Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 30 Dec 2015 13:50:56 -0600 Subject: [PATCH 27/36] Bug 1235874 - handle null filename in DescribeScriptedCaller (r=sunfish) --HG-- extra : commitid : 7o7x0q1IYrb --- js/src/jit-test/tests/basic/testBug1235874.js | 1 + js/src/jsapi.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 js/src/jit-test/tests/basic/testBug1235874.js diff --git a/js/src/jit-test/tests/basic/testBug1235874.js b/js/src/jit-test/tests/basic/testBug1235874.js new file mode 100644 index 000000000000..8e7841081482 --- /dev/null +++ b/js/src/jit-test/tests/basic/testBug1235874.js @@ -0,0 +1 @@ +evaluate('evalcx("1")', { fileName: null }); diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 0f771237d3a5..76f3a2d756aa 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5909,6 +5909,8 @@ JS_PUBLIC_API(bool) DescribeScriptedCaller(JSContext* cx, UniqueChars* filename, unsigned* lineno, unsigned* column) { + if (filename) + filename->reset(); if (lineno) *lineno = 0; if (column) @@ -5923,7 +5925,7 @@ DescribeScriptedCaller(JSContext* cx, UniqueChars* filename, unsigned* lineno, if (i.activation()->scriptedCallerIsHidden()) return false; - if (filename) { + if (filename && i.filename()) { UniqueChars copy = make_string_copy(i.filename()); if (!copy) return false; From 2066f6d7b3aea7f06d3f62223b247bfb59f3b7fa Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Wed, 30 Dec 2015 19:16:13 +0200 Subject: [PATCH 28/36] Bug 1120016 - Allocate short lived JS wrappers in the Nursery, r=mccr8,terrence --HG-- extra : rebase_source : 3d51b7fc9962a93eb6071328db84b5b327225246 --- dom/base/nsWrapperCache.cpp | 17 +++++- dom/base/nsWrapperCache.h | 21 +++---- dom/base/nsWrapperCacheInlines.h | 6 -- dom/bindings/Codegen.py | 2 + dom/bindings/parser/WebIDL.py | 14 ++++- dom/events/Event.cpp | 3 - dom/webidl/Event.webidl | 2 +- dom/webidl/MutationObserver.webidl | 1 + js/src/devtools/rootAnalysis/annotations.js | 5 +- js/src/gc/GCRuntime.h | 4 ++ js/src/gc/Marking.cpp | 2 + js/src/gc/Nursery.cpp | 5 ++ js/src/jsapi.cpp | 8 +++ js/src/jsapi.h | 7 +++ js/src/jsgc.cpp | 15 +++++ xpcom/base/CycleCollectedJSRuntime.cpp | 59 +++++++++++++++++++ xpcom/base/CycleCollectedJSRuntime.h | 14 +++++ xpcom/base/nsCycleCollector.cpp | 20 ++++--- xpcom/base/nsCycleCollectorTraceJSHelpers.cpp | 7 +++ xpcom/glue/nsCycleCollectionParticipant.h | 4 ++ 20 files changed, 183 insertions(+), 33 deletions(-) diff --git a/dom/base/nsWrapperCache.cpp b/dom/base/nsWrapperCache.cpp index 0b19e1a3630f..e1d88feaee10 100644 --- a/dom/base/nsWrapperCache.cpp +++ b/dom/base/nsWrapperCache.cpp @@ -9,6 +9,7 @@ #include "js/Class.h" #include "js/Proxy.h" #include "mozilla/dom/DOMJSProxyHandler.h" +#include "mozilla/CycleCollectedJSRuntime.h" #include "mozilla/HoldDropJSObjects.h" #include "nsCycleCollectionTraversalCallback.h" #include "nsCycleCollector.h" @@ -24,11 +25,25 @@ nsWrapperCache::HasJSObjectMovedOp(JSObject* aWrapper) } #endif -/* static */ void +void nsWrapperCache::HoldJSObjects(void* aScriptObjectHolder, nsScriptObjectTracer* aTracer) { cyclecollector::HoldJSObjectsImpl(aScriptObjectHolder, aTracer); + if (mWrapper && !JS::ObjectIsTenured(mWrapper)) { + CycleCollectedJSRuntime::Get()->NurseryWrapperPreserved(mWrapper); + } +} + +void +nsWrapperCache::SetWrapperJSObject(JSObject* aWrapper) +{ + mWrapper = aWrapper; + UnsetWrapperFlags(kWrapperFlagsMask & ~WRAPPER_IS_NOT_DOM_BINDING); + + if (aWrapper && !JS::ObjectIsTenured(aWrapper)) { + CycleCollectedJSRuntime::Get()->NurseryWrapperAdded(this); + } } void diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h index af645a66a8b4..0c8daaa35baa 100644 --- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -258,14 +258,15 @@ protected: void TraceWrapper(JSTracer* aTrc, const char* name) { if (mWrapper) { - JS_CallObjectTracer(aTrc, &mWrapper, name); + JS_CallUnbarrieredObjectTracer(aTrc, &mWrapper, name); } } void PoisonWrapper() { if (mWrapper) { - mWrapper.setToCrashOnTouch(); + // See setToCrashOnTouch() in RootingAPI.h + mWrapper = reinterpret_cast(1); } } @@ -287,13 +288,7 @@ private: return mWrapper; } - void SetWrapperJSObject(JSObject* aWrapper) - { - mWrapper = aWrapper; - UnsetWrapperFlags(kWrapperFlagsMask & ~WRAPPER_IS_NOT_DOM_BINDING); - } - - void TraceWrapperJSObject(JSTracer* aTrc, const char* aName); + void SetWrapperJSObject(JSObject* aWrapper); FlagsType GetWrapperFlags() const { @@ -318,8 +313,8 @@ private: mFlags &= ~aFlagsToUnset; } - static void HoldJSObjects(void* aScriptObjectHolder, - nsScriptObjectTracer* aTracer); + void HoldJSObjects(void* aScriptObjectHolder, + nsScriptObjectTracer* aTracer); #ifdef DEBUG public: @@ -349,8 +344,8 @@ private: enum { kWrapperFlagsMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_NOT_DOM_BINDING) }; - JS::Heap mWrapper; - FlagsType mFlags; + JSObject* mWrapper; + FlagsType mFlags; }; enum { WRAPPER_CACHE_FLAGS_BITS_USED = 2 }; diff --git a/dom/base/nsWrapperCacheInlines.h b/dom/base/nsWrapperCacheInlines.h index 6bba5350acf9..f91e5db591ea 100644 --- a/dom/base/nsWrapperCacheInlines.h +++ b/dom/base/nsWrapperCacheInlines.h @@ -53,10 +53,4 @@ nsWrapperCache::IsBlackAndDoesNotNeedTracing(nsISupports* aThis) return IsBlack() && HasNothingToTrace(aThis); } -inline void -nsWrapperCache::TraceWrapperJSObject(JSTracer* aTrc, const char* aName) -{ - JS_CallObjectTracer(aTrc, &mWrapper, aName); -} - #endif /* nsWrapperCache_h___ */ diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 66d66c9fb879..6dfe6825f270 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -422,6 +422,8 @@ class CGDOMJSClass(CGThing): classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount traceHook = 'nullptr' reservedSlots = slotCount + if self.descriptor.interface.isProbablyShortLivingObject(): + classFlags += " | JSCLASS_SKIP_NURSERY_FINALIZE" if self.descriptor.interface.getExtendedAttribute("NeedResolve"): resolveHook = RESOLVE_HOOK_NAME mayResolveHook = MAY_RESOLVE_HOOK_NAME diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index bee6af4d92cc..e664988d2c01 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -564,6 +564,9 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins): def isJSImplemented(self): return False + def isProbablyShortLivingObject(self): + return False + def getNavigatorProperty(self): return None @@ -1408,7 +1411,8 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): identifier == "ChromeOnly" or identifier == "Unforgeable" or identifier == "UnsafeInPrerendering" or - identifier == "LegacyEventInit"): + identifier == "LegacyEventInit" or + identifier == "ProbablyShortLivingObject"): # Known extended attributes that do not take values if not attr.noArguments(): raise WebIDLError("[%s] must take no arguments" % identifier, @@ -1522,6 +1526,14 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): def isJSImplemented(self): return bool(self.getJSImplementation()) + def isProbablyShortLivingObject(self): + current = self + while current: + if current.getExtendedAttribute("ProbablyShortLivingObject"): + return True + current = current.parent + return False + def getNavigatorProperty(self): naviProp = self.getExtendedAttribute("NavigatorProperty") if not naviProp: diff --git a/dom/events/Event.cpp b/dom/events/Event.cpp index 9d12b2fb4609..e600094e90c9 100644 --- a/dom/events/Event.cpp +++ b/dom/events/Event.cpp @@ -237,9 +237,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END JSObject* Event::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { - if (mIsMainThreadEvent && !GetWrapperPreserveColor()) { - nsJSContext::LikelyShortLivingObjectCreated(); - } return WrapObjectInternal(aCx, aGivenProto); } diff --git a/dom/webidl/Event.webidl b/dom/webidl/Event.webidl index 8e908db743e0..3b479c1f0920 100644 --- a/dom/webidl/Event.webidl +++ b/dom/webidl/Event.webidl @@ -11,7 +11,7 @@ */ [Constructor(DOMString type, optional EventInit eventInitDict), - Exposed=(Window,Worker,System)] + Exposed=(Window,Worker,System), ProbablyShortLivingObject] interface Event { [Pure] readonly attribute DOMString type; diff --git a/dom/webidl/MutationObserver.webidl b/dom/webidl/MutationObserver.webidl index ccb188b65e7e..a891205c2773 100644 --- a/dom/webidl/MutationObserver.webidl +++ b/dom/webidl/MutationObserver.webidl @@ -7,6 +7,7 @@ * http://dom.spec.whatwg.org */ +[ProbablyShortLivingObject] interface MutationRecord { [Constant] readonly attribute DOMString type; diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js index 860e06eacb52..911af6ff73ab 100644 --- a/js/src/devtools/rootAnalysis/annotations.js +++ b/js/src/devtools/rootAnalysis/annotations.js @@ -78,7 +78,8 @@ var ignoreCallees = { "z_stream_s.zfree" : true, "GrGLInterface.fCallback" : true, "std::strstreambuf._M_alloc_fun" : true, - "std::strstreambuf._M_free_fun" : true + "std::strstreambuf._M_free_fun" : true, + "struct js::gc::Callback.op" : true, }; function fieldCallCannotGC(csu, fullfield) @@ -187,6 +188,8 @@ var ignoreFunctions = { "void test::RingbufferDumper::OnTestPartResult(testing::TestPartResult*)" : true, "float64 JS_GetCurrentEmbedderTime()" : true, + + "uint64 js::TenuringTracer::moveObjectToTenured(JSObject*, JSObject*, int32)" : true, }; function isProtobuf(name) diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index d7cf559b9874..0ee6357a11c7 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -756,6 +756,9 @@ class GCRuntime void setGCCallback(JSGCCallback callback, void* data); void callGCCallback(JSGCStatus status) const; + void setObjectsTenuredCallback(JSObjectsTenuredCallback callback, + void* data); + void callObjectsTenuredCallback(); bool addFinalizeCallback(JSFinalizeCallback callback, void* data); void removeFinalizeCallback(JSFinalizeCallback func); bool addWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback, void* data); @@ -1273,6 +1276,7 @@ class GCRuntime bool fullCompartmentChecks; Callback gcCallback; + Callback tenuredCallback; CallbackVector finalizeCallbacks; CallbackVector updateWeakPointerZoneGroupCallbacks; CallbackVector updateWeakPointerCompartmentCallbacks; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 8df3c3c6d226..2627b12cc9ae 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2215,6 +2215,8 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind tenuredSize += UnboxedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind); } else if (src->is()) { tenuredSize += ArgumentsObject::objectMovedDuringMinorGC(this, dst, src); + } else if (JSObjectMovedOp op = dst->getClass()->ext.objectMovedOp) { + op(dst, src); } else { // Objects with JSCLASS_SKIP_NURSERY_FINALIZE need to be handled above // to ensure any additional nursery buffers they hold are moved. diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index a5bcb6b9696d..8d03adc05073 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -496,6 +496,10 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList forwardedBuffers.finish(); TIME_END(updateJitActivations); + TIME_START(objectsTenuredCallback); + rt->gc.callObjectsTenuredCallback(); + TIME_END(objectsTenuredCallback); + // Sweep. TIME_START(freeMallocedBuffers); freeMallocedBuffers(); @@ -576,6 +580,7 @@ js::Nursery::collect(JSRuntime* rt, JS::gcreason::Reason reason, ObjectGroupList {"mkDbgr", TIME_TOTAL(markDebugger)}, {"clrNOC", TIME_TOTAL(clearNewObjectCache)}, {"collct", TIME_TOTAL(collectToFP)}, + {" tenCB", TIME_TOTAL(objectsTenuredCallback)}, {"swpABO", TIME_TOTAL(sweepArrayBufferViewList)}, {"updtIn", TIME_TOTAL(updateJitActivations)}, {"frSlts", TIME_TOTAL(freeMallocedBuffers)}, diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 76f3a2d756aa..3d217e17485c 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1395,6 +1395,14 @@ JS_SetGCCallback(JSRuntime* rt, JSGCCallback cb, void* data) rt->gc.setGCCallback(cb, data); } +JS_PUBLIC_API(void) +JS_SetObjectsTenuredCallback(JSRuntime* rt, JSObjectsTenuredCallback cb, + void* data) +{ + AssertHeapIsIdle(rt); + rt->gc.setObjectsTenuredCallback(cb, data); +} + JS_PUBLIC_API(bool) JS_AddFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb, void* data) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 2ac2e606440a..b8a8b04641b2 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -572,6 +572,9 @@ typedef enum JSGCStatus { typedef void (* JSGCCallback)(JSRuntime* rt, JSGCStatus status, void* data); +typedef void +(* JSObjectsTenuredCallback)(JSRuntime* rt, void* data); + typedef enum JSFinalizeStatus { /** * Called when preparing to sweep a group of compartments, before anything @@ -1654,6 +1657,10 @@ JS_MaybeGC(JSContext* cx); extern JS_PUBLIC_API(void) JS_SetGCCallback(JSRuntime* rt, JSGCCallback cb, void* data); +extern JS_PUBLIC_API(void) +JS_SetObjectsTenuredCallback(JSRuntime* rt, JSObjectsTenuredCallback cb, + void* data); + extern JS_PUBLIC_API(bool) JS_AddFinalizeCallback(JSRuntime* rt, JSFinalizeCallback cb, void* data); diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index e66ee1e717a4..c1568822c39d 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1606,6 +1606,21 @@ GCRuntime::callGCCallback(JSGCStatus status) const gcCallback.op(rt, status, gcCallback.data); } +void +GCRuntime::setObjectsTenuredCallback(JSObjectsTenuredCallback callback, + void* data) +{ + tenuredCallback.op = callback; + tenuredCallback.data = data; +} + +void +GCRuntime::callObjectsTenuredCallback() +{ + if (tenuredCallback.op) + tenuredCallback.op(rt, tenuredCallback.data); +} + namespace { class AutoNotifyGCActivity { diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 8e92c4278ba7..d7da4ff126e0 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -73,6 +73,7 @@ #include "nsCycleCollector.h" #include "nsDOMJSUtils.h" #include "nsJSUtils.h" +#include "nsWrapperCache.h" #ifdef MOZ_CRASHREPORTER #include "nsExceptionHandler.h" @@ -397,6 +398,12 @@ NoteJSChildGrayWrapperShim(void* aData, JS::GCCellPtr aThing) // CycleCollectedJSRuntime. It should never be used directly. static const JSZoneParticipant sJSZoneCycleCollectorGlobal; +static +void JSObjectsTenuredCb(JSRuntime* aRuntime, void* aData) +{ + static_cast(aData)->JSObjectsTenured(aRuntime); +} + CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSRuntime* aParentRuntime, uint32_t aMaxBytes, uint32_t aMaxNurseryBytes) @@ -430,6 +437,7 @@ CycleCollectedJSRuntime::CycleCollectedJSRuntime(JSRuntime* aParentRuntime, JS_SetGrayGCRootsTracer(mJSRuntime, TraceGrayJS, this); JS_SetGCCallback(mJSRuntime, GCCallback, this); mPrevGCSliceCallback = JS::SetGCSliceCallback(mJSRuntime, GCSliceCallback); + JS_SetObjectsTenuredCallback(mJSRuntime, JSObjectsTenuredCb, this); JS::SetOutOfMemoryCallback(mJSRuntime, OutOfMemoryCallback, this); JS::SetLargeAllocationFailureCallback(mJSRuntime, LargeAllocationFailureCallback, this); @@ -785,6 +793,11 @@ struct JsGcTracer : public TraceCallbacks { JS_CallObjectTracer(static_cast(aClosure), aPtr, aName); } + virtual void Trace(JSObject** aPtr, const char* aName, + void* aClosure) const override + { + JS_CallUnbarrieredObjectTracer(static_cast(aClosure), aPtr, aName); + } virtual void Trace(JS::TenuredHeap* aPtr, const char* aName, void* aClosure) const override { @@ -852,6 +865,12 @@ struct ClearJSHolder : TraceCallbacks *aPtr = nullptr; } + virtual void Trace(JSObject** aPtr, const char* aName, + void* aClosure) const override + { + *aPtr = nullptr; + } + virtual void Trace(JS::TenuredHeap* aPtr, const char*, void*) const override { *aPtr = nullptr; @@ -1008,6 +1027,46 @@ CycleCollectedJSRuntime::GarbageCollect(uint32_t aReason) const JS::GCForReason(mJSRuntime, GC_NORMAL, gcreason); } +void +CycleCollectedJSRuntime::JSObjectsTenured(JSRuntime* aRuntime) +{ + for (auto iter = mNurseryObjects.Iter(); !iter.Done(); iter.Next()) { + nsWrapperCache* cache = iter.Get(); + JSObject* wrapper = cache->GetWrapperPreserveColor(); + MOZ_ASSERT(wrapper); + if (!JS::ObjectIsTenured(wrapper)) { + MOZ_ASSERT(!cache->PreservingWrapper()); + const JSClass* jsClass = js::GetObjectJSClass(wrapper); + jsClass->finalize(nullptr, wrapper); + } + } + +#ifdef DEBUG +for (auto iter = mPreservedNurseryObjects.Iter(); !iter.Done(); iter.Next()) { + MOZ_ASSERT(JS::ObjectIsTenured(iter.Get().get())); +} +#endif + + mNurseryObjects.Clear(); + mPreservedNurseryObjects.Clear(); +} + +void +CycleCollectedJSRuntime::NurseryWrapperAdded(nsWrapperCache* aCache) +{ + MOZ_ASSERT(aCache); + MOZ_ASSERT(aCache->GetWrapperPreserveColor()); + MOZ_ASSERT(!JS::ObjectIsTenured(aCache->GetWrapperPreserveColor())); + mNurseryObjects.InfallibleAppend(aCache); +} + +void +CycleCollectedJSRuntime::NurseryWrapperPreserved(JSObject* aWrapper) +{ + mPreservedNurseryObjects.InfallibleAppend( + JS::PersistentRooted(mJSRuntime, aWrapper)); +} + void CycleCollectedJSRuntime::DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc, DeferredFinalizeFunction aFunc, diff --git a/xpcom/base/CycleCollectedJSRuntime.h b/xpcom/base/CycleCollectedJSRuntime.h index 53875db9085d..e9d83bd9363b 100644 --- a/xpcom/base/CycleCollectedJSRuntime.h +++ b/xpcom/base/CycleCollectedJSRuntime.h @@ -10,7 +10,9 @@ #include #include "mozilla/DeferredFinalize.h" +#include "mozilla/mozalloc.h" #include "mozilla/MemoryReporting.h" +#include "mozilla/SegmentedVector.h" #include "jsapi.h" #include "nsCycleCollectionParticipant.h" @@ -22,6 +24,7 @@ class nsCycleCollectionNoteRootCallback; class nsIException; class nsIRunnable; class nsThread; +class nsWrapperCache; namespace js { struct Class; @@ -280,6 +283,10 @@ public: bool AreGCGrayBitsValid() const; void GarbageCollect(uint32_t aReason) const; + void NurseryWrapperAdded(nsWrapperCache* aCache); + void NurseryWrapperPreserved(JSObject* aWrapper); + void JSObjectsTenured(JSRuntime* aRuntime); + void DeferredFinalize(DeferredFinalizeAppendFunction aAppendFunc, DeferredFinalizeFunction aFunc, void* aThing); @@ -361,6 +368,13 @@ private: OOMState mOutOfMemoryState; OOMState mLargeAllocationFailureState; + + static const size_t kSegmentSize = 512; + SegmentedVector + mNurseryObjects; + SegmentedVector, kSegmentSize, + InfallibleAllocPolicy> + mPreservedNurseryObjects; }; void TraceScriptHolder(nsISupports* aHolder, JSTracer* aTracer); diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index a046f6ea705d..cc92b560278a 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -2677,7 +2677,7 @@ public: } virtual void Trace(JS::Heap* aValue, const char* aName, - void* aClosure) const + void* aClosure) const override { if (aValue->isMarkable() && ValueIsGrayCCThing(*aValue)) { MOZ_ASSERT(!js::gc::IsInsideNursery(aValue->toGCThing())); @@ -2686,7 +2686,7 @@ public: } virtual void Trace(JS::Heap* aId, const char* aName, - void* aClosure) const + void* aClosure) const override { } @@ -2699,29 +2699,35 @@ public: } virtual void Trace(JS::Heap* aObject, const char* aName, - void* aClosure) const + void* aClosure) const override + { + AppendJSObjectToPurpleBuffer(*aObject); + } + + virtual void Trace(JSObject** aObject, const char* aName, + void* aClosure) const override { AppendJSObjectToPurpleBuffer(*aObject); } virtual void Trace(JS::TenuredHeap* aObject, const char* aName, - void* aClosure) const + void* aClosure) const override { AppendJSObjectToPurpleBuffer(*aObject); } virtual void Trace(JS::Heap* aString, const char* aName, - void* aClosure) const + void* aClosure) const override { } virtual void Trace(JS::Heap* aScript, const char* aName, - void* aClosure) const + void* aClosure) const override { } virtual void Trace(JS::Heap* aFunction, const char* aName, - void* aClosure) const + void* aClosure) const override { } diff --git a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp index 7687be0ccebd..0e4e5d876a4f 100644 --- a/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp +++ b/xpcom/base/nsCycleCollectorTraceJSHelpers.cpp @@ -61,6 +61,13 @@ TraceCallbackFunc::Trace(JS::Heap* aPtr, const char* aName, mCallback(JS::GCCellPtr(aPtr->get()), aName, aClosure); } +void +TraceCallbackFunc::Trace(JSObject** aPtr, const char* aName, + void* aClosure) const +{ + mCallback(JS::GCCellPtr(*aPtr), aName, aClosure); +} + void TraceCallbackFunc::Trace(JS::TenuredHeap* aPtr, const char* aName, void* aClosure) const diff --git a/xpcom/glue/nsCycleCollectionParticipant.h b/xpcom/glue/nsCycleCollectionParticipant.h index 5db54b3adc8b..fd114b76f018 100644 --- a/xpcom/glue/nsCycleCollectionParticipant.h +++ b/xpcom/glue/nsCycleCollectionParticipant.h @@ -64,6 +64,8 @@ struct TraceCallbacks void* aClosure) const = 0; virtual void Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const = 0; + virtual void Trace(JSObject** aPtr, const char* aName, + void* aClosure) const = 0; virtual void Trace(JS::TenuredHeap* aPtr, const char* aName, void* aClosure) const = 0; virtual void Trace(JS::Heap* aPtr, const char* aName, @@ -90,6 +92,8 @@ struct TraceCallbackFunc : public TraceCallbacks void* aClosure) const override; virtual void Trace(JS::Heap* aPtr, const char* aName, void* aClosure) const override; + virtual void Trace(JSObject** aPtr, const char* aName, + void* aClosure) const override; virtual void Trace(JS::TenuredHeap* aPtr, const char* aName, void* aClosure) const override; virtual void Trace(JS::Heap* aPtr, const char* aName, From e7bc0ea9a2feaf6f124b9884ea4f09cbc170a6fe Mon Sep 17 00:00:00 2001 From: Robert Longson Date: Wed, 30 Dec 2015 20:19:33 +0000 Subject: [PATCH 29/36] Bug 1156581 - Add null check to nsSVGEffects::InvalidateRenderingObservers to prevent crashes r=dholbert --- layout/svg/crashtests/1156581-1.svg | 12 ++++++++++++ layout/svg/crashtests/crashtests.list | 1 + layout/svg/nsSVGEffects.cpp | 10 ++++++---- 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 layout/svg/crashtests/1156581-1.svg diff --git a/layout/svg/crashtests/1156581-1.svg b/layout/svg/crashtests/1156581-1.svg new file mode 100644 index 000000000000..97e5fb1ca91b --- /dev/null +++ b/layout/svg/crashtests/1156581-1.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/layout/svg/crashtests/crashtests.list b/layout/svg/crashtests/crashtests.list index 115315abbcbe..ba3820dc1eaf 100644 --- a/layout/svg/crashtests/crashtests.list +++ b/layout/svg/crashtests/crashtests.list @@ -192,6 +192,7 @@ load 1016145.svg load 1028512.svg load 1140080-1.svg load 1149542-1.svg +load 1156581-1.svg load 1182496-1.html load 1209525-1.svg load 1223281-1.svg diff --git a/layout/svg/nsSVGEffects.cpp b/layout/svg/nsSVGEffects.cpp index 1e9418d603a0..5e29229b4f08 100644 --- a/layout/svg/nsSVGEffects.cpp +++ b/layout/svg/nsSVGEffects.cpp @@ -770,14 +770,15 @@ nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame) { NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation"); - if (!aFrame->GetContent()->IsElement()) + nsIContent* content = aFrame->GetContent(); + if (!content || !content->IsElement()) return; // If the rendering has changed, the bounds may well have changed too: aFrame->Properties().Delete(nsSVGUtils::ObjectBoundingBoxProperty()); nsSVGRenderingObserverList *observerList = - GetObserverList(aFrame->GetContent()->AsElement()); + GetObserverList(content->AsElement()); if (observerList) { observerList->InvalidateAll(); return; @@ -821,7 +822,8 @@ nsSVGEffects::InvalidateDirectRenderingObservers(Element *aElement, uint32_t aFl void nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame, uint32_t aFlags /* = 0 */) { - if (aFrame->GetContent() && aFrame->GetContent()->IsElement()) { - InvalidateDirectRenderingObservers(aFrame->GetContent()->AsElement(), aFlags); + nsIContent* content = aFrame->GetContent(); + if (content && content->IsElement()) { + InvalidateDirectRenderingObservers(content->AsElement(), aFlags); } } From 49400588df589615365e92783c8f5eeef00c3a1f Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Wed, 30 Dec 2015 11:51:26 +0000 Subject: [PATCH 30/36] Bug 739117 - Reftest for Arabic ligature in an AAT font. r=jdaggett --- layout/reftests/svg/svg-integration/reftest.list | 4 ++-- .../reftests/text/arabic-final-ligature-spacing-ref.html | 6 ++++++ layout/reftests/text/arabic-final-ligature-spacing.html | 9 +++++++++ layout/reftests/text/reftest.list | 1 + 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 layout/reftests/text/arabic-final-ligature-spacing-ref.html create mode 100644 layout/reftests/text/arabic-final-ligature-spacing.html diff --git a/layout/reftests/svg/svg-integration/reftest.list b/layout/reftests/svg/svg-integration/reftest.list index 338c0ca340c5..0bb152a8d063 100644 --- a/layout/reftests/svg/svg-integration/reftest.list +++ b/layout/reftests/svg/svg-integration/reftest.list @@ -8,8 +8,8 @@ == clipPath-html-04-extref.xhtml clipPath-html-04-ref.xhtml fuzzy-if(true,140,70) == clipPath-html-05.xhtml clipPath-html-05-ref.xhtml # Bug 776089 fuzzy-if(true,140,70) == clipPath-html-05-extref.xhtml clipPath-html-05-ref.xhtml # Bug 776089 -fuzzy-if(Android&&AndroidVersion==18,255,30) == clipPath-html-06.xhtml clipPath-html-06-ref.xhtml -fuzzy-if(Android&&AndroidVersion==18,255,30) == clipPath-html-06-extref.xhtml clipPath-html-06-ref.xhtml +fuzzy-if(Android,255,30) == clipPath-html-06.xhtml clipPath-html-06-ref.xhtml +fuzzy-if(Android,255,30) == clipPath-html-06-extref.xhtml clipPath-html-06-ref.xhtml == clipPath-html-07.xhtml clipPath-html-07-ref.svg == clipPath-html-08.xhtml clipPath-html-07-ref.svg # reuse 07-ref.svg == clipPath-html-zoomed-01.xhtml clipPath-html-01-ref.svg diff --git a/layout/reftests/text/arabic-final-ligature-spacing-ref.html b/layout/reftests/text/arabic-final-ligature-spacing-ref.html new file mode 100644 index 000000000000..5f25cbbe9242 --- /dev/null +++ b/layout/reftests/text/arabic-final-ligature-spacing-ref.html @@ -0,0 +1,6 @@ + + + +

سلام

diff --git a/layout/reftests/text/arabic-final-ligature-spacing.html b/layout/reftests/text/arabic-final-ligature-spacing.html new file mode 100644 index 000000000000..f1019ba9bf5c --- /dev/null +++ b/layout/reftests/text/arabic-final-ligature-spacing.html @@ -0,0 +1,9 @@ + + + + +

سلام

diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list index 7e2c4c5a63ff..ebea62a70f1d 100644 --- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -165,6 +165,7 @@ fails-if(cocoaWidget||Android||B2G) HTTP(..) == arabic-fallback-2.html arabic-fa fails-if(cocoaWidget||Android||B2G) HTTP(..) == arabic-fallback-3.html arabic-fallback-3-ref.html fails-if(!cocoaWidget&&!Android&&!B2G) HTTP(..) != arabic-fallback-4.html arabic-fallback-4-notref.html == arabic-marks-1.html arabic-marks-1-ref.html +fails-if(cocoaWidget) == arabic-final-ligature-spacing.html arabic-final-ligature-spacing-ref.html # bug 739117 # harfbuzz fallback mark stacking in the absence of GPOS: HTTP(..) != fallback-mark-stacking-1.html fallback-mark-stacking-1-notref.html From 9137c3ddf5d3cbd542c8b3b8d2084028543d7ebe Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Wed, 30 Dec 2015 20:29:48 +0000 Subject: [PATCH 31/36] Bug 739117 - Avoid bidi-wrapping the text to be shaped if Core Text direction override API is available. r=jdaggett --- gfx/thebes/gfxCoreTextShaper.cpp | 218 +++++++++++++++++++++--------- gfx/thebes/gfxCoreTextShaper.h | 8 +- layout/reftests/text/reftest.list | 2 +- 3 files changed, 161 insertions(+), 67 deletions(-) diff --git a/gfx/thebes/gfxCoreTextShaper.cpp b/gfx/thebes/gfxCoreTextShaper.cpp index 69f84f428cd6..cb1575e6cc83 100644 --- a/gfx/thebes/gfxCoreTextShaper.cpp +++ b/gfx/thebes/gfxCoreTextShaper.cpp @@ -13,6 +13,8 @@ #include +#include + using namespace mozilla; // standard font descriptors that we construct the first time they're needed @@ -21,28 +23,85 @@ CTFontDescriptorRef gfxCoreTextShaper::sDisableLigaturesDescriptor = nullptr; CTFontDescriptorRef gfxCoreTextShaper::sIndicFeaturesDescriptor = nullptr; CTFontDescriptorRef gfxCoreTextShaper::sIndicDisableLigaturesDescriptor = nullptr; +static CFStringRef sCTWritingDirectionAttributeName = nullptr; + +// See CTStringAttributes.h +enum { + kMyCTWritingDirectionEmbedding = (0 << 1), + kMyCTWritingDirectionOverride = (1 << 1) +}; + +// Helper to create a CFDictionary with the right attributes for shaping our +// text, including imposing the given directionality. +// This will only be called if we're on 10.8 or later. +CFDictionaryRef +gfxCoreTextShaper::CreateAttrDict(bool aRightToLeft) +{ + // Because we always shape unidirectional runs, and may have applied + // directional overrides, we want to force a direction rather than + // allowing CoreText to do its own unicode-based bidi processing. + SInt16 dirOverride = kMyCTWritingDirectionOverride | + (aRightToLeft ? kCTWritingDirectionRightToLeft + : kCTWritingDirectionLeftToRight); + CFNumberRef dirNumber = + ::CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt16Type, &dirOverride); + CFArrayRef dirArray = + ::CFArrayCreate(kCFAllocatorDefault, + (const void **) &dirNumber, 1, + &kCFTypeArrayCallBacks); + ::CFRelease(dirNumber); + CFTypeRef attrs[] = { kCTFontAttributeName, sCTWritingDirectionAttributeName }; + CFTypeRef values[] = { mCTFont, dirArray }; + CFDictionaryRef attrDict = + ::CFDictionaryCreate(kCFAllocatorDefault, + attrs, values, ArrayLength(attrs), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + ::CFRelease(dirArray); + return attrDict; +} + +CFDictionaryRef +gfxCoreTextShaper::CreateAttrDictWithoutDirection() +{ + CFTypeRef attrs[] = { kCTFontAttributeName }; + CFTypeRef values[] = { mCTFont }; + CFDictionaryRef attrDict = + ::CFDictionaryCreate(kCFAllocatorDefault, + attrs, values, ArrayLength(attrs), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + return attrDict; +} + gfxCoreTextShaper::gfxCoreTextShaper(gfxMacFont *aFont) : gfxFontShaper(aFont) + , mAttributesDictLTR(nullptr) + , mAttributesDictRTL(nullptr) { + static bool sInitialized = false; + if (!sInitialized) { + CFStringRef* pstr = (CFStringRef*) + dlsym(RTLD_DEFAULT, "kCTWritingDirectionAttributeName"); + if (pstr) { + sCTWritingDirectionAttributeName = *pstr; + } + sInitialized = true; + } + // Create our CTFontRef mCTFont = CreateCTFontWithFeatures(aFont->GetAdjustedSize(), GetDefaultFeaturesDescriptor()); - - // Set up the default attribute dictionary that we will need each time we - // create a CFAttributedString (unless we need to use custom features, - // in which case a new dictionary will be created on the fly). - mAttributesDict = ::CFDictionaryCreate(kCFAllocatorDefault, - (const void**) &kCTFontAttributeName, - (const void**) &mCTFont, - 1, // count of attributes - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); } gfxCoreTextShaper::~gfxCoreTextShaper() { - if (mAttributesDict) { - ::CFRelease(mAttributesDict); + if (mAttributesDictLTR) { + ::CFRelease(mAttributesDictLTR); + } + if (mAttributesDictRTL) { + ::CFRelease(mAttributesDictRTL); } if (mCTFont) { ::CFRelease(mCTFont); @@ -65,54 +124,81 @@ gfxCoreTextShaper::ShapeText(gfxContext *aContext, gfxShapedText *aShapedText) { // Create a CFAttributedString with text and style info, so we can use CoreText to lay it out. - bool isRightToLeft = aShapedText->IsRightToLeft(); + const UniChar* text = reinterpret_cast(aText); uint32_t length = aLength; - // we need to bidi-wrap the text if the run is RTL, - // or if it is an LTR run but may contain (overridden) RTL chars - bool bidiWrap = isRightToLeft; - if (!bidiWrap && !aShapedText->TextIs8Bit()) { - uint32_t i; - for (i = 0; i < length; ++i) { - if (gfxFontUtils::PotentialRTLChar(aText[i])) { - bidiWrap = true; - break; - } - } - } - - // If there's a possibility of any bidi, we wrap the text with direction overrides - // to ensure neutrals or characters that were bidi-overridden in HTML behave properly. - const UniChar beginLTR[] = { 0x202d, 0x20 }; - const UniChar beginRTL[] = { 0x202e, 0x20 }; - const UniChar endBidiWrap[] = { 0x20, 0x2e, 0x202c }; - uint32_t startOffset; CFStringRef stringObj; - if (bidiWrap) { - startOffset = isRightToLeft ? - mozilla::ArrayLength(beginRTL) : mozilla::ArrayLength(beginLTR); - CFMutableStringRef mutableString = - ::CFStringCreateMutable(kCFAllocatorDefault, - length + startOffset + mozilla::ArrayLength(endBidiWrap)); - ::CFStringAppendCharacters(mutableString, - isRightToLeft ? beginRTL : beginLTR, - startOffset); - ::CFStringAppendCharacters(mutableString, reinterpret_cast(aText), length); - ::CFStringAppendCharacters(mutableString, - endBidiWrap, mozilla::ArrayLength(endBidiWrap)); - stringObj = mutableString; - } else { + CFDictionaryRef attrObj; + + if (sCTWritingDirectionAttributeName) { startOffset = 0; stringObj = ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, - reinterpret_cast(aText), - length, kCFAllocatorNull); + text, length, + kCFAllocatorNull); + + // Get an attributes dictionary suitable for shaping text in the + // current direction, creating it if necessary. + attrObj = isRightToLeft ? mAttributesDictRTL : mAttributesDictLTR; + if (!attrObj) { + attrObj = CreateAttrDict(isRightToLeft); + (isRightToLeft ? mAttributesDictRTL : mAttributesDictLTR) = attrObj; + } + } else { + // OS is too old to support kCTWritingDirectionAttributeName: + // we need to bidi-wrap the text if the run is RTL, + // or if it is an LTR run but may contain (overridden) RTL chars + bool bidiWrap = isRightToLeft; + if (!bidiWrap && !aShapedText->TextIs8Bit()) { + uint32_t i; + for (i = 0; i < length; ++i) { + if (gfxFontUtils::PotentialRTLChar(aText[i])) { + bidiWrap = true; + break; + } + } + } + + // If there's a possibility of any bidi, we wrap the text with + // direction overrides to ensure neutrals or characters that were + // bidi-overridden in HTML behave properly. + static const UniChar beginLTR[] = { 0x202d, 0x20 }; + static const UniChar beginRTL[] = { 0x202e, 0x20 }; + static const UniChar endBidiWrap[] = { 0x20, 0x2e, 0x202c }; + + if (bidiWrap) { + startOffset = isRightToLeft ? ArrayLength(beginRTL) + : ArrayLength(beginLTR); + CFMutableStringRef mutableString = + ::CFStringCreateMutable(kCFAllocatorDefault, + length + startOffset + + ArrayLength(endBidiWrap)); + ::CFStringAppendCharacters(mutableString, + isRightToLeft ? beginRTL : beginLTR, + startOffset); + ::CFStringAppendCharacters(mutableString, text, length); + ::CFStringAppendCharacters(mutableString, endBidiWrap, + ArrayLength(endBidiWrap)); + stringObj = mutableString; + } else { + startOffset = 0; + stringObj = + ::CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, + text, length, + kCFAllocatorNull); + } + + // Get an attributes dictionary suitable for shaping text, + // creating it if necessary. (This dict is not LTR-specific, + // but we use that field to store it anyway.) + if (!mAttributesDictLTR) { + mAttributesDictLTR = CreateAttrDictWithoutDirection(); + } + attrObj = mAttributesDictLTR; } - CFDictionaryRef attrObj; CTFontRef tempCTFont = nullptr; - if (IsBuggyIndicScript(aScript)) { // To work around buggy Indic AAT fonts shipped with OS X, // we re-enable the Line Initial Smart Swashes feature that is needed @@ -132,21 +218,18 @@ gfxCoreTextShaper::ShapeText(gfxContext *aContext, GetDisableLigaturesDescriptor()); } + // For the disabled-ligature or buggy-indic-font case, we need to replace + // the standard CTFont in the attribute dictionary with a tweaked version. + CFMutableDictionaryRef mutableAttr = nullptr; if (tempCTFont) { - attrObj = - ::CFDictionaryCreate(kCFAllocatorDefault, - (const void**) &kCTFontAttributeName, - (const void**) &tempCTFont, - 1, // count of attributes - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + mutableAttr = ::CFDictionaryCreateMutableCopy(kCFAllocatorDefault, 2, + attrObj); + ::CFDictionaryReplaceValue(mutableAttr, + kCTFontAttributeName, tempCTFont); // Having created the dict, we're finished with our temporary // Indic and/or ligature-disabled CTFontRef. ::CFRelease(tempCTFont); - } else { - // The default case is to use our preallocated attr dict - attrObj = mAttributesDict; - ::CFRetain(attrObj); + attrObj = mutableAttr; } // Now we can create an attributed string @@ -180,8 +263,10 @@ gfxCoreTextShaper::ShapeText(gfxContext *aContext, // If Core Text manufactured a new dictionary, this may indicate // unexpected font substitution. In that case, we fail (and fall // back to harfbuzz shaping)... - const void* font1 = ::CFDictionaryGetValue(attrObj, kCTFontAttributeName); - const void* font2 = ::CFDictionaryGetValue(runAttr, kCTFontAttributeName); + const void* font1 = + ::CFDictionaryGetValue(attrObj, kCTFontAttributeName); + const void* font2 = + ::CFDictionaryGetValue(runAttr, kCTFontAttributeName); if (font1 != font2) { // ...except that if the fallback was only for a variation // selector or join control that is otherwise unsupported, @@ -198,13 +283,16 @@ gfxCoreTextShaper::ShapeText(gfxContext *aContext, break; } } - if (SetGlyphsFromRun(aShapedText, aOffset, aLength, aCTRun, startOffset) != NS_OK) { + if (SetGlyphsFromRun(aShapedText, aOffset, aLength, aCTRun, + startOffset) != NS_OK) { success = false; break; } } - ::CFRelease(attrObj); + if (mutableAttr) { + ::CFRelease(mutableAttr); + } ::CFRelease(line); return success; diff --git a/gfx/thebes/gfxCoreTextShaper.h b/gfx/thebes/gfxCoreTextShaper.h index 0bef3fb651ed..0cded07e5af8 100644 --- a/gfx/thebes/gfxCoreTextShaper.h +++ b/gfx/thebes/gfxCoreTextShaper.h @@ -31,7 +31,10 @@ public: protected: CTFontRef mCTFont; - CFDictionaryRef mAttributesDict; + + // attributes for shaping text with LTR or RTL directionality + CFDictionaryRef mAttributesDictLTR; + CFDictionaryRef mAttributesDictRTL; nsresult SetGlyphsFromRun(gfxShapedText *aShapedText, uint32_t aOffset, @@ -42,6 +45,9 @@ protected: CTFontRef CreateCTFontWithFeatures(CGFloat aSize, CTFontDescriptorRef aDescriptor); + CFDictionaryRef CreateAttrDict(bool aRightToLeft); + CFDictionaryRef CreateAttrDictWithoutDirection(); + static CTFontDescriptorRef CreateFontFeaturesDescriptor(const std::pair aFeatures[], size_t aCount); diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list index ebea62a70f1d..f1a55ad6527d 100644 --- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -165,7 +165,7 @@ fails-if(cocoaWidget||Android||B2G) HTTP(..) == arabic-fallback-2.html arabic-fa fails-if(cocoaWidget||Android||B2G) HTTP(..) == arabic-fallback-3.html arabic-fallback-3-ref.html fails-if(!cocoaWidget&&!Android&&!B2G) HTTP(..) != arabic-fallback-4.html arabic-fallback-4-notref.html == arabic-marks-1.html arabic-marks-1-ref.html -fails-if(cocoaWidget) == arabic-final-ligature-spacing.html arabic-final-ligature-spacing-ref.html # bug 739117 +fails-if(OSX<1008) == arabic-final-ligature-spacing.html arabic-final-ligature-spacing-ref.html # harfbuzz fallback mark stacking in the absence of GPOS: HTTP(..) != fallback-mark-stacking-1.html fallback-mark-stacking-1-notref.html From 04de56a8e6c9afd91ea041c67740274d12e26ee2 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Wed, 30 Dec 2015 22:15:03 +0100 Subject: [PATCH 32/36] Bug 1235868 - Change nonWritableJITCode to ifdefs. r=jandem --- js/src/jit/ExecutableAllocator.cpp | 12 ++++-------- js/src/jit/ExecutableAllocator.h | 14 ++++++++------ js/src/jit/ExecutableAllocatorPosix.cpp | 9 +++++---- js/src/jit/ExecutableAllocatorWin.cpp | 9 +++++---- js/src/jit/JitCompartment.h | 6 +++--- js/src/shell/js.cpp | 9 +++------ 6 files changed, 28 insertions(+), 31 deletions(-) diff --git a/js/src/jit/ExecutableAllocator.cpp b/js/src/jit/ExecutableAllocator.cpp index 071b820d268e..f20095c8151b 100644 --- a/js/src/jit/ExecutableAllocator.cpp +++ b/js/src/jit/ExecutableAllocator.cpp @@ -340,27 +340,25 @@ ExecutableAllocator::addSizeOfCode(JS::CodeSizes* sizes) const void ExecutableAllocator::reprotectAll(ProtectionSetting protection) { - if (!nonWritableJitCode) - return; - +#ifdef NON_WRITABLE_JIT_CODE if (!m_pools.initialized()) return; for (ExecPoolHashSet::Range r = m_pools.all(); !r.empty(); r.popFront()) reprotectPool(rt_, r.front(), protection); +#endif } /* static */ void ExecutableAllocator::reprotectPool(JSRuntime* rt, ExecutablePool* pool, ProtectionSetting protection) { +#ifdef NON_WRITABLE_JIT_CODE // Don't race with reprotectAll called from the signal handler. MOZ_ASSERT(rt->jitRuntime()->preventBackedgePatching() || rt->handlingJitInterrupt()); - if (!nonWritableJitCode) - return; - char* start = pool->m_allocation.pages; reprotectRegion(start, pool->m_freePtr - start, protection); +#endif } /* static */ void @@ -407,5 +405,3 @@ ExecutableAllocator::poisonCode(JSRuntime* rt, JitPoisonRangeVector& ranges) pool->release(); } } - -bool ExecutableAllocator::nonWritableJitCode = true; diff --git a/js/src/jit/ExecutableAllocator.h b/js/src/jit/ExecutableAllocator.h index b6d1fa20ee19..930d865516f6 100644 --- a/js/src/jit/ExecutableAllocator.h +++ b/js/src/jit/ExecutableAllocator.h @@ -157,6 +157,8 @@ struct JitPoisonRange typedef Vector JitPoisonRangeVector; +#define NON_WRITABLE_JIT_CODE 1 + class ExecutableAllocator { #ifdef XP_WIN @@ -183,8 +185,6 @@ class ExecutableAllocator static void initStatic(); - static bool nonWritableJitCode; - private: static size_t pageSize; static size_t largeAllocSize; @@ -206,14 +206,16 @@ class ExecutableAllocator public: static void makeWritable(void* start, size_t size) { - if (nonWritableJitCode) - reprotectRegion(start, size, Writable); +#ifdef NON_WRITABLE_JIT_CODE + reprotectRegion(start, size, Writable); +#endif } static void makeExecutable(void* start, size_t size) { - if (nonWritableJitCode) - reprotectRegion(start, size, Executable); +#ifdef NON_WRITABLE_JIT_CODE + reprotectRegion(start, size, Executable); +#endif } void makeAllWritable() { diff --git a/js/src/jit/ExecutableAllocatorPosix.cpp b/js/src/jit/ExecutableAllocatorPosix.cpp index d6d791174d6b..7eb33b01297f 100644 --- a/js/src/jit/ExecutableAllocatorPosix.cpp +++ b/js/src/jit/ExecutableAllocatorPosix.cpp @@ -81,7 +81,7 @@ static const unsigned FLAGS_RX = PROT_READ | PROT_EXEC; void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting) { - MOZ_ASSERT(nonWritableJitCode); + MOZ_ASSERT(NON_WRITABLE_JIT_CODE); MOZ_ASSERT(pageSize); // Calculate the start of the page containing this region, @@ -101,8 +101,9 @@ ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting /* static */ unsigned ExecutableAllocator::initialProtectionFlags(ProtectionSetting protection) { - if (!nonWritableJitCode) - return FLAGS_RW | FLAGS_RX; - +#ifdef NON_WRITABLE_JIT_CODE return (protection == Writable) ? FLAGS_RW : FLAGS_RX; +#else + return FLAGS_RW | FLAGS_RX; +#endif } diff --git a/js/src/jit/ExecutableAllocatorWin.cpp b/js/src/jit/ExecutableAllocatorWin.cpp index 965b5c37fcc4..4636f606ec9c 100644 --- a/js/src/jit/ExecutableAllocatorWin.cpp +++ b/js/src/jit/ExecutableAllocatorWin.cpp @@ -242,7 +242,7 @@ ExecutableAllocator::systemRelease(const ExecutablePool::Allocation& alloc) void ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting setting) { - MOZ_ASSERT(nonWritableJitCode); + MOZ_ASSERT(NON_WRITABLE_JIT_CODE); MOZ_ASSERT(pageSize); // Calculate the start of the page containing this region, @@ -265,8 +265,9 @@ ExecutableAllocator::reprotectRegion(void* start, size_t size, ProtectionSetting /* static */ unsigned ExecutableAllocator::initialProtectionFlags(ProtectionSetting protection) { - if (!nonWritableJitCode) - return PAGE_EXECUTE_READWRITE; - +#ifdef NON_WRITABLE_JIT_CODE return (protection == Writable) ? PAGE_READWRITE : PAGE_EXECUTE_READ; +#else + return PAGE_EXECUTE_READWRITE; +#endif } diff --git a/js/src/jit/JitCompartment.h b/js/src/jit/JitCompartment.h index 52e72f603752..a0d897fb78ed 100644 --- a/js/src/jit/JitCompartment.h +++ b/js/src/jit/JitCompartment.h @@ -526,9 +526,9 @@ void FinishInvalidation(FreeOp* fop, JSScript* script); const unsigned WINDOWS_BIG_FRAME_TOUCH_INCREMENT = 4096 - 1; #endif -// If ExecutableAllocator::nonWritableJitCode is |true|, this class will ensure -// JIT code is writable (has RW permissions) in its scope. If nonWritableJitCode -// is |false|, it's a no-op. +// If NON_WRITABLE_JIT_CODE is enabled, this class will ensure +// JIT code is writable (has RW permissions) in its scope. +// Otherwise it's a no-op. class MOZ_STACK_CLASS AutoWritableJitCode { // Backedge patching from the signal handler will change memory protection diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index bce8129bc881..f008a3fa590a 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3781,11 +3781,13 @@ EscapeForShell(AutoCStringVector& argv) static Vector sPropagatedFlags; +#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) static bool PropagateFlagToNestedShells(const char* flag) { return sPropagatedFlags.append(flag); } +#endif static bool NestedShell(JSContext* cx, unsigned argc, Value* vp) @@ -6690,7 +6692,7 @@ main(int argc, char** argv, char** envp) || !op.addIntOption('\0', "baseline-warmup-threshold", "COUNT", "Wait for COUNT calls or iterations before baseline-compiling " "(default: 10)", -1) - || !op.addBoolOption('\0', "non-writable-jitcode", "Allocate JIT code as non-writable memory.") + || !op.addBoolOption('\0', "non-writable-jitcode", "(NOP for fuzzers) Allocate JIT code as non-writable memory.") || !op.addBoolOption('\0', "no-fpu", "Pretend CPU does not support floating-point operations " "to test JIT codegen (no-op on platforms other than x86).") || !op.addBoolOption('\0', "no-sse3", "Pretend CPU does not support SSE3 instructions and above " @@ -6769,11 +6771,6 @@ main(int argc, char** argv, char** envp) OOM_printAllocationCount = op.getBoolOption('O'); #endif - if (op.getBoolOption("non-writable-jitcode")) { - js::jit::ExecutableAllocator::nonWritableJitCode = true; - PropagateFlagToNestedShells("--non-writable-jitcode"); - } - #ifdef JS_CODEGEN_X86 if (op.getBoolOption("no-fpu")) js::jit::CPUInfo::SetFloatingPointDisabled(); From b29022c1deb243576e873873c3f50a308ef2b347 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Tue, 29 Dec 2015 15:47:04 -0800 Subject: [PATCH 33/36] Bug 1215197: Implements onBeforeRedirect by using a channel event sink (r=billm) --- .../components/extensions/ext-webRequest.js | 4 +- .../test/mochitest/file_WebRequest_page1.html | 2 +- .../extensions/test/mochitest/mochitest.ini | 1 + .../extensions/test/mochitest/redirection.sjs | 4 + .../test/mochitest/test_ext_webrequest.html | 42 ++++- toolkit/modules/addons/WebRequest.jsm | 151 +++++++++++------- .../tests/browser/WebRequest_redirection.sjs | 4 + toolkit/modules/tests/browser/browser.ini | 1 + .../tests/browser/browser_WebRequest.js | 51 ++++-- .../tests/browser/file_WebRequest_page1.html | 2 +- 10 files changed, 184 insertions(+), 78 deletions(-) create mode 100644 toolkit/components/extensions/test/mochitest/redirection.sjs create mode 100644 toolkit/modules/tests/browser/WebRequest_redirection.sjs diff --git a/toolkit/components/extensions/ext-webRequest.js b/toolkit/components/extensions/ext-webRequest.js index b86272b8b284..2e205315bef7 100644 --- a/toolkit/components/extensions/ext-webRequest.js +++ b/toolkit/components/extensions/ext-webRequest.js @@ -48,7 +48,7 @@ function WebRequestEventManager(context, eventName) { return; } - let optional = ["requestHeaders", "responseHeaders", "statusCode"]; + let optional = ["requestHeaders", "responseHeaders", "statusCode", "redirectUrl"]; for (let opt of optional) { if (opt in data) { data2[opt] = data[opt]; @@ -100,6 +100,7 @@ extensions.registerSchemaAPI("webRequest", "webRequest", (extension, context) => onBeforeSendHeaders: new WebRequestEventManager(context, "onBeforeSendHeaders").api(), onSendHeaders: new WebRequestEventManager(context, "onSendHeaders").api(), onHeadersReceived: new WebRequestEventManager(context, "onHeadersReceived").api(), + onBeforeRedirect: new WebRequestEventManager(context, "onBeforeRedirect").api(), onResponseStarted: new WebRequestEventManager(context, "onResponseStarted").api(), onCompleted: new WebRequestEventManager(context, "onCompleted").api(), handlerBehaviorChanged: function() { @@ -107,7 +108,6 @@ extensions.registerSchemaAPI("webRequest", "webRequest", (extension, context) => }, // TODO - onBeforeRedirect: ignoreEvent(context, "webRequest.onBeforeRedirect"), onErrorOccurred: ignoreEvent(context, "webRequest.onErrorOccurred"), }, }; diff --git a/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html b/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html index 420b1c29575c..218ccc5d22e3 100644 --- a/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html +++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_page1.html @@ -24,6 +24,6 @@ - + diff --git a/toolkit/components/extensions/test/mochitest/mochitest.ini b/toolkit/components/extensions/test/mochitest/mochitest.ini index 7f458d22dba6..cc3fb37308ad 100644 --- a/toolkit/components/extensions/test/mochitest/mochitest.ini +++ b/toolkit/components/extensions/test/mochitest/mochitest.ini @@ -18,6 +18,7 @@ support-files = file_script_redirect.js file_script_xhr.js file_sample.html + redirection.sjs file_privilege_escalation.html file_ext_background_api_injection.js file_permission_xhr.html diff --git a/toolkit/components/extensions/test/mochitest/redirection.sjs b/toolkit/components/extensions/test/mochitest/redirection.sjs new file mode 100644 index 000000000000..b26411884bcb --- /dev/null +++ b/toolkit/components/extensions/test/mochitest/redirection.sjs @@ -0,0 +1,4 @@ +function handleRequest(aRequest, aResponse) { + aResponse.setStatusLine(aRequest.httpVersion, 302); + aResponse.setHeader("Location", "./dummy_page.html"); +} \ No newline at end of file diff --git a/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html b/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html index 72cb045f4216..b347c4465ff9 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest.html @@ -28,9 +28,10 @@ const expected_requested = [BASE + "/file_WebRequest_page1.html", BASE + "/file_script_xhr.js", BASE + "/file_WebRequest_page2.html", BASE + "/nonexistent_script_url.js", + BASE + "/redirection.sjs", BASE + "/xhr_resource"]; -const expected_sendHeaders = [BASE + "/file_WebRequest_page1.html", +const expected_beforeSendHeaders = [BASE + "/file_WebRequest_page1.html", BASE + "/file_style_good.css", BASE + "/file_style_redirect.css", BASE + "/file_image_good.png", @@ -40,8 +41,16 @@ const expected_sendHeaders = [BASE + "/file_WebRequest_page1.html", BASE + "/file_script_xhr.js", BASE + "/file_WebRequest_page2.html", BASE + "/nonexistent_script_url.js", + BASE + "/redirection.sjs", + BASE + "/dummy_page.html", BASE + "/xhr_resource"]; +const expected_sendHeaders = expected_beforeSendHeaders.filter(u => !/_redirect\./.test(u)) + .concat(BASE + "/redirection.sjs"); + +const expected_redirect = expected_beforeSendHeaders.filter(u => /_redirect\./.test(u)) + .concat(BASE + "/redirection.sjs"); + const expected_complete = [BASE + "/file_WebRequest_page1.html", BASE + "/file_style_good.css", BASE + "/file_image_good.png", @@ -49,6 +58,7 @@ const expected_complete = [BASE + "/file_WebRequest_page1.html", BASE + "/file_script_xhr.js", BASE + "/file_WebRequest_page2.html", BASE + "/nonexistent_script_url.js", + BASE + "/dummy_page.html", BASE + "/xhr_resource"]; function removeDupes(list) @@ -91,7 +101,7 @@ function backgroundScript() expected_type = "script"; } else if (details.url.indexOf("page1") != -1) { expected_type = "main_frame"; - } else if (details.url.indexOf("page2") != -1) { + } else if (/page2|redirection|dummy_page/.test(details.url)) { expected_type = "sub_frame"; } else if (details.url.indexOf("xhr") != -1) { expected_type = "xmlhttprequest"; @@ -103,6 +113,7 @@ function backgroundScript() var recorded = {requested: [], beforeSendHeaders: [], + beforeRedirect: [], sendHeaders: [], responseStarted: [], completed: []}; @@ -164,6 +175,27 @@ function backgroundScript() return {}; } + function onBeforeRedirect(details) + { + browser.test.log(`onBeforeRedirect ${details.url} -> ${details.redirectUrl}`); + checkResourceType(details.type); + if (details.url.startsWith(BASE)) { + recorded.beforeRedirect.push(details.url); + + browser.test.assertEq(details.tabId, savedTabId, "correct tab ID"); + checkType(details); + + var id = frameIDs.get(details.url); + browser.test.assertEq(id, details.frameId, "frame ID same in onBeforeRedirect as onBeforeRequest"); + frameIDs.set(details.redirectUrl, details.frameId); + } + if (details.url.indexOf("_redirect.") != -1) { + let expectedUrl = details.url.replace("_redirect.", "_good."); + browser.test.assertEq(details.redirectUrl, expectedUrl, "correct redirectUrl value"); + } + return {}; + } + function onRecord(kind, details) { checkResourceType(details.type); @@ -175,6 +207,7 @@ function backgroundScript() browser.webRequest.onBeforeRequest.addListener(onBeforeRequest, {urls: [""]}, ["blocking"]); browser.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {urls: [""]}, ["blocking"]); browser.webRequest.onSendHeaders.addListener(onRecord.bind(null, "sendHeaders"), {urls: [""]}); + browser.webRequest.onBeforeRedirect.addListener(onBeforeRedirect, {urls: [""]}); browser.webRequest.onResponseStarted.addListener(onRecord.bind(null, "responseStarted"), {urls: [""]}); browser.webRequest.onCompleted.addListener(onRecord.bind(null, "completed"), {urls: [""]}); @@ -243,8 +276,9 @@ function* test_once() let recorded = yield extension.awaitMessage("results"); compareLists(recorded.requested, expected_requested, "requested"); - compareLists(recorded.beforeSendHeaders, expected_sendHeaders, "beforeSendHeaders"); - compareLists(recorded.sendHeaders, expected_complete, "sendHeaders"); + compareLists(recorded.beforeSendHeaders, expected_beforeSendHeaders, "beforeSendHeaders"); + compareLists(recorded.sendHeaders, expected_sendHeaders, "sendHeaders"); + compareLists(recorded.beforeRedirect, expected_redirect, "beforeRedirect"); compareLists(recorded.responseStarted, expected_complete, "responseStarted"); compareLists(recorded.completed, expected_complete, "completed"); diff --git a/toolkit/modules/addons/WebRequest.jsm b/toolkit/modules/addons/WebRequest.jsm index 76b09e22b946..3f6caae66701 100644 --- a/toolkit/modules/addons/WebRequest.jsm +++ b/toolkit/modules/addons/WebRequest.jsm @@ -151,14 +151,60 @@ StartStopListener.prototype = { }, }; +var ChannelEventSink = { + _classDescription: "WebRequest channel event sink", + _classID: Components.ID("115062f8-92f1-11e5-8b7f-080027b0f7ec"), + _contractID: "@mozilla.org/webrequest/channel-event-sink;1", + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink, + Ci.nsIFactory]), + + init() { + Components.manager.QueryInterface(Ci.nsIComponentRegistrar) + .registerFactory(this._classID, this._classDescription, this._contractID, this); + }, + + register() { + let catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager); + catMan.addCategoryEntry("net-channel-event-sinks", this._contractID, this._contractID, false, true); + }, + + unregister() { + let catMan = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager); + catMan.deleteCategoryEntry("net-channel-event-sinks", this._contractID, false); + }, + + // nsIChannelEventSink implementation + asyncOnChannelRedirect(oldChannel, newChannel, flags, redirectCallback) { + Services.tm.currentThread.dispatch(() => redirectCallback.onRedirectVerifyCallback(Cr.NS_OK), Ci.nsIEventTarget.DISPATCH_NORMAL); + try { + HttpObserverManager.onChannelReplaced(oldChannel, newChannel); + } catch (e) { + // we don't wanna throw: it would abort the redirection + } + }, + + // nsIFactory implementation + createInstance(outer, iid) { + if (outer) { + throw Cr.NS_ERROR_NO_AGGREGATION; + } + return this.QueryInterface(iid); + } +} + +ChannelEventSink.init(); + var HttpObserverManager = { modifyInitialized: false, examineInitialized: false, + redirectInitialized: false, listeners: { modify: new Map(), afterModify: new Map(), headersReceived: new Map(), + onRedirect: new Map(), onStart: new Map(), onStop: new Map(), }, @@ -187,6 +233,15 @@ var HttpObserverManager = { Services.obs.removeObserver(this, "http-on-examine-cached-response"); Services.obs.removeObserver(this, "http-on-examine-merged-response"); } + + let needRedirect = this.listeners.onRedirect.size; + if (needRedirect && !this.redirectInitialized) { + this.redirectInitialized = true; + ChannelEventSink.register(); + } else if (!needRedirect && this.redirectInitialized) { + this.redirectInitialized = false; + ChannelEventSink.unregister(); + } }, addListener(kind, callback, opts) { @@ -247,7 +302,7 @@ var HttpObserverManager = { WebRequestCommon.urlMatches(uri, filter.urls); }, - runChannelListener(channel, loadContext, kind) { + runChannelListener(channel, loadContext, kind, extraData = null) { let listeners = this.listeners[kind]; let browser = loadContext ? loadContext.topFrameElement : null; let loadInfo = channel.loadInfo; @@ -258,7 +313,10 @@ var HttpObserverManager = { let requestHeaders; let responseHeaders; - let includeStatus = kind == "headersReceived" || kind == "onStart" || kind == "onStop"; + let includeStatus = kind === "headersReceived" || + kind === "onBeforeRedirect" || + kind === "onStart" || + kind === "onStop"; for (let [callback, opts] of listeners.entries()) { if (!this.shouldRunListener(policyType, channel.URI, opts.filter)) { @@ -273,6 +331,9 @@ var HttpObserverManager = { windowId: loadInfo ? loadInfo.outerWindowID : 0, parentWindowId: loadInfo ? loadInfo.parentOuterWindowID : 0, }; + if (extraData) { + Object.assign(data, extraData); + } if (opts.requestHeaders) { if (!requestHeaders) { requestHeaders = this.getHeaders(channel, "visitRequestHeaders"); @@ -344,16 +405,25 @@ var HttpObserverManager = { let loadContext = this.getLoadContext(channel); if (this.listeners.onStart.size || this.listeners.onStop.size) { - if (channel instanceof Components.interfaces.nsITraceableChannel) { - let listener = new StartStopListener(this, loadContext); - let orig = channel.setNewListener(listener); - listener.orig = orig; + if (channel instanceof Ci.nsITraceableChannel) { + let responseStatus = channel.responseStatus; + // skip redirections, https://bugzilla.mozilla.org/show_bug.cgi?id=728901#c8 + if (responseStatus < 300 || responseStatus >= 400) { + let listener = new StartStopListener(this, loadContext); + let orig = channel.setNewListener(listener); + listener.orig = orig; + } } } this.runChannelListener(channel, loadContext, "headersReceived"); }, + onChannelReplaced(oldChannel, newChannel) { + this.runChannelListener(oldChannel, this.getLoadContext(oldChannel), + "onRedirect", { redirectUrl: newChannel.URI.spec }); + }, + onStartRequest(channel, loadContext) { this.runChannelListener(channel, loadContext, "onStart"); }, @@ -376,65 +446,29 @@ var onBeforeRequest = { }, }; -var onBeforeSendHeaders = { +function HttpEvent(internalEvent, options) { + this.internalEvent = internalEvent; + this.options = options; +} + +HttpEvent.prototype = { addListener(callback, filter = null, opt_extraInfoSpec = null) { - let opts = parseExtra(opt_extraInfoSpec, ["requestHeaders", "blocking"]); + let opts = parseExtra(opt_extraInfoSpec, this.options); opts.filter = parseFilter(filter); - HttpObserverManager.addListener("modify", callback, opts); + HttpObserverManager.addListener(this.internalEvent, callback, opts); }, removeListener(callback) { - HttpObserverManager.removeListener("modify", callback); + HttpObserverManager.removeListener(this.internalEvent, callback); }, }; -var onSendHeaders = { - addListener(callback, filter = null, opt_extraInfoSpec = null) { - let opts = parseExtra(opt_extraInfoSpec, ["requestHeaders"]); - opts.filter = parseFilter(filter); - HttpObserverManager.addListener("afterModify", callback, opts); - }, - - removeListener(callback) { - HttpObserverManager.removeListener("afterModify", callback); - }, -}; - -var onHeadersReceived = { - addListener(callback, filter = null, opt_extraInfoSpec = null) { - let opts = parseExtra(opt_extraInfoSpec, ["blocking", "responseHeaders"]); - opts.filter = parseFilter(filter); - HttpObserverManager.addListener("headersReceived", callback, opts); - }, - - removeListener(callback) { - HttpObserverManager.removeListener("headersReceived", callback); - }, -}; - -var onResponseStarted = { - addListener(callback, filter = null, opt_extraInfoSpec = null) { - let opts = parseExtra(opt_extraInfoSpec, ["responseHeaders"]); - opts.filter = parseFilter(filter); - HttpObserverManager.addListener("onStart", callback, opts); - }, - - removeListener(callback) { - HttpObserverManager.removeListener("onStart", callback); - }, -}; - -var onCompleted = { - addListener(callback, filter = null, opt_extraInfoSpec = null) { - let opts = parseExtra(opt_extraInfoSpec, ["responseHeaders"]); - opts.filter = parseFilter(filter); - HttpObserverManager.addListener("onStop", callback, opts); - }, - - removeListener(callback) { - HttpObserverManager.removeListener("onStop", callback); - }, -}; +var onBeforeSendHeaders = new HttpEvent("modify", ["requestHeaders", "blocking"]); +var onSendHeaders = new HttpEvent("afterModify", ["requestHeaders"]); +var onHeadersReceived = new HttpEvent("headersReceived", ["blocking", "responseHeaders"]); +var onBeforeRedirect = new HttpEvent("onRedirect", ["responseHeaders"]); +var onResponseStarted = new HttpEvent("onStart", ["responseHeaders"]); +var onCompleted = new HttpEvent("onStop", ["responseHeaders"]); var WebRequest = { // Handled via content policy. @@ -449,6 +483,9 @@ var WebRequest = { // http-on-examine-*observer. onHeadersReceived: onHeadersReceived, + // nsIChannelEventSink + onBeforeRedirect: onBeforeRedirect, + // OnStartRequest channel listener. onResponseStarted: onResponseStarted, diff --git a/toolkit/modules/tests/browser/WebRequest_redirection.sjs b/toolkit/modules/tests/browser/WebRequest_redirection.sjs new file mode 100644 index 000000000000..370ecd213fed --- /dev/null +++ b/toolkit/modules/tests/browser/WebRequest_redirection.sjs @@ -0,0 +1,4 @@ +function handleRequest(aRequest, aResponse) { + aResponse.setStatusLine(aRequest.httpVersion, 302); + aResponse.setHeader("Location", "./dummy_page.html"); +} diff --git a/toolkit/modules/tests/browser/browser.ini b/toolkit/modules/tests/browser/browser.ini index 2937d30041e4..d021c3e50f8d 100644 --- a/toolkit/modules/tests/browser/browser.ini +++ b/toolkit/modules/tests/browser/browser.ini @@ -19,6 +19,7 @@ support-files = file_script_redirect.js file_script_xhr.js WebRequest_dynamic.sjs + WebRequest_redirection.sjs [browser_Battery.js] [browser_Deprecated.js] diff --git a/toolkit/modules/tests/browser/browser_WebRequest.js b/toolkit/modules/tests/browser/browser_WebRequest.js index 3776349e82e0..82804ec645e7 100644 --- a/toolkit/modules/tests/browser/browser_WebRequest.js +++ b/toolkit/modules/tests/browser/browser_WebRequest.js @@ -20,7 +20,7 @@ function checkType(details) expected_type = "script"; } else if (details.url.indexOf("page1") != -1) { expected_type = "main_frame"; - } else if (details.url.indexOf("page2") != -1) { + } else if (/page2|_redirection\.|dummy_page/.test(details.url)) { expected_type = "sub_frame"; } else if (details.url.indexOf("xhr") != -1) { expected_type = "xmlhttprequest"; @@ -72,6 +72,28 @@ function onBeforeSendHeaders(details) } } +var beforeRedirect = []; + +function onBeforeRedirect(details) +{ + info(`onBeforeRedirect ${details.url} -> ${details.redirectUrl}`); + checkType(details); + if (details.url.startsWith(BASE)) { + beforeRedirect.push(details.url); + + is(details.browser, expected_browser, "correct element"); + checkType(details); + + let expectedUrl = details.url.replace("_redirect.", "_good.").replace(/\w+_redirection\..*/, "dummy_page.html") + is(details.redirectUrl, expectedUrl, "Correct redirectUrl value"); + } + let id = windowIDs.get(details.url); + is(id, details.windowId, "window ID same in onBeforeRedirect as onBeforeRequest"); + // associate stored windowId with final url + windowIDs.set(details.redirectUrl, details.windowId); + return {}; +} + var headersReceived = []; function onResponseStarted(details) @@ -94,6 +116,7 @@ const expected_requested = [BASE + "/file_WebRequest_page1.html", BASE + "/file_script_xhr.js", BASE + "/file_WebRequest_page2.html", BASE + "/nonexistent_script_url.js", + BASE + "/WebRequest_redirection.sjs", BASE + "/xhr_resource"]; const expected_sendHeaders = [BASE + "/file_WebRequest_page1.html", @@ -106,8 +129,13 @@ const expected_sendHeaders = [BASE + "/file_WebRequest_page1.html", BASE + "/file_script_xhr.js", BASE + "/file_WebRequest_page2.html", BASE + "/nonexistent_script_url.js", + BASE + "/WebRequest_redirection.sjs", + BASE + "/dummy_page.html", BASE + "/xhr_resource"]; +const expected_beforeRedirect = expected_sendHeaders.filter(u => /_redirect\./.test(u)) + .concat(BASE + "/WebRequest_redirection.sjs"); + const expected_headersReceived = [BASE + "/file_WebRequest_page1.html", BASE + "/file_style_good.css", BASE + "/file_image_good.png", @@ -115,6 +143,7 @@ const expected_headersReceived = [BASE + "/file_WebRequest_page1.html", BASE + "/file_script_xhr.js", BASE + "/file_WebRequest_page2.html", BASE + "/nonexistent_script_url.js", + BASE + "/dummy_page.html", BASE + "/xhr_resource"]; function removeDupes(list) @@ -144,17 +173,20 @@ function* test_once() { WebRequest.onBeforeRequest.addListener(onBeforeRequest, null, ["blocking"]); WebRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, null, ["blocking"]); + WebRequest.onBeforeRedirect.addListener(onBeforeRedirect); WebRequest.onResponseStarted.addListener(onResponseStarted); gBrowser.selectedTab = gBrowser.addTab(); let browser = gBrowser.selectedBrowser; expected_browser = browser; - yield waitForLoad(); + yield BrowserTestUtils.browserLoaded(expected_browser); browser.messageManager.loadFrameScript(`data:,content.location = "${URL}";`, false); - yield waitForLoad(); + yield BrowserTestUtils.browserLoaded(expected_browser); + + expected_browser = null; let win = browser.contentWindow.wrappedJSObject; is(win.success, 2, "Good script ran"); @@ -163,26 +195,19 @@ function* test_once() let style = browser.contentWindow.getComputedStyle(browser.contentDocument.getElementById("test"), null); is(style.getPropertyValue("color"), "rgb(255, 0, 0)", "Good CSS loaded"); - gBrowser.removeCurrentTab(); + BrowserTestUtils.removeTab(gBrowser.selectedTab); compareLists(requested, expected_requested, "requested"); compareLists(sendHeaders, expected_sendHeaders, "sendHeaders"); + compareLists(beforeRedirect, expected_beforeRedirect, "beforeRedirect"); compareLists(headersReceived, expected_headersReceived, "headersReceived"); WebRequest.onBeforeRequest.removeListener(onBeforeRequest); WebRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders); + WebRequest.onBeforeRedirect.removeListener(onBeforeRedirect); WebRequest.onResponseStarted.removeListener(onResponseStarted); } // Run the test twice to make sure it works with caching. add_task(test_once); add_task(test_once); - -function waitForLoad(browser = gBrowser.selectedBrowser) { - return new Promise(resolve => { - browser.addEventListener("load", function listener() { - browser.removeEventListener("load", listener, true); - resolve(); - }, true); - }); -} diff --git a/toolkit/modules/tests/browser/file_WebRequest_page1.html b/toolkit/modules/tests/browser/file_WebRequest_page1.html index 420b1c29575c..00a0b9b4b67f 100644 --- a/toolkit/modules/tests/browser/file_WebRequest_page1.html +++ b/toolkit/modules/tests/browser/file_WebRequest_page1.html @@ -24,6 +24,6 @@ - + From f0ea1c2a47f8bfbf96b3df7e3ff5aab64d77a875 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Wed, 23 Dec 2015 21:51:43 -0600 Subject: [PATCH 34/36] Add a semicolon to avoid relying on ASI in one place in String.js. No bug, r=trivial --HG-- extra : rebase_source : 71c6b8d85f35953db9eb5efb9cb9f874e99df2b4 --- js/src/builtin/String.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index 0b23ce8932da..6551af904f57 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -68,7 +68,7 @@ function String_substr(start, length) { intStart = std_Math_max(intStart + size, 0); // Step 9. - var resultLength = std_Math_min(std_Math_max(end, 0), size - intStart) + var resultLength = std_Math_min(std_Math_max(end, 0), size - intStart); // Step 10. if (resultLength <= 0) From 5be7be38a11aa9c206bea7e26690c1dda0178d68 Mon Sep 17 00:00:00 2001 From: Jeff Walden Date: Mon, 28 Dec 2015 16:15:52 -0600 Subject: [PATCH 35/36] Bug 1235615 - Split JS::CompartmentOptions into JS::CompartmentCreationOptions that are immutable characteristics of a compartment, and JS::CompartmentBehaviors that may be changed after the compartment's been created. r=terrence --HG-- extra : rebase_source : f08c380ae247d3308d4c36788ac765de1b75af50 --- .../heapsnapshot/tests/gtest/DevTools.h | 2 +- dom/base/nsFrameMessageManager.cpp | 4 +- dom/base/nsGlobalWindow.cpp | 8 +- dom/bindings/BindingUtils.h | 2 +- dom/workers/RuntimeService.cpp | 4 +- dom/workers/WorkerScope.cpp | 7 +- ipc/testshell/XPCShellEnvironment.cpp | 5 +- js/src/builtin/TestingFunctions.cpp | 4 +- js/src/frontend/BytecodeCompiler.cpp | 6 +- js/src/gdb/gdb-tests.cpp | 5 +- js/src/jit/BaselineCompiler.cpp | 5 +- js/src/jit/CompileWrappers.cpp | 5 +- .../testFreshGlobalEvalRedefinition.cpp | 1 - js/src/jsapi-tests/testGCFinalizeCallback.cpp | 1 - js/src/jsapi-tests/testPreserveJitCode.cpp | 4 +- js/src/jsapi-tests/testSourcePolicy.cpp | 10 +- js/src/jsapi-tests/testWeakMap.cpp | 12 +- js/src/jsapi-tests/tests.cpp | 8 +- js/src/jsapi.cpp | 57 ++-- js/src/jsapi.h | 249 ++++++++++++------ js/src/jscntxt.cpp | 8 +- js/src/jscompartment.cpp | 14 +- js/src/jscompartment.h | 19 +- js/src/jsexn.cpp | 2 +- js/src/jsgc.cpp | 6 +- js/src/jsobj.cpp | 4 +- js/src/jsscript.cpp | 6 +- js/src/shell/js.cpp | 34 +-- js/src/vm/Debugger.cpp | 12 +- js/src/vm/Debugger.h | 7 +- js/src/vm/GlobalObject.cpp | 9 +- js/src/vm/HelperThreads.cpp | 18 +- js/src/vm/Interpreter.cpp | 4 +- js/src/vm/NativeObject.cpp | 4 +- js/src/vm/SelfHosting.cpp | 4 +- js/xpconnect/loader/mozJSComponentLoader.cpp | 7 +- js/xpconnect/src/Sandbox.cpp | 24 +- js/xpconnect/src/XPCShellImpl.cpp | 6 +- js/xpconnect/src/XPCWrappedNative.cpp | 2 +- js/xpconnect/src/nsXPConnect.cpp | 4 +- netwerk/base/ProxyAutoConfig.cpp | 4 +- xpcom/glue/tests/gtest/TestGCPostBarriers.cpp | 2 +- 42 files changed, 362 insertions(+), 237 deletions(-) diff --git a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h index e61d750453d9..76c913ff8773 100644 --- a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h +++ b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h @@ -113,7 +113,7 @@ struct DevTools : public ::testing::Test { /* Create the global object. */ JS::RootedObject newGlobal(cx); JS::CompartmentOptions options; - options.setVersion(JSVERSION_LATEST); + options.behaviors().setVersion(JSVERSION_LATEST); newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook, options); if (!newGlobal) diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index eee2ef1863e4..c1251d865027 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -1809,8 +1809,8 @@ nsMessageManagerScriptExecutor::InitChildGlobalInternal( const uint32_t flags = nsIXPConnect::INIT_JS_STANDARD_CLASSES; JS::CompartmentOptions options; - options.setZone(JS::SystemZone) - .setVersion(JSVERSION_LATEST); + options.creationOptions().setZone(JS::SystemZone); + options.behaviors().setVersion(JSVERSION_LATEST); nsresult rv = xpc->InitClassesWithNewWrappedGlobal(cx, aScope, mPrincipal, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 3f0b4a6864f6..eccab0f4551c 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -2325,13 +2325,11 @@ CreateNativeGlobalForInner(JSContext* aCx, // windows or inside a browser element. In such cases we want to tag the // window's compartment with the add-on ID. See bug 1092156. if (nsContentUtils::IsSystemPrincipal(aPrincipal)) { - options.setAddonId(MapURIToAddonID(aURI)); + options.creationOptions().setAddonId(MapURIToAddonID(aURI)); } - if (top) { - if (top->GetGlobalJSObject()) { - options.setSameZoneAs(top->GetGlobalJSObject()); - } + if (top && top->GetGlobalJSObject()) { + options.creationOptions().setSameZoneAs(top->GetGlobalJSObject()); } // Determine if we need the Components object. diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 5e4edf022ac8..0dd9041a169e 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -3048,7 +3048,7 @@ CreateGlobal(JSContext* aCx, T* aNative, nsWrapperCache* aCache, JSPrincipals* aPrincipal, bool aInitStandardClasses, JS::MutableHandle aGlobal) { - aOptions.setTrace(CreateGlobalOptions::TraceGlobal); + aOptions.creationOptions().setTrace(CreateGlobalOptions::TraceGlobal); aGlobal.set(JS_NewGlobalObject(aCx, aClass, aPrincipal, JS::DontFireOnNewGlobalHook, aOptions)); diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 76487e6be061..698d01a18471 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -1845,7 +1845,7 @@ RuntimeService::Init() if (!sDefaultJSSettings.gcSettings[0].IsSet()) { sDefaultJSSettings.runtimeOptions = JS::RuntimeOptions(); sDefaultJSSettings.chrome.maxScriptRuntime = -1; - sDefaultJSSettings.chrome.compartmentOptions.setVersion(JSVERSION_LATEST); + sDefaultJSSettings.chrome.compartmentOptions.behaviors().setVersion(JSVERSION_LATEST); sDefaultJSSettings.content.maxScriptRuntime = MAX_SCRIPT_RUN_TIME_SEC; #ifdef JS_GC_ZEAL sDefaultJSSettings.gcZealFrequency = JS_DEFAULT_ZEAL_FREQ; @@ -2622,7 +2622,7 @@ RuntimeService::JSVersionChanged(const char* /* aPrefName */, void* /* aClosure bool useLatest = Preferences::GetBool("dom.workers.latestJSVersion", false); JS::CompartmentOptions& options = sDefaultJSSettings.content.compartmentOptions; - options.setVersion(useLatest ? JSVERSION_LATEST : JSVERSION_DEFAULT); + options.behaviors().setVersion(useLatest ? JSVERSION_LATEST : JSVERSION_DEFAULT); } NS_IMPL_ISUPPORTS_INHERITED0(LogViolationDetailsRunnable, nsRunnable) diff --git a/dom/workers/WorkerScope.cpp b/dom/workers/WorkerScope.cpp index 859ed7c27208..bf7892edce19 100644 --- a/dom/workers/WorkerScope.cpp +++ b/dom/workers/WorkerScope.cpp @@ -432,8 +432,9 @@ DedicatedWorkerGlobalScope::WrapGlobalObject(JSContext* aCx, const bool extraWarnings = usesSystemPrincipal && xpc::ExtraWarningsForSystemJS(); - options.setDiscardSource(discardSource) - .extraWarningsOverride().set(extraWarnings); + JS::CompartmentBehaviors& behaviors = options.behaviors(); + behaviors.setDiscardSource(discardSource) + .extraWarningsOverride().set(extraWarnings); return DedicatedWorkerGlobalScopeBinding_workers::Wrap(aCx, this, this, options, @@ -796,7 +797,7 @@ WorkerDebuggerGlobalScope::CreateSandbox(JSContext* aCx, const nsAString& aName, mWorkerPrivate->AssertIsOnWorkerThread(); JS::CompartmentOptions options; - options.setInvisibleToDebugger(true); + options.creationOptions().setInvisibleToDebugger(true); JS::Rooted sandbox(aCx, JS_NewGlobalObject(aCx, js::Jsvalify(&workerdebuggersandbox_class), nullptr, diff --git a/ipc/testshell/XPCShellEnvironment.cpp b/ipc/testshell/XPCShellEnvironment.cpp index 221bb3fb06ee..2b54bba908da 100644 --- a/ipc/testshell/XPCShellEnvironment.cpp +++ b/ipc/testshell/XPCShellEnvironment.cpp @@ -514,8 +514,9 @@ XPCShellEnvironment::Init() } JS::CompartmentOptions options; - options.setZone(JS::SystemZone) - .setVersion(JSVERSION_LATEST); + options.creationOptions().setZone(JS::SystemZone); + options.behaviors().setVersion(JSVERSION_LATEST); + nsCOMPtr holder; rv = xpc->InitClassesWithNewWrappedGlobal(cx, static_cast(backstagePass), diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 6ef46a1414ea..cb3068ca45c8 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -2753,7 +2753,7 @@ SetLazyParsingDisabled(JSContext* cx, unsigned argc, Value* vp) CallArgs args = CallArgsFromVp(argc, vp); bool disable = !args.hasDefined(0) || ToBoolean(args[0]); - JS::CompartmentOptionsRef(cx->compartment()).setDisableLazyParsing(disable); + cx->compartment()->behaviors().setDisableLazyParsing(disable); args.rval().setUndefined(); return true; @@ -2765,7 +2765,7 @@ SetDiscardSource(JSContext* cx, unsigned argc, Value* vp) CallArgs args = CallArgsFromVp(argc, vp); bool discard = !args.hasDefined(0) || ToBoolean(args[0]); - JS::CompartmentOptionsRef(cx->compartment()).setDiscardSource(discard); + cx->compartment()->behaviors().setDiscardSource(discard); args.rval().setUndefined(); return true; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index a5ec2f31ccac..7a434af4d812 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -199,7 +199,7 @@ BytecodeCompiler::maybeCompressSource() sourceCompressor = maybeSourceCompressor.ptr(); } - if (!cx->compartment()->options().discardSource()) { + if (!cx->compartment()->behaviors().discardSource()) { if (options.sourceIsLazy) { scriptSource->setSourceRetrievable(); } else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceArgumentsNotIncluded, @@ -217,8 +217,8 @@ BytecodeCompiler::canLazilyParse() { return options.canLazilyParse && !HasNonSyntacticStaticScopeChain(enclosingStaticScope) && - !cx->compartment()->options().disableLazyParsing() && - !cx->compartment()->options().discardSource() && + !cx->compartment()->behaviors().disableLazyParsing() && + !cx->compartment()->behaviors().discardSource() && !options.sourceIsLazy && !cx->lcovEnabled(); } diff --git a/js/src/gdb/gdb-tests.cpp b/js/src/gdb/gdb-tests.cpp index c9f74a37191c..414cf8a1865f 100644 --- a/js/src/gdb/gdb-tests.cpp +++ b/js/src/gdb/gdb-tests.cpp @@ -60,7 +60,7 @@ void breakpoint() { GDBFragment* GDBFragment::allFragments = nullptr; int -main (int argc, const char** argv) +main(int argc, const char** argv) { if (!JS_Init()) return 1; JSRuntime* runtime = checkPtr(JS_NewRuntime(1024 * 1024)); @@ -74,7 +74,8 @@ main (int argc, const char** argv) /* Create the global object. */ JS::CompartmentOptions options; - options.setVersion(JSVERSION_LATEST); + options.behaviors().setVersion(JSVERSION_LATEST); + RootedObject global(cx, checkPtr(JS_NewGlobalObject(cx, &global_class, nullptr, JS::FireOnNewGlobalHook, options))); JSAutoCompartment ac(cx, global); diff --git a/js/src/jit/BaselineCompiler.cpp b/js/src/jit/BaselineCompiler.cpp index 1c6e0b540193..4a2ad63990e8 100644 --- a/js/src/jit/BaselineCompiler.cpp +++ b/js/src/jit/BaselineCompiler.cpp @@ -1491,7 +1491,8 @@ static const VMFunction DeepCloneObjectLiteralInfo = bool BaselineCompiler::emit_JSOP_OBJECT() { - if (JS::CompartmentOptionsRef(cx).cloneSingletons()) { + JSCompartment* comp = cx->compartment(); + if (comp->creationOptions().cloneSingletons()) { RootedObject obj(cx, script->getObject(GET_UINT32_INDEX(pc))); if (!obj) return false; @@ -1510,7 +1511,7 @@ BaselineCompiler::emit_JSOP_OBJECT() return true; } - JS::CompartmentOptionsRef(cx).setSingletonsAsValues(); + comp->behaviors().setSingletonsAsValues(); frame.push(ObjectValue(*script->getObject(pc))); return true; } diff --git a/js/src/jit/CompileWrappers.cpp b/js/src/jit/CompileWrappers.cpp index 40ff1c6989de..b245ea2786a7 100644 --- a/js/src/jit/CompileWrappers.cpp +++ b/js/src/jit/CompileWrappers.cpp @@ -284,7 +284,7 @@ CompileCompartment::hasObjectMetadataCallback() void CompileCompartment::setSingletonsAsValues() { - return JS::CompartmentOptionsRef(compartment()).setSingletonsAsValues(); + compartment()->behaviors().setSingletonsAsValues(); } JitCompileOptions::JitCompileOptions() @@ -296,8 +296,7 @@ JitCompileOptions::JitCompileOptions() JitCompileOptions::JitCompileOptions(JSContext* cx) { - JS::CompartmentOptions& options = cx->compartment()->options(); - cloneSingletons_ = options.cloneSingletons(); + cloneSingletons_ = cx->compartment()->creationOptions().cloneSingletons(); spsSlowAssertionsEnabled_ = cx->runtime()->spsProfiler.enabled() && cx->runtime()->spsProfiler.slowAssertionsEnabled(); offThreadCompilationAvailable_ = OffThreadCompilationAvailable(cx); diff --git a/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp b/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp index ddf82c617564..9faf3f4638b3 100644 --- a/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp +++ b/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp @@ -31,7 +31,6 @@ BEGIN_TEST(testRedefineGlobalEval) /* Create the global object. */ JS::CompartmentOptions options; - options.setVersion(JSVERSION_LATEST); JS::Rooted g(cx, JS_NewGlobalObject(cx, &cls, nullptr, JS::FireOnNewGlobalHook, options)); if (!g) return false; diff --git a/js/src/jsapi-tests/testGCFinalizeCallback.cpp b/js/src/jsapi-tests/testGCFinalizeCallback.cpp index cc0da55d2d5d..a89a08124620 100644 --- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp +++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp @@ -123,7 +123,6 @@ BEGIN_TEST(testGCFinalizeCallback) JSObject* createTestGlobal() { JS::CompartmentOptions options; - options.setVersion(JSVERSION_LATEST); return JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook, options); } diff --git a/js/src/jsapi-tests/testPreserveJitCode.cpp b/js/src/jsapi-tests/testPreserveJitCode.cpp index 622f3631826a..08329be68587 100644 --- a/js/src/jsapi-tests/testPreserveJitCode.cpp +++ b/js/src/jsapi-tests/testPreserveJitCode.cpp @@ -90,8 +90,8 @@ JSObject* createTestGlobal(bool preserveJitCode) { JS::CompartmentOptions options; - options.setVersion(JSVERSION_LATEST); - options.setPreserveJitCode(preserveJitCode); + options.creationOptions().setPreserveJitCode(preserveJitCode); + options.behaviors().setVersion(JSVERSION_LATEST); return JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook, options); } END_TEST(test_PreserveJitCode) diff --git a/js/src/jsapi-tests/testSourcePolicy.cpp b/js/src/jsapi-tests/testSourcePolicy.cpp index 640b7555494a..6614fe7b2e7b 100644 --- a/js/src/jsapi-tests/testSourcePolicy.cpp +++ b/js/src/jsapi-tests/testSourcePolicy.cpp @@ -9,24 +9,32 @@ BEGIN_TEST(testBug795104) { JS::CompileOptions opts(cx); - JS::CompartmentOptionsRef(cx->compartment()).setDiscardSource(true); + JS::CompartmentBehaviorsRef(cx->compartment()).setDiscardSource(true); + const size_t strLen = 60002; char* s = static_cast(JS_malloc(cx, strLen)); CHECK(s); + s[0] = '"'; memset(s + 1, 'x', strLen - 2); s[strLen - 1] = '"'; + // We don't want an rval for our Evaluate call opts.setNoScriptRval(true); + JS::RootedValue unused(cx); CHECK(JS::Evaluate(cx, opts, s, strLen, &unused)); + JS::RootedFunction fun(cx); JS::AutoObjectVector emptyScopeChain(cx); + // But when compiling a function we don't want to use no-rval // mode, since it's not supported for functions. opts.setNoScriptRval(false); + CHECK(JS::CompileFunction(cx, emptyScopeChain, opts, "f", 0, nullptr, s, strLen, &fun)); CHECK(fun); + JS_free(cx, s); return true; diff --git a/js/src/jsapi-tests/testWeakMap.cpp b/js/src/jsapi-tests/testWeakMap.cpp index 9fce8bebae0f..4a32a7ad1ba6 100644 --- a/js/src/jsapi-tests/testWeakMap.cpp +++ b/js/src/jsapi-tests/testWeakMap.cpp @@ -230,12 +230,14 @@ JSObject* newDelegate() /* Create the global object. */ JS::CompartmentOptions options; - options.setVersion(JSVERSION_LATEST); - JS::RootedObject global(cx); - global = JS_NewGlobalObject(cx, Jsvalify(&delegateClass), nullptr, JS::FireOnNewGlobalHook, - options); - JS_SetReservedSlot(global, 0, JS::Int32Value(42)); + options.behaviors().setVersion(JSVERSION_LATEST); + JS::RootedObject global(cx, JS_NewGlobalObject(cx, Jsvalify(&delegateClass), nullptr, + JS::FireOnNewGlobalHook, options)); + if (!global) + return nullptr; + + JS_SetReservedSlot(global, 0, JS::Int32Value(42)); return global; } diff --git a/js/src/jsapi-tests/tests.cpp b/js/src/jsapi-tests/tests.cpp index a40c99b738a7..0cc90ba4ba6a 100644 --- a/js/src/jsapi-tests/tests.cpp +++ b/js/src/jsapi-tests/tests.cpp @@ -74,12 +74,12 @@ bool JSAPITest::definePrint() return JS_DefineFunction(cx, global, "print", (JSNative) print, 0, 0); } -JSObject * JSAPITest::createGlobal(JSPrincipals* principals) +JSObject* JSAPITest::createGlobal(JSPrincipals* principals) { /* Create the global object. */ JS::RootedObject newGlobal(cx); JS::CompartmentOptions options; - options.setVersion(JSVERSION_LATEST); + options.behaviors().setVersion(JSVERSION_LATEST); newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals, JS::FireOnNewGlobalHook, options); if (!newGlobal) @@ -87,8 +87,8 @@ JSObject * JSAPITest::createGlobal(JSPrincipals* principals) JSAutoCompartment ac(cx, newGlobal); - /* Populate the global object with the standard globals, like Object and - Array. */ + // Populate the global object with the standard globals like Object and + // Array. if (!JS_InitStandardClasses(cx, newGlobal)) return nullptr; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 3d217e17485c..07a75f3f9d71 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -637,7 +637,7 @@ JS_GetVersion(JSContext* cx) JS_PUBLIC_API(void) JS_SetVersionForCompartment(JSCompartment* compartment, JSVersion version) { - compartment->options().setVersion(version); + compartment->behaviors().setVersion(version); } static const struct v2smap { @@ -827,7 +827,7 @@ JS::StringOfAddonId(JSAddonId* id) JS_PUBLIC_API(JSAddonId*) JS::AddonIdOfObject(JSObject* obj) { - return obj->compartment()->addonId; + return obj->compartment()->creationOptions().addonIdOrNull(); } JS_PUBLIC_API(void) @@ -1795,47 +1795,65 @@ JS_GetConstructor(JSContext* cx, HandleObject proto) } bool -JS::CompartmentOptions::extraWarnings(JSRuntime* rt) const +JS::CompartmentBehaviors::extraWarnings(JSRuntime* rt) const { return extraWarningsOverride_.get(rt->options().extraWarnings()); } bool -JS::CompartmentOptions::extraWarnings(JSContext* cx) const +JS::CompartmentBehaviors::extraWarnings(JSContext* cx) const { return extraWarnings(cx->runtime()); } -JS::CompartmentOptions& -JS::CompartmentOptions::setZone(ZoneSpecifier spec) +JS::CompartmentCreationOptions& +JS::CompartmentCreationOptions::setZone(ZoneSpecifier spec) { zone_.spec = spec; return *this; } -JS::CompartmentOptions& -JS::CompartmentOptions::setSameZoneAs(JSObject* obj) +JS::CompartmentCreationOptions& +JS::CompartmentCreationOptions::setSameZoneAs(JSObject* obj) { zone_.pointer = static_cast(obj->zone()); return *this; } -JS::CompartmentOptions& -JS::CompartmentOptionsRef(JSCompartment* compartment) +const JS::CompartmentCreationOptions& +JS::CompartmentCreationOptionsRef(JSCompartment* compartment) { - return compartment->options(); + return compartment->creationOptions(); } -JS::CompartmentOptions& -JS::CompartmentOptionsRef(JSObject* obj) +const JS::CompartmentCreationOptions& +JS::CompartmentCreationOptionsRef(JSObject* obj) { - return obj->compartment()->options(); + return obj->compartment()->creationOptions(); } -JS::CompartmentOptions& -JS::CompartmentOptionsRef(JSContext* cx) +const JS::CompartmentCreationOptions& +JS::CompartmentCreationOptionsRef(JSContext* cx) { - return cx->compartment()->options(); + return cx->compartment()->creationOptions(); +} + +JS::CompartmentBehaviors& +JS::CompartmentBehaviorsRef(JSCompartment* compartment) +{ + return compartment->behaviors(); +} + +JS::CompartmentBehaviors& +JS::CompartmentBehaviorsRef(JSObject* obj) +{ + return obj->compartment()->behaviors(); +} + +JS::CompartmentBehaviors& +JS::CompartmentBehaviorsRef(JSContext* cx) +{ + return cx->compartment()->behaviors(); } JS_PUBLIC_API(JSObject*) @@ -1865,8 +1883,7 @@ JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global) // compartment is live. global->compartment()->trace(trc); - JSTraceOp trace = global->compartment()->options().getTrace(); - if (trace) + if (JSTraceOp trace = global->compartment()->creationOptions().getTrace()) trace(trc, global); } @@ -3897,7 +3914,7 @@ JS::CompileOptions::CompileOptions(JSContext* cx, JSVersion version) this->version = (version != JSVERSION_UNKNOWN) ? version : cx->findVersion(); strictOption = cx->runtime()->options().strictMode(); - extraWarningsOption = cx->compartment()->options().extraWarnings(cx); + extraWarningsOption = cx->compartment()->behaviors().extraWarnings(cx); werrorOption = cx->runtime()->options().werror(); if (!cx->runtime()->options().asmJS()) asmJSOption = AsmJSOption::Disabled; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index b8a8b04641b2..c4ac9cb69c75 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2163,7 +2163,104 @@ enum ZoneSpecifier { SystemZone = 1 }; -class JS_PUBLIC_API(CompartmentOptions) +/** + * CompartmentCreationOptions specifies options relevant to creating a new + * compartment, that are either immutable characteristics of that compartment + * or that are discarded after the compartment has been created. + * + * Access to these options on an existing compartment is read-only: if you + * need particular selections, make them before you create the compartment. + */ +class JS_PUBLIC_API(CompartmentCreationOptions) +{ + public: + CompartmentCreationOptions() + : addonId_(nullptr), + traceGlobal_(nullptr), + invisibleToDebugger_(false), + mergeable_(false), + preserveJitCode_(false), + cloneSingletons_(false) + { + zone_.spec = JS::FreshZone; + } + + // A null add-on ID means that the compartment is not associated with an + // add-on. + JSAddonId* addonIdOrNull() const { return addonId_; } + CompartmentCreationOptions& setAddonId(JSAddonId* id) { + addonId_ = id; + return *this; + } + + JSTraceOp getTrace() const { + return traceGlobal_; + } + CompartmentCreationOptions& setTrace(JSTraceOp op) { + traceGlobal_ = op; + return *this; + } + + void* zonePointer() const { + MOZ_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone)); + return zone_.pointer; + } + ZoneSpecifier zoneSpecifier() const { return zone_.spec; } + CompartmentCreationOptions& setZone(ZoneSpecifier spec); + CompartmentCreationOptions& setSameZoneAs(JSObject* obj); + + // Certain scopes (i.e. XBL compilation scopes) are implementation details + // of the embedding, and references to them should never leak out to script. + // This flag causes the this compartment to skip firing onNewGlobalObject + // and makes addDebuggee a no-op for this global. + bool invisibleToDebugger() const { return invisibleToDebugger_; } + CompartmentCreationOptions& setInvisibleToDebugger(bool flag) { + invisibleToDebugger_ = flag; + return *this; + } + + // Compartments used for off-thread compilation have their contents merged + // into a target compartment when the compilation is finished. This is only + // allowed if this flag is set. The invisibleToDebugger flag must also be + // set for such compartments. + bool mergeable() const { return mergeable_; } + CompartmentCreationOptions& setMergeable(bool flag) { + mergeable_ = flag; + return *this; + } + + // Determines whether this compartment should preserve JIT code on + // non-shrinking GCs. + bool preserveJitCode() const { return preserveJitCode_; } + CompartmentCreationOptions& setPreserveJitCode(bool flag) { + preserveJitCode_ = flag; + return *this; + } + + bool cloneSingletons() const { return cloneSingletons_; } + CompartmentCreationOptions& setCloneSingletons(bool flag) { + cloneSingletons_ = flag; + return *this; + } + + private: + JSAddonId* addonId_; + JSTraceOp traceGlobal_; + union { + ZoneSpecifier spec; + void* pointer; // js::Zone* is not exposed in the API. + } zone_; + bool invisibleToDebugger_; + bool mergeable_; + bool preserveJitCode_; + bool cloneSingletons_; +}; + +/** + * CompartmentBehaviors specifies behaviors of a compartment that can be + * changed after the compartment's been created. + */ +class JS_PUBLIC_API(CompartmentBehaviors) { public: class Override { @@ -2194,140 +2291,120 @@ class JS_PUBLIC_API(CompartmentOptions) Mode mode_; }; - explicit CompartmentOptions() + CompartmentBehaviors() : version_(JSVERSION_UNKNOWN) - , invisibleToDebugger_(false) - , mergeable_(false) , discardSource_(false) , disableLazyParsing_(false) - , cloneSingletons_(false) - , traceGlobal_(nullptr) , singletonsAsTemplates_(true) - , addonId_(nullptr) - , preserveJitCode_(false) { - zone_.spec = JS::FreshZone; } JSVersion version() const { return version_; } - CompartmentOptions& setVersion(JSVersion aVersion) { + CompartmentBehaviors& setVersion(JSVersion aVersion) { MOZ_ASSERT(aVersion != JSVERSION_UNKNOWN); version_ = aVersion; return *this; } - // Certain scopes (i.e. XBL compilation scopes) are implementation details - // of the embedding, and references to them should never leak out to script. - // This flag causes the this compartment to skip firing onNewGlobalObject - // and makes addDebuggee a no-op for this global. - bool invisibleToDebugger() const { return invisibleToDebugger_; } - CompartmentOptions& setInvisibleToDebugger(bool flag) { - invisibleToDebugger_ = flag; - return *this; - } - - // Compartments used for off-thread compilation have their contents merged - // into a target compartment when the compilation is finished. This is only - // allowed if this flag is set. The invisibleToDebugger flag must also be - // set for such compartments. - bool mergeable() const { return mergeable_; } - CompartmentOptions& setMergeable(bool flag) { - mergeable_ = flag; - return *this; - } - // For certain globals, we know enough about the code that will run in them // that we can discard script source entirely. bool discardSource() const { return discardSource_; } - CompartmentOptions& setDiscardSource(bool flag) { + CompartmentBehaviors& setDiscardSource(bool flag) { discardSource_ = flag; return *this; } bool disableLazyParsing() const { return disableLazyParsing_; } - CompartmentOptions& setDisableLazyParsing(bool flag) { + CompartmentBehaviors& setDisableLazyParsing(bool flag) { disableLazyParsing_ = flag; return *this; } - bool cloneSingletons() const { return cloneSingletons_; } - CompartmentOptions& setCloneSingletons(bool flag) { - cloneSingletons_ = flag; - return *this; - } - bool extraWarnings(JSRuntime* rt) const; bool extraWarnings(JSContext* cx) const; Override& extraWarningsOverride() { return extraWarningsOverride_; } - void* zonePointer() const { - MOZ_ASSERT(uintptr_t(zone_.pointer) > uintptr_t(JS::SystemZone)); - return zone_.pointer; - } - ZoneSpecifier zoneSpecifier() const { return zone_.spec; } - CompartmentOptions& setZone(ZoneSpecifier spec); - CompartmentOptions& setSameZoneAs(JSObject* obj); - - void setSingletonsAsValues() { - singletonsAsTemplates_ = false; - } bool getSingletonsAsTemplates() const { return singletonsAsTemplates_; } - - // A null add-on ID means that the compartment is not associated with an - // add-on. - JSAddonId* addonIdOrNull() const { return addonId_; } - CompartmentOptions& setAddonId(JSAddonId* id) { - addonId_ = id; - return *this; - } - - CompartmentOptions& setTrace(JSTraceOp op) { - traceGlobal_ = op; - return *this; - } - JSTraceOp getTrace() const { - return traceGlobal_; - } - - bool preserveJitCode() const { return preserveJitCode_; } - CompartmentOptions& setPreserveJitCode(bool flag) { - preserveJitCode_ = flag; + CompartmentBehaviors& setSingletonsAsValues() { + singletonsAsTemplates_ = false; return *this; } private: JSVersion version_; - bool invisibleToDebugger_; - bool mergeable_; bool discardSource_; bool disableLazyParsing_; - bool cloneSingletons_; Override extraWarningsOverride_; - union { - ZoneSpecifier spec; - void* pointer; // js::Zone* is not exposed in the API. - } zone_; - JSTraceOp traceGlobal_; // To XDR singletons, we need to ensure that all singletons are all used as // templates, by making JSOP_OBJECT return a clone of the JSScript // singleton, instead of returning the value which is baked in the JSScript. bool singletonsAsTemplates_; - - JSAddonId* addonId_; - bool preserveJitCode_; }; -JS_PUBLIC_API(CompartmentOptions&) -CompartmentOptionsRef(JSCompartment* compartment); +/** + * CompartmentOptions specifies compartment characteristics: both those that + * can't be changed on a compartment once it's been created + * (CompartmentCreationOptions), and those that can be changed on an existing + * compartment (CompartmentBehaviors). + */ +class JS_PUBLIC_API(CompartmentOptions) +{ + public: + explicit CompartmentOptions() + : creationOptions_(), + behaviors_() + {} -JS_PUBLIC_API(CompartmentOptions&) -CompartmentOptionsRef(JSObject* obj); + CompartmentOptions(const CompartmentCreationOptions& compartmentCreation, + const CompartmentBehaviors& compartmentBehaviors) + : creationOptions_(compartmentCreation), + behaviors_(compartmentBehaviors) + {} -JS_PUBLIC_API(CompartmentOptions&) -CompartmentOptionsRef(JSContext* cx); + // CompartmentCreationOptions specify fundamental compartment + // characteristics that must be specified when the compartment is created, + // that can't be changed after the compartment is created. + CompartmentCreationOptions& creationOptions() { + return creationOptions_; + } + const CompartmentCreationOptions& creationOptions() const { + return creationOptions_; + } + + // CompartmentBehaviors specify compartment characteristics that can be + // changed after the compartment is created. + CompartmentBehaviors& behaviors() { + return behaviors_; + } + const CompartmentBehaviors& behaviors() const { + return behaviors_; + } + + private: + CompartmentCreationOptions creationOptions_; + CompartmentBehaviors behaviors_; +}; + +JS_PUBLIC_API(const CompartmentCreationOptions&) +CompartmentCreationOptionsRef(JSCompartment* compartment); + +JS_PUBLIC_API(const CompartmentCreationOptions&) +CompartmentCreationOptionsRef(JSObject* obj); + +JS_PUBLIC_API(const CompartmentCreationOptions&) +CompartmentCreationOptionsRef(JSContext* cx); + +JS_PUBLIC_API(CompartmentBehaviors&) +CompartmentBehaviorsRef(JSCompartment* compartment); + +JS_PUBLIC_API(CompartmentBehaviors&) +CompartmentBehaviorsRef(JSObject* obj); + +JS_PUBLIC_API(CompartmentBehaviors&) +CompartmentBehaviorsRef(JSContext* cx); /** * During global creation, we fire notifications to callbacks registered diff --git a/js/src/jscntxt.cpp b/js/src/jscntxt.cpp index f020bf15a86d..2421f88e086c 100644 --- a/js/src/jscntxt.cpp +++ b/js/src/jscntxt.cpp @@ -398,13 +398,13 @@ checkReportFlags(JSContext* cx, unsigned* flags) JSScript* script = cx->currentScript(&pc); if (script && IsCheckStrictOp(JSOp(*pc))) *flags &= ~JSREPORT_WARNING; - else if (cx->compartment()->options().extraWarnings(cx)) + else if (cx->compartment()->behaviors().extraWarnings(cx)) *flags |= JSREPORT_WARNING; else return true; } else if (JSREPORT_IS_STRICT(*flags)) { /* Warning/error only when JSOPTION_STRICT is set. */ - if (!cx->compartment()->options().extraWarnings(cx)) + if (!cx->compartment()->behaviors().extraWarnings(cx)) return true; } @@ -1160,8 +1160,8 @@ JSContext::findVersion() const if (JSScript* script = currentScript(nullptr, ALLOW_CROSS_COMPARTMENT)) return script->getVersion(); - if (compartment() && compartment()->options().version() != JSVERSION_UNKNOWN) - return compartment()->options().version(); + if (compartment() && compartment()->behaviors().version() != JSVERSION_UNKNOWN) + return compartment()->behaviors().version(); return runtime()->defaultVersion(); } diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index 749d8e94b83c..4dd8521caf59 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -41,7 +41,8 @@ using mozilla::DebugOnly; using mozilla::PodArrayZero; JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = JS::CompartmentOptions()) - : options_(options), + : creationOptions_(options.creationOptions()), + behaviors_(options.behaviors()), zone_(zone), runtime_(zone->runtimeFromMainThread()), principals_(nullptr), @@ -51,7 +52,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = warnedAboutFlagsArgument(false), warnedAboutExprClosure(false), warnedAboutRegExpMultiline(false), - addonId(options.addonIdOrNull()), #ifdef DEBUG firedOnNewGlobalObject(false), #endif @@ -71,7 +71,6 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = lazyArrayBuffers(nullptr), nonSyntacticLexicalScopes_(nullptr), gcIncomingGrayPointers(nullptr), - gcPreserveJitCode(options.preserveJitCode()), debugModeBits(0), watchpointMap(nullptr), scriptCountsMap(nullptr), @@ -88,7 +87,8 @@ JSCompartment::JSCompartment(Zone* zone, const JS::CompartmentOptions& options = { PodArrayZero(sawDeprecatedLanguageExtension); runtime_->numCompartments++; - MOZ_ASSERT_IF(options.mergeable(), options.invisibleToDebugger()); + MOZ_ASSERT_IF(creationOptions_.mergeable(), + creationOptions_.invisibleToDebugger()); } JSCompartment::~JSCompartment() @@ -1148,7 +1148,7 @@ JSCompartment::reportTelemetry() // Hazard analysis can't tell that the telemetry callbacks don't GC. JS::AutoSuppressGCAnalysis nogc; - int id = addonId + int id = creationOptions_.addonIdOrNull() ? JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS : JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT; @@ -1163,7 +1163,9 @@ void JSCompartment::addTelemetry(const char* filename, DeprecatedLanguageExtension e) { // Only report telemetry for web content and add-ons, not chrome JS. - if (isSystem_ || (!addonId && (!filename || strncmp(filename, "http", 4) != 0))) + if (isSystem_) + return; + if (!creationOptions_.addonIdOrNull() && (!filename || strncmp(filename, "http", 4) != 0)) return; sawDeprecatedLanguageExtension[e] = true; diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index 7552cd2cf9d5..8951384c544c 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -223,7 +223,8 @@ class WeakMapBase; struct JSCompartment { - JS::CompartmentOptions options_; + const JS::CompartmentCreationOptions creationOptions_; + JS::CompartmentBehaviors behaviors_; private: JS::Zone* zone_; @@ -280,10 +281,6 @@ struct JSCompartment bool warnedAboutExprClosure; bool warnedAboutRegExpMultiline; - // A null add-on ID means that the compartment is not associated with an - // add-on. - JSAddonId* const addonId; - #ifdef DEBUG bool firedOnNewGlobalObject; #endif @@ -312,8 +309,10 @@ struct JSCompartment JS::Zone* zone() { return zone_; } const JS::Zone* zone() const { return zone_; } - JS::CompartmentOptions& options() { return options_; } - const JS::CompartmentOptions& options() const { return options_; } + + const JS::CompartmentCreationOptions& creationOptions() const { return creationOptions_; } + JS::CompartmentBehaviors& behaviors() { return behaviors_; } + const JS::CompartmentBehaviors& behaviors() const { return behaviors_; } JSRuntime* runtimeFromMainThread() { MOZ_ASSERT(CurrentThreadCanAccessRuntime(runtime_)); @@ -473,9 +472,6 @@ struct JSCompartment JSObject* gcIncomingGrayPointers; private: - /* Whether to preserve JIT code on non-shrinking GCs. */ - bool gcPreserveJitCode; - enum { IsDebuggee = 1 << 0, DebuggerObservesAllExecution = 1 << 1, @@ -553,7 +549,8 @@ struct JSCompartment void traceOutgoingCrossCompartmentWrappers(JSTracer* trc); static void traceIncomingCrossCompartmentEdgesForZoneGC(JSTracer* trc); - bool preserveJitCode() { return gcPreserveJitCode; } + /* Whether to preserve JIT code on non-shrinking GCs. */ + bool preserveJitCode() { return creationOptions_.preserveJitCode(); } void sweepAfterMinorGC(); diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index 868af1a99cce..8040117bed44 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -727,7 +727,7 @@ ErrorReport::ReportAddonExceptionToTelementry(JSContext* cx) return; JSCompartment* comp = stack->compartment(); - JSAddonId* addonId = comp->addonId; + JSAddonId* addonId = comp->creationOptions().addonIdOrNull(); // We only want to send the report if the scope that just have thrown belongs to an add-on. // Let's check the compartment of the youngest function on the stack, to determine that. diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index c1568822c39d..99ee99ee1b53 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -6784,9 +6784,11 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target) { // The source compartment must be specifically flagged as mergable. This // also implies that the compartment is not visible to the debugger. - MOZ_ASSERT(source->options_.mergeable()); + MOZ_ASSERT(source->creationOptions_.mergeable()); + MOZ_ASSERT(source->creationOptions_.invisibleToDebugger()); - MOZ_ASSERT(source->addonId == target->addonId); + MOZ_ASSERT(source->creationOptions().addonIdOrNull() == + target->creationOptions().addonIdOrNull()); JSRuntime* rt = source->runtimeFromMainThread(); diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 65319beab980..a5d66dc672b5 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1275,7 +1275,7 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin { /* NB: Keep this in sync with XDRObjectLiteral. */ MOZ_ASSERT_IF(obj->isSingleton(), - JS::CompartmentOptionsRef(cx).getSingletonsAsTemplates()); + cx->compartment()->behaviors().getSingletonsAsTemplates()); MOZ_ASSERT(obj->is() || obj->is() || obj->is() || obj->is()); MOZ_ASSERT(newKind != SingletonObject); @@ -1389,7 +1389,7 @@ js::XDRObjectLiteral(XDRState* xdr, MutableHandleObject obj) JSContext* cx = xdr->cx(); MOZ_ASSERT_IF(mode == XDR_ENCODE && obj->isSingleton(), - JS::CompartmentOptionsRef(cx).getSingletonsAsTemplates()); + cx->compartment()->behaviors().getSingletonsAsTemplates()); // Distinguish between objects and array classes. uint32_t isArray = 0; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 71914c725a86..7f69df123543 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -658,8 +658,10 @@ js::XDRScript(XDRState* xdr, HandleObject enclosingScopeArg, HandleScript // JSOP_OBJECT that then got modified. So throw if we're not // cloning in JSOP_OBJECT or if we ever didn't clone in it in the // past. - const JS::CompartmentOptions& opts = JS::CompartmentOptionsRef(cx); - if (!opts.cloneSingletons() || !opts.getSingletonsAsTemplates()) { + JSCompartment* comp = cx->compartment(); + if (!comp->creationOptions().cloneSingletons() || + !comp->behaviors().getSingletonsAsTemplates()) + { JS_ReportError(cx, "Can't serialize a run-once non-function script " "when we're not doing singleton cloning"); diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index f008a3fa590a..b7e90943b8ef 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -1349,14 +1349,14 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp) { if (saveBytecode) { - if (!JS::CompartmentOptionsRef(cx).cloneSingletons()) { + if (!JS::CompartmentCreationOptionsRef(cx).cloneSingletons()) { JS_ReportErrorNumber(cx, my_GetErrorMessage, nullptr, JSSMSG_CACHE_SINGLETON_FAILED); return false; } // cloneSingletons implies that singletons are used as template objects. - MOZ_ASSERT(JS::CompartmentOptionsRef(cx).getSingletonsAsTemplates()); + MOZ_ASSERT(JS::CompartmentBehaviorsRef(cx).getSingletonsAsTemplates()); } if (loadBytecode) { @@ -2760,7 +2760,7 @@ WorkerMain(void* arg) JSAutoRequest ar(cx); JS::CompartmentOptions compartmentOptions; - compartmentOptions.setVersion(JSVERSION_DEFAULT); + compartmentOptions.behaviors().setVersion(JSVERSION_DEFAULT); RootedObject global(cx, NewGlobalObject(cx, compartmentOptions, nullptr)); if (!global) break; @@ -3954,33 +3954,38 @@ static bool NewGlobal(JSContext* cx, unsigned argc, Value* vp) { JSPrincipals* principals = nullptr; + JS::CompartmentOptions options; - options.setVersion(JSVERSION_DEFAULT); + + JS::CompartmentCreationOptions& creationOptions = options.creationOptions(); + JS::CompartmentBehaviors& behaviors = options.behaviors(); + + behaviors.setVersion(JSVERSION_DEFAULT); CallArgs args = CallArgsFromVp(argc, vp); if (args.length() == 1 && args[0].isObject()) { RootedObject opts(cx, &args[0].toObject()); RootedValue v(cx); - if (!JS_GetProperty(cx, opts, "sameZoneAs", &v)) - return false; - if (v.isObject()) - options.setSameZoneAs(UncheckedUnwrap(&v.toObject())); - if (!JS_GetProperty(cx, opts, "invisibleToDebugger", &v)) return false; if (v.isBoolean()) - options.setInvisibleToDebugger(v.toBoolean()); + creationOptions.setInvisibleToDebugger(v.toBoolean()); if (!JS_GetProperty(cx, opts, "cloneSingletons", &v)) return false; if (v.isBoolean()) - options.setCloneSingletons(v.toBoolean()); + creationOptions.setCloneSingletons(v.toBoolean()); + + if (!JS_GetProperty(cx, opts, "sameZoneAs", &v)) + return false; + if (v.isObject()) + creationOptions.setSameZoneAs(UncheckedUnwrap(&v.toObject())); if (!JS_GetProperty(cx, opts, "disableLazyParsing", &v)) return false; if (v.isBoolean()) - options.setDisableLazyParsing(v.toBoolean()); + behaviors.setDisableLazyParsing(v.toBoolean()); if (!JS_GetProperty(cx, opts, "principal", &v)) return false; @@ -6508,10 +6513,9 @@ Shell(JSContext* cx, OptionParser* op, char** envp) if (op->getBoolOption("disable-oom-functions")) disableOOMFunctions = true; - RootedObject glob(cx); JS::CompartmentOptions options; - options.setVersion(JSVERSION_DEFAULT); - glob = NewGlobalObject(cx, options, nullptr); + options.behaviors().setVersion(JSVERSION_DEFAULT); + RootedObject glob(cx, NewGlobalObject(cx, options, nullptr)); if (!glob) return 1; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 57254de15498..90a307800e83 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -1661,7 +1661,7 @@ void Debugger::slowPathOnNewGlobalObject(JSContext* cx, Handle global) { MOZ_ASSERT(!JS_CLIST_IS_EMPTY(&cx->runtime()->onNewGlobalObjectWatchers)); - if (global->compartment()->options().invisibleToDebugger()) + if (global->compartment()->creationOptions().invisibleToDebugger()) return; /* @@ -3144,7 +3144,7 @@ Debugger::addAllGlobalsAsDebuggees(JSContext* cx, unsigned argc, Value* vp) THIS_DEBUGGER(cx, argc, vp, "addAllGlobalsAsDebuggees", args, dbg); for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) { for (CompartmentsInZoneIter c(zone); !c.done(); c.next()) { - if (c == dbg->object->compartment() || c->options().invisibleToDebugger()) + if (c == dbg->object->compartment() || c->creationOptions().invisibleToDebugger()) continue; c->scheduledForDestruction = false; GlobalObject* global = c->maybeGlobal(); @@ -3365,7 +3365,7 @@ Debugger::addDebuggeeGlobal(JSContext* cx, Handle global) // with certain testing aides we expose in the shell, so just make addDebuggee // throw in that case. JSCompartment* debuggeeCompartment = global->compartment(); - if (debuggeeCompartment->options().invisibleToDebugger()) { + if (debuggeeCompartment->creationOptions().invisibleToDebugger()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_CANT_DEBUG_GLOBAL); return false; @@ -4247,7 +4247,7 @@ Debugger::findAllGlobals(JSContext* cx, unsigned argc, Value* vp) JS::AutoCheckCannotGC nogc; for (CompartmentsIter c(cx->runtime(), SkipAtoms); !c.done(); c.next()) { - if (c->options().invisibleToDebugger()) + if (c->creationOptions().invisibleToDebugger()) continue; c->scheduledForDestruction = false; @@ -4301,7 +4301,7 @@ Debugger::makeGlobalObjectReference(JSContext* cx, unsigned argc, Value* vp) // then from it we can reach function objects, scripts, environments, etc., // none of which we're ever supposed to see. JSCompartment* globalCompartment = global->compartment(); - if (globalCompartment->options().invisibleToDebugger()) { + if (globalCompartment->creationOptions().invisibleToDebugger()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_INVISIBLE_COMPARTMENT); return false; @@ -7802,7 +7802,7 @@ DebuggerObject_unwrap(JSContext* cx, unsigned argc, Value* vp) // invisible-to-Debugger global. (If our referent is a *wrapper* to such, // and the wrapper is in a visible compartment, that's fine.) JSCompartment* unwrappedCompartment = unwrapped->compartment(); - if (unwrappedCompartment->options().invisibleToDebugger()) { + if (unwrappedCompartment->creationOptions().invisibleToDebugger()) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_DEBUG_INVISIBLE_COMPARTMENT); return false; diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index a54458738599..0d021051615e 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -117,8 +117,9 @@ class DebuggerWeakMap : private WeakMap, Relocata template bool relookupOrAdd(AddPtr& p, const KeyInput& k, const ValueInput& v) { MOZ_ASSERT(v->compartment() == this->compartment); - MOZ_ASSERT(!k->compartment()->options_.mergeable()); - MOZ_ASSERT_IF(!InvisibleKeysOk, !k->compartment()->options_.invisibleToDebugger()); + MOZ_ASSERT(!k->compartment()->creationOptions().mergeable()); + MOZ_ASSERT_IF(!InvisibleKeysOk, + !k->compartment()->creationOptions().invisibleToDebugger()); MOZ_ASSERT(!Base::has(k)); if (!incZoneCount(k->zone())) return false; @@ -1081,7 +1082,7 @@ Debugger::onNewScript(JSContext* cx, HandleScript script) { // We early return in slowPathOnNewScript for self-hosted scripts, so we can // ignore those in our assertion here. - MOZ_ASSERT_IF(!script->compartment()->options().invisibleToDebugger() && + MOZ_ASSERT_IF(!script->compartment()->creationOptions().invisibleToDebugger() && !script->selfHosted(), script->compartment()->firedOnNewGlobalObject); if (script->compartment()->isDebuggee()) diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index f88f67d7cd71..6d5af074b874 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -280,20 +280,21 @@ GlobalObject::new_(JSContext* cx, const Class* clasp, JSPrincipals* principals, JSRuntime* rt = cx->runtime(); + auto zoneSpecifier = options.creationOptions().zoneSpecifier(); Zone* zone; - if (options.zoneSpecifier() == JS::SystemZone) + if (zoneSpecifier == JS::SystemZone) zone = rt->gc.systemZone; - else if (options.zoneSpecifier() == JS::FreshZone) + else if (zoneSpecifier == JS::FreshZone) zone = nullptr; else - zone = static_cast(options.zonePointer()); + zone = static_cast(options.creationOptions().zonePointer()); JSCompartment* compartment = NewCompartment(cx, zone, principals, options); if (!compartment) return nullptr; // Lazily create the system zone. - if (!rt->gc.systemZone && options.zoneSpecifier() == JS::SystemZone) { + if (!rt->gc.systemZone && zoneSpecifier == JS::SystemZone) { rt->gc.systemZone = compartment->zone(); rt->gc.systemZone->isSystem = true; } diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index a31a8e90b36c..5c76855d6a10 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -350,20 +350,26 @@ js::StartOffThreadParseScript(JSContext* cx, const ReadOnlyCompileOptions& optio // which could require barriers on the atoms compartment. gc::AutoSuppressGC suppress(cx); - JS::CompartmentOptions compartmentOptions(cx->compartment()->options()); - compartmentOptions.setZone(JS::FreshZone); - compartmentOptions.setInvisibleToDebugger(true); - compartmentOptions.setMergeable(true); + JSCompartment* currentCompartment = cx->compartment(); + + JS::CompartmentOptions compartmentOptions(currentCompartment->creationOptions(), + currentCompartment->behaviors()); + + auto& creationOptions = compartmentOptions.creationOptions(); + + creationOptions.setInvisibleToDebugger(true) + .setMergeable(true) + .setZone(JS::FreshZone); // Don't falsely inherit the host's global trace hook. - compartmentOptions.setTrace(nullptr); + creationOptions.setTrace(nullptr); JSObject* global = JS_NewGlobalObject(cx, &parseTaskGlobalClass, nullptr, JS::FireOnNewGlobalHook, compartmentOptions); if (!global) return false; - JS_SetCompartmentPrincipals(global->compartment(), cx->compartment()->principals()); + JS_SetCompartmentPrincipals(global->compartment(), currentCompartment->principals()); // Initialize all classes required for parsing while still on the main // thread, for both the target and the new global so that prototype diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 3d399610ff25..736bc1aef7ae 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -2988,13 +2988,13 @@ END_CASE(JSOP_SYMBOL) CASE(JSOP_OBJECT) { ReservedRooted ref(&rootObject0, script->getObject(REGS.pc)); - if (JS::CompartmentOptionsRef(cx).cloneSingletons()) { + if (cx->compartment()->creationOptions().cloneSingletons()) { JSObject* obj = DeepCloneObjectLiteral(cx, ref, TenuredObject); if (!obj) goto error; PUSH_OBJECT(*obj); } else { - JS::CompartmentOptionsRef(cx).setSingletonsAsValues(); + cx->compartment()->behaviors().setSingletonsAsValues(); PUSH_OBJECT(*ref); } } diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index f0488a546b5e..f86c8fb6b6cf 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -1822,7 +1822,7 @@ GetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id, // // Don't warn if extra warnings not enabled or for random getprop // operations. - if (!cx->compartment()->options().extraWarnings(cx)) + if (!cx->compartment()->behaviors().extraWarnings(cx)) return true; jsbytecode* pc; @@ -2001,7 +2001,7 @@ MaybeReportUndeclaredVarAssignment(JSContext* cx, JSString* propname) // check is needed. if (IsStrictSetPC(pc)) flags = JSREPORT_ERROR; - else if (cx->compartment()->options().extraWarnings(cx)) + else if (cx->compartment()->behaviors().extraWarnings(cx)) flags = JSREPORT_WARNING | JSREPORT_STRICT; else return true; diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 491aeb6dfbe9..e20ae08cdf41 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -1719,8 +1719,8 @@ JSRuntime::createSelfHostingGlobal(JSContext* cx) MOZ_ASSERT(!cx->runtime()->isAtomsCompartment(cx->compartment())); JS::CompartmentOptions options; - options.setDiscardSource(true); - options.setZone(JS::FreshZone); + options.creationOptions().setZone(JS::FreshZone); + options.behaviors().setDiscardSource(true); JSCompartment* compartment = NewCompartment(cx, nullptr, nullptr, options); if (!compartment) diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index a8787a44dbeb..4d33fcd825ae 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -542,10 +542,13 @@ mozJSComponentLoader::PrepareObjectForLocation(JSContext* aCx, NS_ENSURE_SUCCESS(rv, nullptr); CompartmentOptions options; - options.setZone(SystemZone) - .setVersion(JSVERSION_LATEST) + + options.creationOptions() + .setZone(SystemZone) .setAddonId(aReuseLoaderGlobal ? nullptr : MapURIToAddonID(aURI)); + options.behaviors().setVersion(JSVERSION_LATEST); + // Defer firing OnNewGlobalObject until after the __URI__ property has // been defined so the JS debugger can tell what module the global is // for diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 73ddd935a16e..17aab1cda33e 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -988,16 +988,18 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin MOZ_ASSERT(principal); JS::CompartmentOptions compartmentOptions; - if (options.sameZoneAs) - compartmentOptions.setSameZoneAs(js::UncheckedUnwrap(options.sameZoneAs)); - else if (options.freshZone) - compartmentOptions.setZone(JS::FreshZone); - else - compartmentOptions.setZone(JS::SystemZone); - compartmentOptions.setInvisibleToDebugger(options.invisibleToDebugger) - .setDiscardSource(options.discardSource) - .setTrace(TraceXPCGlobal); + auto& creationOptions = compartmentOptions.creationOptions(); + + if (options.sameZoneAs) + creationOptions.setSameZoneAs(js::UncheckedUnwrap(options.sameZoneAs)); + else if (options.freshZone) + creationOptions.setZone(JS::FreshZone); + else + creationOptions.setZone(JS::SystemZone); + + creationOptions.setInvisibleToDebugger(options.invisibleToDebugger) + .setTrace(TraceXPCGlobal); // Try to figure out any addon this sandbox should be associated with. // The addon could have been passed in directly, as part of the metadata, @@ -1011,7 +1013,9 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin addonId = id; } - compartmentOptions.setAddonId(addonId); + creationOptions.setAddonId(addonId); + + compartmentOptions.behaviors().setDiscardSource(options.discardSource); const Class* clasp = options.writeToGlobalPrototype ? &SandboxWriteToProtoClass diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index 1c89cc3cac82..ed997d4afc83 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -1478,8 +1478,8 @@ XRE_XPCShellMain(int argc, char** argv, char** envp) // Make the default XPCShell global use a fresh zone (rather than the // System Zone) to improve cross-zone test coverage. JS::CompartmentOptions options; - options.setZone(JS::FreshZone) - .setVersion(JSVERSION_LATEST); + options.creationOptions().setZone(JS::FreshZone); + options.behaviors().setVersion(JSVERSION_LATEST); nsCOMPtr holder; rv = xpc->InitClassesWithNewWrappedGlobal(cx, static_cast(backstagePass), @@ -1504,7 +1504,7 @@ XRE_XPCShellMain(int argc, char** argv, char** envp) // Even if we're building in a configuration where source is // discarded, there's no reason to do that on XPCShell, and doing so // might break various automation scripts. - JS::CompartmentOptionsRef(glob).setDiscardSource(false); + JS::CompartmentBehaviorsRef(glob).setDiscardSource(false); backstagePass->SetGlobalObject(glob); diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index 273e1465b8f0..f22eaa66a424 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -182,7 +182,7 @@ XPCWrappedNative::WrapNewGlobal(xpcObjectHelper& nativeHelper, MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL); // Create the global. - aOptions.setTrace(XPCWrappedNative::Trace); + aOptions.creationOptions().setTrace(XPCWrappedNative::Trace); RootedObject global(cx, xpc::CreateGlobalObject(cx, clasp, principal, aOptions)); if (!global) return NS_ERROR_FAILURE; diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 801ee252ebfc..cf5c614b01c7 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -411,14 +411,14 @@ InitGlobalObject(JSContext* aJSContext, JS::Handle aGlobal, uint32_t isSystem = status == nsIPrincipal::APP_STATUS_PRIVILEGED || status == nsIPrincipal::APP_STATUS_CERTIFIED; } - JS::CompartmentOptionsRef(aGlobal).setDiscardSource(isSystem); + JS::CompartmentBehaviorsRef(aGlobal).setDiscardSource(isSystem); } if (ExtraWarningsForSystemJS()) { nsIPrincipal* prin = GetObjectPrincipal(aGlobal); bool isSystem = nsContentUtils::IsSystemPrincipal(prin); if (isSystem) - JS::CompartmentOptionsRef(aGlobal).extraWarningsOverride().set(true); + JS::CompartmentBehaviorsRef(aGlobal).extraWarningsOverride().set(true); } // Stuff coming through this path always ends up as a DOM global. diff --git a/netwerk/base/ProxyAutoConfig.cpp b/netwerk/base/ProxyAutoConfig.cpp index 660cefda01dc..deba4f8738a8 100644 --- a/netwerk/base/ProxyAutoConfig.cpp +++ b/netwerk/base/ProxyAutoConfig.cpp @@ -646,8 +646,8 @@ private: JSAutoRequest ar(mContext); JS::CompartmentOptions options; - options.setZone(JS::SystemZone) - .setVersion(JSVERSION_LATEST); + options.creationOptions().setZone(JS::SystemZone); + options.behaviors().setVersion(JSVERSION_LATEST); mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr, JS::DontFireOnNewGlobalHook, options); NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY); diff --git a/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp index f3374d466d2a..70feef96313f 100644 --- a/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp +++ b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp @@ -93,7 +93,7 @@ CreateGlobalAndRunTest(JSRuntime* rt, JSContext* cx) }; JS::CompartmentOptions options; - options.setVersion(JSVERSION_LATEST); + options.behaviors().setVersion(JSVERSION_LATEST); JS::PersistentRootedObject global(cx); global = JS_NewGlobalObject(cx, &GlobalClass, nullptr, JS::FireOnNewGlobalHook, options); ASSERT_TRUE(global != nullptr); From cde8e15ecd179e64ba5131557ecfa11e22e292d7 Mon Sep 17 00:00:00 2001 From: Edwin Flores Date: Wed, 30 Dec 2015 17:03:24 -0500 Subject: [PATCH 36/36] Bug 1235605 - Use CheckedInt in Deinterlacer and make its buffer allocation fallible. r=tn --- image/Deinterlacer.cpp | 18 ++++++++++++++---- image/Deinterlacer.h | 1 + image/decoders/nsGIFDecoder2.cpp | 6 ++++++ image/test/crashtests/1235605.gif | Bin 0 -> 2360 bytes image/test/crashtests/crashtests.list | 1 + 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 image/test/crashtests/1235605.gif diff --git a/image/Deinterlacer.cpp b/image/Deinterlacer.cpp index 96a6512c3aa3..73ef29fd0538 100644 --- a/image/Deinterlacer.cpp +++ b/image/Deinterlacer.cpp @@ -6,16 +6,24 @@ #include "Downscaler.h" +#include "mozilla/UniquePtrExtensions.h" namespace mozilla { namespace image { Deinterlacer::Deinterlacer(const nsIntSize& aImageSize) : mImageSize(aImageSize) - , mBuffer(MakeUnique(mImageSize.width * - mImageSize.height * - sizeof(uint32_t))) -{ } +{ + CheckedInt bufferSize = mImageSize.width; + bufferSize *= mImageSize.height; + bufferSize *= sizeof(uint32_t); + + if (!bufferSize.isValid()) { + return; + } + + mBuffer = MakeUniqueFallible(bufferSize.value()); +} uint32_t Deinterlacer::RowSize() const @@ -27,6 +35,7 @@ uint8_t* Deinterlacer::RowBuffer(uint32_t aRow) { uint32_t offset = aRow * RowSize(); + MOZ_ASSERT(IsValid(), "Deinterlacer in invalid state"); MOZ_ASSERT(offset < mImageSize.width * mImageSize.height * sizeof(uint32_t), "Row is outside of image"); return mBuffer.get() + offset; @@ -35,6 +44,7 @@ Deinterlacer::RowBuffer(uint32_t aRow) void Deinterlacer::PropagatePassToDownscaler(Downscaler& aDownscaler) { + MOZ_ASSERT(IsValid(), "Deinterlacer in invalid state"); for (int32_t row = 0 ; row < mImageSize.height ; ++row) { memcpy(aDownscaler.RowBuffer(), RowBuffer(row), RowSize()); aDownscaler.CommitRow(); diff --git a/image/Deinterlacer.h b/image/Deinterlacer.h index 74ffd86ea4d1..93a720423d8a 100644 --- a/image/Deinterlacer.h +++ b/image/Deinterlacer.h @@ -32,6 +32,7 @@ class Deinterlacer { public: explicit Deinterlacer(const nsIntSize& aImageSize); + bool IsValid() { return !!mBuffer; } uint8_t* RowBuffer(uint32_t aRow); void PropagatePassToDownscaler(Downscaler& aDownscaler); diff --git a/image/decoders/nsGIFDecoder2.cpp b/image/decoders/nsGIFDecoder2.cpp index d24b47aa1660..b100a08d554d 100644 --- a/image/decoders/nsGIFDecoder2.cpp +++ b/image/decoders/nsGIFDecoder2.cpp @@ -1178,6 +1178,12 @@ nsGIFDecoder2::WriteInternal(const char* aBuffer, uint32_t aCount) mGIFStruct.ipass = 1; if (mDownscaler) { mDeinterlacer.emplace(mDownscaler->FrameSize()); + + if (!mDeinterlacer->IsValid()) { + mDeinterlacer.reset(); + mGIFStruct.state = gif_error; + break; + } } } else { mGIFStruct.interlaced = false; diff --git a/image/test/crashtests/1235605.gif b/image/test/crashtests/1235605.gif new file mode 100644 index 0000000000000000000000000000000000000000..e7c3ea0b876b0cbbd42b49c65b54878f32f1e7d8 GIT binary patch literal 2360 zcmZ?wbhEHb{P+L&|K|-1{qq)_dtSBeJ=@l&M=vBDVOVIxKnf5bMKLb5Ot>UK;&>(T zX(UdLg*atIscImkijj~46nR`>iy9)RJO)(%aDWYLU|;|uR2dYTNadi}iL6}#nS;ru zq9YnGO-B`hcpfCC_@CR)HRQ6hV}PrXo&hr`8WexBFo*$Z9gsXIFF3Gp2b}a=z1QOP z+1>vu!1AyEL*>~Se*SOqJ*s@$F6xmSOP9W0#-ICV>OeZN#V9N90bscBG0IHfyv9<17Dcu9q#kx_y)6?8d=MMfq`>M|H{*E z`4`XG19mt+(0Fi|@-ck+-#k0;$kF5@6Y)6o%YOlemImu$=FaTu2{wkV)w^aY%y9_& zE`)F<1JD+901e}NurLN&`QiV&|Bd>hHb-SXFKAjirM@D6S@S%uMm}`SSoy%1bYNgW zq#3M=K!QwgAFl!X_zx`1-~7M*zqy6=Zbig#!=*F1SC-2&TB4YOl)xad%nX#)Q2-LG z48Q+3PJhOc*Rp8aq#_heIP)#KQ_&$n}6Yu{9O3)o6G7T zr;3Bk>yT|i*Z&6QFJ^`}{~MR`lqx>C?vTFS;nSgtuhOrc%~N*CM%Ip#jqXk?3em0p z0kN8qfuDh!p~V5A1EWYpz zFeV{x!b&1*02Od>PyPP?<$vR^J7!lH6c`$?X=P$W7e_V=Z28Ck%nU8F*}FgcaBJQA z&IflT$QA_@GZB#jE&!QO%G%%mSs5COgo-5%F7LawNkm`;C(8yD-MBco(hVvb8Gt2&sd>aK`w5LKOO`&V#