From d77aa7d59a78bead8676043fc9f3f54d074f5697 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Wed, 22 Mar 2017 17:07:25 -0400 Subject: [PATCH 01/96] Bug 1333858 - Intersect should be fallible on overflow. r=daoshengmu MozReview-Commit-ID: 6lmIKKyXXah --- dom/canvas/WebGLContext.cpp | 54 ++++++++++++++++++++++--------- dom/canvas/WebGLContext.h | 7 ++-- dom/canvas/WebGLContextGL.cpp | 34 +++++++++++-------- dom/canvas/WebGLTextureUpload.cpp | 14 +++++--- 4 files changed, 71 insertions(+), 38 deletions(-) diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 82f382f63471..52fdd160824d 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -2225,25 +2225,47 @@ ScopedLazyBind::UnwrapImpl() //////////////////////////////////////// -void -Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize, - uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst, - uint32_t* const out_intSize) +bool +Intersect(const int32_t srcSize, const int32_t read0, const int32_t readSize, + int32_t* const out_intRead0, int32_t* const out_intWrite0, + int32_t* const out_intSize) { - // Only >0 if dstStartInSrc is >0: - // 0 3 // src coords - // | [========] // dst box - // ^--^ - *out_intStartInSrc = std::max(0, dstStartInSrc); + MOZ_ASSERT(srcSize >= 0); + MOZ_ASSERT(readSize >= 0); + const auto read1 = int64_t(read0) + readSize; - // Only >0 if dstStartInSrc is <0: - //-6 0 // src coords - // [=====|==] // dst box - // ^-----^ - *out_intStartInDst = std::max(0, 0 - dstStartInSrc); + int32_t intRead0 = read0; // Clearly doesn't need validation. + int64_t intWrite0 = 0; + int64_t intSize = readSize; - int32_t intEndInSrc = std::min(srcSize, dstStartInSrc + dstSize); - *out_intSize = std::max(0, intEndInSrc - *out_intStartInSrc); + if (read1 <= 0 || read0 >= srcSize) { + // Disjoint ranges. + intSize = 0; + } else { + if (read0 < 0) { + const auto diff = int64_t(0) - read0; + MOZ_ASSERT(diff >= 0); + intRead0 = 0; + intWrite0 = diff; + intSize -= diff; + } + if (read1 > srcSize) { + const auto diff = int64_t(read1) - srcSize; + MOZ_ASSERT(diff >= 0); + intSize -= diff; + } + + if (!CheckedInt(intWrite0).isValid() || + !CheckedInt(intSize).isValid()) + { + return false; + } + } + + *out_intRead0 = intRead0; + *out_intWrite0 = intWrite0; + *out_intSize = intSize; + return true; } //////////////////////////////////////////////////////////////////////////////// diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index ce0e5e544618..37ac2929bcd0 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -2164,10 +2164,9 @@ private: //// -void -Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize, - uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst, - uint32_t* const out_intSize); +bool +Intersect(int32_t srcSize, int32_t read0, int32_t readSize, int32_t* out_intRead0, + int32_t* out_intWrite0, int32_t* out_intSize); //// diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 0a9ac679d88f..91328e8f5ae4 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -1556,18 +1556,32 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig return; } + //// + + int32_t readX, readY; + int32_t writeX, writeY; + int32_t rwWidth, rwHeight; + if (!Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth) || + !Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight)) + { + ErrorOutOfMemory("readPixels: Bad subrect selection."); + return; + } + //////////////// // Now that the errors are out of the way, on to actually reading! OnBeforeReadCall(); - uint32_t readX, readY; - uint32_t writeX, writeY; - uint32_t rwWidth, rwHeight; - Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth); - Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight); + if (!rwWidth || !rwHeight) { + // Disjoint rects, so we're done already. + DummyReadFramebufferOperation("readPixels"); + return; + } - if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height)) { + if (uint32_t(rwWidth) == width && + uint32_t(rwHeight) == height) + { DoReadPixelsAndConvert(srcFormat->format, x, y, width, height, packFormat, packType, dest, dataLen, rowStride); return; @@ -1586,12 +1600,6 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig //////////////////////////////////// // Read only the in-bounds pixels. - if (!rwWidth || !rwHeight) { - // There aren't any, so we're 'done'. - DummyReadFramebufferOperation("readPixels"); - return; - } - if (IsWebGL2()) { if (!mPixelStore_PackRowLength) { gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, @@ -1611,7 +1619,7 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig uint8_t* row = (uint8_t*)dest + writeX * bytesPerPixel; row += writeY * rowStride; - for (uint32_t j = 0; j < rwHeight; j++) { + for (uint32_t j = 0; j < uint32_t(rwHeight); j++) { DoReadPixelsAndConvert(srcFormat->format, readX, readY+j, rwWidth, 1, packFormat, packType, row, dataLen, rowStride); row += rowStride; diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp index b104f38a8200..80564f8062b2 100644 --- a/dom/canvas/WebGLTextureUpload.cpp +++ b/dom/canvas/WebGLTextureUpload.cpp @@ -2011,11 +2011,15 @@ DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage, //// - uint32_t readX, readY; - uint32_t writeX, writeY; - uint32_t rwWidth, rwHeight; - Intersect(srcTotalWidth, xWithinSrc, dstWidth, &readX, &writeX, &rwWidth); - Intersect(srcTotalHeight, yWithinSrc, dstHeight, &readY, &writeY, &rwHeight); + int32_t readX, readY; + int32_t writeX, writeY; + int32_t rwWidth, rwHeight; + if (!Intersect(srcTotalWidth, xWithinSrc, dstWidth, &readX, &writeX, &rwWidth) || + !Intersect(srcTotalHeight, yWithinSrc, dstHeight, &readY, &writeY, &rwHeight)) + { + webgl->ErrorOutOfMemory("%s: Bad subrect selection.", funcName); + return false; + } writeX += xOffset; writeY += yOffset; From ccc234ac923af33f0ca655021d8ecdbe0702f7fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=83=C2=A9bastien=20Blin?= Date: Tue, 17 Jan 2017 07:03:00 -0500 Subject: [PATCH 02/96] Bug 1298321 - Refactor tests related to getHash. r=francois --- .../url-classifier/tests/mochitest/chrome.ini | 3 +- .../url-classifier/tests/mochitest/head.js | 36 +++++++++++++++ .../tests/mochitest/mochitest.ini | 1 + .../tests/mochitest/test_bug1254766.html | 46 ++----------------- .../test_classifier_changetablepref.html | 42 +---------------- .../tests/mochitest/test_gethash.html | 44 ++---------------- 6 files changed, 49 insertions(+), 123 deletions(-) create mode 100644 toolkit/components/url-classifier/tests/mochitest/head.js diff --git a/toolkit/components/url-classifier/tests/mochitest/chrome.ini b/toolkit/components/url-classifier/tests/mochitest/chrome.ini index 01dcf697d7b8..a6fe2539623c 100644 --- a/toolkit/components/url-classifier/tests/mochitest/chrome.ini +++ b/toolkit/components/url-classifier/tests/mochitest/chrome.ini @@ -9,11 +9,12 @@ support-files = gethash.sjs classifierCommon.js classifierHelper.js + head.js [test_lookup_system_principal.html] [test_classified_annotations.html] tags = trackingprotection -skip-if = os == 'linux' && asan # Bug 1202548 +skip-if = os == 'linux' && asan # Bug 1202548 [test_allowlisted_annotations.html] tags = trackingprotection [test_privatebrowsing_trackingprotection.html] diff --git a/toolkit/components/url-classifier/tests/mochitest/head.js b/toolkit/components/url-classifier/tests/mochitest/head.js new file mode 100644 index 000000000000..897dff87fac9 --- /dev/null +++ b/toolkit/components/url-classifier/tests/mochitest/head.js @@ -0,0 +1,36 @@ +// calculate the fullhash and send it to gethash server +function addCompletionToServer(list, url, mochitestUrl) { + return new Promise(function(resolve, reject) { + var listParam = "list=" + list; + var fullhashParam = "fullhash=" + hash(url); + + var xhr = new XMLHttpRequest; + xhr.open("PUT", mochitestUrl + "?" + listParam + "&" + fullhashParam, true); + xhr.setRequestHeader("Content-Type", "text/plain"); + xhr.onreadystatechange = function() { + if (this.readyState == this.DONE) { + resolve(); + } + }; + xhr.send(); + }); +} + +function hash(str) { + function bytesFromString(str) { + var converter = + SpecialPowers.Cc["@mozilla.org/intl/scriptableunicodeconverter"] + .createInstance(SpecialPowers.Ci.nsIScriptableUnicodeConverter); + converter.charset = "UTF-8"; + return converter.convertToByteArray(str); + } + + var hasher = SpecialPowers.Cc["@mozilla.org/security/hash;1"] + .createInstance(SpecialPowers.Ci.nsICryptoHash); + + var data = bytesFromString(str); + hasher.init(hasher.SHA256); + hasher.update(data, data.length); + + return hasher.finish(true); +} diff --git a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini index 27671fad5958..303308c55397 100644 --- a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini +++ b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini @@ -6,6 +6,7 @@ support-files = classifierHelper.js cleanWorker.js good.js + head.js evil.css evil.css^headers^ evil.js diff --git a/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html b/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html index 1c149406ace9..d8a86e81dd0b 100644 --- a/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html +++ b/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html @@ -13,6 +13,7 @@
 
+
 
 
 
+
+
diff --git a/dom/xslt/crashtests/crashtests.list b/dom/xslt/crashtests/crashtests.list
index 5958655d6473..8e9a9e72dbdf 100644
--- a/dom/xslt/crashtests/crashtests.list
+++ b/dom/xslt/crashtests/crashtests.list
@@ -18,3 +18,4 @@ load 667315.xml
 load 1089049.html
 load 1205163.xml
 load 1243337.xml
+load 1338277.html
diff --git a/dom/xslt/xslt/txExecutionState.cpp b/dom/xslt/xslt/txExecutionState.cpp
index a32fdb0b8065..f7286a0e5d77 100644
--- a/dom/xslt/xslt/txExecutionState.cpp
+++ b/dom/xslt/xslt/txExecutionState.cpp
@@ -529,7 +529,9 @@ txExecutionState::bindVariable(const txExpandedName& aName,
 void
 txExecutionState::removeVariable(const txExpandedName& aName)
 {
-    mLocalVariables->removeVariable(aName);
+    if (mLocalVariables) {
+      mLocalVariables->removeVariable(aName);
+    }
 }
 
 nsresult

From b215cfd1e13f14a0542a02ea2a713d7cc1a744f9 Mon Sep 17 00:00:00 2001
From: Kartikaya Gupta 
Date: Wed, 22 Mar 2017 17:36:25 -0400
Subject: [PATCH 08/96] Bug 1342450 - Rename MOZ_ENABLE_WEBRENDER to
 MOZ_BUILD_WEBRENDER. r=rhunt

MozReview-Commit-ID: 3GkmCJJq8et
---
 gfx/gl/GLLibraryEGL.cpp                               | 2 +-
 gfx/layers/ipc/CompositorBridgeParent.cpp             | 4 ++--
 gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp | 4 ++--
 gfx/thebes/gfxPlatform.cpp                            | 2 +-
 gfx/webrender_bindings/webrender_ffi.h                | 2 +-
 modules/libpref/init/all.js                           | 2 +-
 toolkit/library/gtest/rust/moz.build                  | 2 +-
 toolkit/library/moz.build                             | 2 +-
 toolkit/library/rust/moz.build                        | 2 +-
 toolkit/moz.configure                                 | 4 ++--
 10 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/gfx/gl/GLLibraryEGL.cpp b/gfx/gl/GLLibraryEGL.cpp
index 6cfcf9797ff7..c502f9f0827e 100644
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -154,7 +154,7 @@ IsAccelAngleSupported(const nsCOMPtr& gfxInfo,
     if (CompositorThreadHolder::IsInCompositorThread()) {
         // We can only enter here with WebRender, so assert that this is a
         // WebRender-enabled build.
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
         MOZ_ASSERT(false);
 #endif
         return true;
diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp
index b30b9405e04f..812f126319a0 100644
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1579,7 +1579,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
                                                     TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                                     uint32_t* aIdNamespace)
 {
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
   // Extra guard since this in the parent process and we don't want a malicious
   // child process invoking this codepath before it's ready
   MOZ_RELEASE_ASSERT(false);
@@ -1614,7 +1614,7 @@ CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipel
 bool
 CompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor)
 {
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
   // Extra guard since this in the parent process and we don't want a malicious
   // child process invoking this codepath before it's ready
   MOZ_RELEASE_ASSERT(false);
diff --git a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
index 3f5d968589aa..9369d7317acf 100644
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -203,7 +203,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli
                                                                 TextureFactoryIdentifier* aTextureFactoryIdentifier,
                                                                 uint32_t *aIdNamespace)
 {
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
   // Extra guard since this in the parent process and we don't want a malicious
   // child process invoking this codepath before it's ready
   MOZ_RELEASE_ASSERT(false);
@@ -238,7 +238,7 @@ CrossProcessCompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::Pipeli
 bool
 CrossProcessCompositorBridgeParent::DeallocPWebRenderBridgeParent(PWebRenderBridgeParent* aActor)
 {
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
   // Extra guard since this in the parent process and we don't want a malicious
   // child process invoking this codepath before it's ready
   MOZ_RELEASE_ASSERT(false);
diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp
index 9a4bd2ae07cd..4bf2a68ca35d 100644
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2314,7 +2314,7 @@ gfxPlatform::InitWebRenderConfig()
       NS_LITERAL_CSTRING("FEATURE_FAILURE_SAFE_MODE"));
   }
 
-#ifndef MOZ_ENABLE_WEBRENDER
+#ifndef MOZ_BUILD_WEBRENDER
   featureWebRender.ForceDisable(
     FeatureStatus::Unavailable,
     "Build doesn't include WebRender",
diff --git a/gfx/webrender_bindings/webrender_ffi.h b/gfx/webrender_bindings/webrender_ffi.h
index b4f5a3c009d4..b662785c0d58 100644
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -452,7 +452,7 @@ struct WrVecU8 {
 // an error and causes the build to fail. So for wr_* functions called by
 // destructors in C++ classes, use WR_DESTRUCTOR_SAFE_FUNC instead, which omits
 // the unreachable annotation.
-#ifdef MOZ_ENABLE_WEBRENDER
+#ifdef MOZ_BUILD_WEBRENDER
 #  define WR_INLINE
 #  define WR_FUNC
 #  define WR_DESTRUCTOR_SAFE_FUNC
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 8887ee65770e..1db9a0fa19c7 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5639,7 +5639,7 @@ pref("fuzzing.enabled", false);
 
 // Set advanced layers preferences here.
 pref("layers.advanced.border-layers", false);
-#ifdef MOZ_ENABLE_WEBRENDER
+#ifdef MOZ_BUILD_WEBRENDER
 pref("layers.advanced.caret-layers", true);
 #else
 pref("layers.advanced.caret-layers", false);
diff --git a/toolkit/library/gtest/rust/moz.build b/toolkit/library/gtest/rust/moz.build
index 26ba750e09f3..b62f55543d83 100644
--- a/toolkit/library/gtest/rust/moz.build
+++ b/toolkit/library/gtest/rust/moz.build
@@ -11,7 +11,7 @@ if CONFIG['MOZ_STYLO']:
     if CONFIG['MOZ_STYLO_BINDGEN']:
         features += ['bindgen']
 
-if CONFIG['MOZ_ENABLE_WEBRENDER']:
+if CONFIG['MOZ_BUILD_WEBRENDER']:
     features += ['quantum_render']
 
 RustLibrary('gkrust-gtest', features, '../..')
diff --git a/toolkit/library/moz.build b/toolkit/library/moz.build
index fa6755ae4c59..d8c694953bdb 100644
--- a/toolkit/library/moz.build
+++ b/toolkit/library/moz.build
@@ -380,7 +380,7 @@ if CONFIG['COMPILE_ENVIRONMENT']:
     FINAL_TARGET_FILES += ['!dependentlibs.list', '!dependentlibs.list.gtest']
 
 # WebRender dependencies
-if CONFIG['MOZ_ENABLE_WEBRENDER']:
+if CONFIG['MOZ_BUILD_WEBRENDER']:
     if CONFIG['OS_ARCH'] == 'Linux':
         OS_LIBS += [
             'GL',
diff --git a/toolkit/library/rust/moz.build b/toolkit/library/rust/moz.build
index 069a8d4ecde7..6db1e217f9f4 100644
--- a/toolkit/library/rust/moz.build
+++ b/toolkit/library/rust/moz.build
@@ -11,7 +11,7 @@ if CONFIG['MOZ_STYLO']:
     if CONFIG['MOZ_STYLO_BINDGEN']:
         features += ['bindgen']
 
-if CONFIG['MOZ_ENABLE_WEBRENDER']:
+if CONFIG['MOZ_BUILD_WEBRENDER']:
     features += ['quantum_render']
 
 RustLibrary('gkrust', features, '..')
diff --git a/toolkit/moz.configure b/toolkit/moz.configure
index e79bbab9cc2d..30b4ba944b36 100644
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -695,9 +695,9 @@ set_config('SERVO_TARGET_DIR', servo_target_dir)
 # WebRender integration
 option('--enable-webrender', help='Include WebRender')
 
-set_config('MOZ_ENABLE_WEBRENDER',
+set_config('MOZ_BUILD_WEBRENDER',
            depends_if('--enable-webrender')(lambda _: True))
-set_define('MOZ_ENABLE_WEBRENDER',
+set_define('MOZ_BUILD_WEBRENDER',
            depends_if('--enable-webrender')(lambda _: True))
 
 # Printing

From 301e315b2fde1d9be0989a55f8466dec7929f9d1 Mon Sep 17 00:00:00 2001
From: Kartikaya Gupta 
Date: Wed, 22 Mar 2017 17:38:09 -0400
Subject: [PATCH 09/96] Bug 1342450 - Extract a MOZ_ENABLE_WEBRENDER from
 MOZ_BUILD_WEBRENDER so that we build but disable by default.
 r=rhunt,froydnj,ted

This adds back a MOZ_ENABLE_WEBRENDER define, which only controls whether or
not WebRender is enabled at runtime. The default behaviour is changed so that:
- if the user specifies --disable-webrender in the mozconfig, WebRender is
  neither built nor enabled
- if the user specifies --enable-webrender in the mozconfig, WebRender is
  built and enabled
- if the user specifies --enable-webrender=build in the mozconfig, WebRender is
  built but not enabled, except on Android where it is neither built nor enabled
- if the user doesn't specify any of the above, the default behaviour is:
  - on nightly/local builds, the same as --enable-webrender=build
  - on other channels (e.g. aurora), the same as --disable-webrender

The net effect is that local/Nightly-automation builds will have WebRender
built-in but not enabled where possible (i.e. not Android). However the user
can override this behaviour via mozconfig options to either not build WebRender
at all, or to enable it in addition to building it.

MozReview-Commit-ID: IM7DdSHkIB
---
 gfx/thebes/gfxPlatform.cpp  | 11 ++++++-----
 modules/libpref/init/all.js |  6 +++++-
 modules/libpref/moz.build   |  2 ++
 toolkit/moz.configure       | 35 ++++++++++++++++++++++++++++++-----
 4 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp
index 4bf2a68ca35d..f61a82a02b57 100644
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2289,12 +2289,13 @@ gfxPlatform::InitWebRenderConfig()
 {
   FeatureState& featureWebRender = gfxConfig::GetFeature(Feature::WEBRENDER);
 
-  featureWebRender.EnableByDefault();
+  featureWebRender.DisableByDefault(
+      FeatureStatus::OptIn,
+      "WebRender is an opt-in feature",
+      NS_LITERAL_CSTRING("FEATURE_FAILURE_DEFAULT_OFF"));
 
-  if (!Preferences::GetBool("gfx.webrender.enabled", false)) {
-    featureWebRender.UserDisable(
-      "User disabled WebRender",
-      NS_LITERAL_CSTRING("FEATURE_FAILURE_WEBRENDER_DISABLED"));
+  if (Preferences::GetBool("gfx.webrender.enabled", false)) {
+    featureWebRender.UserEnable("Enabled by pref");
   }
 
   // WebRender relies on the GPU process when on Windows
diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js
index 1db9a0fa19c7..da28a1d79860 100644
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -818,7 +818,11 @@ pref("gfx.logging.peak-texture-usage.enabled", false);
 
 pref("gfx.ycbcr.accurate-conversion", false);
 
+#ifdef MOZ_ENABLE_WEBRENDER
 pref("gfx.webrender.enabled", true);
+#else
+pref("gfx.webrender.enabled", false);
+#endif
 
 pref("accessibility.browsewithcaret", false);
 pref("accessibility.warn_on_browsewithcaret", true);
@@ -5639,7 +5643,7 @@ pref("fuzzing.enabled", false);
 
 // Set advanced layers preferences here.
 pref("layers.advanced.border-layers", false);
-#ifdef MOZ_BUILD_WEBRENDER
+#ifdef MOZ_ENABLE_WEBRENDER
 pref("layers.advanced.caret-layers", true);
 #else
 pref("layers.advanced.caret-layers", false);
diff --git a/modules/libpref/moz.build b/modules/libpref/moz.build
index cd8b526bc93e..4cfa17fb8a9d 100644
--- a/modules/libpref/moz.build
+++ b/modules/libpref/moz.build
@@ -45,6 +45,8 @@ FINAL_LIBRARY = 'xul'
 
 DEFINES['OS_ARCH'] = CONFIG['OS_ARCH']
 DEFINES['MOZ_WIDGET_TOOLKIT'] = CONFIG['MOZ_WIDGET_TOOLKIT']
+if CONFIG['MOZ_ENABLE_WEBRENDER']:
+    DEFINES['MOZ_ENABLE_WEBRENDER'] = True
 
 FINAL_TARGET_PP_FILES += [
     'greprefs.js',
diff --git a/toolkit/moz.configure b/toolkit/moz.configure
index 30b4ba944b36..084077dcd100 100644
--- a/toolkit/moz.configure
+++ b/toolkit/moz.configure
@@ -693,12 +693,37 @@ def servo_target_dir(value):
 set_config('SERVO_TARGET_DIR', servo_target_dir)
 
 # WebRender integration
-option('--enable-webrender', help='Include WebRender')
+option('--enable-webrender', nargs='?', choices=('build',),
+       help='Include WebRender in the build and/or enable it at runtime')
 
-set_config('MOZ_BUILD_WEBRENDER',
-           depends_if('--enable-webrender')(lambda _: True))
-set_define('MOZ_BUILD_WEBRENDER',
-           depends_if('--enable-webrender')(lambda _: True))
+@depends('--enable-webrender', milestone, target)
+def webrender(value, milestone, target):
+    build_webrender = None
+    enable_webrender = None
+
+    if target.os == 'Android':
+        # we can't yet build WebRender on Android, see bug 1323612.
+        pass
+    elif value.origin == 'default':
+        # if nothing is specified, default to just building on Nightly
+        build_webrender = milestone.is_nightly
+    elif value == 'build':
+        # if explicitly set to 'build', then we build but don't enable
+        build_webrender = True
+    elif bool(value):
+        # if set to true, then build and enable
+        build_webrender = True
+        enable_webrender = True
+
+    # in all other cases, don't build it or enable it (defaults are fine)
+    return namespace(
+        build = build_webrender,
+        enable = enable_webrender,
+    )
+
+set_config('MOZ_BUILD_WEBRENDER', delayed_getattr(webrender, 'build'))
+set_define('MOZ_BUILD_WEBRENDER', delayed_getattr(webrender, 'build'))
+set_config('MOZ_ENABLE_WEBRENDER', delayed_getattr(webrender, 'enable'))
 
 # Printing
 # ==============================================================

From 42ab51af17ebede6d57f2ece34182538ce88dacd Mon Sep 17 00:00:00 2001
From: Kartikaya Gupta 
Date: Wed, 22 Mar 2017 17:38:10 -0400
Subject: [PATCH 10/96] Bug 1342450 - Keep webrender disabled by default on OS
 X buildbot builders. r=ted

MozReview-Commit-ID: 9Ydrr67qKGu
---
 build/macosx/local-mozconfig.common | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/build/macosx/local-mozconfig.common b/build/macosx/local-mozconfig.common
index c49a0680f2c2..30d911615fee 100644
--- a/build/macosx/local-mozconfig.common
+++ b/build/macosx/local-mozconfig.common
@@ -32,6 +32,11 @@ fi
 ldflags="$ldflags -Wl,-no_data_in_code_info"
 export LDFLAGS="$ldflags"
 
+# Until bug 1342503 is fixed, we can't build some of the webrender dependencies
+# on buildbot OS X builders, because rustc will use some random system toolchain
+# instead of the one we package with tooltool.
+ac_add_options --disable-webrender
+
 # If not set use the system default clang
 if [ -z "$CC" ]; then
     export CC=clang

From 03b2ac1e5947e8bba4d4c40c2a2ef7146a692e97 Mon Sep 17 00:00:00 2001
From: Sebastian Hengst 
Date: Wed, 22 Mar 2017 22:50:54 +0100
Subject: [PATCH 11/96] Backed out changeset 5f62af954609 (bug 1333858) for
 bustage. r=backout on a CLOSED TREE

---
 dom/canvas/WebGLContext.cpp       | 54 +++++++++----------------------
 dom/canvas/WebGLContext.h         |  7 ++--
 dom/canvas/WebGLContextGL.cpp     | 34 ++++++++-----------
 dom/canvas/WebGLTextureUpload.cpp | 14 +++-----
 4 files changed, 38 insertions(+), 71 deletions(-)

diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp
index 52fdd160824d..82f382f63471 100644
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -2225,47 +2225,25 @@ ScopedLazyBind::UnwrapImpl()
 
 ////////////////////////////////////////
 
-bool
-Intersect(const int32_t srcSize, const int32_t read0, const int32_t readSize,
-          int32_t* const out_intRead0, int32_t* const out_intWrite0,
-          int32_t* const out_intSize)
+void
+Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
+          uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst,
+          uint32_t* const out_intSize)
 {
-    MOZ_ASSERT(srcSize >= 0);
-    MOZ_ASSERT(readSize >= 0);
-    const auto read1 = int64_t(read0) + readSize;
+    // Only >0 if dstStartInSrc is >0:
+    // 0  3          // src coords
+    // |  [========] // dst box
+    // ^--^
+    *out_intStartInSrc = std::max(0, dstStartInSrc);
 
-    int32_t intRead0 = read0; // Clearly doesn't need validation.
-    int64_t intWrite0 = 0;
-    int64_t intSize = readSize;
+    // Only >0 if dstStartInSrc is <0:
+    //-6     0       // src coords
+    // [=====|==]    // dst box
+    // ^-----^
+    *out_intStartInDst = std::max(0, 0 - dstStartInSrc);
 
-    if (read1 <= 0 || read0 >= srcSize) {
-        // Disjoint ranges.
-        intSize = 0;
-    } else {
-        if (read0 < 0) {
-            const auto diff = int64_t(0) - read0;
-            MOZ_ASSERT(diff >= 0);
-            intRead0 = 0;
-            intWrite0 = diff;
-            intSize -= diff;
-        }
-        if (read1 > srcSize) {
-            const auto diff = int64_t(read1) - srcSize;
-            MOZ_ASSERT(diff >= 0);
-            intSize -= diff;
-        }
-
-        if (!CheckedInt(intWrite0).isValid() ||
-            !CheckedInt(intSize).isValid())
-        {
-            return false;
-        }
-    }
-
-    *out_intRead0 = intRead0;
-    *out_intWrite0 = intWrite0;
-    *out_intSize = intSize;
-    return true;
+    int32_t intEndInSrc = std::min(srcSize, dstStartInSrc + dstSize);
+    *out_intSize = std::max(0, intEndInSrc - *out_intStartInSrc);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h
index 37ac2929bcd0..ce0e5e544618 100644
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -2164,9 +2164,10 @@ private:
 
 ////
 
-bool
-Intersect(int32_t srcSize, int32_t read0, int32_t readSize, int32_t* out_intRead0,
-          int32_t* out_intWrite0, int32_t* out_intSize);
+void
+Intersect(uint32_t srcSize, int32_t dstStartInSrc, uint32_t dstSize,
+          uint32_t* const out_intStartInSrc, uint32_t* const out_intStartInDst,
+          uint32_t* const out_intSize);
 
 ////
 
diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp
index 91328e8f5ae4..0a9ac679d88f 100644
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1556,32 +1556,18 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig
         return;
     }
 
-    ////
-
-    int32_t readX, readY;
-    int32_t writeX, writeY;
-    int32_t rwWidth, rwHeight;
-    if (!Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth) ||
-        !Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight))
-    {
-        ErrorOutOfMemory("readPixels: Bad subrect selection.");
-        return;
-    }
-
     ////////////////
     // Now that the errors are out of the way, on to actually reading!
 
     OnBeforeReadCall();
 
-    if (!rwWidth || !rwHeight) {
-        // Disjoint rects, so we're done already.
-        DummyReadFramebufferOperation("readPixels");
-        return;
-    }
+    uint32_t readX, readY;
+    uint32_t writeX, writeY;
+    uint32_t rwWidth, rwHeight;
+    Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth);
+    Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight);
 
-    if (uint32_t(rwWidth) == width &&
-        uint32_t(rwHeight) == height)
-    {
+    if (rwWidth == uint32_t(width) && rwHeight == uint32_t(height)) {
         DoReadPixelsAndConvert(srcFormat->format, x, y, width, height, packFormat,
                                packType, dest, dataLen, rowStride);
         return;
@@ -1600,6 +1586,12 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig
     ////////////////////////////////////
     // Read only the in-bounds pixels.
 
+    if (!rwWidth || !rwHeight) {
+        // There aren't any, so we're 'done'.
+        DummyReadFramebufferOperation("readPixels");
+        return;
+    }
+
     if (IsWebGL2()) {
         if (!mPixelStore_PackRowLength) {
             gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH,
@@ -1619,7 +1611,7 @@ WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeig
 
         uint8_t* row = (uint8_t*)dest + writeX * bytesPerPixel;
         row += writeY * rowStride;
-        for (uint32_t j = 0; j < uint32_t(rwHeight); j++) {
+        for (uint32_t j = 0; j < rwHeight; j++) {
             DoReadPixelsAndConvert(srcFormat->format, readX, readY+j, rwWidth, 1,
                                    packFormat, packType, row, dataLen, rowStride);
             row += rowStride;
diff --git a/dom/canvas/WebGLTextureUpload.cpp b/dom/canvas/WebGLTextureUpload.cpp
index 80564f8062b2..b104f38a8200 100644
--- a/dom/canvas/WebGLTextureUpload.cpp
+++ b/dom/canvas/WebGLTextureUpload.cpp
@@ -2011,15 +2011,11 @@ DoCopyTexOrSubImage(WebGLContext* webgl, const char* funcName, bool isSubImage,
 
     ////
 
-    int32_t readX, readY;
-    int32_t writeX, writeY;
-    int32_t rwWidth, rwHeight;
-    if (!Intersect(srcTotalWidth, xWithinSrc, dstWidth, &readX, &writeX, &rwWidth) ||
-        !Intersect(srcTotalHeight, yWithinSrc, dstHeight, &readY, &writeY, &rwHeight))
-    {
-        webgl->ErrorOutOfMemory("%s: Bad subrect selection.", funcName);
-        return false;
-    }
+    uint32_t readX, readY;
+    uint32_t writeX, writeY;
+    uint32_t rwWidth, rwHeight;
+    Intersect(srcTotalWidth, xWithinSrc, dstWidth, &readX, &writeX, &rwWidth);
+    Intersect(srcTotalHeight, yWithinSrc, dstHeight, &readY, &writeY, &rwHeight);
 
     writeX += xOffset;
     writeY += yOffset;

From 1ad9009da0ab095730d8bbeaf27ec6cc82cbb727 Mon Sep 17 00:00:00 2001
From: Eric Rahm 
Date: Wed, 22 Mar 2017 15:01:49 -0700
Subject: [PATCH 12/96] Bug 1347000 - Fix false-positive sync message not found
 errors on windows builds. r=billm

MozReview-Commit-ID: 6ZLCJKotqEE
---
 ipc/ipdl/sync-messages.ini | 120 +++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/ipc/ipdl/sync-messages.ini b/ipc/ipdl/sync-messages.ini
index 46ef0984c0d8..ac446f695ca9 100644
--- a/ipc/ipdl/sync-messages.ini
+++ b/ipc/ipdl/sync-messages.ini
@@ -233,244 +233,364 @@ description =
 # A11y code
 [PDocAccessible::State]
 description =
+platform = notwin
 [PDocAccessible::NativeState]
 description =
+platform = notwin
 [PDocAccessible::Name]
 description =
+platform = notwin
 [PDocAccessible::Value]
 description =
+platform = notwin
 [PDocAccessible::Help]
 description =
+platform = notwin
 [PDocAccessible::Description]
 description =
+platform = notwin
 [PDocAccessible::Attributes]
 description =
+platform = notwin
 [PDocAccessible::RelationByType]
 description =
+platform = notwin
 [PDocAccessible::Relations]
 description =
+platform = notwin
 [PDocAccessible::IsSearchbox]
 description =
+platform = notwin
 [PDocAccessible::LandmarkRole]
 description =
+platform = notwin
 [PDocAccessible::ARIARoleAtom]
 description =
+platform = notwin
 [PDocAccessible::GetLevelInternal]
 description =
+platform = notwin
 [PDocAccessible::CaretLineNumber]
 description =
+platform = notwin
 [PDocAccessible::CaretOffset]
 description =
+platform = notwin
 [PDocAccessible::CharacterCount]
 description =
+platform = notwin
 [PDocAccessible::SelectionCount]
 description =
+platform = notwin
 [PDocAccessible::TextSubstring]
 description =
+platform = notwin
 [PDocAccessible::GetTextAfterOffset]
 description =
+platform = notwin
 [PDocAccessible::GetTextAtOffset]
 description =
+platform = notwin
 [PDocAccessible::GetTextBeforeOffset]
 description =
+platform = notwin
 [PDocAccessible::CharAt]
 description =
+platform = notwin
 [PDocAccessible::TextAttributes]
 description =
+platform = notwin
 [PDocAccessible::DefaultTextAttributes]
 description =
+platform = notwin
 [PDocAccessible::TextBounds]
 description =
+platform = notwin
 [PDocAccessible::CharBounds]
 description =
+platform = notwin
 [PDocAccessible::OffsetAtPoint]
 description =
+platform = notwin
 [PDocAccessible::SelectionBoundsAt]
 description =
+platform = notwin
 [PDocAccessible::SetSelectionBoundsAt]
 description =
+platform = notwin
 [PDocAccessible::AddToSelection]
 description =
+platform = notwin
 [PDocAccessible::RemoveFromSelection]
 description =
+platform = notwin
 [PDocAccessible::Text]
 description =
+platform = notwin
 [PDocAccessible::ReplaceText]
 description =
+platform = notwin
 [PDocAccessible::InsertText]
 description =
+platform = notwin
 [PDocAccessible::CopyText]
 description =
+platform = notwin
 [PDocAccessible::CutText]
 description =
+platform = notwin
 [PDocAccessible::DeleteText]
 description =
+platform = notwin
 [PDocAccessible::PasteText]
 description =
+platform = notwin
 [PDocAccessible::ImagePosition]
 description =
+platform = notwin
 [PDocAccessible::ImageSize]
 description =
+platform = notwin
 [PDocAccessible::StartOffset]
 description =
+platform = notwin
 [PDocAccessible::EndOffset]
 description =
+platform = notwin
 [PDocAccessible::IsLinkValid]
 description =
+platform = notwin
 [PDocAccessible::AnchorCount]
 description =
+platform = notwin
 [PDocAccessible::AnchorURIAt]
 description =
+platform = notwin
 [PDocAccessible::AnchorAt]
 description =
+platform = notwin
 [PDocAccessible::LinkCount]
 description =
+platform = notwin
 [PDocAccessible::LinkAt]
 description =
+platform = notwin
 [PDocAccessible::LinkIndexOf]
 description =
+platform = notwin
 [PDocAccessible::LinkIndexAtOffset]
 description =
+platform = notwin
 [PDocAccessible::TableOfACell]
 description =
+platform = notwin
 [PDocAccessible::ColIdx]
 description =
+platform = notwin
 [PDocAccessible::RowIdx]
 description =
+platform = notwin
 [PDocAccessible::GetPosition]
 description =
+platform = notwin
 [PDocAccessible::ColExtent]
 description =
+platform = notwin
 [PDocAccessible::RowExtent]
 description =
+platform = notwin
 [PDocAccessible::GetColRowExtents]
 description =
+platform = notwin
 [PDocAccessible::ColHeaderCells]
 description =
+platform = notwin
 [PDocAccessible::RowHeaderCells]
 description =
+platform = notwin
 [PDocAccessible::IsCellSelected]
 description =
+platform = notwin
 [PDocAccessible::TableCaption]
 description =
+platform = notwin
 [PDocAccessible::TableSummary]
 description =
+platform = notwin
 [PDocAccessible::TableColumnCount]
 description =
+platform = notwin
 [PDocAccessible::TableRowCount]
 description =
+platform = notwin
 [PDocAccessible::TableCellAt]
 description =
+platform = notwin
 [PDocAccessible::TableCellIndexAt]
 description =
+platform = notwin
 [PDocAccessible::TableColumnIndexAt]
 description =
+platform = notwin
 [PDocAccessible::TableRowIndexAt]
 description =
+platform = notwin
 [PDocAccessible::TableRowAndColumnIndicesAt]
 description =
+platform = notwin
 [PDocAccessible::TableColumnExtentAt]
 description =
+platform = notwin
 [PDocAccessible::TableRowExtentAt]
 description =
+platform = notwin
 [PDocAccessible::TableColumnDescription]
 description =
+platform = notwin
 [PDocAccessible::TableRowDescription]
 description =
+platform = notwin
 [PDocAccessible::TableColumnSelected]
 description =
+platform = notwin
 [PDocAccessible::TableRowSelected]
 description =
+platform = notwin
 [PDocAccessible::TableCellSelected]
 description =
+platform = notwin
 [PDocAccessible::TableSelectedCellCount]
 description =
+platform = notwin
 [PDocAccessible::TableSelectedColumnCount]
 description =
+platform = notwin
 [PDocAccessible::TableSelectedRowCount]
 description =
+platform = notwin
 [PDocAccessible::TableSelectedCells]
 description =
+platform = notwin
 [PDocAccessible::TableSelectedCellIndices]
 description =
+platform = notwin
 [PDocAccessible::TableSelectedColumnIndices]
 description =
+platform = notwin
 [PDocAccessible::TableSelectedRowIndices]
 description =
+platform = notwin
 [PDocAccessible::TableSelectColumn]
 description =
+platform = notwin
 [PDocAccessible::TableSelectRow]
 description =
+platform = notwin
 [PDocAccessible::TableUnselectColumn]
 description =
+platform = notwin
 [PDocAccessible::TableUnselectRow]
 description =
+platform = notwin
 [PDocAccessible::TableIsProbablyForLayout]
 description =
+platform = notwin
 [PDocAccessible::AtkTableColumnHeader]
 description =
+platform = notwin
 [PDocAccessible::AtkTableRowHeader]
 description =
+platform = notwin
 [PDocAccessible::SelectedItems]
 description =
+platform = notwin
 [PDocAccessible::SelectedItemCount]
 description =
+platform = notwin
 [PDocAccessible::GetSelectedItem]
 description =
+platform = notwin
 [PDocAccessible::IsItemSelected]
 description =
+platform = notwin
 [PDocAccessible::AddItemToSelection]
 description =
+platform = notwin
 [PDocAccessible::RemoveItemFromSelection]
 description =
+platform = notwin
 [PDocAccessible::SelectAll]
 description =
+platform = notwin
 [PDocAccessible::UnselectAll]
 description =
+platform = notwin
 [PDocAccessible::DoAction]
 description =
+platform = notwin
 [PDocAccessible::ActionCount]
 description =
+platform = notwin
 [PDocAccessible::ActionDescriptionAt]
 description =
+platform = notwin
 [PDocAccessible::ActionNameAt]
 description =
+platform = notwin
 [PDocAccessible::AccessKey]
 description =
+platform = notwin
 [PDocAccessible::KeyboardShortcut]
 description =
+platform = notwin
 [PDocAccessible::AtkKeyBinding]
 description =
+platform = notwin
 [PDocAccessible::CurValue]
 description =
+platform = notwin
 [PDocAccessible::SetCurValue]
 description =
+platform = notwin
 [PDocAccessible::MinValue]
 description =
+platform = notwin
 [PDocAccessible::MaxValue]
 description =
+platform = notwin
 [PDocAccessible::Step]
 description =
+platform = notwin
 [PDocAccessible::FocusedChild]
 description =
+platform = notwin
 [PDocAccessible::Language]
 description =
+platform = notwin
 [PDocAccessible::DocType]
 description =
+platform = notwin
 [PDocAccessible::Title]
 description =
+platform = notwin
 [PDocAccessible::URL]
 description =
+platform = notwin
 [PDocAccessible::MimeType]
 description =
+platform = notwin
 [PDocAccessible::URLDocTypeMimeType]
 description =
+platform = notwin
 [PDocAccessible::AccessibleAtPoint]
 description =
+platform = notwin
 [PDocAccessible::Extents]
 description =
+platform = notwin
 [PDocAccessible::DOMNodeID]
 description =
+platform = notwin
 [PDocAccessible::GetWindowedPluginIAccessible]
 description =
 platform = win

From 3693cc51e3a53488fd020df9875803d358361d63 Mon Sep 17 00:00:00 2001
From: Eric Rahm 
Date: Wed, 22 Mar 2017 15:01:50 -0700
Subject: [PATCH 13/96] Bug 1349350 - Make IPDL checker sync IPC message errors
 fatal. r=ehsan

The IPDL sync IPC message error checker needs to actually return a result and
exit if it fails.

MozReview-Commit-ID: 1ZAuAWRlsvk
---
 ipc/ipdl/ipdl.py         | 4 +++-
 ipc/ipdl/ipdl/checker.py | 3 +++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/ipc/ipdl/ipdl.py b/ipc/ipdl/ipdl.py
index d94e8536b8a6..de0132168996 100755
--- a/ipc/ipdl/ipdl.py
+++ b/ipc/ipdl/ipdl.py
@@ -151,7 +151,9 @@ for f in files:
         log(3, '  pretty printed code:')
         ipdl.genipdl(ast, codedir)
 
-ipdl.checkFixedSyncMessages(parser)
+if not ipdl.checkFixedSyncMessages(parser):
+    # Errors have alraedy been printed to stderr, just exit
+    sys.exit(1)
 
 # Second pass: generate code
 for f in files:
diff --git a/ipc/ipdl/ipdl/checker.py b/ipc/ipdl/ipdl/checker.py
index df836e9bcc00..114380035625 100644
--- a/ipc/ipdl/ipdl/checker.py
+++ b/ipc/ipdl/ipdl/checker.py
@@ -55,6 +55,7 @@ def checkSyncMessage(tu, syncMsgList, errout=sys.stderr):
 
 def checkFixedSyncMessages(config, errout=sys.stderr):
     fixed = SyncMessageChecker.getFixedSyncMessages()
+    error_free = True
     for item in fixed:
         protocol = item.split('::')[0]
         # Ignore things like sync messages in test protocols we didn't compile.
@@ -63,3 +64,5 @@ def checkFixedSyncMessages(config, errout=sys.stderr):
            'platform' not in config.options(item):
             print >>errout, 'Error: Sync IPC message %s not found, it appears to be fixed.\n' \
                             'Please remove it from sync-messages.ini.' % item
+            error_free = False
+    return error_free

From 8565c76302aed4a960808292f4a08e0ae86fb77c Mon Sep 17 00:00:00 2001
From: Jonathan Watt 
Date: Mon, 20 Feb 2017 12:47:19 +0000
Subject: [PATCH 14/96] Bug 1349731 - Document how SVG frames use
 nsIFrame::mRect. r=longsonr

MozReview-Commit-ID: EcrJfuVWsJg
---
 layout/generic/nsIFrame.h | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
index f4f583ab917c..00a6b3ec4eab 100644
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -838,9 +838,30 @@ public:
                                           nsIFrame* aSubFrame) const;
 
   /**
-   * Bounding rect of the frame. The values are in app units, and the origin is
-   * relative to the upper-left of the geometric parent. The size includes the
-   * content area, borders, and padding.
+   * Bounding rect of the frame.
+   *
+   * For frames that are laid out according to CSS box model rules the values
+   * are in app units, and the origin is relative to the upper-left of the
+   * geometric parent.  The size includes the content area, borders, and
+   * padding.
+   *
+   * Frames that are laid out according to SVG's coordinate space based rules
+   * (frames with the NS_FRAME_SVG_LAYOUT bit set, which *excludes*
+   * nsSVGOuterSVGFrame) are different.  Many frames of this type do not set or
+   * use mRect, in which case the frame rect is undefined.  The exceptions are:
+   *
+   *   - nsSVGInnerSVGFrame
+   *   - SVGGeometryFrame (used for , , etc.)
+   *   - nsSVGImageFrame
+   *   - nsSVGForeignObjectFrame
+   *
+   * For these frames the frame rect contains the frame's element's userspace
+   * bounds including fill, stroke and markers, but converted to app units
+   * rather than being in user units (CSS px).  In the SVG code "userspace" is
+   * defined to be the coordinate system for the attributes that define an
+   * element's geometry (such as the 'cx' attribute for ).  For more
+   * precise details see these frames' implementations of the ReflowSVG method
+   * where mRect is set.
    *
    * Note: moving or sizing the frame does not affect the view's size or
    * position.

From fc37ee19400ca99cd87d67cb2ea89bb28b7f1f1d Mon Sep 17 00:00:00 2001
From: Jonathan Watt 
Date: Tue, 21 Feb 2017 09:37:09 +0000
Subject: [PATCH 15/96] Bug 1349477, part 1 - Use AutoReferenceChainGuard in
 nsSVGFilterFrame. r=longsonr

MozReview-Commit-ID: HTcySIH3qNt
---
 layout/svg/nsSVGFilterFrame.cpp | 92 +++++++++++++++------------------
 layout/svg/nsSVGFilterFrame.h   |  2 -
 2 files changed, 43 insertions(+), 51 deletions(-)

diff --git a/layout/svg/nsSVGFilterFrame.cpp b/layout/svg/nsSVGFilterFrame.cpp
index 13ce16993d78..60817bd7d050 100644
--- a/layout/svg/nsSVGFilterFrame.cpp
+++ b/layout/svg/nsSVGFilterFrame.cpp
@@ -7,6 +7,7 @@
 #include "nsSVGFilterFrame.h"
 
 // Keep others in (case-insensitive) order:
+#include "AutoReferenceChainGuard.h"
 #include "gfxUtils.h"
 #include "nsGkAtoms.h"
 #include "nsSVGEffects.h"
@@ -17,6 +18,7 @@
 #include "nsSVGUtils.h"
 #include "nsContentUtils.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 nsIFrame*
@@ -27,26 +29,6 @@ NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGFilterFrame)
 
-class MOZ_RAII nsSVGFilterFrame::AutoFilterReferencer
-{
-public:
-  explicit AutoFilterReferencer(nsSVGFilterFrame *aFrame MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    : mFrame(aFrame)
-  {
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    // Reference loops should normally be detected in advance and handled, so
-    // we're not expecting to encounter them here
-    MOZ_ASSERT(!mFrame->mLoopFlag, "Undetected reference loop!");
-    mFrame->mLoopFlag = true;
-  }
-  ~AutoFilterReferencer() {
-    mFrame->mLoopFlag = false;
-  }
-private:
-  nsSVGFilterFrame *mFrame;
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 uint16_t
 nsSVGFilterFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
 {
@@ -56,12 +38,22 @@ nsSVGFilterFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
   if (thisEnum.IsExplicitlySet())
     return thisEnum.GetAnimValue();
 
-  AutoFilterReferencer filterRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return static_cast(aDefault)->
+    mEnumAttributes[aIndex].GetAnimValue();
+  }
 
-  nsSVGFilterFrame *next = GetReferencedFilterIfNotInUse();
-  return next ? next->GetEnumValue(aIndex, aDefault) :
-    static_cast(aDefault)->
-      mEnumAttributes[aIndex].GetAnimValue();
+  nsSVGFilterFrame *next = GetReferencedFilter();
+
+  return next ? next->GetEnumValue(aIndex, aDefault)
+              : static_cast(aDefault)->
+                  mEnumAttributes[aIndex].GetAnimValue();
 }
 
 const nsSVGLength2 *
@@ -73,11 +65,20 @@ nsSVGFilterFrame::GetLengthValue(uint32_t aIndex, nsIContent *aDefault)
   if (thisLength->IsExplicitlySet())
     return thisLength;
 
-  AutoFilterReferencer filterRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return &static_cast(aDefault)->mLengthAttributes[aIndex];
+  }
 
-  nsSVGFilterFrame *next = GetReferencedFilterIfNotInUse();
-  return next ? next->GetLengthValue(aIndex, aDefault) :
-    &static_cast(aDefault)->mLengthAttributes[aIndex];
+  nsSVGFilterFrame *next = GetReferencedFilter();
+
+  return next ? next->GetLengthValue(aIndex, aDefault)
+              : &static_cast(aDefault)->mLengthAttributes[aIndex];
 }
 
 const SVGFilterElement *
@@ -93,11 +94,20 @@ nsSVGFilterFrame::GetFilterContent(nsIContent *aDefault)
     }
   }
 
-  AutoFilterReferencer filterRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return static_cast(aDefault);
+  }
 
-  nsSVGFilterFrame *next = GetReferencedFilterIfNotInUse();
-  return next ? next->GetFilterContent(aDefault) :
-    static_cast(aDefault);
+  nsSVGFilterFrame *next = GetReferencedFilter();
+
+  return next ? next->GetFilterContent(aDefault)
+              : static_cast(aDefault);
 }
 
 nsSVGFilterFrame *
@@ -150,22 +160,6 @@ nsSVGFilterFrame::GetReferencedFilter()
   return static_cast(result);
 }
 
-nsSVGFilterFrame *
-nsSVGFilterFrame::GetReferencedFilterIfNotInUse()
-{
-  nsSVGFilterFrame *referenced = GetReferencedFilter();
-  if (!referenced)
-    return nullptr;
-
-  if (referenced->mLoopFlag) {
-    // XXXjwatt: we should really send an error to the JavaScript Console here:
-    NS_WARNING("Filter reference loop detected while inheriting attribute!");
-    return nullptr;
-  }
-
-  return referenced;
-}
-
 nsresult
 nsSVGFilterFrame::AttributeChanged(int32_t  aNameSpaceID,
                                    nsIAtom* aAttribute,
diff --git a/layout/svg/nsSVGFilterFrame.h b/layout/svg/nsSVGFilterFrame.h
index 223c787f6e85..eac06ce7c9ec 100644
--- a/layout/svg/nsSVGFilterFrame.h
+++ b/layout/svg/nsSVGFilterFrame.h
@@ -69,10 +69,8 @@ private:
   // Parse our xlink:href and set up our nsSVGPaintingProperty if we
   // reference another filter and we don't have a property. Return
   // the referenced filter's frame if available, null otherwise.
-  class AutoFilterReferencer;
   friend class nsSVGFilterInstance;
   nsSVGFilterFrame* GetReferencedFilter();
-  nsSVGFilterFrame* GetReferencedFilterIfNotInUse();
 
   // Accessors to lookup filter attributes
   uint16_t GetEnumValue(uint32_t aIndex, nsIContent *aDefault);

From ae571cea0c38dc4b3307d716770089ebb85dfb57 Mon Sep 17 00:00:00 2001
From: Jonathan Watt 
Date: Tue, 21 Feb 2017 10:10:43 +0000
Subject: [PATCH 16/96] Bug 1349477, part 2 - Use AutoReferenceChainGuard in
 nsSVGGradientFrame. r=longsonr

MozReview-Commit-ID: 5xw5i696ipe
---
 layout/svg/nsSVGGradientFrame.cpp | 120 +++++++++++++++---------------
 layout/svg/nsSVGGradientFrame.h   |   4 -
 2 files changed, 62 insertions(+), 62 deletions(-)

diff --git a/layout/svg/nsSVGGradientFrame.cpp b/layout/svg/nsSVGGradientFrame.cpp
index e3b627ea102c..f6eaf174a986 100644
--- a/layout/svg/nsSVGGradientFrame.cpp
+++ b/layout/svg/nsSVGGradientFrame.cpp
@@ -8,6 +8,7 @@
 #include 
 
 // Keep others in (case-insensitive) order:
+#include "AutoReferenceChainGuard.h"
 #include "gfxPattern.h"
 #include "mozilla/dom/SVGGradientElement.h"
 #include "mozilla/dom/SVGStopElement.h"
@@ -21,30 +22,6 @@ using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
-//----------------------------------------------------------------------
-// Helper classes
-
-class MOZ_RAII nsSVGGradientFrame::AutoGradientReferencer
-{
-public:
-  explicit AutoGradientReferencer(nsSVGGradientFrame *aFrame
-                                  MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    : mFrame(aFrame)
-  {
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    // Reference loops should normally be detected in advance and handled, so
-    // we're not expecting to encounter them here
-    MOZ_ASSERT(!mFrame->mLoopFlag, "Undetected reference loop!");
-    mFrame->mLoopFlag = true;
-  }
-  ~AutoGradientReferencer() {
-    mFrame->mLoopFlag = false;
-  }
-private:
-  nsSVGGradientFrame *mFrame;
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 //----------------------------------------------------------------------
 // Implementation
 
@@ -93,12 +70,22 @@ nsSVGGradientFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
   if (thisEnum.IsExplicitlySet())
     return thisEnum.GetAnimValue();
 
-  AutoGradientReferencer gradientRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return static_cast(aDefault)->
+             mEnumAttributes[aIndex].GetAnimValue();
+  }
 
-  nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
-  return next ? next->GetEnumValue(aIndex, aDefault) :
-    static_cast(aDefault)->
-      mEnumAttributes[aIndex].GetAnimValue();
+  nsSVGGradientFrame *next = GetReferencedGradient();
+
+  return next ? next->GetEnumValue(aIndex, aDefault)
+              : static_cast(aDefault)->
+                  mEnumAttributes[aIndex].GetAnimValue();
 }
 
 uint16_t
@@ -123,12 +110,22 @@ nsSVGGradientFrame::GetGradientTransformList(nsIContent* aDefault)
   if (thisTransformList && thisTransformList->IsExplicitlySet())
     return thisTransformList;
 
-  AutoGradientReferencer gradientRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return static_cast(aDefault)->
+             mGradientTransform.get();
+  }
 
-  nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
-  return next ? next->GetGradientTransformList(aDefault) :
-    static_cast(aDefault)
-      ->mGradientTransform.get();
+  nsSVGGradientFrame *next = GetReferencedGradient();
+
+  return next ? next->GetGradientTransformList(aDefault)
+              : static_cast(aDefault)->
+                  mGradientTransform.get();
 }
 
 gfxMatrix
@@ -167,9 +164,17 @@ nsSVGGradientFrame::GetLinearGradientWithLength(uint32_t aIndex,
   // already found it in nsSVGLinearGradientFrame::GetLinearGradientWithLength.
   // Since we didn't find the length, continue looking down the chain.
 
-  AutoGradientReferencer gradientRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return aDefault;
+  }
 
-  nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
+  nsSVGGradientFrame *next = GetReferencedGradient();
   return next ? next->GetLinearGradientWithLength(aIndex, aDefault) : aDefault;
 }
 
@@ -181,9 +186,17 @@ nsSVGGradientFrame::GetRadialGradientWithLength(uint32_t aIndex,
   // already found it in nsSVGRadialGradientFrame::GetRadialGradientWithLength.
   // Since we didn't find the length, continue looking down the chain.
 
-  AutoGradientReferencer gradientRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return aDefault;
+  }
 
-  nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
+  nsSVGGradientFrame *next = GetReferencedGradient();
   return next ? next->GetRadialGradientWithLength(aIndex, aDefault) : aDefault;
 }
 
@@ -362,22 +375,6 @@ nsSVGGradientFrame::GetReferencedGradient()
   return static_cast(result);
 }
 
-nsSVGGradientFrame *
-nsSVGGradientFrame::GetReferencedGradientIfNotInUse()
-{
-  nsSVGGradientFrame *referenced = GetReferencedGradient();
-  if (!referenced)
-    return nullptr;
-
-  if (referenced->mLoopFlag) {
-    // XXXjwatt: we should really send an error to the JavaScript Console here:
-    NS_WARNING("gradient reference loop detected while inheriting attribute!");
-    return nullptr;
-  }
-
-  return referenced;
-}
-
 void
 nsSVGGradientFrame::GetStopFrames(nsTArray* aStopFrames)
 {
@@ -394,13 +391,20 @@ nsSVGGradientFrame::GetStopFrames(nsTArray* aStopFrames)
 
   // Our gradient element doesn't have stops - try to "inherit" them
 
-  AutoGradientReferencer gradientRef(this);
-  nsSVGGradientFrame* next = GetReferencedGradientIfNotInUse();
-  if (!next) {
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
     return;
   }
 
-  return next->GetStopFrames(aStopFrames);
+  nsSVGGradientFrame* next = GetReferencedGradient();
+  if (next) {
+    next->GetStopFrames(aStopFrames);
+  }
 }
 
 // -------------------------------------------------------------------------
diff --git a/layout/svg/nsSVGGradientFrame.h b/layout/svg/nsSVGGradientFrame.h
index f12b132533a3..c9bc6c2ca5d4 100644
--- a/layout/svg/nsSVGGradientFrame.h
+++ b/layout/svg/nsSVGGradientFrame.h
@@ -86,10 +86,6 @@ protected:
   virtual bool GradientVectorLengthIsZero() = 0;
   virtual already_AddRefed CreateGradient() = 0;
 
-  // Internal methods for handling referenced gradients
-  class AutoGradientReferencer;
-  nsSVGGradientFrame* GetReferencedGradientIfNotInUse();
-
   // Accessors to lookup gradient attributes
   uint16_t GetEnumValue(uint32_t aIndex, nsIContent *aDefault);
   uint16_t GetEnumValue(uint32_t aIndex)

From 1fdd3184b829cdb69d270b7e47bf1565a37f55f3 Mon Sep 17 00:00:00 2001
From: Jonathan Watt 
Date: Tue, 21 Feb 2017 10:34:52 +0000
Subject: [PATCH 17/96] Bug 1349477, part 3 - Use AutoReferenceChainGuard in
 nsSVGPatternFrame. r=longsonr

MozReview-Commit-ID: EUgSIK92Jtq
---
 layout/svg/nsSVGPatternFrame.cpp | 137 +++++++++++++++++--------------
 layout/svg/nsSVGPatternFrame.h   |   2 -
 2 files changed, 74 insertions(+), 65 deletions(-)

diff --git a/layout/svg/nsSVGPatternFrame.cpp b/layout/svg/nsSVGPatternFrame.cpp
index 90548d2d8448..3ab6740d7280 100644
--- a/layout/svg/nsSVGPatternFrame.cpp
+++ b/layout/svg/nsSVGPatternFrame.cpp
@@ -7,6 +7,7 @@
 #include "nsSVGPatternFrame.h"
 
 // Keep others in (case-insensitive) order:
+#include "AutoReferenceChainGuard.h"
 #include "gfx2DGlue.h"
 #include "gfxContext.h"
 #include "gfxMatrix.h"
@@ -29,30 +30,6 @@ using namespace mozilla::dom;
 using namespace mozilla::gfx;
 using namespace mozilla::image;
 
-//----------------------------------------------------------------------
-// Helper classes
-
-class MOZ_RAII nsSVGPatternFrame::AutoPatternReferencer
-{
-public:
-  explicit AutoPatternReferencer(nsSVGPatternFrame *aFrame
-                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-    : mFrame(aFrame)
-  {
-    MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-    // Reference loops should normally be detected in advance and handled, so
-    // we're not expecting to encounter them here
-    MOZ_ASSERT(!mFrame->mLoopFlag, "Undetected reference loop!");
-    mFrame->mLoopFlag = true;
-  }
-  ~AutoPatternReferencer() {
-    mFrame->mLoopFlag = false;
-  }
-private:
-  nsSVGPatternFrame *mFrame;
-  MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-};
-
 //----------------------------------------------------------------------
 // Implementation
 
@@ -443,9 +420,18 @@ nsSVGPatternFrame::GetPatternWithChildren()
     return this;
 
   // No, see if we chain to someone who does
-  AutoPatternReferencer patternRef(this);
 
-  nsSVGPatternFrame* next = GetReferencedPatternIfNotInUse();
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return nullptr;
+  }
+
+  nsSVGPatternFrame* next = GetReferencedPattern();
   if (!next)
     return nullptr;
 
@@ -461,12 +447,21 @@ nsSVGPatternFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
   if (thisEnum.IsExplicitlySet())
     return thisEnum.GetAnimValue();
 
-  AutoPatternReferencer patternRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return static_cast(aDefault)->
+             mEnumAttributes[aIndex].GetAnimValue();
+  }
 
-  nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
-  return next ? next->GetEnumValue(aIndex, aDefault) :
-    static_cast(aDefault)->
-      mEnumAttributes[aIndex].GetAnimValue();
+  nsSVGPatternFrame *next = GetReferencedPattern();
+  return next ? next->GetEnumValue(aIndex, aDefault)
+              : static_cast(aDefault)->
+                  mEnumAttributes[aIndex].GetAnimValue();
 }
 
 nsSVGAnimatedTransformList*
@@ -478,11 +473,19 @@ nsSVGPatternFrame::GetPatternTransformList(nsIContent* aDefault)
   if (thisTransformList && thisTransformList->IsExplicitlySet())
     return thisTransformList;
 
-  AutoPatternReferencer patternRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return static_cast(aDefault)->mPatternTransform.get();
+  }
 
-  nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
-  return next ? next->GetPatternTransformList(aDefault) :
-    static_cast(aDefault)->mPatternTransform.get();
+  nsSVGPatternFrame *next = GetReferencedPattern();
+  return next ? next->GetPatternTransformList(aDefault)
+              : static_cast(aDefault)->mPatternTransform.get();
 }
 
 gfxMatrix
@@ -505,11 +508,19 @@ nsSVGPatternFrame::GetViewBox(nsIContent* aDefault)
   if (thisViewBox.IsExplicitlySet())
     return thisViewBox;
 
-  AutoPatternReferencer patternRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return static_cast(aDefault)->mViewBox;
+  }
 
-  nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
-  return next ? next->GetViewBox(aDefault) :
-    static_cast(aDefault)->mViewBox;
+  nsSVGPatternFrame *next = GetReferencedPattern();
+  return next ? next->GetViewBox(aDefault)
+              : static_cast(aDefault)->mViewBox;
 }
 
 const SVGAnimatedPreserveAspectRatio &
@@ -521,11 +532,19 @@ nsSVGPatternFrame::GetPreserveAspectRatio(nsIContent *aDefault)
   if (thisPar.IsExplicitlySet())
     return thisPar;
 
-  AutoPatternReferencer patternRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return static_cast(aDefault)->mPreserveAspectRatio;
+  }
 
-  nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
-  return next ? next->GetPreserveAspectRatio(aDefault) :
-    static_cast(aDefault)->mPreserveAspectRatio;
+  nsSVGPatternFrame *next = GetReferencedPattern();
+  return next ? next->GetPreserveAspectRatio(aDefault)
+              : static_cast(aDefault)->mPreserveAspectRatio;
 }
 
 const nsSVGLength2 *
@@ -537,11 +556,19 @@ nsSVGPatternFrame::GetLengthValue(uint32_t aIndex, nsIContent *aDefault)
   if (thisLength->IsExplicitlySet())
     return thisLength;
 
-  AutoPatternReferencer patternRef(this);
+  // Before we recurse, make sure we'll break reference loops and over long
+  // reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
+    return &static_cast(aDefault)->mLengthAttributes[aIndex];
+  }
 
-  nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
-  return next ? next->GetLengthValue(aIndex, aDefault) :
-    &static_cast(aDefault)->mLengthAttributes[aIndex];
+  nsSVGPatternFrame *next = GetReferencedPattern();
+  return next ? next->GetLengthValue(aIndex, aDefault)
+              : &static_cast(aDefault)->mLengthAttributes[aIndex];
 }
 
 // Private (helper) methods
@@ -595,22 +622,6 @@ nsSVGPatternFrame::GetReferencedPattern()
   return static_cast(result);
 }
 
-nsSVGPatternFrame *
-nsSVGPatternFrame::GetReferencedPatternIfNotInUse()
-{
-  nsSVGPatternFrame *referenced = GetReferencedPattern();
-  if (!referenced)
-    return nullptr;
-
-  if (referenced->mLoopFlag) {
-    // XXXjwatt: we should really send an error to the JavaScript Console here:
-    NS_WARNING("pattern reference loop detected while inheriting attribute!");
-    return nullptr;
-  }
-
-  return referenced;
-}
-
 gfxRect
 nsSVGPatternFrame::GetPatternRect(uint16_t aPatternUnits,
                                   const gfxRect &aTargetBBox,
diff --git a/layout/svg/nsSVGPatternFrame.h b/layout/svg/nsSVGPatternFrame.h
index 5182e55385eb..3443d630f3c7 100644
--- a/layout/svg/nsSVGPatternFrame.h
+++ b/layout/svg/nsSVGPatternFrame.h
@@ -81,9 +81,7 @@ public:
 
 protected:
   // Internal methods for handling referenced patterns
-  class AutoPatternReferencer;
   nsSVGPatternFrame* GetReferencedPattern();
-  nsSVGPatternFrame* GetReferencedPatternIfNotInUse();
 
   // Accessors to lookup pattern attributes
   uint16_t GetEnumValue(uint32_t aIndex, nsIContent *aDefault);

From 2773e5508df4fae636df24b8c7f93dd07290a805 Mon Sep 17 00:00:00 2001
From: Jonathan Watt 
Date: Tue, 21 Feb 2017 10:47:22 +0000
Subject: [PATCH 18/96] Bug 1349477, part 4 - Use AutoReferenceChainGuard in
 nsSVGMaskFrame. r=longsonr

MozReview-Commit-ID: 5tVLBcTOLQZ
---
 layout/svg/nsSVGMaskFrame.cpp | 13 +++++++------
 layout/svg/nsSVGMaskFrame.h   | 22 ----------------------
 2 files changed, 7 insertions(+), 28 deletions(-)

diff --git a/layout/svg/nsSVGMaskFrame.cpp b/layout/svg/nsSVGMaskFrame.cpp
index a9887e57348c..47346d0f5ecd 100644
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -7,6 +7,7 @@
 #include "nsSVGMaskFrame.h"
 
 // Keep others in (case-insensitive) order:
+#include "AutoReferenceChainGuard.h"
 #include "gfx2DGlue.h"
 #include "gfxContext.h"
 #include "mozilla/gfx/2D.h"
@@ -204,14 +205,14 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSVGMaskFrame)
 mozilla::Pair>
 nsSVGMaskFrame::GetMaskForMaskedFrame(MaskParams& aParams)
 {
-  // If the flag is set when we get here, it means this mask frame
-  // has already been used painting the current mask, and the document
-  // has a mask reference loop.
-  if (mInUse) {
-    NS_WARNING("Mask loop detected!");
+  // Make sure we break reference loops and over long reference chains:
+  static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
+  AutoReferenceChainGuard refChainGuard(this, &mInUse,
+                                        &sRefChainLengthCounter);
+  if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
+    // Break reference chain
     return MakePair(DrawResult::SUCCESS, RefPtr());
   }
-  AutoMaskReferencer maskRef(this);
 
   gfxRect maskArea = GetMaskArea(aParams.maskedFrame);
   gfxContext* context = aParams.ctx;
diff --git a/layout/svg/nsSVGMaskFrame.h b/layout/svg/nsSVGMaskFrame.h
index 40ba0b555af0..32c23ad083d9 100644
--- a/layout/svg/nsSVGMaskFrame.h
+++ b/layout/svg/nsSVGMaskFrame.h
@@ -111,28 +111,6 @@ private:
    */
   gfxMatrix GetMaskTransform(nsIFrame* aMaskedFrame);
 
-  // A helper class to allow us to paint masks safely. The helper
-  // automatically sets and clears the mInUse flag on the mask frame
-  // (to prevent nasty reference loops). It's easy to mess this up
-  // and break things, so this helper makes the code far more robust.
-  class MOZ_RAII AutoMaskReferencer
-  {
-  public:
-    explicit AutoMaskReferencer(nsSVGMaskFrame *aFrame
-                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
-       : mFrame(aFrame) {
-      MOZ_GUARD_OBJECT_NOTIFIER_INIT;
-      NS_ASSERTION(!mFrame->mInUse, "reference loop!");
-      mFrame->mInUse = true;
-    }
-    ~AutoMaskReferencer() {
-      mFrame->mInUse = false;
-    }
-  private:
-    nsSVGMaskFrame *mFrame;
-    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
-  };
-
   gfxMatrix mMatrixForChildren;
   // recursion prevention flag
   bool mInUse;

From 7d7b3c1dbe748dc2259c3a111a30358b0c818876 Mon Sep 17 00:00:00 2001
From: Alexander Surkov 
Date: Wed, 22 Mar 2017 18:31:18 -0400
Subject: [PATCH 19/96] Bug 1346518 - extend Accessible::RemoveChild debugging
 assertions, part2, r=yzen

---
 accessible/base/nsAccessibilityService.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp
index 31eeb4f47ae1..fa7d89002097 100644
--- a/accessible/base/nsAccessibilityService.cpp
+++ b/accessible/base/nsAccessibilityService.cpp
@@ -595,6 +595,7 @@ nsAccessibilityService::ContentRemoved(nsIPresShell* aPresShell,
     }
 
     if (child) {
+      MOZ_DIAGNOSTIC_ASSERT(child->Parent(), "Unattached accessible from tree");
       document->ContentRemoved(child->Parent(), aChildNode);
 #ifdef A11Y_LOG
       if (logging::IsEnabled(logging::eTree))

From ed96f9e4ea9bd4de103bc14177c8c2b2990659df Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:11:48 -0500
Subject: [PATCH 20/96] Bug 1334504 - Baldr: always enable profiling prologue
 (r=bbouvier)

MozReview-Commit-ID: 6bPt7dtuwPU

--HG--
extra : rebase_source : 06f9a37e14c18261da25ff234ea45df07bf5d6f3
---
 js/src/jit-test/tests/asm.js/testProfiling.js |   2 +-
 js/src/jit/MacroAssembler-inl.h               |   6 +-
 js/src/jit/arm/MacroAssembler-arm.cpp         |   2 +-
 js/src/jit/shared/Assembler-shared.h          |  37 +-
 .../x86-shared/MacroAssembler-x86-shared.cpp  |   2 +-
 js/src/vm/GeckoProfiler.cpp                   |   6 +
 js/src/wasm/WasmCode.cpp                      | 159 +++----
 js/src/wasm/WasmCode.h                        |  89 ++--
 js/src/wasm/WasmCompartment.cpp               |  41 +-
 js/src/wasm/WasmCompartment.h                 |   8 +-
 js/src/wasm/WasmFrameIterator.cpp             | 407 +++++-------------
 js/src/wasm/WasmFrameIterator.h               |  21 +-
 js/src/wasm/WasmGenerator.cpp                 |  24 +-
 js/src/wasm/WasmGenerator.h                   |   2 +-
 js/src/wasm/WasmInstance.cpp                  |  60 +--
 js/src/wasm/WasmInstance.h                    |   4 -
 js/src/wasm/WasmModule.cpp                    |   9 +-
 js/src/wasm/WasmStubs.cpp                     |  22 +-
 js/src/wasm/WasmStubs.h                       |   6 +-
 js/src/wasm/WasmTable.h                       |   4 +-
 js/src/wasm/WasmTypes.h                       |  75 +---
 21 files changed, 310 insertions(+), 676 deletions(-)

diff --git a/js/src/jit-test/tests/asm.js/testProfiling.js b/js/src/jit-test/tests/asm.js/testProfiling.js
index 7c3f348e8b20..732cea43f26d 100644
--- a/js/src/jit-test/tests/asm.js/testProfiling.js
+++ b/js/src/jit-test/tests/asm.js/testProfiling.js
@@ -69,7 +69,7 @@ var f = asmLink(asmCompile('global','ffis',USE_ASM + "var ffi=ffis.ffi; function
 f(0);
 assertStackContainsSeq(stacks, "");
 f(+1);
-assertStackContainsSeq(stacks, "");
+assertStackContainsSeq(stacks, "<,g,f,>");
 f(0);
 assertStackContainsSeq(stacks, "<,g,f,>");
 f(-1);
diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h
index edca338fab0e..0ec15f179384 100644
--- a/js/src/jit/MacroAssembler-inl.h
+++ b/js/src/jit/MacroAssembler-inl.h
@@ -84,21 +84,21 @@ void
 MacroAssembler::call(const wasm::CallSiteDesc& desc, const Register reg)
 {
     CodeOffset l = call(reg);
-    append(desc, l, framePushed());
+    append(desc, l);
 }
 
 void
 MacroAssembler::call(const wasm::CallSiteDesc& desc, uint32_t funcDefIndex)
 {
     CodeOffset l = callWithPatch();
-    append(desc, l, framePushed(), funcDefIndex);
+    append(desc, l, funcDefIndex);
 }
 
 void
 MacroAssembler::call(const wasm::CallSiteDesc& desc, wasm::Trap trap)
 {
     CodeOffset l = callWithPatch();
-    append(desc, l, framePushed(), trap);
+    append(desc, l, trap);
 }
 
 // ===============================================================
diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp
index 8fa1d70cf279..99dc9a1dfec8 100644
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -5138,7 +5138,7 @@ MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc)
 {
     CodeOffset offset(currentOffset());
     ma_nop();
-    append(desc, CodeOffset(currentOffset()), framePushed());
+    append(desc, CodeOffset(currentOffset()));
     return offset;
 }
 
diff --git a/js/src/jit/shared/Assembler-shared.h b/js/src/jit/shared/Assembler-shared.h
index 19f80e609b05..0c8a1cf3d39a 100644
--- a/js/src/jit/shared/Assembler-shared.h
+++ b/js/src/jit/shared/Assembler-shared.h
@@ -749,6 +749,25 @@ struct GlobalAccess
 
 typedef Vector GlobalAccessVector;
 
+// A CallFarJump records the offset of a jump that needs to be patched to a
+// call at the end of the module when all calls have been emitted.
+
+struct CallFarJump
+{
+    uint32_t funcIndex;
+    jit::CodeOffset jump;
+
+    CallFarJump(uint32_t funcIndex, jit::CodeOffset jump)
+      : funcIndex(funcIndex), jump(jump)
+    {}
+
+    void offsetBy(size_t delta) {
+        jump.offsetBy(delta);
+    }
+};
+
+typedef Vector CallFarJumpVector;
+
 // The TrapDesc struct describes a wasm trap that is about to be emitted. This
 // includes the logical wasm bytecode offset to report, the kind of instruction
 // causing the trap, and the stack depth right before control is transferred to
@@ -808,6 +827,7 @@ namespace jit {
 class AssemblerShared
 {
     wasm::CallSiteAndTargetVector callSites_;
+    wasm::CallFarJumpVector callFarJumps_;
     wasm::TrapSiteVector trapSites_;
     wasm::TrapFarJumpVector trapFarJumps_;
     wasm::MemoryAccessVector memoryAccesses_;
@@ -842,16 +862,18 @@ class AssemblerShared
     }
 
     template 
-    void append(const wasm::CallSiteDesc& desc, CodeOffset retAddr, size_t framePushed,
-                Args&&... args)
+    void append(const wasm::CallSiteDesc& desc, CodeOffset retAddr, Args&&... args)
     {
-        // framePushed does not include sizeof(wasm:Frame), so add it in explicitly when
-        // setting the CallSite::stackDepth.
-        wasm::CallSite cs(desc, retAddr.offset(), framePushed + sizeof(wasm::Frame));
+        wasm::CallSite cs(desc, retAddr.offset());
         enoughMemory_ &= callSites_.emplaceBack(cs, mozilla::Forward(args)...);
     }
     wasm::CallSiteAndTargetVector& callSites() { return callSites_; }
 
+    void append(wasm::CallFarJump jmp) {
+        enoughMemory_ &= callFarJumps_.append(jmp);
+    }
+    const wasm::CallFarJumpVector& callFarJumps() const { return callFarJumps_; }
+
     void append(wasm::TrapSite trapSite) {
         enoughMemory_ &= trapSites_.append(trapSite);
     }
@@ -911,6 +933,11 @@ class AssemblerShared
 
         MOZ_ASSERT(other.trapSites_.empty(), "should have been cleared by wasmEmitTrapOutOfLineCode");
 
+        i = callFarJumps_.length();
+        enoughMemory_ &= callFarJumps_.appendAll(other.callFarJumps_);
+        for (; i < callFarJumps_.length(); i++)
+            callFarJumps_[i].offsetBy(delta);
+
         i = trapFarJumps_.length();
         enoughMemory_ &= trapFarJumps_.appendAll(other.trapFarJumps_);
         for (; i < trapFarJumps_.length(); i++)
diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
index 1359bb1aaa4b..9045f0b2716a 100644
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -741,7 +741,7 @@ MacroAssembler::nopPatchableToCall(const wasm::CallSiteDesc& desc)
 {
     CodeOffset offset(currentOffset());
     masm.nop_five();
-    append(desc, CodeOffset(currentOffset()), framePushed());
+    append(desc, CodeOffset(currentOffset()));
     MOZ_ASSERT_IF(!oom(), size() - offset.offset() == ToggledCallSize(nullptr));
     return offset;
 }
diff --git a/js/src/vm/GeckoProfiler.cpp b/js/src/vm/GeckoProfiler.cpp
index 08ae4cef8fd0..8a8efe2e3131 100644
--- a/js/src/vm/GeckoProfiler.cpp
+++ b/js/src/vm/GeckoProfiler.cpp
@@ -141,6 +141,12 @@ GeckoProfiler::enable(bool enabled)
         }
     }
 
+    // WebAssembly code does not need to be released, but profiling string
+    // labels have to be generated so that they are available during async
+    // profiling stack iteration.
+    for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
+        c->wasm.ensureProfilingLabels(enabled);
+
     return true;
 }
 
diff --git a/js/src/wasm/WasmCode.cpp b/js/src/wasm/WasmCode.cpp
index 4d928ceaeda3..54cc84547b21 100644
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -299,15 +299,11 @@ FuncImport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
 
 CodeRange::CodeRange(Kind kind, Offsets offsets)
   : begin_(offsets.begin),
-    profilingReturn_(0),
+    ret_(0),
     end_(offsets.end),
     funcIndex_(0),
     funcLineOrBytecode_(0),
-    funcBeginToTableEntry_(0),
-    funcBeginToTableProfilingJump_(0),
-    funcBeginToNonProfilingEntry_(0),
-    funcProfilingJumpToProfilingReturn_(0),
-    funcProfilingEpilogueToProfilingReturn_(0),
+    funcBeginToNormalEntry_(0),
     kind_(kind)
 {
     MOZ_ASSERT(begin_ <= end_);
@@ -315,44 +311,32 @@ CodeRange::CodeRange(Kind kind, Offsets offsets)
                kind_ == FarJumpIsland || kind_ == DebugTrap);
 }
 
-CodeRange::CodeRange(Kind kind, ProfilingOffsets offsets)
+CodeRange::CodeRange(Kind kind, CallableOffsets offsets)
   : begin_(offsets.begin),
-    profilingReturn_(offsets.profilingReturn),
+    ret_(offsets.ret),
     end_(offsets.end),
     funcIndex_(0),
     funcLineOrBytecode_(0),
-    funcBeginToTableEntry_(0),
-    funcBeginToTableProfilingJump_(0),
-    funcBeginToNonProfilingEntry_(0),
-    funcProfilingJumpToProfilingReturn_(0),
-    funcProfilingEpilogueToProfilingReturn_(0),
+    funcBeginToNormalEntry_(0),
     kind_(kind)
 {
-    MOZ_ASSERT(begin_ < profilingReturn_);
-    MOZ_ASSERT(profilingReturn_ < end_);
+    MOZ_ASSERT(begin_ < ret_);
+    MOZ_ASSERT(ret_ < end_);
     MOZ_ASSERT(kind_ == ImportJitExit || kind_ == ImportInterpExit || kind_ == TrapExit);
 }
 
 CodeRange::CodeRange(uint32_t funcIndex, uint32_t funcLineOrBytecode, FuncOffsets offsets)
   : begin_(offsets.begin),
-    profilingReturn_(offsets.profilingReturn),
+    ret_(offsets.ret),
     end_(offsets.end),
     funcIndex_(funcIndex),
     funcLineOrBytecode_(funcLineOrBytecode),
-    funcBeginToTableEntry_(offsets.tableEntry - begin_),
-    funcBeginToTableProfilingJump_(offsets.tableProfilingJump - begin_),
-    funcBeginToNonProfilingEntry_(offsets.nonProfilingEntry - begin_),
-    funcProfilingJumpToProfilingReturn_(profilingReturn_ - offsets.profilingJump),
-    funcProfilingEpilogueToProfilingReturn_(profilingReturn_ - offsets.profilingEpilogue),
+    funcBeginToNormalEntry_(offsets.normalEntry - begin_),
     kind_(Function)
 {
-    MOZ_ASSERT(begin_ < profilingReturn_);
-    MOZ_ASSERT(profilingReturn_ < end_);
-    MOZ_ASSERT(offsets.tableEntry - begin_ <= UINT8_MAX);
-    MOZ_ASSERT(offsets.tableProfilingJump - begin_ <= UINT8_MAX);
-    MOZ_ASSERT(offsets.nonProfilingEntry - begin_ <= UINT8_MAX);
-    MOZ_ASSERT(profilingReturn_ - offsets.profilingJump <= UINT8_MAX);
-    MOZ_ASSERT(profilingReturn_ - offsets.profilingEpilogue <= UINT8_MAX);
+    MOZ_ASSERT(begin_ < ret_);
+    MOZ_ASSERT(ret_ < end_);
+    MOZ_ASSERT(offsets.normalEntry - begin_ <= UINT8_MAX);
 }
 
 static size_t
@@ -413,7 +397,6 @@ Metadata::serializedSize() const
            SerializedPodVectorSize(memoryAccesses) +
            SerializedPodVectorSize(codeRanges) +
            SerializedPodVectorSize(callSites) +
-           SerializedPodVectorSize(callThunks) +
            SerializedPodVectorSize(funcNames) +
            SerializedPodVectorSize(customSections) +
            filename.serializedSize();
@@ -434,7 +417,6 @@ Metadata::serialize(uint8_t* cursor) const
     cursor = SerializePodVector(cursor, memoryAccesses);
     cursor = SerializePodVector(cursor, codeRanges);
     cursor = SerializePodVector(cursor, callSites);
-    cursor = SerializePodVector(cursor, callThunks);
     cursor = SerializePodVector(cursor, funcNames);
     cursor = SerializePodVector(cursor, customSections);
     cursor = filename.serialize(cursor);
@@ -453,7 +435,6 @@ Metadata::deserialize(const uint8_t* cursor)
     (cursor = DeserializePodVector(cursor, &memoryAccesses)) &&
     (cursor = DeserializePodVector(cursor, &codeRanges)) &&
     (cursor = DeserializePodVector(cursor, &callSites)) &&
-    (cursor = DeserializePodVector(cursor, &callThunks)) &&
     (cursor = DeserializePodVector(cursor, &funcNames)) &&
     (cursor = DeserializePodVector(cursor, &customSections)) &&
     (cursor = filename.deserialize(cursor));
@@ -476,7 +457,6 @@ Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const
            memoryAccesses.sizeOfExcludingThis(mallocSizeOf) +
            codeRanges.sizeOfExcludingThis(mallocSizeOf) +
            callSites.sizeOfExcludingThis(mallocSizeOf) +
-           callThunks.sizeOfExcludingThis(mallocSizeOf) +
            funcNames.sizeOfExcludingThis(mallocSizeOf) +
            customSections.sizeOfExcludingThis(mallocSizeOf) +
            filename.sizeOfExcludingThis(mallocSizeOf);
@@ -578,7 +558,6 @@ Code::Code(UniqueCodeSegment segment,
   : segment_(Move(segment)),
     metadata_(&metadata),
     maybeBytecode_(maybeBytecode),
-    profilingEnabled_(false),
     enterAndLeaveFrameTrapsCounter_(0)
 {
     MOZ_ASSERT_IF(metadata_->debugEnabled, maybeBytecode);
@@ -986,77 +965,67 @@ Code::clearBreakpointsIn(JSContext* cx, WasmInstanceObject* instance, js::Debugg
 }
 
 
-bool
-Code::ensureProfilingState(JSRuntime* rt, bool newProfilingEnabled)
+// When enabled, generate profiling labels for every name in funcNames_ that is
+// the name of some Function CodeRange. This involves malloc() so do it now
+// since, once we start sampling, we'll be in a signal-handing context where we
+// cannot malloc.
+void
+Code::ensureProfilingLabels(bool profilingEnabled)
 {
-    if (profilingEnabled_ == newProfilingEnabled)
-        return true;
+    if (!profilingEnabled) {
+        profilingLabels_.clear();
+        return;
+    }
 
-    // When enabled, generate profiling labels for every name in funcNames_
-    // that is the name of some Function CodeRange. This involves malloc() so
-    // do it now since, once we start sampling, we'll be in a signal-handing
-    // context where we cannot malloc.
-    if (newProfilingEnabled) {
-        for (const CodeRange& codeRange : metadata_->codeRanges) {
-            if (!codeRange.isFunction())
-                continue;
+    if (!profilingLabels_.empty())
+        return;
 
-            ToCStringBuf cbuf;
-            const char* bytecodeStr = NumberToCString(nullptr, &cbuf, codeRange.funcLineOrBytecode());
-            MOZ_ASSERT(bytecodeStr);
+    for (const CodeRange& codeRange : metadata_->codeRanges) {
+        if (!codeRange.isFunction())
+            continue;
 
-            UTF8Bytes name;
-            if (!getFuncName(codeRange.funcIndex(), &name) || !name.append(" (", 2))
-                return false;
+        ToCStringBuf cbuf;
+        const char* bytecodeStr = NumberToCString(nullptr, &cbuf, codeRange.funcLineOrBytecode());
+        MOZ_ASSERT(bytecodeStr);
 
-            if (const char* filename = metadata_->filename.get()) {
-                if (!name.append(filename, strlen(filename)))
-                    return false;
-            } else {
-                if (!name.append('?'))
-                    return false;
-            }
+        UTF8Bytes name;
+        if (!getFuncName(codeRange.funcIndex(), &name) || !name.append(" (", 2))
+            return;
 
-            if (!name.append(':') ||
-                !name.append(bytecodeStr, strlen(bytecodeStr)) ||
-                !name.append(")\0", 2))
-            {
-                return false;
-            }
-
-            UniqueChars label(name.extractOrCopyRawBuffer());
-            if (!label)
-                return false;
-
-            if (codeRange.funcIndex() >= funcLabels_.length()) {
-                if (!funcLabels_.resize(codeRange.funcIndex() + 1))
-                    return false;
-            }
-
-            funcLabels_[codeRange.funcIndex()] = Move(label);
+        if (const char* filename = metadata_->filename.get()) {
+            if (!name.append(filename, strlen(filename)))
+                return;
+        } else {
+            if (!name.append('?'))
+                return;
         }
-    } else {
-        funcLabels_.clear();
+
+        if (!name.append(':') ||
+            !name.append(bytecodeStr, strlen(bytecodeStr)) ||
+            !name.append(")\0", 2))
+        {
+            return;
+        }
+
+        UniqueChars label(name.extractOrCopyRawBuffer());
+        if (!label)
+            return;
+
+        if (codeRange.funcIndex() >= profilingLabels_.length()) {
+            if (!profilingLabels_.resize(codeRange.funcIndex() + 1))
+                return;
+        }
+
+        profilingLabels_[codeRange.funcIndex()] = Move(label);
     }
+}
 
-    // Only mutate the code after the fallible operations are complete to avoid
-    // the need to rollback.
-    profilingEnabled_ = newProfilingEnabled;
-
-    {
-        AutoWritableJitCode awjc(segment_->base(), segment_->length());
-        AutoFlushICache afc("Code::ensureProfilingState");
-        AutoFlushICache::setRange(uintptr_t(segment_->base()), segment_->length());
-
-        for (const CallSite& callSite : metadata_->callSites)
-            ToggleProfiling(*this, callSite, newProfilingEnabled);
-        for (const CallThunk& callThunk : metadata_->callThunks)
-            ToggleProfiling(*this, callThunk, newProfilingEnabled);
-        for (const CodeRange& codeRange : metadata_->codeRanges)
-            ToggleProfiling(*this, codeRange, newProfilingEnabled);
-    }
-
-    return true;
+const char*
+Code::profilingLabel(uint32_t funcIndex) const
+{
+    if (funcIndex >= profilingLabels_.length() || !profilingLabels_[funcIndex])
+        return "?";
+    return profilingLabels_[funcIndex].get();
 }
 
 void
diff --git a/js/src/wasm/WasmCode.h b/js/src/wasm/WasmCode.h
index 6c26ec8043a6..1ba7bd0a6c44 100644
--- a/js/src/wasm/WasmCode.h
+++ b/js/src/wasm/WasmCode.h
@@ -57,9 +57,6 @@ class CodeSegment
     uint8_t* outOfBoundsCode_;
     uint8_t* unalignedAccessCode_;
 
-    // The profiling mode may be changed dynamically.
-    bool profilingEnabled_;
-
   public:
 #ifdef MOZ_VTUNE
     unsigned vtune_method_id_; // Zero if unset.
@@ -249,21 +246,17 @@ class CodeRange
   private:
     // All fields are treated as cacheable POD:
     uint32_t begin_;
-    uint32_t profilingReturn_;
+    uint32_t ret_;
     uint32_t end_;
     uint32_t funcIndex_;
     uint32_t funcLineOrBytecode_;
-    uint8_t funcBeginToTableEntry_;
-    uint8_t funcBeginToTableProfilingJump_;
-    uint8_t funcBeginToNonProfilingEntry_;
-    uint8_t funcProfilingJumpToProfilingReturn_;
-    uint8_t funcProfilingEpilogueToProfilingReturn_;
+    uint8_t funcBeginToNormalEntry_;
     Kind kind_ : 8;
 
   public:
     CodeRange() = default;
     CodeRange(Kind kind, Offsets offsets);
-    CodeRange(Kind kind, ProfilingOffsets offsets);
+    CodeRange(Kind kind, CallableOffsets offsets);
     CodeRange(uint32_t funcIndex, uint32_t lineOrBytecode, FuncOffsets offsets);
 
     // All CodeRanges have a begin and end.
@@ -293,41 +286,30 @@ class CodeRange
     bool isInline() const {
         return kind() == Inline;
     }
+    bool isThunk() const {
+        return kind() == FarJumpIsland;
+    }
 
-    // Every CodeRange except entry and inline stubs has a profiling return
-    // which is used for asynchronous profiling to determine the frame pointer.
+    // Every CodeRange except entry and inline stubs are callable and have a
+    // return statement. Asynchronous frame iteration needs to know the offset
+    // of the return instruction to calculate the frame pointer.
 
-    uint32_t profilingReturn() const {
+    uint32_t ret() const {
         MOZ_ASSERT(isFunction() || isImportExit() || isTrapExit());
-        return profilingReturn_;
+        return ret_;
     }
 
-    // Functions have offsets which allow patching to selectively execute
-    // profiling prologues/epilogues.
+    // Function CodeRanges have two entry points: one for normal calls (with a
+    // known signature) and one for table calls (which involves dynamic
+    // signature checking).
 
-    uint32_t funcProfilingEntry() const {
-        MOZ_ASSERT(isFunction());
-        return begin();
-    }
     uint32_t funcTableEntry() const {
         MOZ_ASSERT(isFunction());
-        return begin_ + funcBeginToTableEntry_;
+        return begin_;
     }
-    uint32_t funcTableProfilingJump() const {
+    uint32_t funcNormalEntry() const {
         MOZ_ASSERT(isFunction());
-        return begin_ + funcBeginToTableProfilingJump_;
-    }
-    uint32_t funcNonProfilingEntry() const {
-        MOZ_ASSERT(isFunction());
-        return begin_ + funcBeginToNonProfilingEntry_;
-    }
-    uint32_t funcProfilingJump() const {
-        MOZ_ASSERT(isFunction());
-        return profilingReturn_ - funcProfilingJumpToProfilingReturn_;
-    }
-    uint32_t funcProfilingEpilogue() const {
-        MOZ_ASSERT(isFunction());
-        return profilingReturn_ - funcProfilingEpilogueToProfilingReturn_;
+        return begin_ + funcBeginToNormalEntry_;
     }
     uint32_t funcIndex() const {
         MOZ_ASSERT(isFunction());
@@ -354,25 +336,6 @@ class CodeRange
 
 WASM_DECLARE_POD_VECTOR(CodeRange, CodeRangeVector)
 
-// A CallThunk describes the offset and target of thunks so that they may be
-// patched at runtime when profiling is toggled. Thunks are emitted to connect
-// callsites that are too far away from callees to fit in a single call
-// instruction's relative offset.
-
-struct CallThunk
-{
-    uint32_t offset;
-    union {
-        uint32_t funcIndex;
-        uint32_t codeRangeIndex;
-    } u;
-
-    CallThunk(uint32_t offset, uint32_t funcIndex) : offset(offset) { u.funcIndex = funcIndex; }
-    CallThunk() = default;
-};
-
-WASM_DECLARE_POD_VECTOR(CallThunk, CallThunkVector)
-
 // A wasm module can either use no memory, a unshared memory (ArrayBuffer) or
 // shared memory (SharedArrayBuffer).
 
@@ -463,7 +426,6 @@ struct Metadata : ShareableBase, MetadataCacheablePod
     MemoryAccessVector    memoryAccesses;
     CodeRangeVector       codeRanges;
     CallSiteVector        callSites;
-    CallThunkVector       callThunks;
     NameInBytecodeVector  funcNames;
     CustomSectionVector   customSections;
     CacheableChars        filename;
@@ -560,8 +522,9 @@ class Code
     const SharedMetadata     metadata_;
     const SharedBytes        maybeBytecode_;
     UniqueGeneratedSourceMap maybeSourceMap_;
-    CacheableCharsVector     funcLabels_;
-    bool                     profilingEnabled_;
+
+    // Mutated at runtime:
+    CacheableCharsVector     profilingLabels_;
 
     // State maintained when debugging is enabled:
 
@@ -602,15 +565,11 @@ class Code
     bool getOffsetLocation(JSContext* cx, uint32_t offset, bool* found, size_t* lineno, size_t* column);
     bool totalSourceLines(JSContext* cx, uint32_t* count);
 
-    // Each Code has a profiling mode that is updated to match the runtime's
-    // profiling mode when there are no other activations of the code live on
-    // the stack. Once in profiling mode, ProfilingFrameIterator can be used to
-    // asynchronously walk the stack. Otherwise, the ProfilingFrameIterator will
-    // skip any activations of this code.
+    // To save memory, profilingLabels_ are generated lazily when profiling mode
+    // is enabled.
 
-    MOZ_MUST_USE bool ensureProfilingState(JSRuntime* rt, bool enabled);
-    bool profilingEnabled() const { return profilingEnabled_; }
-    const char* profilingLabel(uint32_t funcIndex) const { return funcLabels_[funcIndex].get(); }
+    void ensureProfilingLabels(bool profilingEnabled);
+    const char* profilingLabel(uint32_t funcIndex) const;
 
     // The Code can track enter/leave frame events. Any such event triggers
     // debug trap. The enter/leave frame events enabled or disabled across
diff --git a/js/src/wasm/WasmCompartment.cpp b/js/src/wasm/WasmCompartment.cpp
index 60a1b566f2bd..53779e9eff1d 100644
--- a/js/src/wasm/WasmCompartment.cpp
+++ b/js/src/wasm/WasmCompartment.cpp
@@ -29,8 +29,7 @@ using namespace wasm;
 
 Compartment::Compartment(Zone* zone)
   : mutatingInstances_(false),
-    activationCount_(0),
-    profilingEnabled_(false)
+    activationCount_(0)
 {}
 
 Compartment::~Compartment()
@@ -73,8 +72,7 @@ Compartment::registerInstance(JSContext* cx, HandleWasmInstanceObject instanceOb
     Instance& instance = instanceObj->instance();
     MOZ_ASSERT(this == &instance.compartment()->wasm);
 
-    if (!instance.ensureProfilingState(cx, profilingEnabled_))
-        return false;
+    instance.code().ensureProfilingLabels(cx->runtime()->geckoProfiler().enabled());
 
     size_t index;
     if (BinarySearchIf(instances_, 0, instances_.length(), InstanceComparator(instance), &index))
@@ -139,38 +137,11 @@ Compartment::lookupInstanceDeprecated(const void* pc) const
     return instances_[index];
 }
 
-bool
-Compartment::ensureProfilingState(JSContext* cx)
+void
+Compartment::ensureProfilingLabels(bool profilingEnabled)
 {
-    bool newProfilingEnabled = cx->runtime()->geckoProfiler().enabled();
-    if (profilingEnabled_ == newProfilingEnabled)
-        return true;
-
-    // Since one Instance can call another Instance in the same compartment
-    // directly without calling through Instance::callExport(), when profiling
-    // is enabled, enable it for the entire compartment at once. It is only safe
-    // to enable profiling when the wasm is not on the stack, so delay enabling
-    // profiling until there are no live WasmActivations in this compartment.
-
-    if (activationCount_ > 0)
-        return true;
-
-    for (Instance* instance : instances_) {
-        if (!instance->ensureProfilingState(cx, newProfilingEnabled))
-            return false;
-    }
-
-    profilingEnabled_ = newProfilingEnabled;
-    return true;
-}
-
-bool
-Compartment::profilingEnabled() const
-{
-    // Profiling can asynchronously interrupt the mutation of the instances_
-    // vector which is used by lookupCode() during stack-walking. To handle
-    // this rare case, disable profiling during mutation.
-    return profilingEnabled_ && !mutatingInstances_;
+    for (Instance* instance : instances_)
+        instance->code().ensureProfilingLabels(profilingEnabled);
 }
 
 void
diff --git a/js/src/wasm/WasmCompartment.h b/js/src/wasm/WasmCompartment.h
index dcdd75d0c317..b255f80ff6f6 100644
--- a/js/src/wasm/WasmCompartment.h
+++ b/js/src/wasm/WasmCompartment.h
@@ -40,7 +40,6 @@ class Compartment
     InstanceVector instances_;
     volatile bool  mutatingInstances_;
     size_t         activationCount_;
-    bool           profilingEnabled_;
 
     friend class js::WasmActivation;
 
@@ -89,12 +88,9 @@ class Compartment
 
     Instance* lookupInstanceDeprecated(const void* pc) const;
 
-    // To ensure profiling is enabled (so that wasm frames are not lost in
-    // profiling callstacks), ensureProfilingState must be called before calling
-    // the first wasm function in a compartment.
+    // Ensure all Instances in this JSCompartment have profiling labels created.
 
-    bool ensureProfilingState(JSContext* cx);
-    bool profilingEnabled() const;
+    void ensureProfilingLabels(bool profilingEnabled);
 
     // about:memory reporting
 
diff --git a/js/src/wasm/WasmFrameIterator.cpp b/js/src/wasm/WasmFrameIterator.cpp
index 232774966aac..da60f3427ef9 100644
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -45,11 +45,10 @@ CallerFPFromFP(void* fp)
     return reinterpret_cast(fp)->callerFP;
 }
 
-static TlsData*
-TlsDataFromFP(void *fp)
+static DebugFrame*
+FrameToDebugFrame(void* fp)
 {
-    void* debugFrame = (uint8_t*)fp - DebugFrame::offsetOfFrame();
-    return reinterpret_cast(debugFrame)->tlsData();
+    return reinterpret_cast((uint8_t*)fp - DebugFrame::offsetOfFrame());
 }
 
 FrameIterator::FrameIterator()
@@ -69,33 +68,30 @@ FrameIterator::FrameIterator(WasmActivation* activation, Unwind unwind)
     code_(nullptr),
     callsite_(nullptr),
     codeRange_(nullptr),
-    fp_(activation->fp()),
+    fp_(nullptr),
     unwind_(unwind),
     missingFrameMessage_(false)
 {
-    if (fp_) {
-        settle();
+    // When execution is interrupted, the embedding may capture a stack trace.
+    // Since we've lost all the register state, we can't unwind the full stack
+    // like ProfilingFrameIterator does. However, we can recover the interrupted
+    // function via the resumePC and at least print that frame.
+    if (void* resumePC = activation->resumePC()) {
+        code_ = activation->compartment()->wasm.lookupCode(resumePC);
+        codeRange_ = code_->lookupRange(resumePC);
+        MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
+        MOZ_ASSERT(!done());
         return;
     }
 
-    void* pc = activation_->resumePC();
-    if (!pc) {
+    fp_ = activation->fp();
+
+    if (!fp_) {
         MOZ_ASSERT(done());
         return;
     }
 
-    code_ = activation_->compartment()->wasm.lookupCode(pc);
-    MOZ_ASSERT(code_);
-
-    const CodeRange* codeRange = code_->lookupRange(pc);
-    MOZ_ASSERT(codeRange);
-
-    if (codeRange->kind() == CodeRange::Function)
-        codeRange_ = codeRange;
-    else
-        missingFrameMessage_ = true;
-
-    MOZ_ASSERT(!done());
+    settle();
 }
 
 bool
@@ -127,14 +123,9 @@ FrameIterator::settle()
 
     void* returnAddress = ReturnAddressFromFP(fp_);
 
-    code_ = activation_->compartment()->wasm.lookupCode(returnAddress);
-    MOZ_ASSERT(code_);
+    fp_ = CallerFPFromFP(fp_);
 
-    codeRange_ = code_->lookupRange(returnAddress);
-    MOZ_ASSERT(codeRange_);
-
-    if (codeRange_->kind() == CodeRange::Entry) {
-        fp_ = nullptr;
+    if (!fp_) {
         code_ = nullptr;
         codeRange_ = nullptr;
         callsite_ = nullptr;
@@ -146,15 +137,15 @@ FrameIterator::settle()
         return;
     }
 
-    MOZ_RELEASE_ASSERT(codeRange_->kind() == CodeRange::Function);
+    code_ = activation_->compartment()->wasm.lookupCode(returnAddress);
+    MOZ_ASSERT(code_);
+
+    codeRange_ = code_->lookupRange(returnAddress);
+    MOZ_ASSERT(codeRange_->kind() == CodeRange::Function);
 
     callsite_ = code_->lookupCallSite(returnAddress);
     MOZ_ASSERT(callsite_);
 
-    DebugOnly oldfp = fp_;
-    fp_ += callsite_->stackDepth();
-    MOZ_ASSERT_IF(code_->profilingEnabled(), fp_ == CallerFPFromFP(oldfp));
-
     MOZ_ASSERT(!done());
 }
 
@@ -187,8 +178,7 @@ FrameIterator::functionDisplayAtom() const
     JSContext* cx = activation_->cx();
 
     if (missingFrameMessage_) {
-        const char* msg = "asm.js/wasm frames may be missing; enable the profiler before running "
-                          "to see all frames";
+        const char* msg = "asm.js/wasm frames may be missing below this one";
         JSAtom* atom = Atomize(cx, msg, strlen(msg));
         if (!atom) {
             cx->clearPendingException();
@@ -221,7 +211,7 @@ Instance*
 FrameIterator::instance() const
 {
     MOZ_ASSERT(!done() && debugEnabled());
-    return TlsDataFromFP(fp_)->instance;
+    return FrameToDebugFrame(fp_)->instance();
 }
 
 bool
@@ -238,9 +228,7 @@ DebugFrame*
 FrameIterator::debugFrame() const
 {
     MOZ_ASSERT(!done() && debugEnabled());
-    // The fp() points to wasm::Frame.
-    void* buf = static_cast(fp_) - DebugFrame::offsetOfFrame();
-    return static_cast(buf);
+    return FrameToDebugFrame(fp_);
 }
 
 const CallSite*
@@ -255,7 +243,7 @@ FrameIterator::debugTrapCallsite() const
 /*****************************************************************************/
 // Prologue/epilogue code generation
 
-// These constants reflect statically-determined offsets in the profiling
+// These constants reflect statically-determined offsets in the
 // prologue/epilogue. The offsets are dynamically asserted during code
 // generation.
 #if defined(JS_CODEGEN_X64)
@@ -311,35 +299,34 @@ PushRetAddr(MacroAssembler& masm)
 }
 
 // Generate a prologue that maintains WasmActivation::fp as the virtual frame
-// pointer so that ProfilingFrameIterator can walk the stack at any pc in
-// generated code.
+// pointer so that FrameIterator can walk the stack at any pc in generated code.
 static void
-GenerateProfilingPrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
-                          ProfilingOffsets* offsets)
+GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
+                         uint32_t* entry)
 {
     Register scratch = ABINonArgReg0;
 
-    // ProfilingFrameIterator needs to know the offsets of several key
-    // instructions from entry. To save space, we make these offsets static
-    // constants and assert that they match the actual codegen below. On ARM,
-    // this requires AutoForbidPools to prevent a constant pool from being
-    // randomly inserted between two instructions.
+    // FrameIterator needs to know the offsets of several key instructions from
+    // entry. To save space, we make these offsets static constants and assert
+    // that they match the actual codegen below. On ARM, this requires
+    // AutoForbidPools to prevent a constant pool from being randomly inserted
+    // between two instructions.
     {
 #if defined(JS_CODEGEN_ARM)
         AutoForbidPools afp(&masm, /* number of instructions in scope = */ 8);
 #endif
 
-        offsets->begin = masm.currentOffset();
+        *entry = masm.currentOffset();
 
         PushRetAddr(masm);
-        MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - offsets->begin);
+        MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - *entry);
 
         masm.loadWasmActivationFromSymbolicAddress(scratch);
         masm.push(Address(scratch, WasmActivation::offsetOfFP()));
-        MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - offsets->begin);
+        MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - *entry);
 
         masm.storePtr(masm.getStackPointer(), Address(scratch, WasmActivation::offsetOfFP()));
-        MOZ_ASSERT_IF(!masm.oom(), StoredFP == masm.currentOffset() - offsets->begin);
+        MOZ_ASSERT_IF(!masm.oom(), StoredFP == masm.currentOffset() - *entry);
     }
 
     if (reason != ExitReason::None)
@@ -349,10 +336,10 @@ GenerateProfilingPrologue(MacroAssembler& masm, unsigned framePushed, ExitReason
         masm.subFromStackPtr(Imm32(framePushed));
 }
 
-// Generate the inverse of GenerateProfilingPrologue.
+// Generate the inverse of GenerateCallablePrologue.
 static void
-GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
-                          ProfilingOffsets* offsets)
+GenerateCallableEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
+                         uint32_t* ret)
 {
     Register scratch = ABINonArgReturnReg0;
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
@@ -370,61 +357,47 @@ GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason
                      Address(scratch, WasmActivation::offsetOfExitReason()));
     }
 
-    // ProfilingFrameIterator assumes fixed offsets of the last few
-    // instructions from profilingReturn, so AutoForbidPools to ensure that
-    // unintended instructions are not automatically inserted.
-    {
 #if defined(JS_CODEGEN_ARM)
-        AutoForbidPools afp(&masm, /* number of instructions in scope = */ 4);
+    // FrameIterator assumes there is nothing after the pop of the stack before
+    // the return instruction so AutoForbidPools to ensure that no pool is
+    // automatically inserted by the ARM MacroAssembler.
+    AutoForbidPools afp(&masm, /* number of instructions in scope = */ 4);
 #endif
 
-        // sp protects the stack from clobber via asynchronous signal handlers
-        // and the async interrupt exit. Since activation.fp can be read at any
-        // time and still points to the current frame, be careful to only update
-        // sp after activation.fp has been repointed to the caller's frame.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
-    defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-        masm.loadPtr(Address(masm.getStackPointer(), 0), scratch2);
-        masm.storePtr(scratch2, Address(scratch, WasmActivation::offsetOfFP()));
-        DebugOnly prePop = masm.currentOffset();
-        masm.addToStackPtr(Imm32(sizeof(void *)));
-        MOZ_ASSERT_IF(!masm.oom(), PostStorePrePopFP == masm.currentOffset() - prePop);
+    // sp protects the stack from clobber via asynchronous signal handlers and
+    // the async interrupt exit. Since activation.fp can be read at any time and
+    // still points to the current frame, be careful to only update sp after
+    // activation.fp has been repointed to the caller's frame.
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+    masm.loadPtr(Address(masm.getStackPointer(), 0), scratch2);
+    masm.storePtr(scratch2, Address(scratch, WasmActivation::offsetOfFP()));
+
+    DebugOnly prePop = masm.currentOffset();
+    masm.addToStackPtr(Imm32(sizeof(void *)));
+    MOZ_ASSERT_IF(!masm.oom(), PostStorePrePopFP == masm.currentOffset() - prePop);
 #else
-        masm.pop(Address(scratch, WasmActivation::offsetOfFP()));
-        MOZ_ASSERT(PostStorePrePopFP == 0);
+    masm.pop(Address(scratch, WasmActivation::offsetOfFP()));
+    MOZ_ASSERT(PostStorePrePopFP == 0);
 #endif
 
-        offsets->profilingReturn = masm.currentOffset();
-        masm.ret();
-    }
+    *ret = masm.currentOffset();
+    masm.ret();
 }
 
-// In profiling mode, we need to maintain fp so that we can unwind the stack at
-// any pc. In non-profiling mode, the only way to observe WasmActivation::fp is
-// to call out to C++ so, as an optimization, we don't update fp. To avoid
-// recompilation when the profiling mode is toggled, we generate both prologues
-// a priori and switch between prologues when the profiling mode is toggled.
-// Specifically, ToggleProfiling patches all callsites to either call the
-// profiling or non-profiling entry point.
 void
 wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId,
                                FuncOffsets* offsets)
 {
 #if defined(JS_CODEGEN_ARM)
     // Flush pending pools so they do not get dumped between the 'begin' and
-    // 'entry' offsets since the difference must be less than UINT8_MAX.
+    // 'normalEntry' offsets since the difference must be less than UINT8_MAX
+    // to be stored in CodeRange::funcBeginToNormalEntry_.
     masm.flushBuffer();
 #endif
-
     masm.haltingAlign(CodeAlignment);
 
-    GenerateProfilingPrologue(masm, framePushed, ExitReason::None, offsets);
-    Label body;
-    masm.jump(&body);
-
-    // Generate table entry thunk:
-    masm.haltingAlign(CodeAlignment);
-    offsets->tableEntry = masm.currentOffset();
+    // Generate table entry:
+    offsets->begin = masm.currentOffset();
     TrapOffset trapOffset(0);  // ignored by masm.wasmEmitTrapOutOfLineCode
     TrapDesc trap(trapOffset, Trap::IndirectCallBadSig, masm.framePushed());
     switch (sigId.kind()) {
@@ -440,66 +413,38 @@ wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, const
       case SigIdDesc::Kind::None:
         break;
     }
-    offsets->tableProfilingJump = masm.nopPatchableToNearJump().offset();
 
-    // Generate normal prologue:
+    // Generate normal entry:
     masm.nopAlign(CodeAlignment);
-    offsets->nonProfilingEntry = masm.currentOffset();
-    PushRetAddr(masm);
-    masm.subFromStackPtr(Imm32(framePushed + FrameBytesAfterReturnAddress));
+    GenerateCallablePrologue(masm, framePushed, ExitReason::None, &offsets->normalEntry);
 
-    // Prologue join point, body begin:
-    masm.bind(&body);
     masm.setFramePushed(framePushed);
 }
 
-// Similar to GenerateFunctionPrologue (see comment), we generate both a
-// profiling and non-profiling epilogue a priori. When the profiling mode is
-// toggled, ToggleProfiling patches the 'profiling jump' to either be a nop
-// (falling through to the normal prologue) or a jump (jumping to the profiling
-// epilogue).
 void
 wasm::GenerateFunctionEpilogue(MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets)
 {
     MOZ_ASSERT(masm.framePushed() == framePushed);
-
-#if defined(JS_CODEGEN_ARM)
-    // Flush pending pools so they do not get dumped between the profilingReturn
-    // and profilingJump/profilingEpilogue offsets since the difference must be
-    // less than UINT8_MAX.
-    masm.flushBuffer();
-#endif
-
-    // Generate a nop that is overwritten by a jump to the profiling epilogue
-    // when profiling is enabled.
-    offsets->profilingJump = masm.nopPatchableToNearJump().offset();
-
-    // Normal epilogue:
-    masm.addToStackPtr(Imm32(framePushed + FrameBytesAfterReturnAddress));
-    masm.ret();
+    GenerateCallableEpilogue(masm, framePushed, ExitReason::None, &offsets->ret);
     masm.setFramePushed(0);
-
-    // Profiling epilogue:
-    offsets->profilingEpilogue = masm.currentOffset();
-    GenerateProfilingEpilogue(masm, framePushed, ExitReason::None, offsets);
 }
 
 void
 wasm::GenerateExitPrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
-                           ProfilingOffsets* offsets)
+                           CallableOffsets* offsets)
 {
     masm.haltingAlign(CodeAlignment);
-    GenerateProfilingPrologue(masm, framePushed, reason, offsets);
+    GenerateCallablePrologue(masm, framePushed, reason, &offsets->begin);
     masm.setFramePushed(framePushed);
 }
 
 void
 wasm::GenerateExitEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
-                           ProfilingOffsets* offsets)
+                           CallableOffsets* offsets)
 {
     // Inverse of GenerateExitPrologue:
     MOZ_ASSERT(masm.framePushed() == framePushed);
-    GenerateProfilingEpilogue(masm, framePushed, reason, offsets);
+    GenerateCallableEpilogue(masm, framePushed, reason, &offsets->ret);
     masm.setFramePushed(0);
 }
 
@@ -527,21 +472,11 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation)
     stackAddress_(nullptr),
     exitReason_(ExitReason::None)
 {
-    // If profiling hasn't been enabled for this instance, then CallerFPFromFP
-    // will be trash, so ignore the entire activation. In practice, this only
-    // happens if profiling is enabled while the instance is on the stack (in
-    // which case profiling will be enabled when the instance becomes inactive
-    // and gets called again).
-    if (!activation_->compartment()->wasm.profilingEnabled()) {
-        MOZ_ASSERT(done());
-        return;
-    }
-
     initFromFP();
 }
 
 static inline void
-AssertMatchesCallSite(const WasmActivation& activation, void* callerPC, void* callerFP, void* fp)
+AssertMatchesCallSite(const WasmActivation& activation, void* callerPC, void* callerFP)
 {
 #ifdef DEBUG
     Code* code = activation.compartment()->wasm.lookupCode(callerPC);
@@ -557,8 +492,6 @@ AssertMatchesCallSite(const WasmActivation& activation, void* callerPC, void* ca
 
     const CallSite* callsite = code->lookupCallSite(callerPC);
     MOZ_ASSERT(callsite);
-
-    MOZ_ASSERT(callerFP == (uint8_t*)fp + callsite->stackDepth());
 #endif
 }
 
@@ -600,7 +533,7 @@ ProfilingFrameIterator::initFromFP()
         fp = CallerFPFromFP(fp);
         callerPC_ = ReturnAddressFromFP(fp);
         callerFP_ = CallerFPFromFP(fp);
-        AssertMatchesCallSite(*activation_, callerPC_, callerFP_, fp);
+        AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
         break;
       case CodeRange::ImportJitExit:
       case CodeRange::ImportInterpExit:
@@ -626,17 +559,6 @@ ProfilingFrameIterator::initFromFP()
 
 typedef JS::ProfilingFrameIterator::RegisterState RegisterState;
 
-static bool
-InThunk(const CodeRange& codeRange, uint32_t offsetInModule)
-{
-    if (codeRange.kind() == CodeRange::FarJumpIsland)
-        return true;
-
-    return codeRange.isFunction() &&
-           offsetInModule >= codeRange.funcTableEntry() &&
-           offsetInModule < codeRange.funcNonProfilingEntry();
-}
-
 ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
                                                const RegisterState& state)
   : activation_(&activation),
@@ -647,16 +569,6 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
     stackAddress_(nullptr),
     exitReason_(ExitReason::None)
 {
-    // If profiling hasn't been enabled for this instance, then CallerFPFromFP
-    // will be trash, so ignore the entire activation. In practice, this only
-    // happens if profiling is enabled while the instance is on the stack (in
-    // which case profiling will be enabled when the instance becomes inactive
-    // and gets called again).
-    if (!activation_->compartment()->wasm.profilingEnabled()) {
-        MOZ_ASSERT(done());
-        return;
-    }
-
     // If pc isn't in the instance's code, we must have exited the code via an
     // exit trampoline or signal handler.
     code_ = activation_->compartment()->wasm.lookupCode(state.pc);
@@ -665,67 +577,78 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
         return;
     }
 
-    // Note: fp may be null while entering and leaving the activation.
+    // When the pc is inside the prologue/epilogue, the innermost call's Frame
+    // is not complete and thus fp points to the second-to-innermost call's
+    // Frame. Since fp can only tell you about its caller, naively unwinding
+    // while pc is in the prologue/epilogue would skip the second-to-innermost
+    // call. To avoid this problem, we use the static structure of the code in
+    // the prologue and epilogue to do the Right Thing.
     uint8_t* fp = activation.fp();
+    uint8_t* pc = (uint8_t*)state.pc;
+    void** sp = (void**)state.sp;
+
+    const CodeRange* codeRange = code_->lookupRange(pc);
+    uint32_t offsetInModule = pc - code_->segment().base();
+    MOZ_ASSERT(offsetInModule >= codeRange->begin());
+    MOZ_ASSERT(offsetInModule < codeRange->end());
+
+    // Compute the offset of the pc from the (normal) entry of the code range.
+    // The stack state of the pc for the entire table-entry is equivalent to
+    // that of the first pc of the normal-entry. Thus, we can simplify the below
+    // case analysis by redirecting all pc-in-table-entry cases to the
+    // pc-at-normal-entry case.
+    uint32_t offsetFromEntry;
+    if (codeRange->isFunction()) {
+        if (offsetInModule < codeRange->funcNormalEntry())
+            offsetFromEntry = 0;
+        else
+            offsetFromEntry = offsetInModule - codeRange->funcNormalEntry();
+    } else {
+        offsetFromEntry = offsetInModule - codeRange->begin();
+    }
 
-    const CodeRange* codeRange = code_->lookupRange(state.pc);
     switch (codeRange->kind()) {
       case CodeRange::Function:
       case CodeRange::FarJumpIsland:
       case CodeRange::ImportJitExit:
       case CodeRange::ImportInterpExit:
-      case CodeRange::TrapExit: {
-        // When the pc is inside the prologue/epilogue, the innermost call's
-        // Frame is not complete and thus fp points to the second-to-innermost
-        // call's Frame. Since fp can only tell you about its caller (via
-        // ReturnAddressFromFP(fp)), naively unwinding while pc is in the
-        // prologue/epilogue would skip the second-to- innermost call. To avoid
-        // this problem, we use the static structure of the code in the prologue
-        // and epilogue to do the Right Thing.
-        uint32_t offsetInModule = (uint8_t*)state.pc - code_->segment().base();
-        MOZ_ASSERT(offsetInModule >= codeRange->begin());
-        MOZ_ASSERT(offsetInModule < codeRange->end());
-        uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
-        void** sp = (void**)state.sp;
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-        if (offsetInCodeRange < PushedRetAddr || InThunk(*codeRange, offsetInModule)) {
+      case CodeRange::TrapExit:
+#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+        if (offsetFromEntry < PushedRetAddr || codeRange->isThunk()) {
             // First instruction of the ARM/MIPS function; the return address is
             // still in lr and fp still holds the caller's fp.
             callerPC_ = state.lr;
             callerFP_ = fp;
-            AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp - 2);
-        } else if (offsetInModule == codeRange->profilingReturn() - PostStorePrePopFP) {
+            AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
+        } else if (offsetInModule == codeRange->ret() - PostStorePrePopFP) {
             // Second-to-last instruction of the ARM/MIPS function; fp points to
             // the caller's fp; have not yet popped Frame.
             callerPC_ = ReturnAddressFromFP(sp);
             callerFP_ = CallerFPFromFP(sp);
-            AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp);
+            AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
         } else
 #endif
-        if (offsetInCodeRange < PushedFP || offsetInModule == codeRange->profilingReturn() ||
-            InThunk(*codeRange, offsetInModule))
-        {
+        if (offsetFromEntry < PushedFP || codeRange->isThunk() || offsetInModule == codeRange->ret()) {
             // The return address has been pushed on the stack but not fp; fp
             // still points to the caller's fp.
             callerPC_ = *sp;
             callerFP_ = fp;
-            AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp - 1);
-        } else if (offsetInCodeRange < StoredFP) {
+            AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
+        } else if (offsetFromEntry < StoredFP) {
             // The full Frame has been pushed; fp still points to the caller's
             // frame.
             MOZ_ASSERT(fp == CallerFPFromFP(sp));
             callerPC_ = ReturnAddressFromFP(sp);
             callerFP_ = CallerFPFromFP(sp);
-            AssertMatchesCallSite(*activation_, callerPC_, callerFP_, sp);
+            AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
         } else {
             // Not in the prologue/epilogue.
             callerPC_ = ReturnAddressFromFP(fp);
             callerFP_ = CallerFPFromFP(fp);
-            AssertMatchesCallSite(*activation_, callerPC_, callerFP_, fp);
+            AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
         }
         break;
-      }
-      case CodeRange::Entry: {
+      case CodeRange::Entry:
         // The entry trampoline is the final frame in an WasmActivation. The entry
         // trampoline also doesn't GeneratePrologue/Epilogue so we can't use
         // the general unwinding logic above.
@@ -733,9 +656,8 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
         callerPC_ = nullptr;
         callerFP_ = nullptr;
         break;
-      }
       case CodeRange::DebugTrap:
-      case CodeRange::Inline: {
+      case CodeRange::Inline:
         // The throw stub clears WasmActivation::fp on it's way out.
         if (!fp) {
             MOZ_ASSERT(done());
@@ -749,9 +671,8 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
         // skipped frames. Thus, we use simply unwind based on fp.
         callerPC_ = ReturnAddressFromFP(fp);
         callerFP_ = CallerFPFromFP(fp);
-        AssertMatchesCallSite(*activation_, callerPC_, callerFP_, fp);
+        AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
         break;
-      }
     }
 
     codeRange_ = codeRange;
@@ -796,7 +717,7 @@ ProfilingFrameIterator::operator++()
       case CodeRange::FarJumpIsland:
         stackAddress_ = callerFP_;
         callerPC_ = ReturnAddressFromFP(callerFP_);
-        AssertMatchesCallSite(*activation_, callerPC_, CallerFPFromFP(callerFP_), callerFP_);
+        AssertMatchesCallSite(*activation_, callerPC_, CallerFPFromFP(callerFP_));
         callerFP_ = CallerFPFromFP(callerFP_);
         break;
     }
@@ -848,95 +769,3 @@ ProfilingFrameIterator::label() const
 
     MOZ_CRASH("bad code range kind");
 }
-
-/*****************************************************************************/
-// Runtime patching to enable/disable profiling
-
-void
-wasm::ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled)
-{
-    if (callSite.kind() != CallSite::Func)
-        return;
-
-    uint8_t* callerRetAddr = code.segment().base() + callSite.returnAddressOffset();
-
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-    void* callee = X86Encoding::GetRel32Target(callerRetAddr);
-#elif defined(JS_CODEGEN_ARM)
-    uint8_t* caller = callerRetAddr - 4;
-    Instruction* callerInsn = reinterpret_cast(caller);
-    BOffImm calleeOffset;
-    callerInsn->as()->extractImm(&calleeOffset);
-    void* callee = calleeOffset.getDest(callerInsn);
-#elif defined(JS_CODEGEN_ARM64)
-    MOZ_CRASH();
-    void* callee = nullptr;
-    (void)callerRetAddr;
-#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-    uint8_t* caller = callerRetAddr - 2 * sizeof(uint32_t);
-    InstImm* callerInsn = reinterpret_cast(caller);
-    BOffImm16 calleeOffset;
-    callerInsn->extractImm16(&calleeOffset);
-    void* callee = calleeOffset.getDest(reinterpret_cast(caller));
-#elif defined(JS_CODEGEN_NONE)
-    MOZ_CRASH();
-    void* callee = nullptr;
-#else
-# error "Missing architecture"
-#endif
-
-    const CodeRange* codeRange = code.lookupRange(callee);
-    if (!codeRange->isFunction())
-        return;
-
-    uint8_t* from = code.segment().base() + codeRange->funcNonProfilingEntry();
-    uint8_t* to = code.segment().base() + codeRange->funcProfilingEntry();
-    if (!enabled)
-        Swap(from, to);
-
-    MOZ_ASSERT(callee == from);
-
-#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
-    X86Encoding::SetRel32(callerRetAddr, to);
-#elif defined(JS_CODEGEN_ARM)
-    new (caller) InstBLImm(BOffImm(to - caller), Assembler::Always);
-#elif defined(JS_CODEGEN_ARM64)
-    (void)to;
-    MOZ_CRASH();
-#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-    new (caller) InstImm(op_regimm, zero, rt_bgezal, BOffImm16(to - caller));
-#elif defined(JS_CODEGEN_NONE)
-    MOZ_CRASH();
-#else
-# error "Missing architecture"
-#endif
-}
-
-void
-wasm::ToggleProfiling(const Code& code, const CallThunk& callThunk, bool enabled)
-{
-    const CodeRange& cr = code.metadata().codeRanges[callThunk.u.codeRangeIndex];
-    uint32_t calleeOffset = enabled ? cr.funcProfilingEntry() : cr.funcNonProfilingEntry();
-    MacroAssembler::repatchFarJump(code.segment().base(), callThunk.offset, calleeOffset);
-}
-
-void
-wasm::ToggleProfiling(const Code& code, const CodeRange& codeRange, bool enabled)
-{
-    if (!codeRange.isFunction())
-        return;
-
-    uint8_t* codeBase = code.segment().base();
-    uint8_t* profilingEntry     = codeBase + codeRange.funcProfilingEntry();
-    uint8_t* tableProfilingJump = codeBase + codeRange.funcTableProfilingJump();
-    uint8_t* profilingJump      = codeBase + codeRange.funcProfilingJump();
-    uint8_t* profilingEpilogue  = codeBase + codeRange.funcProfilingEpilogue();
-
-    if (enabled) {
-        MacroAssembler::patchNopToNearJump(tableProfilingJump, profilingEntry);
-        MacroAssembler::patchNopToNearJump(profilingJump, profilingEpilogue);
-    } else {
-        MacroAssembler::patchNearJumpToNop(tableProfilingJump);
-        MacroAssembler::patchNearJumpToNop(profilingJump);
-    }
-}
diff --git a/js/src/wasm/WasmFrameIterator.h b/js/src/wasm/WasmFrameIterator.h
index 7c8e440b61cc..08b8ccbe6c68 100644
--- a/js/src/wasm/WasmFrameIterator.h
+++ b/js/src/wasm/WasmFrameIterator.h
@@ -36,9 +36,8 @@ class CodeRange;
 class DebugFrame;
 class Instance;
 class SigIdDesc;
-struct CallThunk;
 struct FuncOffsets;
-struct ProfilingOffsets;
+struct CallableOffsets;
 struct TrapOffset;
 
 // Iterates over the frames of a single WasmActivation, called synchronously
@@ -95,8 +94,7 @@ enum class ExitReason : uint32_t
 };
 
 // Iterates over the frames of a single WasmActivation, given an
-// asynchrously-interrupted thread's state. If the activation's
-// module is not in profiling mode, the activation is skipped.
+// asynchronously-interrupted thread's state.
 class ProfilingFrameIterator
 {
     const WasmActivation* activation_;
@@ -125,27 +123,16 @@ class ProfilingFrameIterator
 
 void
 GenerateExitPrologue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason,
-                     ProfilingOffsets* offsets);
+                     CallableOffsets* offsets);
 void
 GenerateExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason,
-                     ProfilingOffsets* offsets);
+                     CallableOffsets* offsets);
 void
 GenerateFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId,
                          FuncOffsets* offsets);
 void
 GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets);
 
-// Runtime patching to enable/disable profiling
-
-void
-ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled);
-
-void
-ToggleProfiling(const Code& code, const CallThunk& callThunk, bool enabled);
-
-void
-ToggleProfiling(const Code& code, const CodeRange& codeRange, bool enabled);
-
 } // namespace wasm
 } // namespace js
 
diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp
index e1f3a7639d17..2994a96ca416 100644
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -338,7 +338,7 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits)
             break;
           case CallSiteDesc::Func: {
             if (funcIsCompiled(cs.funcIndex())) {
-                uint32_t calleeOffset = funcCodeRange(cs.funcIndex()).funcNonProfilingEntry();
+                uint32_t calleeOffset = funcCodeRange(cs.funcIndex()).funcNormalEntry();
                 MOZ_RELEASE_ASSERT(calleeOffset < INT32_MAX);
 
                 if (uint32_t(abs(int32_t(calleeOffset) - int32_t(callerOffset))) < JumpRange()) {
@@ -351,7 +351,7 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits)
             if (!p) {
                 Offsets offsets;
                 offsets.begin = masm_.currentOffset();
-                uint32_t jumpOffset = masm_.farJumpWithPatch().offset();
+                masm_.append(CallFarJump(cs.funcIndex(), masm_.farJumpWithPatch()));
                 offsets.end = masm_.currentOffset();
                 if (masm_.oom())
                     return false;
@@ -360,11 +360,6 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits)
                     return false;
                 if (!existingCallFarJumps.add(p, cs.funcIndex(), offsets.begin))
                     return false;
-
-                // Record calls' far jumps in metadata since they must be
-                // repatched at runtime when profiling mode is toggled.
-                if (!metadata_->callThunks.emplaceBack(jumpOffset, cs.funcIndex()))
-                    return false;
             }
 
             masm_.patchCall(callerOffset, p->value());
@@ -429,12 +424,8 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits)
 bool
 ModuleGenerator::patchFarJumps(const TrapExitOffsetArray& trapExits, const Offsets& debugTrapStub)
 {
-    for (CallThunk& callThunk : metadata_->callThunks) {
-        uint32_t funcIndex = callThunk.u.funcIndex;
-        callThunk.u.codeRangeIndex = funcToCodeRange_[funcIndex];
-        CodeOffset farJump(callThunk.offset);
-        masm_.patchFarJump(farJump, funcCodeRange(funcIndex).funcNonProfilingEntry());
-    }
+    for (const CallFarJump& farJump : masm_.callFarJumps())
+        masm_.patchFarJump(farJump.jump, funcCodeRange(farJump.funcIndex).funcNormalEntry());
 
     for (const TrapFarJump& farJump : masm_.trapFarJumps())
         masm_.patchFarJump(farJump.jump, trapExits[farJump.trap].begin);
@@ -534,7 +525,7 @@ ModuleGenerator::finishFuncExports()
 }
 
 typedef Vector OffsetVector;
-typedef Vector ProfilingOffsetVector;
+typedef Vector CallableOffsetVector;
 
 bool
 ModuleGenerator::finishCodegen()
@@ -550,8 +541,8 @@ ModuleGenerator::finishCodegen()
     // due to the large absolute offsets temporarily stored by Label::bind().
 
     OffsetVector entries;
-    ProfilingOffsetVector interpExits;
-    ProfilingOffsetVector jitExits;
+    CallableOffsetVector interpExits;
+    CallableOffsetVector jitExits;
     TrapExitOffsetArray trapExits;
     Offsets outOfBoundsExit;
     Offsets unalignedAccessExit;
@@ -1168,7 +1159,6 @@ ModuleGenerator::finish(const ShareableBytes& bytecode)
     metadata_->memoryAccesses.podResizeToFit();
     metadata_->codeRanges.podResizeToFit();
     metadata_->callSites.podResizeToFit();
-    metadata_->callThunks.podResizeToFit();
     metadata_->debugTrapFarJumpOffsets.podResizeToFit();
     metadata_->debugFuncToCodeRange.podResizeToFit();
 
diff --git a/js/src/wasm/WasmGenerator.h b/js/src/wasm/WasmGenerator.h
index b7a1630a55d6..e9f6595fdae0 100644
--- a/js/src/wasm/WasmGenerator.h
+++ b/js/src/wasm/WasmGenerator.h
@@ -212,7 +212,7 @@ class MOZ_STACK_CLASS ModuleGenerator
     typedef HashSet, SystemAllocPolicy> Uint32Set;
     typedef Vector CompileTaskVector;
     typedef Vector CompileTaskPtrVector;
-    typedef EnumeratedArray TrapExitOffsetArray;
+    typedef EnumeratedArray TrapExitOffsetArray;
 
     // Constant parameters
     CompileMode                     compileMode_;
diff --git a/js/src/wasm/WasmInstance.cpp b/js/src/wasm/WasmInstance.cpp
index ba8e759008b5..019bd1239648 100644
--- a/js/src/wasm/WasmInstance.cpp
+++ b/js/src/wasm/WasmInstance.cpp
@@ -352,7 +352,7 @@ Instance::Instance(JSContext* cx,
             const CodeRange& codeRange = calleeInstanceObj->getExportedFunctionCodeRange(f);
             Instance& calleeInstance = calleeInstanceObj->instance();
             import.tls = calleeInstance.tlsData();
-            import.code = calleeInstance.codeSegment().base() + codeRange.funcNonProfilingEntry();
+            import.code = calleeInstance.codeSegment().base() + codeRange.funcNormalEntry();
             import.baselineScript = nullptr;
             import.obj = calleeInstanceObj;
         } else {
@@ -538,9 +538,6 @@ Instance::callExport(JSContext* cx, uint32_t funcIndex, CallArgs args)
     // If there has been a moving grow, this Instance should have been notified.
     MOZ_RELEASE_ASSERT(!memory_ || tlsData()->memoryBase == memory_->buffer().dataPointerEither());
 
-    if (!cx->compartment()->wasm.ensureProfilingState(cx))
-        return false;
-
     const FuncExport& func = metadata().lookupFuncExport(funcIndex);
 
     // The calling convention for an external call into wasm is to pass an
@@ -782,61 +779,6 @@ Instance::deoptimizeImportExit(uint32_t funcImportIndex)
     import.baselineScript = nullptr;
 }
 
-static void
-UpdateEntry(const Code& code, bool profilingEnabled, void** entry)
-{
-    const CodeRange& codeRange = *code.lookupRange(*entry);
-    void* from = code.segment().base() + codeRange.funcNonProfilingEntry();
-    void* to = code.segment().base() + codeRange.funcProfilingEntry();
-
-    if (!profilingEnabled)
-        Swap(from, to);
-
-    MOZ_ASSERT(*entry == from);
-    *entry = to;
-}
-
-bool
-Instance::ensureProfilingState(JSContext* cx, bool newProfilingEnabled)
-{
-    if (code_->profilingEnabled() == newProfilingEnabled)
-        return true;
-
-    if (!code_->ensureProfilingState(cx->runtime(), newProfilingEnabled))
-        return false;
-
-    // Imported wasm functions and typed function tables point directly to
-    // either the profiling or non-profiling prologue and must therefore be
-    // updated when the profiling mode is toggled.
-
-    for (const FuncImport& fi : metadata().funcImports) {
-        FuncImportTls& import = funcImportTls(fi);
-        if (import.obj && import.obj->is()) {
-            Code& code = import.obj->as().instance().code();
-            UpdateEntry(code, newProfilingEnabled, &import.code);
-        }
-    }
-
-    for (const SharedTable& table : tables_) {
-        if (!table->isTypedFunction())
-            continue;
-
-        // This logic will have to be generalized to match the import logic
-        // above if wasm can create typed function tables since a single table
-        // can contain elements from multiple instances.
-        MOZ_ASSERT(metadata().kind == ModuleKind::AsmJS);
-
-        void** array = table->internalArray();
-        uint32_t length = table->length();
-        for (size_t i = 0; i < length; i++) {
-            if (array[i])
-                UpdateEntry(*code_, newProfilingEnabled, &array[i]);
-        }
-    }
-
-    return true;
-}
-
 void
 Instance::ensureEnterFrameTrapsState(JSContext* cx, bool enabled)
 {
diff --git a/js/src/wasm/WasmInstance.h b/js/src/wasm/WasmInstance.h
index 753e89560b45..13ceaa7fa627 100644
--- a/js/src/wasm/WasmInstance.h
+++ b/js/src/wasm/WasmInstance.h
@@ -152,10 +152,6 @@ class Instance
     void onMovingGrowMemory(uint8_t* prevMemoryBase);
     void onMovingGrowTable();
 
-    // See Code::ensureProfilingState comment.
-
-    MOZ_MUST_USE bool ensureProfilingState(JSContext* cx, bool enabled);
-
     // Debug support:
     bool debugEnabled() const { return code_->metadata().debugEnabled; }
     bool enterFrameTrapsEnabled() const { return enterFrameTrapsEnabled_; }
diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp
index bbf926a2ebe1..b4c65082941d 100644
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -440,11 +440,11 @@ Module::extractCode(JSContext* cx, MutableHandleValue vp)
             if (!JS_DefineProperty(cx, segment, "funcIndex", value, JSPROP_ENUMERATE))
                 return false;
 
-            value.setNumber((uint32_t)p.funcNonProfilingEntry());
+            value.setNumber((uint32_t)p.funcNormalEntry());
             if (!JS_DefineProperty(cx, segment, "funcBodyBegin", value, JSPROP_ENUMERATE))
                 return false;
 
-            value.setNumber((uint32_t)p.funcProfilingEpilogue());
+            value.setNumber((uint32_t)p.end());
             if (!JS_DefineProperty(cx, segment, "funcBodyEnd", value, JSPROP_ENUMERATE))
                 return false;
         }
@@ -521,7 +521,6 @@ Module::initSegments(JSContext* cx,
     for (const ElemSegment& seg : elemSegments_) {
         Table& table = *tables[seg.tableIndex];
         uint32_t offset = EvaluateInitExpr(globalImports, seg.offset);
-        bool profilingEnabled = instance.code().profilingEnabled();
         const CodeRangeVector& codeRanges = metadata().codeRanges;
         uint8_t* codeBase = instance.codeBase();
 
@@ -539,9 +538,7 @@ Module::initSegments(JSContext* cx,
             } else {
                 const CodeRange& cr = codeRanges[seg.elemCodeRangeIndices[i]];
                 uint32_t entryOffset = table.isTypedFunction()
-                                       ? profilingEnabled
-                                         ? cr.funcProfilingEntry()
-                                         : cr.funcNonProfilingEntry()
+                                       ? cr.funcNormalEntry()
                                        : cr.funcTableEntry();
                 table.set(offset + i, codeBase + entryOffset, instance);
             }
diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp
index ebe446a7eeb9..0aead44233f2 100644
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -445,8 +445,8 @@ FillArgumentArray(MacroAssembler& masm, const ValTypeVector& args, unsigned argO
 // normal wasm function for the purposes of exports and table calls. In
 // particular, the wrapper function provides:
 //  - a table entry, so JS imports can be put into tables
-//  - normal (non-)profiling entries, so that, if the import is re-exported,
-//    an entry stub can be generated and called without any special cases
+//  - normal entries, so that, if the import is re-exported, an entry stub can
+//    be generated and called without any special cases
 FuncOffsets
 wasm::GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, SigIdDesc sigId)
 {
@@ -497,7 +497,7 @@ wasm::GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, Si
 // Generate a stub that is called via the internal ABI derived from the
 // signature of the import and calls into an appropriate callImport C++
 // function, having boxed all the ABI arguments into a homogeneous Value array.
-ProfilingOffsets
+CallableOffsets
 wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint32_t funcImportIndex,
                                Label* throwLabel)
 {
@@ -519,7 +519,7 @@ wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint3
     unsigned argBytes = Max(1, fi.sig().args().length()) * sizeof(Value);
     unsigned framePushed = StackDecrementForCall(masm, ABIStackAlignment, argOffset + argBytes);
 
-    ProfilingOffsets offsets;
+    CallableOffsets offsets;
     GenerateExitPrologue(masm, framePushed, ExitReason::ImportInterp, &offsets);
 
     // Fill the argument array.
@@ -626,7 +626,7 @@ static const unsigned SavedTlsReg = sizeof(void*);
 // Generate a stub that is called via the internal ABI derived from the
 // signature of the import and calls into a compatible JIT function,
 // having boxed all the ABI arguments into the JIT stack frame layout.
-ProfilingOffsets
+CallableOffsets
 wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLabel)
 {
     masm.setFramePushed(0);
@@ -644,7 +644,7 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
     unsigned jitFramePushed = StackDecrementForCall(masm, JitStackAlignment, totalJitFrameBytes) -
                               sizeOfRetAddr;
 
-    ProfilingOffsets offsets;
+    CallableOffsets offsets;
     GenerateExitPrologue(masm, jitFramePushed, ExitReason::ImportJit, &offsets);
 
     // 1. Descriptor
@@ -864,10 +864,10 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
 }
 
 // Generate a stub that calls into ReportTrap with the right trap reason.
-// This stub is called with ABIStackAlignment by a trap out-of-line path. A
-// profiling prologue/epilogue is used so that stack unwinding picks up the
+// This stub is called with ABIStackAlignment by a trap out-of-line path. An
+// exit prologue/epilogue is used so that stack unwinding picks up the
 // current WasmActivation. Unwinding will begin at the caller of this trap exit.
-ProfilingOffsets
+CallableOffsets
 wasm::GenerateTrapExit(MacroAssembler& masm, Trap trap, Label* throwLabel)
 {
     masm.haltingAlign(CodeAlignment);
@@ -879,7 +879,7 @@ wasm::GenerateTrapExit(MacroAssembler& masm, Trap trap, Label* throwLabel)
 
     uint32_t framePushed = StackDecrementForCall(masm, ABIStackAlignment, args);
 
-    ProfilingOffsets offsets;
+    CallableOffsets offsets;
     GenerateExitPrologue(masm, framePushed, ExitReason::Trap, &offsets);
 
     ABIArgMIRTypeIter i(args);
@@ -1174,7 +1174,7 @@ wasm::GenerateDebugTrapStub(MacroAssembler& masm, Label* throwLabel)
 
     masm.setFramePushed(0);
 
-    ProfilingOffsets offsets;
+    CallableOffsets offsets;
     GenerateExitPrologue(masm, 0, ExitReason::DebugTrap, &offsets);
 
     // Save all registers used between baseline compiler operations.
diff --git a/js/src/wasm/WasmStubs.h b/js/src/wasm/WasmStubs.h
index e2c5a1f20a84..dcd90499510d 100644
--- a/js/src/wasm/WasmStubs.h
+++ b/js/src/wasm/WasmStubs.h
@@ -36,14 +36,14 @@ GenerateEntry(jit::MacroAssembler& masm, const FuncExport& fe);
 extern FuncOffsets
 GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, SigIdDesc sigId);
 
-extern ProfilingOffsets
+extern CallableOffsets
 GenerateImportInterpExit(jit::MacroAssembler& masm, const FuncImport& fi, uint32_t funcImportIndex,
                          jit::Label* throwLabel);
 
-extern ProfilingOffsets
+extern CallableOffsets
 GenerateImportJitExit(jit::MacroAssembler& masm, const FuncImport& fi, jit::Label* throwLabel);
 
-extern ProfilingOffsets
+extern CallableOffsets
 GenerateTrapExit(jit::MacroAssembler& masm, Trap trap, jit::Label* throwLabel);
 
 extern Offsets
diff --git a/js/src/wasm/WasmTable.h b/js/src/wasm/WasmTable.h
index 22c01411ad0a..6c955fc72d5c 100644
--- a/js/src/wasm/WasmTable.h
+++ b/js/src/wasm/WasmTable.h
@@ -62,9 +62,7 @@ class Table : public ShareableBase
     Maybe maximum() const { return maximum_; }
     uint8_t* base() const { return array_.get(); }
 
-    // All updates must go through a set() function with the exception of
-    // (profiling) updates to the callee pointer that do not change which
-    // logical function is being called.
+    // All table updates must go through set() or setNull().
 
     void** internalArray() const;
     ExternalTableElem* externalArray() const;
diff --git a/js/src/wasm/WasmTypes.h b/js/src/wasm/WasmTypes.h
index 910b8d9aaa55..6c1ff6f361b8 100644
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -762,7 +762,7 @@ struct SigWithId : Sig
 typedef Vector SigWithIdVector;
 typedef Vector SigWithIdPtrVector;
 
-// The (,Profiling,Func)Offsets classes are used to record the offsets of
+// The (,Callable,Func)Offsets classes are used to record the offsets of
 // different key points in a CodeRange during compilation.
 
 struct Offsets
@@ -782,62 +782,39 @@ struct Offsets
     }
 };
 
-struct ProfilingOffsets : Offsets
+struct CallableOffsets : Offsets
 {
-    MOZ_IMPLICIT ProfilingOffsets(uint32_t profilingReturn = 0)
-      : Offsets(), profilingReturn(profilingReturn)
+    MOZ_IMPLICIT CallableOffsets(uint32_t ret = 0)
+      : Offsets(), ret(ret)
     {}
 
-    // For CodeRanges with ProfilingOffsets, 'begin' is the offset of the
-    // profiling entry.
-    uint32_t profilingEntry() const { return begin; }
-
-    // The profiling return is the offset of the return instruction, which
-    // precedes the 'end' by a variable number of instructions due to
-    // out-of-line codegen.
-    uint32_t profilingReturn;
+    // The offset of the return instruction precedes 'end' by a variable number
+    // of instructions due to out-of-line codegen.
+    uint32_t ret;
 
     void offsetBy(uint32_t offset) {
         Offsets::offsetBy(offset);
-        profilingReturn += offset;
+        ret += offset;
     }
 };
 
-struct FuncOffsets : ProfilingOffsets
+struct FuncOffsets : CallableOffsets
 {
     MOZ_IMPLICIT FuncOffsets()
-      : ProfilingOffsets(),
-        tableEntry(0),
-        tableProfilingJump(0),
-        nonProfilingEntry(0),
-        profilingJump(0),
-        profilingEpilogue(0)
+      : CallableOffsets(),
+        normalEntry(0)
     {}
 
     // Function CodeRanges have a table entry which takes an extra signature
     // argument which is checked against the callee's signature before falling
-    // through to the normal prologue. When profiling is enabled, a nop on the
-    // fallthrough is patched to instead jump to the profiling epilogue.
-    uint32_t tableEntry;
-    uint32_t tableProfilingJump;
-
-    // Function CodeRanges have an additional non-profiling entry that comes
-    // after the profiling entry and a non-profiling epilogue that comes before
-    // the profiling epilogue.
-    uint32_t nonProfilingEntry;
-
-    // When profiling is enabled, the 'nop' at offset 'profilingJump' is
-    // overwritten to be a jump to 'profilingEpilogue'.
-    uint32_t profilingJump;
-    uint32_t profilingEpilogue;
+    // through to the normal prologue. The table entry is thus at the beginning
+    // of the CodeRange and the normal entry is at some offset after the table
+    // entry.
+    uint32_t normalEntry;
 
     void offsetBy(uint32_t offset) {
-        ProfilingOffsets::offsetBy(offset);
-        tableEntry += offset;
-        tableProfilingJump += offset;
-        nonProfilingEntry += offset;
-        profilingJump += offset;
-        profilingEpilogue += offset;
+        CallableOffsets::offsetBy(offset);
+        normalEntry += offset;
     }
 };
 
@@ -926,26 +903,18 @@ class CallSiteDesc
 class CallSite : public CallSiteDesc
 {
     uint32_t returnAddressOffset_;
-    uint32_t stackDepth_;
 
   public:
     CallSite() {}
 
-    CallSite(CallSiteDesc desc, uint32_t returnAddressOffset, uint32_t stackDepth)
+    CallSite(CallSiteDesc desc, uint32_t returnAddressOffset)
       : CallSiteDesc(desc),
-        returnAddressOffset_(returnAddressOffset),
-        stackDepth_(stackDepth)
+        returnAddressOffset_(returnAddressOffset)
     { }
 
     void setReturnAddressOffset(uint32_t r) { returnAddressOffset_ = r; }
     void offsetReturnAddressBy(int32_t o) { returnAddressOffset_ += o; }
     uint32_t returnAddressOffset() const { return returnAddressOffset_; }
-
-    // The stackDepth measures the amount of stack space pushed since the
-    // function was called. In particular, this includes the pushed return
-    // address on all archs (whether or not the call instruction pushes the
-    // return address (x86/x64) or the prologue does (ARM/MIPS)).
-    uint32_t stackDepth() const { return stackDepth_; }
 };
 
 WASM_DECLARE_POD_VECTOR(CallSite, CallSiteVector)
@@ -1485,10 +1454,8 @@ WASM_DECLARE_POD_VECTOR(MemoryAccess, MemoryAccessVector)
 
 struct Frame
 {
-    // The caller's saved frame pointer. In non-profiling mode, internal
-    // wasm-to-wasm calls don't update fp and thus don't save the caller's
-    // frame pointer; the space is reserved, however, so that profiling mode can
-    // reuse the same function body without recompiling.
+    // The value of WasmActivation::fp on entry to the function (before being
+    // overwritten by this Frame's address).
     uint8_t* callerFP;
 
     // The return address pushed by the call (in the case of ARM/MIPS the return

From d4d809f4c4804f5a1e4485f272c26923637cfcfa Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:13:02 -0500
Subject: [PATCH 21/96] Bug 1334504 - Baldr: save TLS reg in Frame (r=bbouvier)

MozReview-Commit-ID: Lp1YArEH9jh

--HG--
extra : rebase_source : cfb6283b07a417e2d6745bfb066149d1d228b3e2
---
 js/src/jit/MacroAssembler.cpp         |  28 +++++++
 js/src/jit/MacroAssembler.h           |  13 +---
 js/src/jit/x64/MacroAssembler-x64.cpp |   5 +-
 js/src/wasm/WasmDebugFrame.h          |   5 +-
 js/src/wasm/WasmFrameIterator.cpp     | 102 +++++++++++++-------------
 js/src/wasm/WasmStubs.cpp             |   2 +-
 js/src/wasm/WasmTypes.h               |   7 +-
 7 files changed, 94 insertions(+), 68 deletions(-)

diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
index 813fc13de2fa..0426e3fbab73 100644
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2931,6 +2931,13 @@ MacroAssembler::wasmEmitTrapOutOfLineCode()
             if (size_t dec = StackDecrementForCall(ABIStackAlignment, alreadyPushed, toPush))
                 reserveStack(dec);
 
+            // To call the trap handler function, we must have the WasmTlsReg
+            // filled since this is the normal calling ABI. To avoid requiring
+            // every trapping operation to have the TLS register filled for the
+            // rare case that it takes a trap, we instead restore it here on the
+            // out-of-line path.
+            loadWasmTlsRegFromFrame();
+
             // Call the trap's exit, using the bytecode offset of the trap site.
             // Note that this code is inside the same CodeRange::Function as the
             // trap site so it's as if the trapping instruction called the
@@ -2957,6 +2964,27 @@ MacroAssembler::wasmEmitTrapOutOfLineCode()
 
 //}}} check_macroassembler_style
 
+void
+MacroAssembler::loadWasmActivationFromTls(Register dest)
+{
+    loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, cx)), dest);
+    loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest);
+}
+
+void
+MacroAssembler::loadWasmActivationFromSymbolicAddress(Register dest)
+{
+    movePtr(wasm::SymbolicAddress::ContextPtr, dest);
+    loadPtr(Address(dest, 0), dest);
+    loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest);
+}
+
+void
+MacroAssembler::loadWasmTlsRegFromFrame()
+{
+    loadPtr(Address(getStackPointer(), framePushed() + offsetof(wasm::Frame, tls)), WasmTlsReg);
+}
+
 void
 MacroAssembler::BranchType::emit(MacroAssembler& masm)
 {
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
index 2a0d8faefdf8..93d9e998f68a 100644
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1517,15 +1517,10 @@ class MacroAssembler : public MacroAssemblerSpecific
         loadJSContext(dest);
         loadPtr(Address(dest, offsetof(JSContext, activation_)), dest);
     }
-    void loadWasmActivationFromTls(Register dest) {
-        loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, cx)), dest);
-        loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest);
-    }
-    void loadWasmActivationFromSymbolicAddress(Register dest) {
-        movePtr(wasm::SymbolicAddress::ContextPtr, dest);
-        loadPtr(Address(dest, 0), dest);
-        loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest);
-    }
+
+    void loadWasmActivationFromTls(Register dest);
+    void loadWasmActivationFromSymbolicAddress(Register dest);
+    void loadWasmTlsRegFromFrame();
 
     template
     void loadTypedOrValue(const T& src, TypedOrValueRegister dest) {
diff --git a/js/src/jit/x64/MacroAssembler-x64.cpp b/js/src/jit/x64/MacroAssembler-x64.cpp
index 5eedd508fba9..352ba8043d4c 100644
--- a/js/src/jit/x64/MacroAssembler-x64.cpp
+++ b/js/src/jit/x64/MacroAssembler-x64.cpp
@@ -474,9 +474,8 @@ MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromWasm)
         stackForCall += ComputeByteAlignment(stackForCall + sizeof(intptr_t),
                                              ABIStackAlignment);
     } else {
-        static_assert(sizeof(wasm::Frame) % ABIStackAlignment == 0,
-                      "wasm::Frame should be part of the stack alignment.");
-        stackForCall += ComputeByteAlignment(stackForCall + framePushed(),
+        uint32_t alignmentAtPrologue = callFromWasm ? sizeof(wasm::Frame) : 0;
+        stackForCall += ComputeByteAlignment(stackForCall + framePushed() + alignmentAtPrologue,
                                              ABIStackAlignment);
     }
 
diff --git a/js/src/wasm/WasmDebugFrame.h b/js/src/wasm/WasmDebugFrame.h
index 963f54026365..6629dd42a934 100644
--- a/js/src/wasm/WasmDebugFrame.h
+++ b/js/src/wasm/WasmDebugFrame.h
@@ -44,7 +44,6 @@ class DebugFrame
 
     // The fields below are initialized by the baseline compiler.
     uint32_t    funcIndex_;
-    uint32_t    reserved0_;
 
     union
     {
@@ -71,8 +70,8 @@ class DebugFrame
         static_assert(offsetof(DebugFrame, tlsData_) + sizeof(TlsData*) ==
                       offsetof(DebugFrame, frame_),
                       "TLS pointer must be a field just before the wasm frame");
-        static_assert(sizeof(DebugFrame) % 8 == 0 && offsetof(DebugFrame, frame_) % 8 == 0,
-                      "DebugFrame and its portion is 8-bytes aligned for AbstractFramePtr");
+        static_assert(sizeof(DebugFrame) % 8 == 0,
+                      "DebugFrame is 8-bytes aligned for AbstractFramePtr");
     }
 
   public:
diff --git a/js/src/wasm/WasmFrameIterator.cpp b/js/src/wasm/WasmFrameIterator.cpp
index da60f3427ef9..d9606c5ba997 100644
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -210,7 +210,7 @@ FrameIterator::lineOrBytecode() const
 Instance*
 FrameIterator::instance() const
 {
-    MOZ_ASSERT(!done() && debugEnabled());
+    MOZ_ASSERT(!done());
     return FrameToDebugFrame(fp_)->instance();
 }
 
@@ -249,39 +249,45 @@ FrameIterator::debugTrapCallsite() const
 #if defined(JS_CODEGEN_X64)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
-static const unsigned PostStorePrePopFP = 0;
 # endif
-static const unsigned PushedFP = 26;
-static const unsigned StoredFP = 33;
+static const unsigned PushedFP = 16;
+static const unsigned PushedTLS = 18;
+static const unsigned StoredFP = 25;
+static const unsigned RestoreFP = 4;
 #elif defined(JS_CODEGEN_X86)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
-static const unsigned PostStorePrePopFP = 0;
 # endif
-static const unsigned PushedFP = 16;
-static const unsigned StoredFP = 19;
+static const unsigned PushedFP = 11;
+static const unsigned PushedTLS = 12;
+static const unsigned StoredFP = 15;
+static const unsigned RestoreFP = 3;
 #elif defined(JS_CODEGEN_ARM)
 static const unsigned PushedRetAddr = 4;
-static const unsigned PushedFP = 28;
-static const unsigned StoredFP = 32;
-static const unsigned PostStorePrePopFP = 4;
+static const unsigned PushedFP = 20;
+static const unsigned PushedTLS = 24;
+static const unsigned StoredFP = 28;
+static const unsigned RestoreFP = 4;
 #elif defined(JS_CODEGEN_ARM64)
 static const unsigned PushedRetAddr = 0;
 static const unsigned PushedFP = 0;
+static const unsigned PushedTLS = 0;
 static const unsigned StoredFP = 0;
-static const unsigned PostStorePrePopFP = 0;
+static const unsigned RestoreFP = 0;
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
 static const unsigned PushedRetAddr = 8;
-static const unsigned PushedFP = 36;
-static const unsigned StoredFP = 40;
-static const unsigned PostStorePrePopFP = 4;
+static const unsigned PushedFP = 28;
+static const unsigned PushedTLS = 32;
+static const unsigned StoredFP = 36;
+static const unsigned RestoreFP = 4;
 #elif defined(JS_CODEGEN_NONE)
 # if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
-static const unsigned PostStorePrePopFP = 0;
 # endif
 static const unsigned PushedFP = 1;
+static const unsigned PushedTLS = 1;
 static const unsigned StoredFP = 1;
+static const unsigned RestoreFP = 0;
 #else
 # error "Unknown architecture!"
 #endif
@@ -321,10 +327,13 @@ GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason
         PushRetAddr(masm);
         MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - *entry);
 
-        masm.loadWasmActivationFromSymbolicAddress(scratch);
+        masm.loadWasmActivationFromTls(scratch);
         masm.push(Address(scratch, WasmActivation::offsetOfFP()));
         MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - *entry);
 
+        masm.push(WasmTlsReg);
+        MOZ_ASSERT_IF(!masm.oom(), PushedTLS == masm.currentOffset() - *entry);
+
         masm.storePtr(masm.getStackPointer(), Address(scratch, WasmActivation::offsetOfFP()));
         MOZ_ASSERT_IF(!masm.oom(), StoredFP == masm.currentOffset() - *entry);
     }
@@ -342,15 +351,12 @@ GenerateCallableEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason
                          uint32_t* ret)
 {
     Register scratch = ABINonArgReturnReg0;
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
-    defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     Register scratch2 = ABINonArgReturnReg1;
-#endif
 
     if (framePushed)
         masm.addToStackPtr(Imm32(framePushed));
 
-    masm.loadWasmActivationFromSymbolicAddress(scratch);
+    masm.loadWasmActivationFromTls(scratch);
 
     if (reason != ExitReason::None) {
         masm.store32(Imm32(int32_t(ExitReason::None)),
@@ -358,30 +364,23 @@ GenerateCallableEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason
     }
 
 #if defined(JS_CODEGEN_ARM)
-    // FrameIterator assumes there is nothing after the pop of the stack before
-    // the return instruction so AutoForbidPools to ensure that no pool is
-    // automatically inserted by the ARM MacroAssembler.
-    AutoForbidPools afp(&masm, /* number of instructions in scope = */ 4);
+    // Forbid pools for the same reason as described in GenerateCallablePrologue.
+    AutoForbidPools afp(&masm, /* number of instructions in scope = */ 5);
 #endif
 
     // sp protects the stack from clobber via asynchronous signal handlers and
     // the async interrupt exit. Since activation.fp can be read at any time and
     // still points to the current frame, be careful to only update sp after
     // activation.fp has been repointed to the caller's frame.
-#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-    masm.loadPtr(Address(masm.getStackPointer(), 0), scratch2);
+
+    masm.loadPtr(Address(masm.getStackPointer(), offsetof(Frame, callerFP)), scratch2);
     masm.storePtr(scratch2, Address(scratch, WasmActivation::offsetOfFP()));
-
-    DebugOnly prePop = masm.currentOffset();
-    masm.addToStackPtr(Imm32(sizeof(void *)));
-    MOZ_ASSERT_IF(!masm.oom(), PostStorePrePopFP == masm.currentOffset() - prePop);
-#else
-    masm.pop(Address(scratch, WasmActivation::offsetOfFP()));
-    MOZ_ASSERT(PostStorePrePopFP == 0);
-#endif
-
+    DebugOnly afterRestoreFP = masm.currentOffset();
+    masm.addToStackPtr(Imm32(2 * sizeof(void*)));
     *ret = masm.currentOffset();
     masm.ret();
+
+    MOZ_ASSERT_IF(!masm.oom(), RestoreFP == *ret - afterRestoreFP);
 }
 
 void
@@ -620,26 +619,31 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
             callerPC_ = state.lr;
             callerFP_ = fp;
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
-        } else if (offsetInModule == codeRange->ret() - PostStorePrePopFP) {
-            // Second-to-last instruction of the ARM/MIPS function; fp points to
-            // the caller's fp; have not yet popped Frame.
-            callerPC_ = ReturnAddressFromFP(sp);
-            callerFP_ = CallerFPFromFP(sp);
-            AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
         } else
 #endif
-        if (offsetFromEntry < PushedFP || codeRange->isThunk() || offsetInModule == codeRange->ret()) {
-            // The return address has been pushed on the stack but not fp; fp
-            // still points to the caller's fp.
-            callerPC_ = *sp;
+        if (offsetFromEntry < PushedFP || codeRange->isThunk()) {
+            // The return address has been pushed on the stack but fp still
+            // points to the caller's fp.
+            callerPC_ = sp[0];
             callerFP_ = fp;
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
-        } else if (offsetFromEntry < StoredFP) {
-            // The full Frame has been pushed; fp still points to the caller's
-            // frame.
+        } else if (offsetFromEntry < PushedTLS) {
+            // The return address and caller's fp have been pushed on the stack; fp
+            // is still the caller's fp.
+            callerPC_ = sp[1];
+            callerFP_ = fp;
+            AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
+        } else if (offsetFromEntry < StoredFP || offsetInModule == codeRange->ret() - RestoreFP) {
+            // The full Frame has been pushed; fp is still the caller's fp.
             MOZ_ASSERT(fp == CallerFPFromFP(sp));
             callerPC_ = ReturnAddressFromFP(sp);
-            callerFP_ = CallerFPFromFP(sp);
+            callerFP_ = fp;
+            AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
+        } else if (offsetInModule == codeRange->ret()) {
+            // fp has been restored to the caller's frame and both the TLS and
+            // caller FP words have been popped.
+            callerPC_ = sp[0];
+            callerFP_ = fp;
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
         } else {
             // Not in the prologue/epilogue.
diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp
index 0aead44233f2..cda339d2ee1a 100644
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -122,7 +122,7 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe)
     Register scratch = ABINonArgReturnReg1;
 
     // Read the arguments of wasm::ExportFuncPtr according to the native ABI.
-    // The entry stub's frame is only 1 word, not the usual 2 for wasm::Frame.
+    // The entry stub's frame is 1 word.
     const unsigned argBase = sizeof(void*) + masm.framePushed();
     ABIArgGenerator abi;
     ABIArg arg;
diff --git a/js/src/wasm/WasmTypes.h b/js/src/wasm/WasmTypes.h
index 6c1ff6f361b8..1984d9e6706f 100644
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -1454,6 +1454,10 @@ WASM_DECLARE_POD_VECTOR(MemoryAccess, MemoryAccessVector)
 
 struct Frame
 {
+    // The saved value of WasmTlsReg on entry to the function. This is
+    // effectively the callee's instance.
+    TlsData* tls;
+
     // The value of WasmActivation::fp on entry to the function (before being
     // overwritten by this Frame's address).
     uint8_t* callerFP;
@@ -1463,9 +1467,6 @@ struct Frame
     void* returnAddress;
 };
 
-static_assert(sizeof(Frame) == 2 * sizeof(void*), "?!");
-static const uint32_t FrameBytesAfterReturnAddress = sizeof(void*);
-
 } // namespace wasm
 } // namespace js
 

From 2710499799a5f676fa99835c531fc32c9cb80aaf Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:15:18 -0500
Subject: [PATCH 22/96] Bug 1334504 - Baldr: remove baseline's explicit
 TLS-saving (r=yury)

MozReview-Commit-ID: 3MyiHUo0da2

--HG--
extra : rebase_source : c81c5636f58abed9a2763319a72c3080e695bdc6
---
 js/src/jit/MacroAssembler.cpp       |   4 +-
 js/src/jit/MacroAssembler.h         |   2 +-
 js/src/moz.build                    |   1 -
 js/src/vm/Debugger.cpp              |   2 +-
 js/src/vm/Stack-inl.h               |   3 +-
 js/src/vm/Stack.cpp                 |   1 -
 js/src/vm/Stack.h                   |   2 +
 js/src/wasm/WasmBaselineCompile.cpp |  69 ++++----------
 js/src/wasm/WasmDebugFrame.cpp      | 136 ----------------------------
 js/src/wasm/WasmDebugFrame.h        | 126 --------------------------
 js/src/wasm/WasmFrameIterator.cpp   |   1 -
 js/src/wasm/WasmTypes.cpp           | 126 +++++++++++++++++++++++++-
 js/src/wasm/WasmTypes.h             | 111 +++++++++++++++++++++++
 13 files changed, 261 insertions(+), 323 deletions(-)
 delete mode 100644 js/src/wasm/WasmDebugFrame.cpp
 delete mode 100644 js/src/wasm/WasmDebugFrame.h

diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
index 0426e3fbab73..21b5dc1a1eef 100644
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2980,9 +2980,9 @@ MacroAssembler::loadWasmActivationFromSymbolicAddress(Register dest)
 }
 
 void
-MacroAssembler::loadWasmTlsRegFromFrame()
+MacroAssembler::loadWasmTlsRegFromFrame(Register dest)
 {
-    loadPtr(Address(getStackPointer(), framePushed() + offsetof(wasm::Frame, tls)), WasmTlsReg);
+    loadPtr(Address(getStackPointer(), framePushed() + offsetof(wasm::Frame, tls)), dest);
 }
 
 void
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
index 93d9e998f68a..454cc0cf6d3e 100644
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1520,7 +1520,7 @@ class MacroAssembler : public MacroAssemblerSpecific
 
     void loadWasmActivationFromTls(Register dest);
     void loadWasmActivationFromSymbolicAddress(Register dest);
-    void loadWasmTlsRegFromFrame();
+    void loadWasmTlsRegFromFrame(Register dest = WasmTlsReg);
 
     template
     void loadTypedOrValue(const T& src, TypedOrValueRegister dest) {
diff --git a/js/src/moz.build b/js/src/moz.build
index 8b11432f99bc..32459181050e 100644
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -381,7 +381,6 @@ UNIFIED_SOURCES += [
     'wasm/WasmCode.cpp',
     'wasm/WasmCompartment.cpp',
     'wasm/WasmCompile.cpp',
-    'wasm/WasmDebugFrame.cpp',
     'wasm/WasmFrameIterator.cpp',
     'wasm/WasmGenerator.cpp',
     'wasm/WasmInstance.cpp',
diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp
index 8bb44714a4c2..be3db0cc80bb 100644
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -2549,7 +2549,7 @@ Debugger::updateExecutionObservabilityOfFrames(JSContext* cx, const ExecutionObs
                     oldestEnabledFrame.setIsDebuggee();
                 }
                 if (iter.abstractFramePtr().isWasmDebugFrame())
-                    iter.abstractFramePtr().asWasmDebugFrame()->observeFrame(cx);
+                    iter.abstractFramePtr().asWasmDebugFrame()->observe(cx);
             } else {
 #ifdef DEBUG
                 // Debugger.Frame lifetimes are managed by the debug epilogue,
diff --git a/js/src/vm/Stack-inl.h b/js/src/vm/Stack-inl.h
index 8679d6fb7af9..85fc08249574 100644
--- a/js/src/vm/Stack-inl.h
+++ b/js/src/vm/Stack-inl.h
@@ -19,7 +19,6 @@
 #include "js/Debug.h"
 #include "vm/EnvironmentObject.h"
 #include "vm/GeneratorObject.h"
-#include "wasm/WasmDebugFrame.h"
 #include "wasm/WasmInstance.h"
 
 #include "jsobjinlines.h"
@@ -455,7 +454,7 @@ AbstractFramePtr::environmentChain() const
     if (isBaselineFrame())
         return asBaselineFrame()->environmentChain();
     if (isWasmDebugFrame())
-        return asWasmDebugFrame()->environmentChain();
+        return &global()->lexicalEnvironment();
     return asRematerializedFrame()->environmentChain();
 }
 
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
index 8e5fe3060610..9d55ff97318d 100644
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -17,7 +17,6 @@
 #include "js/GCAPI.h"
 #include "vm/Debugger.h"
 #include "vm/Opcodes.h"
-#include "wasm/WasmDebugFrame.h"
 
 #include "jit/JitFrameIterator-inl.h"
 #include "vm/EnvironmentObject-inl.h"
diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
index 582a4da128db..b6a14260feec 100644
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -25,6 +25,7 @@
 #include "vm/ArgumentsObject.h"
 #include "vm/SavedFrame.h"
 #include "wasm/WasmFrameIterator.h"
+#include "wasm/WasmTypes.h"
 
 struct JSCompartment;
 
@@ -166,6 +167,7 @@ class AbstractFramePtr
     MOZ_IMPLICIT AbstractFramePtr(wasm::DebugFrame* fp)
       : ptr_(fp ? uintptr_t(fp) | Tag_WasmDebugFrame : 0)
     {
+        static_assert(wasm::DebugFrame::Alignment >= TagMask, "aligned");
         MOZ_ASSERT_IF(fp, asWasmDebugFrame() == fp);
     }
 
diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp
index cd6ab32fd434..5e62bf5530af 100644
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -97,7 +97,6 @@
 #endif
 
 #include "wasm/WasmBinaryIterator.h"
-#include "wasm/WasmDebugFrame.h"
 #include "wasm/WasmGenerator.h"
 #include "wasm/WasmSignalHandlers.h"
 #include "wasm/WasmValidate.h"
@@ -199,31 +198,19 @@ static constexpr int32_t TlsSlotSize = sizeof(void*);
 static constexpr int32_t TlsSlotOffset = TlsSlotSize;
 
 BaseLocalIter::BaseLocalIter(const ValTypeVector& locals,
-                                     size_t argsLength,
-                                     bool debugEnabled)
+                             size_t argsLength,
+                             bool debugEnabled)
   : locals_(locals),
     argsLength_(argsLength),
     argsRange_(locals.begin(), argsLength),
     argsIter_(argsRange_),
     index_(0),
-    localSize_(0),
+    localSize_(debugEnabled ? DebugFrame::offsetOfFrame() : 0),
+    reservedSize_(localSize_),
     done_(false)
 {
     MOZ_ASSERT(argsLength <= locals.length());
 
-    // Reserve a stack slot for the TLS pointer outside the locals range so it
-    // isn't zero-filled like the normal locals.
-    DebugOnly tlsSlotOffset = pushLocal(TlsSlotSize);
-    MOZ_ASSERT(tlsSlotOffset == TlsSlotOffset);
-    if (debugEnabled) {
-        // If debug information is generated, constructing DebugFrame record:
-        // reserving some data before TLS pointer. The TLS pointer allocated
-        // above and regular wasm::Frame data starts after locals.
-        localSize_ += DebugFrame::offsetOfTlsData();
-        MOZ_ASSERT(DebugFrame::offsetOfFrame() == localSize_);
-    }
-    reservedSize_ = localSize_;
-
     settle();
 }
 
@@ -628,10 +615,6 @@ class BaseCompiler
     Vector localInfo_;
     Vector outOfLine_;
 
-    // Index into localInfo_ of the special local used for saving the TLS
-    // pointer. This follows the function's real arguments and locals.
-    uint32_t                    tlsSlot_;
-
     // On specific platforms we sometimes need to use specific registers.
 
 #ifdef JS_CODEGEN_X64
@@ -2229,9 +2212,6 @@ class BaseCompiler
 
         maxFramePushed_ = localSize_;
 
-        // The TLS pointer is always passed as a hidden argument in WasmTlsReg.
-        // Save it into its assigned local slot.
-        storeToFramePtr(WasmTlsReg, localInfo_[tlsSlot_].offs());
         if (debugEnabled_) {
             // Initialize funcIndex and flag fields of DebugFrame.
             size_t debugFrame = masm.framePushed() - DebugFrame::offsetOfFrame();
@@ -2390,8 +2370,9 @@ class BaseCompiler
             restoreResult();
         }
 
-        // Restore the TLS register in case it was overwritten by the function.
-        loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        // The epilogue assumes WasmTlsReg is valid so reload it in case it was
+        // clobbered by the body.
+        masm.loadWasmTlsRegFromFrame();
 
         GenerateFunctionEpilogue(masm, localSize_, &offsets_);
 
@@ -2481,7 +2462,7 @@ class BaseCompiler
             // On x86 there are no pinned registers, so don't waste time
             // reloading the Tls.
 #ifndef JS_CODEGEN_X86
-            loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+            masm.loadWasmTlsRegFromFrame();
             masm.loadWasmPinnedRegsFromTls();
 #endif
         }
@@ -2678,7 +2659,7 @@ class BaseCompiler
                                    const FunctionCall& call)
     {
         // Builtin method calls assume the TLS register has been set.
-        loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame();
 
         CallSiteDesc desc(call.lineOrBytecode, CallSiteDesc::Symbolic);
         masm.wasmCallBuiltinInstanceMethod(instanceArg, builtin);
@@ -3317,56 +3298,56 @@ class BaseCompiler
     void loadGlobalVarI32(unsigned globalDataOffset, RegI32 r)
     {
         ScratchI32 tmp(*this);
-        loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame(tmp);
         masm.load32(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
     }
 
     void loadGlobalVarI64(unsigned globalDataOffset, RegI64 r)
     {
         ScratchI32 tmp(*this);
-        loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame(tmp);
         masm.load64(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
     }
 
     void loadGlobalVarF32(unsigned globalDataOffset, RegF32 r)
     {
         ScratchI32 tmp(*this);
-        loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame(tmp);
         masm.loadFloat32(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
     }
 
     void loadGlobalVarF64(unsigned globalDataOffset, RegF64 r)
     {
         ScratchI32 tmp(*this);
-        loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame(tmp);
         masm.loadDouble(Address(tmp, globalToTlsOffset(globalDataOffset)), r);
     }
 
     void storeGlobalVarI32(unsigned globalDataOffset, RegI32 r)
     {
         ScratchI32 tmp(*this);
-        loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame(tmp);
         masm.store32(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
     }
 
     void storeGlobalVarI64(unsigned globalDataOffset, RegI64 r)
     {
         ScratchI32 tmp(*this);
-        loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame(tmp);
         masm.store64(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
     }
 
     void storeGlobalVarF32(unsigned globalDataOffset, RegF32 r)
     {
         ScratchI32 tmp(*this);
-        loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame(tmp);
         masm.storeFloat32(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
     }
 
     void storeGlobalVarF64(unsigned globalDataOffset, RegF64 r)
     {
         ScratchI32 tmp(*this);
-        loadFromFramePtr(tmp, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame(tmp);
         masm.storeDouble(r, Address(tmp, globalToTlsOffset(globalDataOffset)));
     }
 
@@ -5804,11 +5785,8 @@ BaseCompiler::emitCallArgs(const ValTypeVector& argTypes, FunctionCall& baseline
     for (size_t i = 0; i < numArgs; ++i)
         passArg(baselineCall, argTypes[i], peek(numArgs - 1 - i));
 
-    // Pass the TLS pointer as a hidden argument in WasmTlsReg.  Load
-    // it directly out if its stack slot so we don't interfere with
-    // the stk_.
     if (baselineCall.loadTlsBefore)
-        loadFromFramePtr(WasmTlsReg, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame();
 
     return true;
 }
@@ -6450,7 +6428,7 @@ BaseCompiler::maybeLoadTlsForAccess(bool omitBoundsCheck)
     RegI32 tls = invalidI32();
     if (needTlsForAccess(omitBoundsCheck)) {
         tls = needI32();
-        loadFromFramePtr(tls, frameOffsetFromSlot(tlsSlot_, MIRType::Pointer));
+        masm.loadWasmTlsRegFromFrame(tls);
     }
     return tls;
 }
@@ -7473,7 +7451,6 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
 #ifdef DEBUG
       scratchRegisterTaken_(false),
 #endif
-      tlsSlot_(0),
 #ifdef JS_CODEGEN_X64
       specific_rax(RegI64(Register64(rax))),
       specific_rcx(RegI64(Register64(rcx))),
@@ -7533,15 +7510,9 @@ BaseCompiler::init()
 
     const ValTypeVector& args = func_.sig().args();
 
-    // localInfo_ contains an entry for every local in locals_, followed by
-    // entries for special locals. Currently the only special local is the TLS
-    // pointer.
-    tlsSlot_ = locals_.length();
-    if (!localInfo_.resize(locals_.length() + 1))
+    if (!localInfo_.resize(locals_.length()))
         return false;
 
-    localInfo_[tlsSlot_].init(MIRType::Pointer, TlsSlotOffset);
-
     BaseLocalIter i(locals_, args.length(), debugEnabled_);
     varLow_ = i.reservedSize();
     for (; !i.done() && i.index() < args.length(); i++) {
diff --git a/js/src/wasm/WasmDebugFrame.cpp b/js/src/wasm/WasmDebugFrame.cpp
deleted file mode 100644
index 274677d92068..000000000000
--- a/js/src/wasm/WasmDebugFrame.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- *
- * Copyright 2016 Mozilla Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "wasm/WasmDebugFrame.h"
-
-#include "vm/EnvironmentObject.h"
-#include "wasm/WasmBaselineCompile.h"
-#include "wasm/WasmInstance.h"
-
-#include "jsobjinlines.h"
-
-using namespace js;
-using namespace js::wasm;
-
-Instance*
-DebugFrame::instance() const
-{
-    return tlsData_->instance;
-}
-
-GlobalObject*
-DebugFrame::global() const
-{
-    return &instance()->object()->global();
-}
-
-JSObject*
-DebugFrame::environmentChain() const
-{
-    return &global()->lexicalEnvironment();
-}
-
-void
-DebugFrame::observeFrame(JSContext* cx)
-{
-   if (observing_)
-       return;
-
-   instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ true);
-   observing_ = true;
-}
-
-void
-DebugFrame::leaveFrame(JSContext* cx)
-{
-   if (!observing_)
-       return;
-
-   instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ false);
-   observing_ = false;
-}
-
-void
-DebugFrame::clearReturnJSValue()
-{
-    hasCachedReturnJSValue_ = true;
-    cachedReturnJSValue_.setUndefined();
-}
-
-void
-DebugFrame::updateReturnJSValue()
-{
-    hasCachedReturnJSValue_ = true;
-    ExprType returnType = instance()->code().debugGetResultType(funcIndex());
-    switch (returnType) {
-      case ExprType::Void:
-          cachedReturnJSValue_.setUndefined();
-          break;
-      case ExprType::I32:
-          cachedReturnJSValue_.setInt32(resultI32_);
-          break;
-      case ExprType::I64:
-          // Just display as a Number; it's ok if we lose some precision
-          cachedReturnJSValue_.setDouble((double)resultI64_);
-          break;
-      case ExprType::F32:
-          cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF32_));
-          break;
-      case ExprType::F64:
-          cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF64_));
-          break;
-      default:
-          MOZ_CRASH("result type");
-    }
-}
-
-bool
-DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp)
-{
-    ValTypeVector locals;
-    size_t argsLength;
-    if (!instance()->code().debugGetLocalTypes(funcIndex(), &locals, &argsLength))
-        return false;
-
-    BaseLocalIter iter(locals, argsLength, /* debugEnabled = */ true);
-    while (!iter.done() && iter.index() < localIndex)
-        iter++;
-    MOZ_ALWAYS_TRUE(!iter.done());
-
-    uint8_t* frame = static_cast((void*)this) + offsetOfFrame();
-    void* dataPtr = frame - iter.frameOffset();
-    switch (iter.mirType()) {
-      case jit::MIRType::Int32:
-          vp.set(Int32Value(*static_cast(dataPtr)));
-          break;
-      case jit::MIRType::Int64:
-          // Just display as a Number; it's ok if we lose some precision
-          vp.set(NumberValue((double)*static_cast(dataPtr)));
-          break;
-      case jit::MIRType::Float32:
-          vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast(dataPtr))));
-          break;
-      case jit::MIRType::Double:
-          vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast(dataPtr))));
-          break;
-      default:
-          MOZ_CRASH("local type");
-    }
-    return true;
-}
-
diff --git a/js/src/wasm/WasmDebugFrame.h b/js/src/wasm/WasmDebugFrame.h
deleted file mode 100644
index 6629dd42a934..000000000000
--- a/js/src/wasm/WasmDebugFrame.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- *
- * Copyright 2016 Mozilla Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef wasmdebugframe_js_h
-#define wasmdebugframe_js_h
-
-#include "gc/Barrier.h"
-#include "js/RootingAPI.h"
-#include "js/TracingAPI.h"
-#include "wasm/WasmTypes.h"
-
-namespace js {
-
-class WasmFunctionCallObject;
-
-namespace wasm {
-
-class DebugFrame
-{
-    union
-    {
-        int32_t resultI32_;
-        int64_t resultI64_;
-        float   resultF32_;
-        double  resultF64_;
-    };
-
-    js::Value   cachedReturnJSValue_;
-
-    // The fields below are initialized by the baseline compiler.
-    uint32_t    funcIndex_;
-
-    union
-    {
-        struct
-        {
-            bool    observing_ : 1;
-            bool    isDebuggee_ : 1;
-            bool    prevUpToDate_ : 1;
-            bool    hasCachedSavedFrame_ : 1;
-            bool    hasCachedReturnJSValue_ : 1;
-        };
-        void*   reserved1_;
-    };
-
-    TlsData*    tlsData_;
-    Frame       frame_;
-
-    explicit DebugFrame() {}
-
-    void StaticAsserts() {
-        // VS2017 doesn't consider offsetOfResults() etc. to be constexpr, so we have to use
-        // offsetof directly. These asserts can't be at class-level because the type is incomplete.
-        static_assert(offsetof(DebugFrame, resultI32_) == 0, "results shall be at offset 0");
-        static_assert(offsetof(DebugFrame, tlsData_) + sizeof(TlsData*) ==
-                      offsetof(DebugFrame, frame_),
-                      "TLS pointer must be a field just before the wasm frame");
-        static_assert(sizeof(DebugFrame) % 8 == 0,
-                      "DebugFrame is 8-bytes aligned for AbstractFramePtr");
-    }
-
-  public:
-    inline uint32_t funcIndex() const { return funcIndex_; }
-    inline TlsData* tlsData() const { return tlsData_; }
-    inline Frame& frame() { return frame_; }
-
-    Instance* instance() const;
-    GlobalObject* global() const;
-
-    JSObject* environmentChain() const;
-
-    void observeFrame(JSContext* cx);
-    void leaveFrame(JSContext* cx);
-
-    void trace(JSTracer* trc);
-
-    // These are opaque boolean flags used by the debugger and
-    // saved-frame-chains code.
-    inline bool isDebuggee() const { return isDebuggee_; }
-    inline void setIsDebuggee() { isDebuggee_ = true; }
-    inline void unsetIsDebuggee() { isDebuggee_ = false; }
-
-    inline bool prevUpToDate() const { return prevUpToDate_; }
-    inline void setPrevUpToDate() { prevUpToDate_ = true; }
-    inline void unsetPrevUpToDate() { prevUpToDate_ = false; }
-
-    inline bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; }
-    inline void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; }
-
-    inline void* resultsPtr() { return &resultI32_; }
-
-    inline HandleValue returnValue() const {
-        MOZ_ASSERT(hasCachedReturnJSValue_);
-        return HandleValue::fromMarkedLocation(&cachedReturnJSValue_);
-    }
-    void updateReturnJSValue();
-    void clearReturnJSValue();
-
-    bool getLocal(uint32_t localIndex, MutableHandleValue vp);
-
-    static constexpr size_t offsetOfResults() { return offsetof(DebugFrame, resultI32_); }
-    static constexpr size_t offsetOfFlagsWord() { return offsetof(DebugFrame, reserved1_); }
-    static constexpr size_t offsetOfFuncIndex() { return offsetof(DebugFrame, funcIndex_); }
-    static constexpr size_t offsetOfTlsData() { return offsetof(DebugFrame, tlsData_); }
-    static constexpr size_t offsetOfFrame() { return offsetof(DebugFrame, frame_); }
-};
-
-} // namespace wasm
-} // namespace js
-
-#endif // wasmdebugframe_js_h
diff --git a/js/src/wasm/WasmFrameIterator.cpp b/js/src/wasm/WasmFrameIterator.cpp
index d9606c5ba997..bd76bdc67b59 100644
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -18,7 +18,6 @@
 
 #include "wasm/WasmFrameIterator.h"
 
-#include "wasm/WasmDebugFrame.h"
 #include "wasm/WasmInstance.h"
 
 #include "jit/MacroAssembler-inl.h"
diff --git a/js/src/wasm/WasmTypes.cpp b/js/src/wasm/WasmTypes.cpp
index 6347f00a56fb..302756f3c542 100644
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -28,6 +28,7 @@
 #include "jit/MacroAssembler.h"
 #include "js/Conversions.h"
 #include "vm/Interpreter.h"
+#include "wasm/WasmBaselineCompile.h"
 #include "wasm/WasmInstance.h"
 #include "wasm/WasmSerialize.h"
 #include "wasm/WasmSignalHandlers.h"
@@ -115,7 +116,7 @@ WasmHandleDebugTrap()
             return true;
         DebugFrame* frame = iter.debugFrame();
         frame->setIsDebuggee();
-        frame->observeFrame(cx);
+        frame->observe(cx);
         // TODO call onEnterFrame
         JSTrapStatus status = Debugger::onEnterFrame(cx, frame);
         if (status == JSTRAP_RETURN) {
@@ -131,7 +132,7 @@ WasmHandleDebugTrap()
         DebugFrame* frame = iter.debugFrame();
         frame->updateReturnJSValue();
         bool ok = Debugger::onLeaveFrame(cx, frame, nullptr, true);
-        frame->leaveFrame(cx);
+        frame->leave(cx);
         return ok;
     }
 
@@ -196,7 +197,7 @@ WasmHandleThrow()
             // TODO properly handle success and resume wasm execution.
             JS_ReportErrorASCII(cx, "Unexpected success from onLeaveFrame");
         }
-        frame->leaveFrame(cx);
+        frame->leave(cx);
      }
 }
 
@@ -998,3 +999,122 @@ wasm::ComputeMappedSize(uint32_t maxSize)
 }
 
 #endif  // WASM_HUGE_MEMORY
+
+void
+DebugFrame::alignmentStaticAsserts()
+{
+    // VS2017 doesn't consider offsetOfFrame() to be a constexpr, so we have
+    // to use offsetof directly. These asserts can't be at class-level
+    // because the type is incomplete.
+
+    static_assert(WasmStackAlignment >= Alignment,
+                  "Aligned by ABI before pushing DebugFrame");
+    static_assert((offsetof(DebugFrame, frame_) + sizeof(Frame)) % Alignment == 0,
+                  "Aligned after pushing DebugFrame");
+}
+
+GlobalObject*
+DebugFrame::global() const
+{
+    return &instance()->object()->global();
+}
+
+JSObject*
+DebugFrame::environmentChain() const
+{
+    return &global()->lexicalEnvironment();
+}
+
+bool
+DebugFrame::getLocal(uint32_t localIndex, MutableHandleValue vp)
+{
+    ValTypeVector locals;
+    size_t argsLength;
+    if (!instance()->code().debugGetLocalTypes(funcIndex(), &locals, &argsLength))
+        return false;
+
+    BaseLocalIter iter(locals, argsLength, /* debugEnabled = */ true);
+    while (!iter.done() && iter.index() < localIndex)
+        iter++;
+    MOZ_ALWAYS_TRUE(!iter.done());
+
+    uint8_t* frame = static_cast((void*)this) + offsetOfFrame();
+    void* dataPtr = frame - iter.frameOffset();
+    switch (iter.mirType()) {
+      case jit::MIRType::Int32:
+          vp.set(Int32Value(*static_cast(dataPtr)));
+          break;
+      case jit::MIRType::Int64:
+          // Just display as a Number; it's ok if we lose some precision
+          vp.set(NumberValue((double)*static_cast(dataPtr)));
+          break;
+      case jit::MIRType::Float32:
+          vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast(dataPtr))));
+          break;
+      case jit::MIRType::Double:
+          vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast(dataPtr))));
+          break;
+      default:
+          MOZ_CRASH("local type");
+    }
+    return true;
+}
+
+void
+DebugFrame::updateReturnJSValue()
+{
+    hasCachedReturnJSValue_ = true;
+    ExprType returnType = instance()->code().debugGetResultType(funcIndex());
+    switch (returnType) {
+      case ExprType::Void:
+          cachedReturnJSValue_.setUndefined();
+          break;
+      case ExprType::I32:
+          cachedReturnJSValue_.setInt32(resultI32_);
+          break;
+      case ExprType::I64:
+          // Just display as a Number; it's ok if we lose some precision
+          cachedReturnJSValue_.setDouble((double)resultI64_);
+          break;
+      case ExprType::F32:
+          cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF32_));
+          break;
+      case ExprType::F64:
+          cachedReturnJSValue_.setDouble(JS::CanonicalizeNaN(resultF64_));
+          break;
+      default:
+          MOZ_CRASH("result type");
+    }
+}
+
+HandleValue
+DebugFrame::returnValue() const
+{
+    MOZ_ASSERT(hasCachedReturnJSValue_);
+    return HandleValue::fromMarkedLocation(&cachedReturnJSValue_);
+}
+
+void
+DebugFrame::clearReturnJSValue()
+{
+    hasCachedReturnJSValue_ = true;
+    cachedReturnJSValue_.setUndefined();
+}
+
+void
+DebugFrame::observe(JSContext* cx)
+{
+   if (!observing_) {
+       instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ true);
+       observing_ = true;
+   }
+}
+
+void
+DebugFrame::leave(JSContext* cx)
+{
+    if (observing_) {
+       instance()->code().adjustEnterAndLeaveFrameTrapsState(cx, /* enabled = */ false);
+       observing_ = false;
+    }
+}
diff --git a/js/src/wasm/WasmTypes.h b/js/src/wasm/WasmTypes.h
index 1984d9e6706f..2ecc111be9c3 100644
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -41,6 +41,7 @@
 namespace js {
 
 class PropertyName;
+class WasmFunctionCallObject;
 namespace jit {
     struct BaselineScript;
     enum class RoundingMode;
@@ -1465,6 +1466,116 @@ struct Frame
     // The return address pushed by the call (in the case of ARM/MIPS the return
     // address is pushed by the first instruction of the prologue).
     void* returnAddress;
+
+    // Helper functions:
+
+    Instance* instance() const { return tls->instance; }
+};
+
+// A DebugFrame is a Frame with additional fields that are added after the
+// normal function prologue by the baseline compiler. If a Module is compiled
+// with debugging enabled, then all its code creates DebugFrames on the stack
+// instead of just Frames. These extra fields are used by the Debugger API.
+
+class DebugFrame
+{
+    // The results field left uninitialized and only used during the baseline
+    // compiler's return sequence to allow the debugger to inspect and modify
+    // the return value of a frame being debugged.
+    union
+    {
+        int32_t resultI32_;
+        int64_t resultI64_;
+        float resultF32_;
+        double resultF64_;
+    };
+
+    // The returnValue() method returns a HandleValue pointing to this field.
+    js::Value cachedReturnJSValue_;
+
+    // The function index of this frame. Technically, this could be derived
+    // given a PC into this frame (which could lookup the CodeRange which has
+    // the function index), but this isn't always readily available.
+    uint32_t funcIndex_;
+
+    // Flags whose meaning are described below.
+    union
+    {
+        struct
+        {
+            bool observing_ : 1;
+            bool isDebuggee_ : 1;
+            bool prevUpToDate_ : 1;
+            bool hasCachedSavedFrame_ : 1;
+            bool hasCachedReturnJSValue_ : 1;
+        };
+        void* flagsWord_;
+    };
+
+    // Padding so that DebugFrame has Alignment.
+#if JS_BITS_PER_WORD == 32
+    void* padding_;
+#endif
+
+    // The Frame goes at the end since the stack grows down.
+    Frame frame_;
+
+  public:
+    Frame& frame() { return frame_; }
+    uint32_t funcIndex() const { return funcIndex_; }
+    Instance* instance() const { return frame_.instance(); }
+    GlobalObject* global() const;
+    JSObject* environmentChain() const;
+    bool getLocal(uint32_t localIndex, MutableHandleValue vp);
+
+    // The return value must be written from the unboxed representation in the
+    // results union into cachedReturnJSValue_ by updateReturnJSValue() before
+    // returnValue() can return a Handle to it.
+
+    void updateReturnJSValue();
+    HandleValue returnValue() const;
+    void clearReturnJSValue();
+
+    // Once the debugger observes a frame, it must be notified via
+    // onLeaveFrame() before the frame is popped. Calling observe() ensures the
+    // leave frame traps are enabled. Both methods are idempotent so the caller
+    // doesn't have to worry about calling them more than once.
+
+    void observe(JSContext* cx);
+    void leave(JSContext* cx);
+
+    // The 'isDebugge' bit is initialized to false and set by the WebAssembly
+    // runtime right before a frame is exposed to the debugger, as required by
+    // the Debugger API. The bit is then used for Debugger-internal purposes
+    // afterwards.
+
+    bool isDebuggee() const { return isDebuggee_; }
+    void setIsDebuggee() { isDebuggee_ = true; }
+    void unsetIsDebuggee() { isDebuggee_ = false; }
+
+    // These are opaque boolean flags used by the debugger to implement
+    // AbstractFramePtr. They are initialized to false and not otherwise read or
+    // written by wasm code or runtime.
+
+    bool prevUpToDate() const { return prevUpToDate_; }
+    void setPrevUpToDate() { prevUpToDate_ = true; }
+    void unsetPrevUpToDate() { prevUpToDate_ = false; }
+
+    bool hasCachedSavedFrame() const { return hasCachedSavedFrame_; }
+    void setHasCachedSavedFrame() { hasCachedSavedFrame_ = true; }
+
+    // DebugFrame is accessed directly by JIT code.
+
+    static constexpr size_t offsetOfResults() { return offsetof(DebugFrame, resultI32_); }
+    static constexpr size_t offsetOfFlagsWord() { return offsetof(DebugFrame, flagsWord_); }
+    static constexpr size_t offsetOfFuncIndex() { return offsetof(DebugFrame, funcIndex_); }
+    static constexpr size_t offsetOfFrame() { return offsetof(DebugFrame, frame_); }
+
+    // DebugFrames are aligned to 8-byte aligned, allowing them to be placed in
+    // an AbstractFramePtr.
+
+    static const unsigned Alignment = 8;
+    static void alignmentStaticAsserts();
 };
 
 } // namespace wasm

From dd552f19d71a979b7336aed31c7a38f5f131fba8 Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:15:50 -0500
Subject: [PATCH 23/96] Bug 1334504 - Baldr: remove ion's explicit TLS-saving
 (r=bbouvier)

MozReview-Commit-ID: 57GppQ6y2Mw

--HG--
extra : rebase_source : 435cca09a8c5f7d764d47ae11b7a17aa467cd0b7
---
 js/src/jit/MIR.cpp                         | 11 +--
 js/src/jit/MIR.h                           | 20 +----
 js/src/jit/shared/CodeGenerator-shared.cpp | 18 +++--
 js/src/jit/shared/LIR-shared.h             |  1 +
 js/src/wasm/WasmIonCompile.cpp             | 87 +++++-----------------
 5 files changed, 35 insertions(+), 102 deletions(-)

diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp
index 44e8c026fe47..184fc33ced6e 100644
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -5700,10 +5700,9 @@ MWasmUnsignedToFloat32::foldsTo(TempAllocator& alloc)
 
 MWasmCall*
 MWasmCall::New(TempAllocator& alloc, const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee,
-               const Args& args, MIRType resultType, uint32_t spIncrement, uint32_t tlsStackOffset,
-               MDefinition* tableIndex)
+               const Args& args, MIRType resultType, uint32_t spIncrement, MDefinition* tableIndex)
 {
-    MWasmCall* call = new(alloc) MWasmCall(desc, callee, spIncrement, tlsStackOffset);
+    MWasmCall* call = new(alloc) MWasmCall(desc, callee, spIncrement);
     call->setResultType(resultType);
 
     if (!call->argRegs_.init(alloc, args.length()))
@@ -5729,12 +5728,10 @@ MWasmCall::NewBuiltinInstanceMethodCall(TempAllocator& alloc,
                                         const ABIArg& instanceArg,
                                         const Args& args,
                                         MIRType resultType,
-                                        uint32_t spIncrement,
-                                        uint32_t tlsStackOffset)
+                                        uint32_t spIncrement)
 {
     auto callee = wasm::CalleeDesc::builtinInstanceMethod(builtin);
-    MWasmCall* call = MWasmCall::New(alloc, desc, callee, args, resultType, spIncrement,
-                                     tlsStackOffset, nullptr);
+    MWasmCall* call = MWasmCall::New(alloc, desc, callee, args, resultType, spIncrement, nullptr);
     if (!call)
         return nullptr;
 
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 596ff609460d..3fe1ee3c7c55 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -14305,15 +14305,12 @@ class MWasmCall final
     wasm::CalleeDesc callee_;
     FixedList argRegs_;
     uint32_t spIncrement_;
-    uint32_t tlsStackOffset_;
     ABIArg instanceArg_;
 
-    MWasmCall(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee, uint32_t spIncrement,
-              uint32_t tlsStackOffset)
+    MWasmCall(const wasm::CallSiteDesc& desc, const wasm::CalleeDesc& callee, uint32_t spIncrement)
       : desc_(desc),
         callee_(callee),
-        spIncrement_(spIncrement),
-        tlsStackOffset_(tlsStackOffset)
+        spIncrement_(spIncrement)
     { }
 
   public:
@@ -14326,15 +14323,12 @@ class MWasmCall final
     };
     typedef Vector Args;
 
-    static const uint32_t DontSaveTls = UINT32_MAX;
-
     static MWasmCall* New(TempAllocator& alloc,
                           const wasm::CallSiteDesc& desc,
                           const wasm::CalleeDesc& callee,
                           const Args& args,
                           MIRType resultType,
                           uint32_t spIncrement,
-                          uint32_t tlsStackOffset,
                           MDefinition* tableIndex = nullptr);
 
     static MWasmCall* NewBuiltinInstanceMethodCall(TempAllocator& alloc,
@@ -14343,8 +14337,7 @@ class MWasmCall final
                                                    const ABIArg& instanceArg,
                                                    const Args& args,
                                                    MIRType resultType,
-                                                   uint32_t spIncrement,
-                                                   uint32_t tlsStackOffset);
+                                                   uint32_t spIncrement);
 
     size_t numArgs() const {
         return argRegs_.length();
@@ -14362,13 +14355,6 @@ class MWasmCall final
     uint32_t spIncrement() const {
         return spIncrement_;
     }
-    bool saveTls() const {
-        return tlsStackOffset_ != DontSaveTls;
-    }
-    uint32_t tlsStackOffset() const {
-        MOZ_ASSERT(saveTls());
-        return tlsStackOffset_;
-    }
 
     bool possiblyCalls() const override {
         return true;
diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp
index b32e1c3fc6c3..7922d16490f2 100644
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -1499,35 +1499,37 @@ CodeGeneratorShared::emitWasmCallBase(LWasmCallBase* ins)
     masm.bind(&ok);
 #endif
 
-    // Save the caller's TLS register in a reserved stack slot (below the
-    // call's stack arguments) for retrieval after the call.
-    if (mir->saveTls())
-        masm.storePtr(WasmTlsReg, Address(masm.getStackPointer(), mir->tlsStackOffset()));
+    // LWasmCallBase::isCallPreserved() assumes that all MWasmCalls preserve the
+    // TLS and pinned regs. The only case where where we don't have to reload
+    // the TLS and pinned regs is when the callee preserves them.
+    bool reloadRegs = true;
 
     const wasm::CallSiteDesc& desc = mir->desc();
     const wasm::CalleeDesc& callee = mir->callee();
     switch (callee.which()) {
       case wasm::CalleeDesc::Func:
         masm.call(desc, callee.funcIndex());
+        reloadRegs = false;
         break;
       case wasm::CalleeDesc::Import:
         masm.wasmCallImport(desc, callee);
         break;
-      case wasm::CalleeDesc::WasmTable:
       case wasm::CalleeDesc::AsmJSTable:
+      case wasm::CalleeDesc::WasmTable:
         masm.wasmCallIndirect(desc, callee, ins->needsBoundsCheck());
+        reloadRegs = callee.which() == wasm::CalleeDesc::WasmTable && callee.wasmTableIsExternal();
         break;
       case wasm::CalleeDesc::Builtin:
         masm.call(callee.builtin());
+        reloadRegs = false;
         break;
       case wasm::CalleeDesc::BuiltinInstanceMethod:
         masm.wasmCallBuiltinInstanceMethod(mir->instanceArg(), callee.builtin());
         break;
     }
 
-    // After return, restore the caller's TLS and pinned registers.
-    if (mir->saveTls()) {
-        masm.loadPtr(Address(masm.getStackPointer(), mir->tlsStackOffset()), WasmTlsReg);
+    if (reloadRegs) {
+        masm.loadWasmTlsRegFromFrame();
         masm.loadWasmPinnedRegsFromTls();
     }
 
diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
index 0c632201ec06..34da708ee535 100644
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -8683,6 +8683,7 @@ class LWasmCallBase : public LInstruction
         //  - internal/indirect calls do by the internal wasm ABI
         //  - import calls do by explicitly saving/restoring at the callsite
         //  - builtin calls do because the TLS reg is non-volatile
+        // See also CodeGeneratorShared::emitWasmCallBase.
         return !reg.isFloat() && reg.gpr() == WasmTlsReg;
     }
 
diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp
index 66d1c788f64d..fa185f27cc8a 100644
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -55,22 +55,6 @@ typedef OpIter IonOpIter;
 
 class FunctionCompiler;
 
-// TlsUsage describes how the TLS register is used during a function call.
-
-enum class TlsUsage
-{
-    Unused,     // No particular action is taken with respect to the TLS register.
-    Need,       // The TLS register must be reloaded just before the call.
-    CallerSaved // Same, plus space must be allocated to save/restore the TLS
-                // register.
-};
-
-static bool
-NeedsTls(TlsUsage usage)
-{
-    return usage == TlsUsage::Need || usage == TlsUsage::CallerSaved;
-}
-
 // CallCompileState describes a call that is being compiled. Due to expression
 // nesting, multiple calls can be in the middle of compilation at the same time
 // and these are tracked in a stack by FunctionCompiler.
@@ -93,11 +77,6 @@ class CallCompileState
     // FunctionCompiler::startCall() comment below.
     uint32_t spIncrement_;
 
-    // Set by FunctionCompiler::finishCall(), tells a potentially-inter-module
-    // call the offset of the reserved space in which it can save the caller's
-    // WasmTlsReg.
-    uint32_t tlsStackOffset_;
-
     // Accumulates the register arguments while compiling arguments.
     MWasmCall::Args regArgs_;
 
@@ -123,7 +102,6 @@ class CallCompileState
       : lineOrBytecode_(lineOrBytecode),
         maxChildStackBytes_(0),
         spIncrement_(0),
-        tlsStackOffset_(MWasmCall::DontSaveTls),
         childClobbers_(false)
     { }
 };
@@ -995,7 +973,7 @@ class FunctionCompiler
             outer->childClobbers_ = true;
     }
 
-    bool finishCall(CallCompileState* call, TlsUsage tls)
+    bool finishCall(CallCompileState* call)
     {
         MOZ_ALWAYS_TRUE(callStack_.popCopy() == call);
 
@@ -1004,22 +982,10 @@ class FunctionCompiler
             return true;
         }
 
-        if (NeedsTls(tls)) {
-            if (!call->regArgs_.append(MWasmCall::Arg(AnyRegister(WasmTlsReg), tlsPointer_)))
-                return false;
-        }
+        if (!call->regArgs_.append(MWasmCall::Arg(AnyRegister(WasmTlsReg), tlsPointer_)))
+            return false;
 
         uint32_t stackBytes = call->abi_.stackBytesConsumedSoFar();
-
-        // If this is a potentially-inter-module call, allocate an extra word of
-        // stack space to save/restore the caller's WasmTlsReg during the call.
-        // Record the stack offset before including spIncrement since MWasmCall
-        // will use this offset after having bumped the stack pointer.
-        if (tls == TlsUsage::CallerSaved) {
-            call->tlsStackOffset_ = stackBytes;
-            stackBytes += sizeof(void*);
-        }
-
         if (call->childClobbers_) {
             call->spIncrement_ = AlignBytes(call->maxChildStackBytes_, WasmStackAlignment);
             for (MWasmStackArg* stackArg : call->stackArgs_)
@@ -1052,8 +1018,7 @@ class FunctionCompiler
         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Func);
         MIRType ret = ToMIRType(sig.ret());
         auto callee = CalleeDesc::function(funcIndex);
-        auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ret,
-                                   call.spIncrement_, MWasmCall::DontSaveTls);
+        auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ret, call.spIncrement_);
         if (!ins)
             return false;
 
@@ -1078,7 +1043,6 @@ class FunctionCompiler
             const TableDesc& table = env_.tables[env_.asmJSSigToTableIndex[sigIndex]];
             MOZ_ASSERT(IsPowerOfTwo(table.limits.initial));
             MOZ_ASSERT(!table.external);
-            MOZ_ASSERT(call.tlsStackOffset_ == MWasmCall::DontSaveTls);
 
             MConstant* mask = MConstant::New(alloc(), Int32Value(table.limits.initial - 1));
             curBlock_->add(mask);
@@ -1091,14 +1055,12 @@ class FunctionCompiler
             MOZ_ASSERT(sig.id.kind() != SigIdDesc::Kind::None);
             MOZ_ASSERT(env_.tables.length() == 1);
             const TableDesc& table = env_.tables[0];
-            MOZ_ASSERT(table.external == (call.tlsStackOffset_ != MWasmCall::DontSaveTls));
-
             callee = CalleeDesc::wasmTable(table, sig.id);
         }
 
         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Dynamic);
         auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(sig.ret()),
-                                   call.spIncrement_, call.tlsStackOffset_, index);
+                                   call.spIncrement_, index);
         if (!ins)
             return false;
 
@@ -1115,12 +1077,10 @@ class FunctionCompiler
             return true;
         }
 
-        MOZ_ASSERT(call.tlsStackOffset_ != MWasmCall::DontSaveTls);
-
         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Dynamic);
         auto callee = CalleeDesc::import(globalDataOffset);
         auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(ret),
-                                   call.spIncrement_, call.tlsStackOffset_);
+                                   call.spIncrement_);
         if (!ins)
             return false;
 
@@ -1140,7 +1100,7 @@ class FunctionCompiler
         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Symbolic);
         auto callee = CalleeDesc::builtin(builtin);
         auto* ins = MWasmCall::New(alloc(), desc, callee, call.regArgs_, ToMIRType(ret),
-                                   call.spIncrement_, MWasmCall::DontSaveTls);
+                                   call.spIncrement_);
         if (!ins)
             return false;
 
@@ -1160,8 +1120,7 @@ class FunctionCompiler
         CallSiteDesc desc(call.lineOrBytecode_, CallSiteDesc::Symbolic);
         auto* ins = MWasmCall::NewBuiltinInstanceMethodCall(alloc(), desc, builtin,
                                                             call.instanceArg_, call.regArgs_,
-                                                            ToMIRType(ret), call.spIncrement_,
-                                                            call.tlsStackOffset_);
+                                                            ToMIRType(ret), call.spIncrement_);
         if (!ins)
             return false;
 
@@ -2018,11 +1977,8 @@ EmitUnreachable(FunctionCompiler& f)
 typedef IonOpIter::ValueVector DefVector;
 
 static bool
-EmitCallArgs(FunctionCompiler& f, const Sig& sig, const DefVector& args, TlsUsage tls,
-             CallCompileState* call)
+EmitCallArgs(FunctionCompiler& f, const Sig& sig, const DefVector& args, CallCompileState* call)
 {
-    MOZ_ASSERT(NeedsTls(tls));
-
     if (!f.startCall(call))
         return false;
 
@@ -2031,7 +1987,7 @@ EmitCallArgs(FunctionCompiler& f, const Sig& sig, const DefVector& args, TlsUsag
             return false;
     }
 
-    return f.finishCall(call, tls);
+    return f.finishCall(call);
 }
 
 static bool
@@ -2048,15 +2004,13 @@ EmitCall(FunctionCompiler& f)
         return true;
 
     const Sig& sig = *f.env().funcSigs[funcIndex];
-    bool import = f.env().funcIsImport(funcIndex);
-    TlsUsage tls = import ? TlsUsage::CallerSaved : TlsUsage::Need;
 
     CallCompileState call(f, lineOrBytecode);
-    if (!EmitCallArgs(f, sig, args, tls, &call))
+    if (!EmitCallArgs(f, sig, args, &call))
         return false;
 
     MDefinition* def;
-    if (import) {
+    if (f.env().funcIsImport(funcIndex)) {
         uint32_t globalDataOffset = f.env().funcImportGlobalDataOffsets[funcIndex];
         if (!f.callImport(globalDataOffset, call, sig.ret(), &def))
             return false;
@@ -2093,12 +2047,8 @@ EmitCallIndirect(FunctionCompiler& f, bool oldStyle)
 
     const Sig& sig = f.env().sigs[sigIndex];
 
-    TlsUsage tls = !f.env().isAsmJS() && f.env().tables[0].external
-                   ? TlsUsage::CallerSaved
-                   : TlsUsage::Need;
-
     CallCompileState call(f, lineOrBytecode);
-    if (!EmitCallArgs(f, sig, args, tls, &call))
+    if (!EmitCallArgs(f, sig, args, &call))
         return false;
 
     MDefinition* def;
@@ -2581,7 +2531,7 @@ EmitUnaryMathBuiltinCall(FunctionCompiler& f, SymbolicAddress callee, ValType op
     if (!f.passArg(input, operandType, &call))
         return false;
 
-    if (!f.finishCall(&call, TlsUsage::Unused))
+    if (!f.finishCall(&call))
         return false;
 
     MDefinition* def;
@@ -2612,7 +2562,7 @@ EmitBinaryMathBuiltinCall(FunctionCompiler& f, SymbolicAddress callee, ValType o
     if (!f.passArg(rhs, operandType, &call))
         return false;
 
-    if (!f.finishCall(&call, TlsUsage::Unused))
+    if (!f.finishCall(&call))
         return false;
 
     MDefinition* def;
@@ -3217,10 +3167,7 @@ EmitGrowMemory(FunctionCompiler& f)
     if (!f.passArg(delta, ValType::I32, &args))
         return false;
 
-    // As a short-cut, pretend this is an inter-module call so that any pinned
-    // heap pointer will be reloaded after the call. This hack will go away once
-    // we can stop pinning registers.
-    f.finishCall(&args, TlsUsage::CallerSaved);
+    f.finishCall(&args);
 
     MDefinition* ret;
     if (!f.builtinInstanceMethodCall(SymbolicAddress::GrowMemory, args, ValType::I32, &ret))
@@ -3246,7 +3193,7 @@ EmitCurrentMemory(FunctionCompiler& f)
     if (!f.passInstance(&args))
         return false;
 
-    f.finishCall(&args, TlsUsage::Need);
+    f.finishCall(&args);
 
     MDefinition* ret;
     if (!f.builtinInstanceMethodCall(SymbolicAddress::CurrentMemory, args, ValType::I32, &ret))

From e24cd03181889e70bc5b476ec3edb91cdc28e6f9 Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:16:35 -0500
Subject: [PATCH 24/96] Bug 1334504 - Baldr: remove stubs' explicit TLS-saving
 (r=bbouvier)

MozReview-Commit-ID: INtxrPyoni7

--HG--
extra : rebase_source : 52f7501be32155358cc8a7a58f6803e2409d33a4
---
 js/src/wasm/WasmStubs.cpp | 27 ++++++---------------------
 1 file changed, 6 insertions(+), 21 deletions(-)

diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp
index cda339d2ee1a..e51dea457dce 100644
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -452,8 +452,7 @@ wasm::GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, Si
 {
     masm.setFramePushed(0);
 
-    unsigned tlsBytes = sizeof(void*);
-    unsigned framePushed = StackDecrementForCall(masm, WasmStackAlignment, fi.sig().args(), tlsBytes);
+    unsigned framePushed = StackDecrementForCall(masm, WasmStackAlignment, fi.sig().args());
 
     FuncOffsets offsets;
     GenerateFunctionPrologue(masm, framePushed, sigId, &offsets);
@@ -474,16 +473,12 @@ wasm::GenerateImportFunction(jit::MacroAssembler& masm, const FuncImport& fi, Si
         StackCopy(masm, i.mirType(), scratch, src, dst);
     }
 
-    // Save the TLS register so it can be restored later.
-    uint32_t tlsStackOffset = i.stackBytesConsumedSoFar();
-    masm.storePtr(WasmTlsReg, Address(masm.getStackPointer(), tlsStackOffset));
-
     // Call the import exit stub.
     CallSiteDesc desc(CallSiteDesc::Dynamic);
     masm.wasmCallImport(desc, CalleeDesc::import(fi.tlsDataOffset()));
 
     // Restore the TLS register and pinned regs, per wasm function ABI.
-    masm.loadPtr(Address(masm.getStackPointer(), tlsStackOffset), WasmTlsReg);
+    masm.loadWasmTlsRegFromFrame();
     masm.loadWasmPinnedRegsFromTls();
 
     GenerateFunctionEpilogue(masm, framePushed, &offsets);
@@ -621,8 +616,6 @@ wasm::GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi, uint3
     return offsets;
 }
 
-static const unsigned SavedTlsReg = sizeof(void*);
-
 // Generate a stub that is called via the internal ABI derived from the
 // signature of the import and calls into a compatible JIT function,
 // having boxed all the ABI arguments into the JIT stack frame layout.
@@ -640,7 +633,7 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
     static_assert(WasmStackAlignment >= JitStackAlignment, "subsumes");
     unsigned sizeOfRetAddr = sizeof(void*);
     unsigned jitFrameBytes = 3 * sizeof(void*) + (1 + fi.sig().args().length()) * sizeof(Value);
-    unsigned totalJitFrameBytes = sizeOfRetAddr + jitFrameBytes + SavedTlsReg;
+    unsigned totalJitFrameBytes = sizeOfRetAddr + jitFrameBytes;
     unsigned jitFramePushed = StackDecrementForCall(masm, JitStackAlignment, totalJitFrameBytes) -
                               sizeOfRetAddr;
 
@@ -684,12 +677,6 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
     argOffset += fi.sig().args().length() * sizeof(Value);
     MOZ_ASSERT(argOffset == jitFrameBytes);
 
-    // 6. Jit code will clobber all registers, even non-volatiles. WasmTlsReg
-    //    must be kept live for the benefit of the epilogue, so push it on the
-    //    stack so that it can be restored before the epilogue.
-    static_assert(SavedTlsReg == sizeof(void*), "stack frame accounting");
-    masm.storePtr(WasmTlsReg, Address(masm.getStackPointer(), jitFrameBytes));
-
     {
         // Enable Activation.
         //
@@ -795,11 +782,9 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
     Label done;
     masm.bind(&done);
 
-    // Ion code does not respect the system ABI's callee-saved register
-    // conventions so reload any assumed-non-volatile registers. Note that the
-    // reserveStack(sizeOfRetAddr) above means that the stack pointer is at a
-    // different offset than when WasmTlsReg was stored.
-    masm.loadPtr(Address(masm.getStackPointer(), jitFrameBytes + sizeOfRetAddr), WasmTlsReg);
+    // The epilogue requires WasmTlsReg and Ion code clobbers all registers,
+    // even ABI non-volatiles.
+    masm.loadWasmTlsRegFromFrame();
 
     GenerateExitEpilogue(masm, masm.framePushed(), ExitReason::ImportJit, &offsets);
 

From 0f64a61281cea813c41413dd0a57d24c9d00262c Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:17:50 -0500
Subject: [PATCH 25/96] Bug 1334504 - Baldr: remove movw/movt requirement for
 wasm on ARM (r=bbouvier)

MozReview-Commit-ID: IPYbhkYqPwU

--HG--
extra : rebase_source : 7eab849de87d86547b0bcbb0aef8c5505aa28041
---
 js/src/jit-test/tests/asm.js/testAtomics.js | 38 ++++++++++++++++++++-
 js/src/jit/arm/Lowering-arm.cpp             | 33 ++++++++++--------
 js/src/wasm/WasmBaselineCompile.cpp         |  3 +-
 js/src/wasm/WasmJS.cpp                      |  7 ----
 4 files changed, 57 insertions(+), 24 deletions(-)

diff --git a/js/src/jit-test/tests/asm.js/testAtomics.js b/js/src/jit-test/tests/asm.js/testAtomics.js
index 5b30fb622034..89582fe686f7 100644
--- a/js/src/jit-test/tests/asm.js/testAtomics.js
+++ b/js/src/jit-test/tests/asm.js/testAtomics.js
@@ -1872,15 +1872,51 @@ setARMHwCapFlags('vfp');
 
 asmCompile('stdlib', 'ffi', 'heap',
     USE_ASM + `
+    var atomic_cmpxchg = stdlib.Atomics.compareExchange;
     var atomic_exchange = stdlib.Atomics.exchange;
+    var atomic_add = stdlib.Atomics.add;
+    var atomic_sub = stdlib.Atomics.sub;
+    var atomic_and = stdlib.Atomics.and;
+    var atomic_or = stdlib.Atomics.or;
+    var atomic_xor = stdlib.Atomics.xor;
     var i8a = new stdlib.Int8Array(heap);
 
+    function do_cas() {
+        var v = 0;
+        v = atomic_cmpxchg(i8a, 100, 0, -1);
+        return v|0;
+    }
     function do_xchg() {
         var v = 0;
         v = atomic_exchange(i8a, 200, 37);
         return v|0;
     }
+    function do_add() {
+        var v = 0;
+        v = atomic_add(i8a, 10, 37);
+        return v|0;
+    }
+    function do_sub() {
+        var v = 0;
+        v = atomic_sub(i8a, 10, 37);
+        return v|0;
+    }
+    function do_and() {
+        var v = 0;
+        v = atomic_and(i8a, 10, 37);
+        return v|0;
+    }
+    function do_or() {
+        var v = 0;
+        v = atomic_or(i8a, 10, 37);
+        return v|0;
+    }
+    function do_xor() {
+        var v = 0;
+        v = atomic_xor(i8a, 10, 37);
+        return v|0;
+    }
 
-    return { xchg: do_xchg }
+    return { cas:do_cas, xchg: do_xchg, add: do_add, sub: do_sub, and: do_and, or: do_or, xor: do_xor }
 `);
 
diff --git a/js/src/jit/arm/Lowering-arm.cpp b/js/src/jit/arm/Lowering-arm.cpp
index 9b9e09cf5523..c488394da0bd 100644
--- a/js/src/jit/arm/Lowering-arm.cpp
+++ b/js/src/jit/arm/Lowering-arm.cpp
@@ -893,11 +893,12 @@ LIRGeneratorARM::visitAsmJSCompareExchangeHeap(MAsmJSCompareExchangeHeap* ins)
 
     if (byteSize(ins->access().type()) != 4 && !HasLDSTREXBHD()) {
         LAsmJSCompareExchangeCallout* lir =
-            new(alloc()) LAsmJSCompareExchangeCallout(useRegisterAtStart(base),
-                                                      useRegisterAtStart(ins->oldValue()),
-                                                      useRegisterAtStart(ins->newValue()),
-                                                      useFixed(ins->tls(), WasmTlsReg),
-                                                      temp(), temp());
+            new(alloc()) LAsmJSCompareExchangeCallout(useFixedAtStart(base, IntArgReg2),
+                                                      useFixedAtStart(ins->oldValue(), IntArgReg3),
+                                                      useFixedAtStart(ins->newValue(), CallTempReg0),
+                                                      useFixedAtStart(ins->tls(), WasmTlsReg),
+                                                      tempFixed(IntArgReg0),
+                                                      tempFixed(IntArgReg1));
         defineReturn(lir, ins);
         return;
     }
@@ -917,17 +918,18 @@ LIRGeneratorARM::visitAsmJSAtomicExchangeHeap(MAsmJSAtomicExchangeHeap* ins)
     MOZ_ASSERT(ins->access().type() < Scalar::Float32);
     MOZ_ASSERT(ins->access().offset() == 0);
 
-    const LAllocation base = useRegisterAtStart(ins->base());
-    const LAllocation value = useRegisterAtStart(ins->value());
-
     if (byteSize(ins->access().type()) < 4 && !HasLDSTREXBHD()) {
         // Call out on ARMv6.
-        defineReturn(new(alloc()) LAsmJSAtomicExchangeCallout(base, value,
-                                                              useFixed(ins->tls(), WasmTlsReg),
-                                                              temp(), temp()), ins);
+        defineReturn(new(alloc()) LAsmJSAtomicExchangeCallout(useFixedAtStart(ins->base(), IntArgReg2),
+                                                              useFixedAtStart(ins->value(), IntArgReg3),
+                                                              useFixedAtStart(ins->tls(), WasmTlsReg),
+                                                              tempFixed(IntArgReg0),
+                                                              tempFixed(IntArgReg1)), ins);
         return;
     }
 
+    const LAllocation base = useRegisterAtStart(ins->base());
+    const LAllocation value = useRegisterAtStart(ins->value());
     define(new(alloc()) LAsmJSAtomicExchangeHeap(base, value), ins);
 }
 
@@ -942,10 +944,11 @@ LIRGeneratorARM::visitAsmJSAtomicBinopHeap(MAsmJSAtomicBinopHeap* ins)
 
     if (byteSize(ins->access().type()) != 4 && !HasLDSTREXBHD()) {
         LAsmJSAtomicBinopCallout* lir =
-            new(alloc()) LAsmJSAtomicBinopCallout(useRegisterAtStart(base),
-                                                  useRegisterAtStart(ins->value()),
-                                                  useFixed(ins->tls(), WasmTlsReg),
-                                                  temp(), temp());
+            new(alloc()) LAsmJSAtomicBinopCallout(useFixedAtStart(base, IntArgReg2),
+                                                  useFixedAtStart(ins->value(), IntArgReg3),
+                                                  useFixedAtStart(ins->tls(), WasmTlsReg),
+                                                  tempFixed(IntArgReg0),
+                                                  tempFixed(IntArgReg1));
         defineReturn(lir, ins);
         return;
     }
diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp
index 5e62bf5530af..a2b15c57fd61 100644
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -2341,8 +2341,9 @@ class BaseCompiler
         masm.breakpoint();
 
         // Patch the add in the prologue so that it checks against the correct
-        // frame size.
+        // frame size. Flush the constant pool in case it needs to be patched.
         MOZ_ASSERT(maxFramePushed_ >= localSize_);
+        masm.flush();
         masm.patchAdd32ToPtr(stackAddOffset_, Imm32(-int32_t(maxFramePushed_ - localSize_)));
 
         // Since we just overflowed the stack, to be on the safe side, pop the
diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp
index 1bbf5e336d3c..7bd49a7fbf42 100644
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -65,13 +65,6 @@ wasm::HasCompilerSupport(JSContext* cx)
     if (!wasm::HaveSignalHandlers())
         return false;
 
-#if defined(JS_CODEGEN_ARM)
-    // movw/t are required for the loadWasmActivationFromSymbolicAddress in
-    // GenerateProfilingPrologue/Epilogue to avoid using the constant pool.
-    if (!HasMOVWT())
-        return false;
-#endif
-
 #if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
     return false;
 #else

From 4fbe090e6e3972b4221b8e1ddbdf73f70c9d869b Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:18:54 -0500
Subject: [PATCH 26/96] Bug 1334504 - Baldr: remove the wasm::Compartment GC
 hack (r=bbouvier)

MozReview-Commit-ID: LVAPQ1Kft8g

--HG--
extra : rebase_source : 6464176d9bd0e5eae8722ecd21bfa0dc4e0ba5f4
---
 js/src/gc/RootMarking.cpp                     |  1 +
 .../tests/debug/wasm-onExceptionUnwind-gc.js  | 50 +++++++++++++++++++
 js/src/jit-test/tests/wasm/timeout/1.js       | 17 +++++++
 js/src/jit-test/tests/wasm/timeout/2.js       | 31 ++++++++++++
 .../tests/wasm/timeout/directives.txt         |  2 +
 js/src/vm/Stack.cpp                           |  5 --
 js/src/wasm/WasmCompartment.cpp               | 27 +++++++---
 js/src/wasm/WasmCompartment.h                 |  7 ++-
 js/src/wasm/WasmFrameIterator.cpp             | 21 ++++++++
 js/src/wasm/WasmFrameIterator.h               |  6 +++
 js/src/wasm/WasmTypes.cpp                     | 36 +++++++++++--
 11 files changed, 187 insertions(+), 16 deletions(-)
 create mode 100644 js/src/jit-test/tests/debug/wasm-onExceptionUnwind-gc.js
 create mode 100644 js/src/jit-test/tests/wasm/timeout/1.js
 create mode 100644 js/src/jit-test/tests/wasm/timeout/2.js
 create mode 100644 js/src/jit-test/tests/wasm/timeout/directives.txt

diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp
index d7905a97f92a..c41825be8d55 100644
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -330,6 +330,7 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
             // Trace active interpreter and JIT stack roots.
             TraceInterpreterActivations(cx, target, trc);
             jit::TraceJitActivations(cx, target, trc);
+            wasm::TraceActivations(cx, target, trc);
 
             // Trace legacy C stack roots.
             AutoGCRooter::traceAll(target, trc);
diff --git a/js/src/jit-test/tests/debug/wasm-onExceptionUnwind-gc.js b/js/src/jit-test/tests/debug/wasm-onExceptionUnwind-gc.js
new file mode 100644
index 000000000000..ca191ea0f772
--- /dev/null
+++ b/js/src/jit-test/tests/debug/wasm-onExceptionUnwind-gc.js
@@ -0,0 +1,50 @@
+
+if (!wasmIsSupported())
+    quit();
+
+var sandbox = newGlobal();
+var dbg = new Debugger(sandbox);
+var counter = 0;
+dbg.onExceptionUnwind = (frame, value) => {
+    if (frame.type !== "wasmcall")
+        return;
+    if (++counter != 2)
+        return;
+    gc();
+};
+
+sandbox.innerCode = wasmTextToBinary(`(module
+    (import "imports" "tbl" (table 1 anyfunc))
+    (import $setNull "imports" "setNull" (func))
+    (func $trap
+        call $setNull
+        unreachable
+    )
+    (elem (i32.const 0) $trap)
+)`);
+sandbox.outerCode = wasmTextToBinary(`(module
+    (import "imports" "tbl" (table 1 anyfunc))
+    (type $v2v (func))
+    (func (export "run")
+        i32.const 0
+        call_indirect $v2v
+    )
+)`);
+
+sandbox.eval(`
+(function() {
+
+var tbl = new WebAssembly.Table({initial:1, element:"anyfunc"});
+function setNull() { tbl.set(0, null) }
+new WebAssembly.Instance(new WebAssembly.Module(innerCode), {imports:{tbl,setNull}});
+var outer = new WebAssembly.Instance(new WebAssembly.Module(outerCode), {imports:{tbl}});
+var caught;
+try {
+    outer.exports.run();
+} catch (e) {
+    caught = e;
+}
+assertEq(caught instanceof WebAssembly.RuntimeError, true);
+
+})();
+`);
diff --git a/js/src/jit-test/tests/wasm/timeout/1.js b/js/src/jit-test/tests/wasm/timeout/1.js
new file mode 100644
index 000000000000..3bcbf8034963
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/timeout/1.js
@@ -0,0 +1,17 @@
+// |jit-test| exitstatus: 6;
+
+// Don't include wasm.js in timeout tests: when wasm isn't supported, it will
+// quit(0) which will cause the test to fail.
+if (!wasmIsSupported())
+    quit(6);
+
+var code = wasmTextToBinary(`(module
+    (func (export "iloop")
+        (loop $top br $top)
+    )
+)`);
+
+var i = new WebAssembly.Instance(new WebAssembly.Module(code));
+timeout(1);
+i.exports.iloop();
+assertEq(true, false);
diff --git a/js/src/jit-test/tests/wasm/timeout/2.js b/js/src/jit-test/tests/wasm/timeout/2.js
new file mode 100644
index 000000000000..ef84b00470d7
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/timeout/2.js
@@ -0,0 +1,31 @@
+// |jit-test| exitstatus: 6;
+
+// Don't include wasm.js in timeout tests: when wasm isn't supported, it will
+// quit(0) which will cause the test to fail.
+if (!wasmIsSupported())
+    quit(6);
+
+var tbl = new WebAssembly.Table({initial:1, element:"anyfunc"});
+
+new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`(module
+    (func $iloop
+        loop $top
+            br $top
+        end
+    )
+    (import "imports" "tbl" (table 1 anyfunc))
+    (elem (i32.const 0) $iloop)
+)`)), {imports:{tbl}});
+
+var outer = new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`(module
+    (import "imports" "tbl" (table 1 anyfunc))
+    (type $v2v (func))
+    (func (export "run")
+        i32.const 0
+        call_indirect $v2v
+    )
+)`)), {imports:{tbl}});
+
+timeout(1, () => { tbl.set(0, null); gc() });
+outer.exports.run();
+assertEq(true, false);
diff --git a/js/src/jit-test/tests/wasm/timeout/directives.txt b/js/src/jit-test/tests/wasm/timeout/directives.txt
new file mode 100644
index 000000000000..8262f0bbae1f
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/timeout/directives.txt
@@ -0,0 +1,2 @@
+|jit-test| test-also-wasm-baseline
+
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
index 9d55ff97318d..472240029456 100644
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1654,8 +1654,6 @@ WasmActivation::WasmActivation(JSContext* cx)
     prevWasm_ = cx->wasmActivationStack_;
     cx->wasmActivationStack_ = this;
 
-    cx->compartment()->wasm.activationCount_++;
-
     // Now that the WasmActivation is fully initialized, make it visible to
     // asynchronous profiling.
     registerProfiling();
@@ -1670,9 +1668,6 @@ WasmActivation::~WasmActivation()
 
     MOZ_ASSERT(cx_->wasmActivationStack_ == this);
     cx_->wasmActivationStack_ = prevWasm_;
-
-    MOZ_ASSERT(cx_->compartment()->wasm.activationCount_ > 0);
-    cx_->compartment()->wasm.activationCount_--;
 }
 
 InterpreterFrameIterator&
diff --git a/js/src/wasm/WasmCompartment.cpp b/js/src/wasm/WasmCompartment.cpp
index 53779e9eff1d..7c6279a053c2 100644
--- a/js/src/wasm/WasmCompartment.cpp
+++ b/js/src/wasm/WasmCompartment.cpp
@@ -29,12 +29,12 @@ using namespace wasm;
 
 Compartment::Compartment(Zone* zone)
   : mutatingInstances_(false),
-    activationCount_(0)
+    interruptedCount_(0)
 {}
 
 Compartment::~Compartment()
 {
-    MOZ_ASSERT(activationCount_ == 0);
+    MOZ_ASSERT(interruptedCount_ == 0);
     MOZ_ASSERT(instances_.empty());
     MOZ_ASSERT(!mutatingInstances_);
 }
@@ -57,10 +57,14 @@ void
 Compartment::trace(JSTracer* trc)
 {
     // A WasmInstanceObject that was initially reachable when called can become
-    // unreachable while executing on the stack. Since wasm does not otherwise
-    // scan the stack during GC to identify live instances, we mark all instance
-    // objects live if there is any running wasm in the compartment.
-    if (activationCount_) {
+    // unreachable while executing on the stack. When execution in a compartment
+    // is interrupted inside wasm code, wasm::TraceActivations() may miss frames
+    // due to its use of FrameIterator which assumes wasm has exited through an
+    // exit stub. This could be fixed by changing wasm::TraceActivations() to
+    // use a ProfilingFrameIterator, which inspects register state, but for now
+    // just mark everything in the compartment in this super-rare case.
+
+    if (interruptedCount_) {
         for (Instance* i : instances_)
             i->trace(trc);
     }
@@ -137,6 +141,17 @@ Compartment::lookupInstanceDeprecated(const void* pc) const
     return instances_[index];
 }
 
+void
+Compartment::setInterrupted(bool interrupted)
+{
+    if (interrupted) {
+        interruptedCount_++;
+    } else {
+        MOZ_ASSERT(interruptedCount_ > 0);
+        interruptedCount_--;
+    }
+}
+
 void
 Compartment::ensureProfilingLabels(bool profilingEnabled)
 {
diff --git a/js/src/wasm/WasmCompartment.h b/js/src/wasm/WasmCompartment.h
index b255f80ff6f6..3ef43f12dedd 100644
--- a/js/src/wasm/WasmCompartment.h
+++ b/js/src/wasm/WasmCompartment.h
@@ -39,7 +39,7 @@ class Compartment
 {
     InstanceVector instances_;
     volatile bool  mutatingInstances_;
-    size_t         activationCount_;
+    size_t         interruptedCount_;
 
     friend class js::WasmActivation;
 
@@ -88,6 +88,11 @@ class Compartment
 
     Instance* lookupInstanceDeprecated(const void* pc) const;
 
+    // The wasm::Compartment must be notified when execution is interrupted
+    // while executing in wasm code in this compartment.
+
+    void setInterrupted(bool interrupted);
+
     // Ensure all Instances in this JSCompartment have profiling labels created.
 
     void ensureProfilingLabels(bool profilingEnabled);
diff --git a/js/src/wasm/WasmFrameIterator.cpp b/js/src/wasm/WasmFrameIterator.cpp
index bd76bdc67b59..783b9bf557b7 100644
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -206,10 +206,18 @@ FrameIterator::lineOrBytecode() const
                      : (codeRange_ ? codeRange_->funcLineOrBytecode() : 0);
 }
 
+bool
+FrameIterator::hasInstance() const
+{
+    MOZ_ASSERT(!done());
+    return !!fp_;
+}
+
 Instance*
 FrameIterator::instance() const
 {
     MOZ_ASSERT(!done());
+    MOZ_ASSERT(hasInstance());
     return FrameToDebugFrame(fp_)->instance();
 }
 
@@ -772,3 +780,16 @@ ProfilingFrameIterator::label() const
 
     MOZ_CRASH("bad code range kind");
 }
+
+void
+wasm::TraceActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc)
+{
+    for (ActivationIterator iter(cx, target); !iter.done(); ++iter) {
+        if (iter.activation()->isWasm()) {
+            for (FrameIterator fi(iter.activation()->asWasm()); !fi.done(); ++fi) {
+                if (fi.hasInstance())
+                    fi.instance()->trace(trc);
+            }
+        }
+    }
+}
diff --git a/js/src/wasm/WasmFrameIterator.h b/js/src/wasm/WasmFrameIterator.h
index 08b8ccbe6c68..962b7c9e903c 100644
--- a/js/src/wasm/WasmFrameIterator.h
+++ b/js/src/wasm/WasmFrameIterator.h
@@ -75,6 +75,7 @@ class FrameIterator
     JSAtom* functionDisplayAtom() const;
     unsigned lineOrBytecode() const;
     const CodeRange* codeRange() const { return codeRange_; }
+    bool hasInstance() const;
     Instance* instance() const;
     bool debugEnabled() const;
     DebugFrame* debugFrame() const;
@@ -133,6 +134,11 @@ GenerateFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed, const
 void
 GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets);
 
+// Mark all instance objects live on the stack.
+
+void
+TraceActivations(JSContext* cx, const CooperatingContext& target, JSTracer* trc);
+
 } // namespace wasm
 } // namespace js
 
diff --git a/js/src/wasm/WasmTypes.cpp b/js/src/wasm/WasmTypes.cpp
index 302756f3c542..af6ff6c368be 100644
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -89,7 +89,13 @@ static bool
 WasmHandleExecutionInterrupt()
 {
     WasmActivation* activation = JSContext::innermostWasmActivation();
+
+    // wasm::Compartment requires notification when execution is interrupted in
+    // the compartment. Only the innermost compartment has been interrupted;
+    // enclosing compartments necessarily exited through an exit stub.
+    activation->compartment()->wasm.setInterrupted(true);
     bool success = CheckForInterrupt(activation->cx());
+    activation->compartment()->wasm.setInterrupted(false);
 
     // Preserve the invariant that having a non-null resumePC means that we are
     // handling an interrupt.  Note that resumePC has already been copied onto
@@ -167,11 +173,33 @@ WasmHandleDebugTrap()
 static void
 WasmHandleThrow()
 {
-    WasmActivation* activation = JSContext::innermostWasmActivation();
-    MOZ_ASSERT(activation);
-    JSContext* cx = activation->cx();
+    JSContext* cx = TlsContext.get();
 
-    for (FrameIterator iter(activation, FrameIterator::Unwind::True); !iter.done(); ++iter) {
+    WasmActivation* activation = cx->wasmActivationStack();
+    MOZ_ASSERT(activation);
+
+    // FrameIterator iterates down wasm frames in the activation starting at
+    // WasmActivation::fp. Pass Unwind::True to pop WasmActivation::fp once each
+    // time FrameIterator is incremented, ultimately leaving WasmActivation::fp
+    // null when the FrameIterator is done(). This is necessary to prevent a
+    // DebugFrame from being observed again after we just called onLeaveFrame
+    // (which would lead to the frame being re-added to the map of live frames,
+    // right as it becomes trash).
+    FrameIterator iter(activation, FrameIterator::Unwind::True);
+    if (iter.done())
+        return;
+
+    // Live wasm code on the stack is kept alive (in wasm::TraceActivations) by
+    // marking the instance of every wasm::Frame found by FrameIterator.
+    // However, as explained above, we're popping frames while iterating which
+    // means that a GC during this loop could collect the code of frames whose
+    // code is still on the stack. This is actually mostly fine: as soon as we
+    // return to the throw stub, the entire stack will be popped as a whole,
+    // returning to the C++ caller. However, we must keep the throw stub alive
+    // itself which is owned by the innermost instance.
+    RootedWasmInstanceObject keepAlive(cx, iter.instance()->object());
+
+    for (; !iter.done(); ++iter) {
         if (!iter.debugEnabled())
             continue;
 

From 2bf1fbb0ccdb5de136baf6bbd675022e7eb23b9a Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:22:16 -0500
Subject: [PATCH 27/96] Bug 1334504 - Baldr: remove SymbolicAddress::ContextPtr
 (r=lth)

MozReview-Commit-ID: HZOVOhq8pdv

--HG--
extra : rebase_source : 2e882f46991077e8bc828e69be64ae41d447b562
---
 js/src/jit/MacroAssembler.cpp                 |   8 -
 js/src/jit/MacroAssembler.h                   |   3 +-
 js/src/jit/arm/Assembler-arm.h                |   1 +
 js/src/jit/arm64/Assembler-arm64.h            |   1 +
 js/src/jit/mips32/Assembler-mips32.h          |   1 +
 js/src/jit/mips64/Assembler-mips64.h          |   1 +
 js/src/jit/none/MacroAssembler-none.h         |   2 +-
 js/src/jit/x64/Assembler-x64.h                |   1 +
 .../x86-shared/MacroAssembler-x86-shared.cpp  |  14 ++
 js/src/jit/x86/Assembler-x86.h                |   3 +-
 js/src/vm/Stack.h                             |   4 -
 js/src/wasm/WasmCode.cpp                      |   2 +-
 js/src/wasm/WasmInstance.h                    |   2 +-
 js/src/wasm/WasmStubs.cpp                     | 144 ++++++++----------
 js/src/wasm/WasmTypes.cpp                     |  29 ++--
 js/src/wasm/WasmTypes.h                       |  17 +--
 16 files changed, 111 insertions(+), 122 deletions(-)

diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
index 21b5dc1a1eef..505f0cc7f833 100644
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2971,14 +2971,6 @@ MacroAssembler::loadWasmActivationFromTls(Register dest)
     loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest);
 }
 
-void
-MacroAssembler::loadWasmActivationFromSymbolicAddress(Register dest)
-{
-    movePtr(wasm::SymbolicAddress::ContextPtr, dest);
-    loadPtr(Address(dest, 0), dest);
-    loadPtr(Address(dest, JSContext::offsetOfWasmActivation()), dest);
-}
-
 void
 MacroAssembler::loadWasmTlsRegFromFrame(Register dest)
 {
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
index 454cc0cf6d3e..84e4bde3b23e 100644
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -447,6 +447,7 @@ class MacroAssembler : public MacroAssemblerSpecific
     void Push(const ImmPtr imm) PER_SHARED_ARCH;
     void Push(const ImmGCPtr ptr) PER_SHARED_ARCH;
     void Push(FloatRegister reg) PER_SHARED_ARCH;
+    void PushFlags() DEFINED_ON(x86_shared);
     void Push(jsid id, Register scratchReg);
     void Push(TypedOrValueRegister v);
     void Push(const ConstantOrRegister& v);
@@ -462,6 +463,7 @@ class MacroAssembler : public MacroAssemblerSpecific
     void Pop(Register reg) PER_SHARED_ARCH;
     void Pop(FloatRegister t) PER_SHARED_ARCH;
     void Pop(const ValueOperand& val) PER_SHARED_ARCH;
+    void PopFlags() DEFINED_ON(x86_shared);
     void popRooted(VMFunction::RootType rootType, Register cellReg, const ValueOperand& valueReg);
 
     // Move the stack pointer based on the requested amount.
@@ -1519,7 +1521,6 @@ class MacroAssembler : public MacroAssemblerSpecific
     }
 
     void loadWasmActivationFromTls(Register dest);
-    void loadWasmActivationFromSymbolicAddress(Register dest);
     void loadWasmTlsRegFromFrame(Register dest = WasmTlsReg);
 
     template
diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h
index 71043b2e1ae2..434352bc6b33 100644
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -168,6 +168,7 @@ static constexpr Register WasmIonExitRegE1 = r1;
 // None of these may be the second scratch register (lr).
 static constexpr Register WasmIonExitRegReturnData = r2;
 static constexpr Register WasmIonExitRegReturnType = r3;
+static constexpr Register WasmIonExitTlsReg = r9;
 static constexpr Register WasmIonExitRegD0 = r0;
 static constexpr Register WasmIonExitRegD1 = r1;
 static constexpr Register WasmIonExitRegD2 = r4;
diff --git a/js/src/jit/arm64/Assembler-arm64.h b/js/src/jit/arm64/Assembler-arm64.h
index 276c6b9eea58..ba6367421682 100644
--- a/js/src/jit/arm64/Assembler-arm64.h
+++ b/js/src/jit/arm64/Assembler-arm64.h
@@ -126,6 +126,7 @@ static constexpr Register WasmIonExitRegE1 = r1;
 // None of these may be the second scratch register.
 static constexpr Register WasmIonExitRegReturnData = r2;
 static constexpr Register WasmIonExitRegReturnType = r3;
+static constexpr Register WasmIonExitTlsReg = r17;
 static constexpr Register WasmIonExitRegD0 = r0;
 static constexpr Register WasmIonExitRegD1 = r1;
 static constexpr Register WasmIonExitRegD2 = r4;
diff --git a/js/src/jit/mips32/Assembler-mips32.h b/js/src/jit/mips32/Assembler-mips32.h
index 3c8a6ffafbe0..dd3fa38f44db 100644
--- a/js/src/jit/mips32/Assembler-mips32.h
+++ b/js/src/jit/mips32/Assembler-mips32.h
@@ -77,6 +77,7 @@ static constexpr FloatRegister SecondScratchDoubleReg = { FloatRegisters::f16, F
 // None of these may be the second scratch register (t8).
 static constexpr Register WasmIonExitRegReturnData = JSReturnReg_Data;
 static constexpr Register WasmIonExitRegReturnType = JSReturnReg_Type;
+static constexpr Register WasmIonExitTlsReg = s5;
 
 static constexpr FloatRegister f0  = { FloatRegisters::f0, FloatRegister::Double };
 static constexpr FloatRegister f2  = { FloatRegisters::f2, FloatRegister::Double };
diff --git a/js/src/jit/mips64/Assembler-mips64.h b/js/src/jit/mips64/Assembler-mips64.h
index eed15b133a09..f9884b9e5063 100644
--- a/js/src/jit/mips64/Assembler-mips64.h
+++ b/js/src/jit/mips64/Assembler-mips64.h
@@ -71,6 +71,7 @@ static constexpr FloatRegister SecondScratchDoubleReg = { FloatRegisters::f21, F
 // None of these may be the second scratch register (t8).
 static constexpr Register WasmIonExitRegReturnData = JSReturnReg_Data;
 static constexpr Register WasmIonExitRegReturnType = JSReturnReg_Type;
+static constexpr Register WasmIonExitTlsReg = s5;
 
 static constexpr FloatRegister f0  = { FloatRegisters::f0, FloatRegisters::Double };
 static constexpr FloatRegister f1  = { FloatRegisters::f1, FloatRegisters::Double };
diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h
index 1795fd869cf1..cb13d834e9f1 100644
--- a/js/src/jit/none/MacroAssembler-none.h
+++ b/js/src/jit/none/MacroAssembler-none.h
@@ -48,6 +48,7 @@ static constexpr Register WasmIonExitRegE1 { Registers::invalid_reg };
 
 static constexpr Register WasmIonExitRegReturnData { Registers::invalid_reg };
 static constexpr Register WasmIonExitRegReturnType { Registers::invalid_reg };
+static constexpr Register WasmIonExitTlsReg = { Registers::invalid_reg };
 static constexpr Register WasmIonExitRegD0 { Registers::invalid_reg };
 static constexpr Register WasmIonExitRegD1 { Registers::invalid_reg };
 static constexpr Register WasmIonExitRegD2 { Registers::invalid_reg };
@@ -415,7 +416,6 @@ class MacroAssemblerNone : public Assembler
     bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); }
     void loadWasmGlobalPtr(uint32_t, Register) { MOZ_CRASH(); }
     void loadWasmActivationFromTls(Register) { MOZ_CRASH(); }
-    void loadWasmActivationFromSymbolicAddress(Register) { MOZ_CRASH(); }
     void loadWasmPinnedRegsFromTls() { MOZ_CRASH(); }
 
     void setPrinter(Sprinter*) { MOZ_CRASH(); }
diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h
index 2fb167dbc061..cf6c5afbc460 100644
--- a/js/src/jit/x64/Assembler-x64.h
+++ b/js/src/jit/x64/Assembler-x64.h
@@ -157,6 +157,7 @@ static constexpr Register WasmIonExitRegE1 = rdi;
 // Registers used in the GenerateFFIIonExit Disable Activation block.
 static constexpr Register WasmIonExitRegReturnData = ecx;
 static constexpr Register WasmIonExitRegReturnType = ecx;
+static constexpr Register WasmIonExitTlsReg = r14;
 static constexpr Register WasmIonExitRegD0 = rax;
 static constexpr Register WasmIonExitRegD1 = rdi;
 static constexpr Register WasmIonExitRegD2 = rbx;
diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
index 9045f0b2716a..8ecc66428649 100644
--- a/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
+++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared.cpp
@@ -600,6 +600,13 @@ MacroAssembler::Push(FloatRegister t)
     adjustFrame(sizeof(double));
 }
 
+void
+MacroAssembler::PushFlags()
+{
+    pushFlags();
+    adjustFrame(sizeof(intptr_t));
+}
+
 void
 MacroAssembler::Pop(const Operand op)
 {
@@ -628,6 +635,13 @@ MacroAssembler::Pop(const ValueOperand& val)
     implicitPop(sizeof(Value));
 }
 
+void
+MacroAssembler::PopFlags()
+{
+    popFlags();
+    implicitPop(sizeof(intptr_t));
+}
+
 // ===============================================================
 // Simple call functions.
 
diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h
index 2fe4ae90c882..c1a9e5a1fc38 100644
--- a/js/src/jit/x86/Assembler-x86.h
+++ b/js/src/jit/x86/Assembler-x86.h
@@ -112,9 +112,10 @@ static constexpr Register WasmIonExitRegE1 = eax;
 // Registers used in the GenerateFFIIonExit Disable Activation block.
 static constexpr Register WasmIonExitRegReturnData = edx;
 static constexpr Register WasmIonExitRegReturnType = ecx;
+static constexpr Register WasmIonExitTlsReg = esi;
 static constexpr Register WasmIonExitRegD0 = edi;
 static constexpr Register WasmIonExitRegD1 = eax;
-static constexpr Register WasmIonExitRegD2 = esi;
+static constexpr Register WasmIonExitRegD2 = ebx;
 
 // Registerd used in RegExpMatcher instruction (do not use JSReturnOperand).
 static constexpr Register RegExpMatcherRegExpReg = CallTempReg0;
diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
index b6a14260feec..e747edbd3e4d 100644
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1755,10 +1755,6 @@ class WasmActivation : public Activation
     // Returns the reason why wasm code called out of wasm code.
     wasm::ExitReason exitReason() const { return exitReason_; }
 
-    // Read by JIT code:
-    static unsigned offsetOfContext() { return offsetof(WasmActivation, cx_); }
-    static unsigned offsetOfResumePC() { return offsetof(WasmActivation, resumePC_); }
-
     // Written by JIT code:
     static unsigned offsetOfEntrySP() { return offsetof(WasmActivation, entrySP_); }
     static unsigned offsetOfFP() { return offsetof(WasmActivation, fp_); }
diff --git a/js/src/wasm/WasmCode.cpp b/js/src/wasm/WasmCode.cpp
index 54cc84547b21..999018fb63f8 100644
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -111,7 +111,7 @@ StaticallyLink(CodeSegment& cs, const LinkData& linkData, JSContext* cx)
         const Uint32Vector& offsets = linkData.symbolicLinks[imm];
         for (size_t i = 0; i < offsets.length(); i++) {
             uint8_t* patchAt = cs.base() + offsets[i];
-            void* target = AddressOf(imm, cx);
+            void* target = AddressOf(imm);
             Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt),
                                                PatchedImmPtr(target),
                                                PatchedImmPtr((void*)-1));
diff --git a/js/src/wasm/WasmInstance.h b/js/src/wasm/WasmInstance.h
index 13ceaa7fa627..46b8a622154f 100644
--- a/js/src/wasm/WasmInstance.h
+++ b/js/src/wasm/WasmInstance.h
@@ -78,7 +78,7 @@ class Instance
     TableTls& tableTls(const TableDesc& td) const;
 
     // Import call slow paths which are called directly from wasm code.
-    friend void* AddressOf(SymbolicAddress, JSContext*);
+    friend void* AddressOf(SymbolicAddress);
     static int32_t callImport_void(Instance*, int32_t, int32_t, uint64_t*);
     static int32_t callImport_i32(Instance*, int32_t, int32_t, uint64_t*);
     static int32_t callImport_i64(Instance*, int32_t, int32_t, uint64_t*);
diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp
index e51dea457dce..60da82cd7a3b 100644
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -687,8 +687,7 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
         Register act = WasmIonExitRegE1;
 
         // JitActivation* act = cx->activation();
-        masm.movePtr(SymbolicAddress::ContextPtr, cx);
-        masm.loadPtr(Address(cx, 0), cx);
+        masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, cx)), cx);
         masm.loadPtr(Address(cx, JSContext::offsetOfActivation()), act);
 
         // act.active_ = true;
@@ -705,20 +704,24 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
     masm.callJitNoProfiler(callee);
     AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr);
 
+    // Reload the TLS reg which has been clobbered by Ion code. The TLS reg is
+    // non-volatile and so preserved by the native-ABI calls below.
+    masm.loadWasmTlsRegFromFrame();
+
     {
         // Disable Activation.
         //
-        // This sequence needs three registers, and must preserve the JSReturnReg_Data and
-        // JSReturnReg_Type, so there are five live registers.
+        // This sequence needs three registers and must preserve WasmTlsReg,
+        // JSReturnReg_Data and JSReturnReg_Type.
         MOZ_ASSERT(JSReturnReg_Data == WasmIonExitRegReturnData);
         MOZ_ASSERT(JSReturnReg_Type == WasmIonExitRegReturnType);
+        MOZ_ASSERT(WasmTlsReg == WasmIonExitTlsReg);
         Register cx = WasmIonExitRegD0;
         Register act = WasmIonExitRegD1;
         Register tmp = WasmIonExitRegD2;
 
         // JitActivation* act = cx->activation();
-        masm.movePtr(SymbolicAddress::ContextPtr, cx);
-        masm.loadPtr(Address(cx, 0), cx);
+        masm.loadPtr(Address(WasmTlsReg, offsetof(TlsData, cx)), cx);
         masm.loadPtr(Address(cx, JSContext::offsetOfActivation()), act);
 
         // cx->jitTop = act->prevJitTop_;
@@ -782,10 +785,6 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
     Label done;
     masm.bind(&done);
 
-    // The epilogue requires WasmTlsReg and Ion code clobbers all registers,
-    // even ABI non-volatiles.
-    masm.loadWasmTlsRegFromFrame();
-
     GenerateExitEpilogue(masm, masm.framePushed(), ExitReason::ImportJit, &offsets);
 
     if (oolConvert.used()) {
@@ -928,13 +927,17 @@ wasm::GenerateUnalignedExit(MacroAssembler& masm, Label* throwLabel)
     return GenerateGenericMemoryAccessTrap(masm, SymbolicAddress::ReportUnalignedAccess, throwLabel);
 }
 
+#if defined(JS_CODEGEN_ARM)
+static const LiveRegisterSet AllRegsExceptPCSP(
+    GeneralRegisterSet(Registers::AllMask & ~((uint32_t(1) << Registers::sp) |
+                                              (uint32_t(1) << Registers::pc))),
+    FloatRegisterSet(FloatRegisters::AllDoubleMask));
+static_assert(!SupportsSimd, "high lanes of SIMD registers need to be saved too.");
+#else
 static const LiveRegisterSet AllRegsExceptSP(
     GeneralRegisterSet(Registers::AllMask & ~(uint32_t(1) << Registers::StackPointer)),
     FloatRegisterSet(FloatRegisters::AllMask));
-
-static const LiveRegisterSet AllAllocatableRegs = LiveRegisterSet(
-    GeneralRegisterSet(Registers::AllocatableMask),
-    FloatRegisterSet(FloatRegisters::AllMask));
+#endif
 
 // The async interrupt-callback exit is called from arbitrarily-interrupted wasm
 // code. That means we must first save *all* registers and restore *all*
@@ -956,18 +959,11 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel)
     // Be very careful here not to perturb the machine state before saving it
     // to the stack. In particular, add/sub instructions may set conditions in
     // the flags register.
-    masm.push(Imm32(0));            // space for resumePC
-    masm.pushFlags();               // after this we are safe to use sub
-    masm.setFramePushed(0);         // set to zero so we can use masm.framePushed() below
+    masm.push(Imm32(0));            // space used as return address, updated below
+    masm.setFramePushed(0);         // set to 0 now so that framePushed is offset of return address
+    masm.PushFlags();               // after this we are safe to use sub
     masm.PushRegsInMask(AllRegsExceptSP); // save all GP/FP registers (except SP)
 
-    Register scratch = ABINonArgReturnReg0;
-
-    // Store resumePC into the reserved space.
-    masm.loadWasmActivationFromSymbolicAddress(scratch);
-    masm.loadPtr(Address(scratch, WasmActivation::offsetOfResumePC()), scratch);
-    masm.storePtr(scratch, Address(masm.getStackPointer(), masm.framePushed() + sizeof(void*)));
-
     // We know that StackPointer is word-aligned, but not necessarily
     // stack-aligned, so we need to align it dynamically.
     masm.moveStackPtrTo(ABINonVolatileReg);
@@ -975,18 +971,27 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel)
     if (ShadowStackSpace)
         masm.subFromStackPtr(Imm32(ShadowStackSpace));
 
+    // Make the call to C++, which preserves ABINonVolatileReg.
     masm.assertStackAlignment(ABIStackAlignment);
     masm.call(SymbolicAddress::HandleExecutionInterrupt);
 
-    masm.branchIfFalseBool(ReturnReg, throwLabel);
+    // HandleExecutionInterrupt returns null if execution is interrupted and
+    // the resumption pc otherwise.
+    masm.branchTestPtr(Assembler::Zero, ReturnReg, ReturnReg, throwLabel);
 
-    // Restore the StackPointer to its position before the call.
+    // Restore the stack pointer then store resumePC into the stack slow that
+    // will be popped by the 'ret' below.
     masm.moveToStackPtr(ABINonVolatileReg);
+    masm.storePtr(ReturnReg, Address(StackPointer, masm.framePushed()));
 
-    // Restore the machine state to before the interrupt.
-    masm.PopRegsInMask(AllRegsExceptSP); // restore all GP/FP registers (except SP)
-    masm.popFlags();              // after this, nothing that sets conditions
-    masm.ret();                   // pop resumePC into PC
+    // Restore the machine state to before the interrupt. After popping flags,
+    // no instructions can be executed which set flags.
+    masm.PopRegsInMask(AllRegsExceptSP);
+    masm.PopFlags();
+
+    // Return to the resumePC stored into this stack slot above.
+    MOZ_ASSERT(masm.framePushed() == 0);
+    masm.ret();
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     // Reserve space to store resumePC and HeapReg.
     masm.subFromStackPtr(Imm32(2 * sizeof(intptr_t)));
@@ -1034,61 +1039,40 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel)
     masm.as_jr(HeapReg);
     masm.loadPtr(Address(StackPointer, -sizeof(intptr_t)), HeapReg);
 #elif defined(JS_CODEGEN_ARM)
-    masm.setFramePushed(0);         // set to zero so we can use masm.framePushed() below
+    masm.push(Imm32(0));            // space used as return address, updated below
+    masm.setFramePushed(0);         // set to 0 now so that framePushed is offset of return address
+    masm.PushRegsInMask(AllRegsExceptPCSP); // save all GP/FP registers (except PC and SP)
 
-    // Save all GPR, except the stack pointer.
-    masm.PushRegsInMask(LiveRegisterSet(
-                            GeneralRegisterSet(Registers::AllMask & ~(1<cx());
-}
-
-static bool
+static void*
 WasmHandleExecutionInterrupt()
 {
     WasmActivation* activation = JSContext::innermostWasmActivation();
@@ -98,12 +92,13 @@ WasmHandleExecutionInterrupt()
     activation->compartment()->wasm.setInterrupted(false);
 
     // Preserve the invariant that having a non-null resumePC means that we are
-    // handling an interrupt.  Note that resumePC has already been copied onto
-    // the stack by the interrupt stub, so we can clear it before returning
-    // to the stub.
+    // handling an interrupt.
+    void* resumePC = activation->resumePC();
     activation->setResumePC(nullptr);
 
-    return success;
+    // Return the resumePC if execution can continue or null if execution should
+    // jump to the throw stub.
+    return success ? resumePC : nullptr;
 }
 
 static bool
@@ -170,7 +165,7 @@ WasmHandleDebugTrap()
     return true;
 }
 
-static void
+static WasmActivation*
 WasmHandleThrow()
 {
     JSContext* cx = TlsContext.get();
@@ -187,7 +182,7 @@ WasmHandleThrow()
     // right as it becomes trash).
     FrameIterator iter(activation, FrameIterator::Unwind::True);
     if (iter.done())
-        return;
+        return activation;
 
     // Live wasm code on the stack is kept alive (in wasm::TraceActivations) by
     // marking the instance of every wasm::Frame found by FrameIterator.
@@ -227,6 +222,8 @@ WasmHandleThrow()
         }
         frame->leave(cx);
      }
+
+    return activation;
 }
 
 static void
@@ -436,13 +433,9 @@ wasm::IsRoundingFunction(SymbolicAddress callee, jit::RoundingMode* mode)
 }
 
 void*
-wasm::AddressOf(SymbolicAddress imm, JSContext* cx)
+wasm::AddressOf(SymbolicAddress imm)
 {
     switch (imm) {
-      case SymbolicAddress::ContextPtr:
-        return cx->zone()->group()->addressOfOwnerContext();
-      case SymbolicAddress::ReportOverRecursed:
-        return FuncCast(WasmReportOverRecursed, Args_General0);
       case SymbolicAddress::HandleExecutionInterrupt:
         return FuncCast(WasmHandleExecutionInterrupt, Args_General0);
       case SymbolicAddress::HandleDebugTrap:
diff --git a/js/src/wasm/WasmTypes.h b/js/src/wasm/WasmTypes.h
index 2ecc111be9c3..39d11dcb0d25 100644
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -41,6 +41,7 @@
 namespace js {
 
 class PropertyName;
+class WasmActivation;
 class WasmFunctionCallObject;
 namespace jit {
     struct BaselineScript;
@@ -948,12 +949,12 @@ class CallSiteAndTarget : public CallSite
 
 typedef Vector CallSiteAndTargetVector;
 
-// A wasm::SymbolicAddress represents a pointer to a well-known function or
-// object that is embedded in wasm code. Since wasm code is serialized and
-// later deserialized into a different address space, symbolic addresses must be
-// used for *all* pointers into the address space. The MacroAssembler records a
-// list of all SymbolicAddresses and the offsets of their use in the code for
-// later patching during static linking.
+// A wasm::SymbolicAddress represents a pointer to a well-known function that is
+// embedded in wasm code. Since wasm code is serialized and later deserialized
+// into a different address space, symbolic addresses must be used for *all*
+// pointers into the address space. The MacroAssembler records a list of all
+// SymbolicAddresses and the offsets of their use in the code for later patching
+// during static linking.
 
 enum class SymbolicAddress
 {
@@ -988,8 +989,6 @@ enum class SymbolicAddress
     LogD,
     PowD,
     ATan2D,
-    ContextPtr,
-    ReportOverRecursed,
     HandleExecutionInterrupt,
     HandleDebugTrap,
     HandleThrow,
@@ -1021,7 +1020,7 @@ bool
 IsRoundingFunction(SymbolicAddress callee, jit::RoundingMode* mode);
 
 void*
-AddressOf(SymbolicAddress imm, JSContext* cx);
+AddressOf(SymbolicAddress imm);
 
 // Assumptions captures ambient state that must be the same when compiling and
 // deserializing a module for the compiled code to be valid. If it's not, then

From b9beec7efdb99d075b708dde051c9ac0e2825bab Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:23:35 -0500
Subject: [PATCH 28/96] Bug 1334504 - Baldr: remove hacky register allocation
 from i64 div/mod (r=bbouvier)

MozReview-Commit-ID: ARySD2vX1xH

--HG--
extra : rebase_source : e96a6ac1a9dfb956722d1b2172db31e8fd535705
---
 js/src/jit/shared/Lowering-shared-inl.h |  6 ++++++
 js/src/jit/shared/Lowering-shared.h     |  1 +
 js/src/jit/x86/CodeGenerator-x86.cpp    | 22 ++--------------------
 js/src/jit/x86/LIR-x86.h                | 16 ++++++++++++----
 js/src/jit/x86/Lowering-x86.cpp         | 20 ++++++++++++--------
 5 files changed, 33 insertions(+), 32 deletions(-)

diff --git a/js/src/jit/shared/Lowering-shared-inl.h b/js/src/jit/shared/Lowering-shared-inl.h
index e2900770f02c..1b13a7f68417 100644
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -817,6 +817,12 @@ LIRGeneratorShared::useInt64Fixed(MDefinition* mir, Register64 regs, bool useAtS
 #endif
 }
 
+LInt64Allocation
+LIRGeneratorShared::useInt64FixedAtStart(MDefinition* mir, Register64 regs)
+{
+    return useInt64Fixed(mir, regs, true);
+}
+
 LInt64Allocation
 LIRGeneratorShared::useInt64(MDefinition* mir, bool useAtStart)
 {
diff --git a/js/src/jit/shared/Lowering-shared.h b/js/src/jit/shared/Lowering-shared.h
index 4247e8ba069d..b3ecd6e9be0f 100644
--- a/js/src/jit/shared/Lowering-shared.h
+++ b/js/src/jit/shared/Lowering-shared.h
@@ -208,6 +208,7 @@ class LIRGeneratorShared : public MDefinitionVisitor
     inline LInt64Allocation useInt64Register(MDefinition* mir, bool useAtStart = false);
     inline LInt64Allocation useInt64RegisterOrConstant(MDefinition* mir, bool useAtStart = false);
     inline LInt64Allocation useInt64Fixed(MDefinition* mir, Register64 regs, bool useAtStart = false);
+    inline LInt64Allocation useInt64FixedAtStart(MDefinition* mir, Register64 regs);
 
     LInt64Allocation useInt64RegisterAtStart(MDefinition* mir) {
         return useInt64Register(mir, /* useAtStart = */ true);
diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp
index dea148125724..ce1880d51fe6 100644
--- a/js/src/jit/x86/CodeGenerator-x86.cpp
+++ b/js/src/jit/x86/CodeGenerator-x86.cpp
@@ -949,20 +949,11 @@ CodeGeneratorX86::visitDivOrModI64(LDivOrModI64* lir)
 {
     Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs));
     Register64 rhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Rhs));
+    Register temp = ToRegister(lir->temp());
     Register64 output = ToOutRegister64(lir);
 
     MOZ_ASSERT(output == ReturnReg64);
 
-    // We are free to clobber all registers, since this is a call instruction.
-    AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
-    regs.take(lhs.low);
-    regs.take(lhs.high);
-    if (lhs != rhs) {
-        regs.take(rhs.low);
-        regs.take(rhs.high);
-    }
-    Register temp = regs.takeAny();
-
     Label done;
 
     // Handle divide by zero.
@@ -1006,20 +997,11 @@ CodeGeneratorX86::visitUDivOrModI64(LUDivOrModI64* lir)
 {
     Register64 lhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Lhs));
     Register64 rhs = ToRegister64(lir->getInt64Operand(LDivOrModI64::Rhs));
+    Register temp = ToRegister(lir->temp());
     Register64 output = ToOutRegister64(lir);
 
     MOZ_ASSERT(output == ReturnReg64);
 
-    // We are free to clobber all registers, since this is a call instruction.
-    AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
-    regs.take(lhs.low);
-    regs.take(lhs.high);
-    if (lhs != rhs) {
-        regs.take(rhs.low);
-        regs.take(rhs.high);
-    }
-    Register temp = regs.takeAny();
-
     // Prevent divide by zero.
     if (lir->canBeDivideByZero())
         masm.branchTest64(Assembler::Zero, rhs, rhs, temp, trap(lir, wasm::Trap::IntegerDivideByZero));
diff --git a/js/src/jit/x86/LIR-x86.h b/js/src/jit/x86/LIR-x86.h
index f49ec7b87667..0c36494eac41 100644
--- a/js/src/jit/x86/LIR-x86.h
+++ b/js/src/jit/x86/LIR-x86.h
@@ -109,7 +109,7 @@ class LWasmUint32ToFloat32: public LInstructionHelper<1, 1, 1>
     }
 };
 
-class LDivOrModI64 : public LCallInstructionHelper
+class LDivOrModI64 : public LCallInstructionHelper
 {
   public:
     LIR_HEADER(DivOrModI64)
@@ -117,10 +117,11 @@ class LDivOrModI64 : public LCallInstructionHelpertoMod()->trapOffset();
         return mir_->toDiv()->trapOffset();
     }
+    const LDefinition* temp() {
+        return getTemp(0);
+    }
 };
 
-class LUDivOrModI64 : public LCallInstructionHelper
+class LUDivOrModI64 : public LCallInstructionHelper
 {
   public:
     LIR_HEADER(UDivOrModI64)
@@ -153,10 +157,11 @@ class LUDivOrModI64 : public LCallInstructionHelpertoMod()->trapOffset();
         return mir_->toDiv()->trapOffset();
     }
+    const LDefinition* temp() {
+        return getTemp(0);
+    }
 };
 
 class LWasmTruncateToInt64 : public LInstructionHelper
diff --git a/js/src/jit/x86/Lowering-x86.cpp b/js/src/jit/x86/Lowering-x86.cpp
index 5c11bac16555..337b165a56ed 100644
--- a/js/src/jit/x86/Lowering-x86.cpp
+++ b/js/src/jit/x86/Lowering-x86.cpp
@@ -618,8 +618,9 @@ LIRGeneratorX86::lowerDivI64(MDiv* div)
         return;
     }
 
-    LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(div->lhs()),
-                                                  useInt64RegisterAtStart(div->rhs()));
+    LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64FixedAtStart(div->lhs(), Register64(eax, ebx)),
+                                                  useInt64FixedAtStart(div->rhs(), Register64(ecx, edx)),
+                                                  tempFixed(esi));
     defineReturn(lir, div);
 }
 
@@ -631,24 +632,27 @@ LIRGeneratorX86::lowerModI64(MMod* mod)
         return;
     }
 
-    LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64RegisterAtStart(mod->lhs()),
-                                                  useInt64RegisterAtStart(mod->rhs()));
+    LDivOrModI64* lir = new(alloc()) LDivOrModI64(useInt64FixedAtStart(mod->lhs(), Register64(eax, ebx)),
+                                                  useInt64FixedAtStart(mod->rhs(), Register64(ecx, edx)),
+                                                  tempFixed(esi));
     defineReturn(lir, mod);
 }
 
 void
 LIRGeneratorX86::lowerUDivI64(MDiv* div)
 {
-    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(div->lhs()),
-                                                    useInt64RegisterAtStart(div->rhs()));
+    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64FixedAtStart(div->lhs(), Register64(eax, ebx)),
+                                                    useInt64FixedAtStart(div->rhs(), Register64(ecx, edx)),
+                                                    tempFixed(esi));
     defineReturn(lir, div);
 }
 
 void
 LIRGeneratorX86::lowerUModI64(MMod* mod)
 {
-    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64RegisterAtStart(mod->lhs()),
-                                                    useInt64RegisterAtStart(mod->rhs()));
+    LUDivOrModI64* lir = new(alloc()) LUDivOrModI64(useInt64FixedAtStart(mod->lhs(), Register64(eax, ebx)),
+                                                    useInt64FixedAtStart(mod->rhs(), Register64(ecx, edx)),
+                                                    tempFixed(esi));
     defineReturn(lir, mod);
 }
 

From 957d1e69d5f80eb0225f68b95a5154d4e54f10b3 Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:24:22 -0500
Subject: [PATCH 29/96] Bug 1334504 - Baldr: set ARM's FrameRegister
 (r=bbouvier)

MozReview-Commit-ID: 7kDJI6HqGD0

--HG--
extra : rebase_source : ea6311187695c48644af487e9c8025f8e85a9844
---
 js/src/jit/RegisterAllocator.h | 4 +++-
 js/src/jit/arm/Assembler-arm.h | 4 ++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/js/src/jit/RegisterAllocator.h b/js/src/jit/RegisterAllocator.h
index d5b4110d5bd6..59cde490876c 100644
--- a/js/src/jit/RegisterAllocator.h
+++ b/js/src/jit/RegisterAllocator.h
@@ -289,8 +289,10 @@ class RegisterAllocator
             allRegisters_.take(AnyRegister(HeapLenReg));
 #endif
         } else {
-            if (FramePointer != InvalidReg && mir->instrumentedProfiling())
+#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM64)
+            if (mir->instrumentedProfiling())
                 allRegisters_.take(AnyRegister(FramePointer));
+#endif
         }
     }
 
diff --git a/js/src/jit/arm/Assembler-arm.h b/js/src/jit/arm/Assembler-arm.h
index 434352bc6b33..0bdc2768c511 100644
--- a/js/src/jit/arm/Assembler-arm.h
+++ b/js/src/jit/arm/Assembler-arm.h
@@ -73,7 +73,7 @@ static constexpr Register IntArgReg0 = r0;
 static constexpr Register IntArgReg1 = r1;
 static constexpr Register IntArgReg2 = r2;
 static constexpr Register IntArgReg3 = r3;
-static constexpr Register HeapReg = r11;
+static constexpr Register HeapReg = r10;
 static constexpr Register CallTempNonArgRegs[] = { r5, r6, r7, r8 };
 static const uint32_t NumCallTempNonArgRegs =
     mozilla::ArrayLength(CallTempNonArgRegs);
@@ -134,7 +134,7 @@ static constexpr FloatRegister InvalidFloatReg;
 static constexpr Register JSReturnReg_Type = r3;
 static constexpr Register JSReturnReg_Data = r2;
 static constexpr Register StackPointer = sp;
-static constexpr Register FramePointer = InvalidReg;
+static constexpr Register FramePointer = r11;
 static constexpr Register ReturnReg = r0;
 static constexpr Register64 ReturnReg64(r1, r0);
 static constexpr FloatRegister ReturnFloat32Reg = { FloatRegisters::d0, VFPRegister::Single };

From 2164377bd8e5e4ba160ba8512975d8f5554664c6 Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:26:05 -0500
Subject: [PATCH 30/96] Bug 1334504 - Baldr: maintain fp register instead a
 virtual fp (r=bbouvier)

MozReview-Commit-ID: 2Mi60u3DyJg

--HG--
extra : rebase_source : 155ce830bcd55e7f9fdf890d4da4b1c12377f12b
---
 js/public/ProfilingFrameIterator.h            |   3 +-
 js/src/jit-test/tests/asm.js/testProfiling.js |   6 +-
 js/src/jit-test/tests/wasm/profiling.js       |   4 +-
 js/src/jit/Lowering.cpp                       |  20 +-
 js/src/jit/MIR.h                              |  11 +-
 js/src/jit/MacroAssembler.cpp                 |  13 ++
 js/src/jit/MacroAssembler.h                   |   3 +
 js/src/jit/RegisterAllocator.h                |   1 +
 js/src/jit/arm/Simulator-arm.h                |   2 +
 js/src/jit/shared/LIR-shared.h                |   6 +-
 js/src/shell/js.cpp                           |   2 +
 js/src/vm/Stack.cpp                           |   5 +-
 js/src/vm/Stack.h                             |  12 +-
 js/src/wasm/WasmBaselineCompile.cpp           |  14 +-
 js/src/wasm/WasmCode.cpp                      |   2 +-
 js/src/wasm/WasmCode.h                        |   4 +-
 js/src/wasm/WasmFrameIterator.cpp             | 192 ++++++++----------
 js/src/wasm/WasmFrameIterator.h               |   5 +-
 js/src/wasm/WasmGenerator.cpp                 |   2 +-
 js/src/wasm/WasmIonCompile.cpp                |   4 +-
 js/src/wasm/WasmStubs.cpp                     |  40 ++--
 js/src/wasm/WasmTypes.cpp                     |   4 +-
 js/src/wasm/WasmTypes.h                       |   3 +-
 tools/profiler/core/platform.cpp              |   1 +
 24 files changed, 178 insertions(+), 181 deletions(-)

diff --git a/js/public/ProfilingFrameIterator.h b/js/public/ProfilingFrameIterator.h
index e769c269a339..550ac518a193 100644
--- a/js/public/ProfilingFrameIterator.h
+++ b/js/public/ProfilingFrameIterator.h
@@ -93,9 +93,10 @@ class MOZ_NON_PARAM JS_PUBLIC_API(ProfilingFrameIterator)
   public:
     struct RegisterState
     {
-        RegisterState() : pc(nullptr), sp(nullptr), lr(nullptr) {}
+        RegisterState() : pc(nullptr), sp(nullptr), fp(nullptr), lr(nullptr) {}
         void* pc;
         void* sp;
+        void* fp;
         void* lr;
     };
 
diff --git a/js/src/jit-test/tests/asm.js/testProfiling.js b/js/src/jit-test/tests/asm.js/testProfiling.js
index 732cea43f26d..1c47da213bf2 100644
--- a/js/src/jit-test/tests/asm.js/testProfiling.js
+++ b/js/src/jit-test/tests/asm.js/testProfiling.js
@@ -112,7 +112,7 @@ function testBuiltinD2D(name) {
         enableSingleStepProfiling();
         assertEq(f(.1), eval("Math." + name + "(.1)"));
         var stacks = disableSingleStepProfiling();
-        assertStackContainsSeq(stacks, ">,f,>,native call,>,f,>,>");
+        assertStackContainsSeq(stacks, ">,f,>,f,>,>");
     }
 }
 for (name of ['sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'ceil', 'floor', 'exp', 'log'])
@@ -125,7 +125,7 @@ function testBuiltinF2F(name) {
         enableSingleStepProfiling();
         assertEq(f(.1), eval("Math.fround(Math." + name + "(Math.fround(.1)))"));
         var stacks = disableSingleStepProfiling();
-        assertStackContainsSeq(stacks, ">,f,>,native call,>,f,>,>");
+        assertStackContainsSeq(stacks, ">,f,>,f,>,>");
     }
 }
 for (name of ['ceil', 'floor'])
@@ -138,7 +138,7 @@ function testBuiltinDD2D(name) {
         enableSingleStepProfiling();
         assertEq(f(.1, .2), eval("Math." + name + "(.1, .2)"));
         var stacks = disableSingleStepProfiling();
-        assertStackContainsSeq(stacks, ">,f,>,native call,>,f,>,>");
+        assertStackContainsSeq(stacks, ">,f,>,f,>,>");
     }
 }
 for (name of ['atan2', 'pow'])
diff --git a/js/src/jit-test/tests/wasm/profiling.js b/js/src/jit-test/tests/wasm/profiling.js
index 108c3c5d978e..6d81add93492 100644
--- a/js/src/jit-test/tests/wasm/profiling.js
+++ b/js/src/jit-test/tests/wasm/profiling.js
@@ -125,7 +125,7 @@ testError(
     (func (export "") (call $foo))
 )`,
 WebAssembly.RuntimeError,
-["", ">", "1,>", "0,1,>", "trap handling,0,1,>", "inline stub,0,1,>", "trap handling,0,1,>", ""]);
+["", ">", "1,>", "0,1,>", "trap handling,0,1,>", ""]);
 
 testError(
 `(module
@@ -140,7 +140,7 @@ WebAssembly.RuntimeError,
 // Technically we have this one *one-instruction* interval where
 // the caller is lost (the stack with "1,>"). It's annoying to fix and shouldn't
 // mess up profiles in practice so we ignore it.
-["", ">", "0,>", "1,0,>", "1,>", "trap handling,0,>", "inline stub,0,>", "trap handling,0,>", ""]);
+["", ">", "0,>", "1,0,>", "1,>", "trap handling,0,>", ""]);
 
 (function() {
     var e = wasmEvalText(`
diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
index f93603c6ab84..573c2ee3c52a 100644
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4369,13 +4369,7 @@ LIRGenerator::visitWasmReturn(MWasmReturn* ins)
     MDefinition* rval = ins->getOperand(0);
 
     if (rval->type() == MIRType::Int64) {
-        LWasmReturnI64* lir = new(alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64));
-
-        // Preserve the TLS pointer we were passed in `WasmTlsReg`.
-        MDefinition* tlsPtr = ins->getOperand(1);
-        lir->setOperand(INT64_PIECES, useFixed(tlsPtr, WasmTlsReg));
-
-        add(lir);
+        add(new(alloc()) LWasmReturnI64(useInt64Fixed(rval, ReturnReg64)));
         return;
     }
 
@@ -4391,23 +4385,13 @@ LIRGenerator::visitWasmReturn(MWasmReturn* ins)
     else
         MOZ_CRASH("Unexpected wasm return type");
 
-    // Preserve the TLS pointer we were passed in `WasmTlsReg`.
-    MDefinition* tlsPtr = ins->getOperand(1);
-    lir->setOperand(1, useFixed(tlsPtr, WasmTlsReg));
-
     add(lir);
 }
 
 void
 LIRGenerator::visitWasmReturnVoid(MWasmReturnVoid* ins)
 {
-    auto* lir = new(alloc()) LWasmReturnVoid;
-
-    // Preserve the TLS pointer we were passed in `WasmTlsReg`.
-    MDefinition* tlsPtr = ins->getOperand(0);
-    lir->setOperand(0, useFixed(tlsPtr, WasmTlsReg));
-
-    add(lir);
+    add(new(alloc()) LWasmReturnVoid);
 }
 
 void
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 3fe1ee3c7c55..63ad3938b6c1 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -14247,12 +14247,11 @@ class MWasmParameter : public MNullaryInstruction
 };
 
 class MWasmReturn
-  : public MAryControlInstruction<2, 0>,
+  : public MAryControlInstruction<1, 0>,
     public NoTypePolicy::Data
 {
-    explicit MWasmReturn(MDefinition* ins, MDefinition* tlsPtr) {
+    explicit MWasmReturn(MDefinition* ins) {
         initOperand(0, ins);
-        initOperand(1, tlsPtr);
     }
 
   public:
@@ -14261,13 +14260,9 @@ class MWasmReturn
 };
 
 class MWasmReturnVoid
-  : public MAryControlInstruction<1, 0>,
+  : public MAryControlInstruction<0, 0>,
     public NoTypePolicy::Data
 {
-    explicit MWasmReturnVoid(MDefinition* tlsPtr) {
-        initOperand(0, tlsPtr);
-    }
-
   public:
     INSTRUCTION_HEADER(WasmReturnVoid)
     TRIVIAL_NEW_WRAPPERS
diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
index 505f0cc7f833..d3f70e1064cd 100644
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2962,6 +2962,19 @@ MacroAssembler::wasmEmitTrapOutOfLineCode()
     clearTrapSites();
 }
 
+void
+MacroAssembler::wasmAssertNonExitInvariants(Register activation)
+{
+#ifdef DEBUG
+    // WasmActivation.exitFP should be null when outside any exit frame.
+    Label ok;
+    Address exitFP(activation, WasmActivation::offsetOfExitFP());
+    branchPtr(Assembler::Equal, exitFP, ImmWord(0), &ok);
+    breakpoint();
+    bind(&ok);
+#endif
+}
+
 //}}} check_macroassembler_style
 
 void
diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h
index 84e4bde3b23e..55c7ab071108 100644
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1464,6 +1464,9 @@ class MacroAssembler : public MacroAssemblerSpecific
     // including "normal" OutOfLineCode.
     void wasmEmitTrapOutOfLineCode();
 
+    // Assert invariants that should be true within any non-exit-stub wasm code.
+    void wasmAssertNonExitInvariants(Register activation);
+
   public:
     // ========================================================================
     // Clamping functions.
diff --git a/js/src/jit/RegisterAllocator.h b/js/src/jit/RegisterAllocator.h
index 59cde490876c..bcc3915d9983 100644
--- a/js/src/jit/RegisterAllocator.h
+++ b/js/src/jit/RegisterAllocator.h
@@ -288,6 +288,7 @@ class RegisterAllocator
             allRegisters_.take(AnyRegister(HeapReg));
             allRegisters_.take(AnyRegister(HeapLenReg));
 #endif
+            allRegisters_.take(FramePointer);
         } else {
 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) || defined(JS_CODEGEN_ARM64)
             if (mir->instrumentedProfiling())
diff --git a/js/src/jit/arm/Simulator-arm.h b/js/src/jit/arm/Simulator-arm.h
index 0259e776ce9e..606261c9c603 100644
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -81,6 +81,8 @@ class Simulator
         r0 = 0, r1, r2, r3, r4, r5, r6, r7,
         r8, r9, r10, r11, r12, r13, r14, r15,
         num_registers,
+        fp = 11,
+        ip = 12,
         sp = 13,
         lr = 14,
         pc = 15,
diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
index 34da708ee535..c67a8e814cc8 100644
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -8605,13 +8605,13 @@ class LWasmParameterI64 : public LInstructionHelper
     LIR_HEADER(WasmParameterI64);
 };
 
-class LWasmReturn : public LInstructionHelper<0, 2, 0>
+class LWasmReturn : public LInstructionHelper<0, 1, 0>
 {
   public:
     LIR_HEADER(WasmReturn);
 };
 
-class LWasmReturnI64 : public LInstructionHelper<0, INT64_PIECES + 1, 0>
+class LWasmReturnI64 : public LInstructionHelper<0, INT64_PIECES, 0>
 {
   public:
     LIR_HEADER(WasmReturnI64)
@@ -8621,7 +8621,7 @@ class LWasmReturnI64 : public LInstructionHelper<0, INT64_PIECES + 1, 0>
     }
 };
 
-class LWasmReturnVoid : public LInstructionHelper<0, 1, 0>
+class LWasmReturnVoid : public LInstructionHelper<0, 0, 0>
 {
   public:
     LIR_HEADER(WasmReturnVoid);
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
index 93966b5d68a6..5e0a70e4aeec 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -5274,9 +5274,11 @@ SingleStepCallback(void* arg, jit::Simulator* sim, void* pc)
 #if defined(JS_SIMULATOR_ARM)
     state.sp = (void*)sim->get_register(jit::Simulator::sp);
     state.lr = (void*)sim->get_register(jit::Simulator::lr);
+    state.fp = (void*)sim->get_register(jit::Simulator::fp);
 #elif defined(JS_SIMULATOR_MIPS64)
     state.sp = (void*)sim->getRegister(jit::Simulator::sp);
     state.lr = (void*)sim->getRegister(jit::Simulator::ra);
+    state.fp = (void*)sim->getRegister(jit::Simulator::fp);
 #else
 #  error "NYI: Single-step profiling support"
 #endif
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
index 472240029456..70150b556b52 100644
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1646,7 +1646,7 @@ WasmActivation::WasmActivation(JSContext* cx)
   : Activation(cx, Wasm),
     entrySP_(nullptr),
     resumePC_(nullptr),
-    fp_(nullptr),
+    exitFP_(nullptr),
     exitReason_(wasm::ExitReason::None)
 {
     (void) entrySP_;  // silence "unused private member" warning
@@ -1664,7 +1664,8 @@ WasmActivation::~WasmActivation()
     // Hide this activation from the profiler before is is destroyed.
     unregisterProfiling();
 
-    MOZ_ASSERT(fp_ == nullptr);
+    MOZ_ASSERT(exitFP_ == nullptr);
+    MOZ_ASSERT(exitReason_ == wasm::ExitReason::None);
 
     MOZ_ASSERT(cx_->wasmActivationStack_ == this);
     cx_->wasmActivationStack_ = prevWasm_;
diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h
index e747edbd3e4d..5655b5f76291 100644
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1735,7 +1735,7 @@ class WasmActivation : public Activation
     WasmActivation* prevWasm_;
     void* entrySP_;
     void* resumePC_;
-    uint8_t* fp_;
+    uint8_t* exitFP_;
     wasm::ExitReason exitReason_;
 
   public:
@@ -1748,16 +1748,16 @@ class WasmActivation : public Activation
         return true;
     }
 
-    // Returns a pointer to the base of the innermost stack frame of wasm code
-    // in this activation.
-    uint8_t* fp() const { return fp_; }
+    // Returns null or the final wasm::Frame* when wasm exited this
+    // WasmActivation.
+    uint8_t* exitFP() const { return exitFP_; }
 
     // Returns the reason why wasm code called out of wasm code.
     wasm::ExitReason exitReason() const { return exitReason_; }
 
     // Written by JIT code:
     static unsigned offsetOfEntrySP() { return offsetof(WasmActivation, entrySP_); }
-    static unsigned offsetOfFP() { return offsetof(WasmActivation, fp_); }
+    static unsigned offsetOfExitFP() { return offsetof(WasmActivation, exitFP_); }
     static unsigned offsetOfExitReason() { return offsetof(WasmActivation, exitReason_); }
 
     // Read/written from SIGSEGV handler:
@@ -1765,7 +1765,7 @@ class WasmActivation : public Activation
     void* resumePC() const { return resumePC_; }
 
     // Used by wasm::FrameIterator during stack unwinding.
-    void unwindFP(uint8_t* fp) { fp_ = fp; }
+    void unwindExitFP(uint8_t* exitFP) { exitFP_ = exitFP; exitReason_ = wasm::ExitReason::None; }
 };
 
 // A FrameIter walks over a context's stack of JS script activations,
diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp
index a2b15c57fd61..c367bfa573d8 100644
--- a/js/src/wasm/WasmBaselineCompile.cpp
+++ b/js/src/wasm/WasmBaselineCompile.cpp
@@ -2371,10 +2371,6 @@ class BaseCompiler
             restoreResult();
         }
 
-        // The epilogue assumes WasmTlsReg is valid so reload it in case it was
-        // clobbered by the body.
-        masm.loadWasmTlsRegFromFrame();
-
         GenerateFunctionEpilogue(masm, localSize_, &offsets_);
 
 #if defined(JS_ION_PERF)
@@ -5169,8 +5165,15 @@ BaseCompiler::sniffConditionalControlCmp(Cond compareOp, ValType operandType)
     MOZ_ASSERT(latentOp_ == LatentOp::None, "Latent comparison state not properly reset");
 
     switch (iter_.peekOp()) {
-      case uint16_t(Op::BrIf):
       case uint16_t(Op::Select):
+#ifdef JS_CODEGEN_X86
+        // On x86, with only 5 available registers, a latent i64 binary
+        // comparison takes 4 leaving only 1 which is not enough for select.
+        if (operandType == ValType::I64)
+            return false;
+#endif
+        MOZ_FALLTHROUGH;
+      case uint16_t(Op::BrIf):
       case uint16_t(Op::If):
         setLatentCompare(compareOp, operandType);
         return true;
@@ -7489,6 +7492,7 @@ BaseCompiler::BaseCompiler(const ModuleEnvironment& env,
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
     availGPR_.take(HeapReg);
 #endif
+    availGPR_.take(FramePointer);
 
 #ifdef DEBUG
     setupRegisterLeakCheck();
diff --git a/js/src/wasm/WasmCode.cpp b/js/src/wasm/WasmCode.cpp
index 999018fb63f8..697390e2b384 100644
--- a/js/src/wasm/WasmCode.cpp
+++ b/js/src/wasm/WasmCode.cpp
@@ -307,7 +307,7 @@ CodeRange::CodeRange(Kind kind, Offsets offsets)
     kind_(kind)
 {
     MOZ_ASSERT(begin_ <= end_);
-    MOZ_ASSERT(kind_ == Entry || kind_ == Inline ||
+    MOZ_ASSERT(kind_ == Entry || kind_ == Inline || kind_ == Throw ||
                kind_ == FarJumpIsland || kind_ == DebugTrap);
 }
 
diff --git a/js/src/wasm/WasmCode.h b/js/src/wasm/WasmCode.h
index 1ba7bd0a6c44..0acb8c3f3c9d 100644
--- a/js/src/wasm/WasmCode.h
+++ b/js/src/wasm/WasmCode.h
@@ -239,8 +239,8 @@ class CodeRange
         DebugTrap,         // calls C++ to handle debug event such as
                            // enter/leave frame or breakpoint
         FarJumpIsland,     // inserted to connect otherwise out-of-range insns
-        Inline             // stub that is jumped-to, not called, and thus
-                           // replaces/loses preceding innermost frame
+        Inline,            // stub that is jumped-to within prologue/epilogue
+        Throw              // special stack-unwinding stub
     };
 
   private:
diff --git a/js/src/wasm/WasmFrameIterator.cpp b/js/src/wasm/WasmFrameIterator.cpp
index 783b9bf557b7..35dde46a53a7 100644
--- a/js/src/wasm/WasmFrameIterator.cpp
+++ b/js/src/wasm/WasmFrameIterator.cpp
@@ -83,7 +83,7 @@ FrameIterator::FrameIterator(WasmActivation* activation, Unwind unwind)
         return;
     }
 
-    fp_ = activation->fp();
+    fp_ = activation->exitFP();
 
     if (!fp_) {
         MOZ_ASSERT(done());
@@ -118,7 +118,7 @@ void
 FrameIterator::settle()
 {
     if (unwind_ == Unwind::True)
-        activation_->unwindFP(fp_);
+        activation_->unwindExitFP(fp_);
 
     void* returnAddress = ReturnAddressFromFP(fp_);
 
@@ -130,7 +130,7 @@ FrameIterator::settle()
         callsite_ = nullptr;
 
         if (unwind_ == Unwind::True)
-            activation_->unwindFP(nullptr);
+            activation_->unwindExitFP(nullptr);
 
         MOZ_ASSERT(done());
         return;
@@ -254,76 +254,65 @@ FrameIterator::debugTrapCallsite() const
 // prologue/epilogue. The offsets are dynamically asserted during code
 // generation.
 #if defined(JS_CODEGEN_X64)
-# if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
-# endif
-static const unsigned PushedFP = 16;
-static const unsigned PushedTLS = 18;
-static const unsigned StoredFP = 25;
-static const unsigned RestoreFP = 4;
+static const unsigned PushedFP = 1;
+static const unsigned PushedTLS = 3;
+static const unsigned PoppedTLS = 1;
 #elif defined(JS_CODEGEN_X86)
-# if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
-# endif
-static const unsigned PushedFP = 11;
-static const unsigned PushedTLS = 12;
-static const unsigned StoredFP = 15;
-static const unsigned RestoreFP = 3;
+static const unsigned PushedFP = 1;
+static const unsigned PushedTLS = 2;
+static const unsigned PoppedTLS = 1;
 #elif defined(JS_CODEGEN_ARM)
+static const unsigned BeforePushRetAddr = 0;
 static const unsigned PushedRetAddr = 4;
-static const unsigned PushedFP = 20;
-static const unsigned PushedTLS = 24;
-static const unsigned StoredFP = 28;
-static const unsigned RestoreFP = 4;
+static const unsigned PushedFP = 8;
+static const unsigned PushedTLS = 12;
+static const unsigned PoppedTLS = 4;
 #elif defined(JS_CODEGEN_ARM64)
+static const unsigned BeforePushRetAddr = 0;
 static const unsigned PushedRetAddr = 0;
 static const unsigned PushedFP = 0;
 static const unsigned PushedTLS = 0;
-static const unsigned StoredFP = 0;
-static const unsigned RestoreFP = 0;
+static const unsigned PoppedTLS = 0;
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-static const unsigned PushedRetAddr = 8;
-static const unsigned PushedFP = 28;
-static const unsigned PushedTLS = 32;
-static const unsigned StoredFP = 36;
-static const unsigned RestoreFP = 4;
+static const unsigned BeforePushRetAddr = 0;
+static const unsigned PushedRetAddr = 4;
+static const unsigned PushedFP = 8;
+static const unsigned PushedTLS = 12;
+static const unsigned PoppedTLS = 4;
 #elif defined(JS_CODEGEN_NONE)
-# if defined(DEBUG)
 static const unsigned PushedRetAddr = 0;
-# endif
-static const unsigned PushedFP = 1;
-static const unsigned PushedTLS = 1;
-static const unsigned StoredFP = 1;
-static const unsigned RestoreFP = 0;
+static const unsigned PushedFP = 0;
+static const unsigned PushedTLS = 0;
+static const unsigned PoppedTLS = 0;
 #else
 # error "Unknown architecture!"
 #endif
 
 static void
-PushRetAddr(MacroAssembler& masm)
+PushRetAddr(MacroAssembler& masm, unsigned entry)
 {
 #if defined(JS_CODEGEN_ARM)
+    MOZ_ASSERT(masm.currentOffset() - entry == BeforePushRetAddr);
     masm.push(lr);
 #elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
+    MOZ_ASSERT(masm.currentOffset() - entry == BeforePushRetAddr);
     masm.push(ra);
 #else
     // The x86/x64 call instruction pushes the return address.
 #endif
 }
 
-// Generate a prologue that maintains WasmActivation::fp as the virtual frame
-// pointer so that FrameIterator can walk the stack at any pc in generated code.
 static void
 GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                          uint32_t* entry)
 {
-    Register scratch = ABINonArgReg0;
-
-    // FrameIterator needs to know the offsets of several key instructions from
-    // entry. To save space, we make these offsets static constants and assert
-    // that they match the actual codegen below. On ARM, this requires
-    // AutoForbidPools to prevent a constant pool from being randomly inserted
-    // between two instructions.
+    // ProfilingFrameIterator needs to know the offsets of several key
+    // instructions from entry. To save space, we make these offsets static
+    // constants and assert that they match the actual codegen below. On ARM,
+    // this requires AutoForbidPools to prevent a constant pool from being
+    // randomly inserted between two instructions.
     {
 #if defined(JS_CODEGEN_ARM)
         AutoForbidPools afp(&masm, /* number of instructions in scope = */ 8);
@@ -331,63 +320,57 @@ GenerateCallablePrologue(MacroAssembler& masm, unsigned framePushed, ExitReason
 
         *entry = masm.currentOffset();
 
-        PushRetAddr(masm);
+        PushRetAddr(masm, *entry);
         MOZ_ASSERT_IF(!masm.oom(), PushedRetAddr == masm.currentOffset() - *entry);
-
-        masm.loadWasmActivationFromTls(scratch);
-        masm.push(Address(scratch, WasmActivation::offsetOfFP()));
+        masm.push(FramePointer);
         MOZ_ASSERT_IF(!masm.oom(), PushedFP == masm.currentOffset() - *entry);
-
         masm.push(WasmTlsReg);
         MOZ_ASSERT_IF(!masm.oom(), PushedTLS == masm.currentOffset() - *entry);
-
-        masm.storePtr(masm.getStackPointer(), Address(scratch, WasmActivation::offsetOfFP()));
-        MOZ_ASSERT_IF(!masm.oom(), StoredFP == masm.currentOffset() - *entry);
+        masm.moveStackPtrTo(FramePointer);
     }
 
-    if (reason != ExitReason::None)
-        masm.store32(Imm32(int32_t(reason)), Address(scratch, WasmActivation::offsetOfExitReason()));
+    if (reason != ExitReason::None) {
+        Register scratch = ABINonArgReg0;
+        masm.loadWasmActivationFromTls(scratch);
+        masm.wasmAssertNonExitInvariants(scratch);
+        Address exitReason(scratch, WasmActivation::offsetOfExitReason());
+        masm.store32(Imm32(int32_t(reason)), exitReason);
+        Address exitFP(scratch, WasmActivation::offsetOfExitFP());
+        masm.storePtr(FramePointer, exitFP);
+    }
 
     if (framePushed)
         masm.subFromStackPtr(Imm32(framePushed));
 }
 
-// Generate the inverse of GenerateCallablePrologue.
 static void
 GenerateCallableEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason reason,
                          uint32_t* ret)
 {
-    Register scratch = ABINonArgReturnReg0;
-    Register scratch2 = ABINonArgReturnReg1;
-
     if (framePushed)
         masm.addToStackPtr(Imm32(framePushed));
 
-    masm.loadWasmActivationFromTls(scratch);
 
     if (reason != ExitReason::None) {
-        masm.store32(Imm32(int32_t(ExitReason::None)),
-                     Address(scratch, WasmActivation::offsetOfExitReason()));
+        Register scratch = ABINonArgReturnReg0;
+        masm.loadWasmActivationFromTls(scratch);
+        Address exitFP(scratch, WasmActivation::offsetOfExitFP());
+        masm.storePtr(ImmWord(0), exitFP);
+        Address exitReason(scratch, WasmActivation::offsetOfExitReason());
+        masm.store32(Imm32(int32_t(ExitReason::None)), exitReason);
     }
 
-#if defined(JS_CODEGEN_ARM)
     // Forbid pools for the same reason as described in GenerateCallablePrologue.
-    AutoForbidPools afp(&masm, /* number of instructions in scope = */ 5);
+#if defined(JS_CODEGEN_ARM)
+    AutoForbidPools afp(&masm, /* number of instructions in scope = */ 3);
 #endif
 
-    // sp protects the stack from clobber via asynchronous signal handlers and
-    // the async interrupt exit. Since activation.fp can be read at any time and
-    // still points to the current frame, be careful to only update sp after
-    // activation.fp has been repointed to the caller's frame.
-
-    masm.loadPtr(Address(masm.getStackPointer(), offsetof(Frame, callerFP)), scratch2);
-    masm.storePtr(scratch2, Address(scratch, WasmActivation::offsetOfFP()));
-    DebugOnly afterRestoreFP = masm.currentOffset();
-    masm.addToStackPtr(Imm32(2 * sizeof(void*)));
+    masm.pop(WasmTlsReg);
+    DebugOnly poppedTLS = masm.currentOffset();
+    masm.pop(FramePointer);
     *ret = masm.currentOffset();
     masm.ret();
-
-    MOZ_ASSERT_IF(!masm.oom(), RestoreFP == *ret - afterRestoreFP);
+    MOZ_ASSERT_IF(!masm.oom(), PoppedTLS == *ret - poppedTLS);
 }
 
 void
@@ -478,7 +461,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation)
     stackAddress_(nullptr),
     exitReason_(ExitReason::None)
 {
-    initFromFP();
+    initFromExitFP();
 }
 
 static inline void
@@ -502,9 +485,9 @@ AssertMatchesCallSite(const WasmActivation& activation, void* callerPC, void* ca
 }
 
 void
-ProfilingFrameIterator::initFromFP()
+ProfilingFrameIterator::initFromExitFP()
 {
-    uint8_t* fp = activation_->fp();
+    uint8_t* fp = activation_->exitFP();
     stackAddress_ = fp;
 
     // If a signal was handled while entering an activation, the frame will
@@ -546,6 +529,7 @@ ProfilingFrameIterator::initFromFP()
       case CodeRange::TrapExit:
       case CodeRange::DebugTrap:
       case CodeRange::Inline:
+      case CodeRange::Throw:
       case CodeRange::FarJumpIsland:
         MOZ_CRASH("Unexpected CodeRange kind");
     }
@@ -554,12 +538,6 @@ ProfilingFrameIterator::initFromFP()
     // This allows the variety of exit reasons to show up in the callstack.
     exitReason_ = activation_->exitReason();
 
-    // In the case of calls to builtins or asynchronous interrupts, no exit path
-    // is taken so the exitReason is None. Coerce these to the Native exit
-    // reason so that self-time is accounted for.
-    if (exitReason_ == ExitReason::None)
-        exitReason_ = ExitReason::Native;
-
     MOZ_ASSERT(!done());
 }
 
@@ -575,11 +553,18 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
     stackAddress_(nullptr),
     exitReason_(ExitReason::None)
 {
+    // In the case of ImportJitExit, the fp register may be temporarily
+    // clobbered on return from Ion so always use activation.fp when it is set.
+    if (activation.exitFP()) {
+        initFromExitFP();
+        return;
+    }
+
     // If pc isn't in the instance's code, we must have exited the code via an
     // exit trampoline or signal handler.
     code_ = activation_->compartment()->wasm.lookupCode(state.pc);
     if (!code_) {
-        initFromFP();
+        MOZ_ASSERT(done());
         return;
     }
 
@@ -589,7 +574,7 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
     // while pc is in the prologue/epilogue would skip the second-to-innermost
     // call. To avoid this problem, we use the static structure of the code in
     // the prologue and epilogue to do the Right Thing.
-    uint8_t* fp = activation.fp();
+    uint8_t* fp = (uint8_t*)state.fp;
     uint8_t* pc = (uint8_t*)state.pc;
     void** sp = (void**)state.sp;
 
@@ -620,35 +605,38 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
       case CodeRange::ImportInterpExit:
       case CodeRange::TrapExit:
 #if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
-        if (offsetFromEntry < PushedRetAddr || codeRange->isThunk()) {
-            // First instruction of the ARM/MIPS function; the return address is
-            // still in lr and fp still holds the caller's fp.
+        if (offsetFromEntry == BeforePushRetAddr || codeRange->isThunk()) {
+            // The return address is still in lr and fp holds the caller's fp.
             callerPC_ = state.lr;
             callerFP_ = fp;
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
         } else
 #endif
-        if (offsetFromEntry < PushedFP || codeRange->isThunk()) {
+        if (offsetFromEntry == PushedRetAddr || codeRange->isThunk()) {
             // The return address has been pushed on the stack but fp still
             // points to the caller's fp.
             callerPC_ = sp[0];
             callerFP_ = fp;
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
-        } else if (offsetFromEntry < PushedTLS) {
+        } else if (offsetFromEntry == PushedFP) {
             // The return address and caller's fp have been pushed on the stack; fp
             // is still the caller's fp.
             callerPC_ = sp[1];
-            callerFP_ = fp;
+            callerFP_ = sp[0];
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
-        } else if (offsetFromEntry < StoredFP || offsetInModule == codeRange->ret() - RestoreFP) {
+        } else if (offsetFromEntry == PushedTLS) {
             // The full Frame has been pushed; fp is still the caller's fp.
             MOZ_ASSERT(fp == CallerFPFromFP(sp));
             callerPC_ = ReturnAddressFromFP(sp);
             callerFP_ = fp;
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
+        } else if (offsetInModule == codeRange->ret() - PoppedTLS) {
+            // The TLS field of the Frame has been popped.
+            callerPC_ = sp[1];
+            callerFP_ = sp[0];
         } else if (offsetInModule == codeRange->ret()) {
-            // fp has been restored to the caller's frame and both the TLS and
-            // caller FP words have been popped.
+            // Both the TLS and callerFP fields have been popped and fp now
+            // points to the caller's frame.
             callerPC_ = sp[0];
             callerFP_ = fp;
             AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
@@ -663,18 +651,11 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
         // The entry trampoline is the final frame in an WasmActivation. The entry
         // trampoline also doesn't GeneratePrologue/Epilogue so we can't use
         // the general unwinding logic above.
-        MOZ_ASSERT(!fp);
         callerPC_ = nullptr;
         callerFP_ = nullptr;
         break;
       case CodeRange::DebugTrap:
       case CodeRange::Inline:
-        // The throw stub clears WasmActivation::fp on it's way out.
-        if (!fp) {
-            MOZ_ASSERT(done());
-            return;
-        }
-
         // Most inline code stubs execute after the prologue/epilogue have
         // completed so we can simply unwind based on fp. The only exception is
         // the async interrupt stub, since it can be executed at any time.
@@ -684,10 +665,16 @@ ProfilingFrameIterator::ProfilingFrameIterator(const WasmActivation& activation,
         callerFP_ = CallerFPFromFP(fp);
         AssertMatchesCallSite(*activation_, callerPC_, callerFP_);
         break;
+      case CodeRange::Throw:
+        // The throw stub executes a small number of instructions before popping
+        // the entire activation. To simplify testing, we simply pretend throw
+        // stubs have already popped the entire stack.
+        MOZ_ASSERT(done());
+        return;
     }
 
     codeRange_ = codeRange;
-    stackAddress_ = state.sp;
+    stackAddress_ = sp;
     MOZ_ASSERT(!done());
 }
 
@@ -716,6 +703,7 @@ ProfilingFrameIterator::operator++()
 
     switch (codeRange_->kind()) {
       case CodeRange::Entry:
+      case CodeRange::Throw:
         MOZ_ASSERT(callerFP_ == nullptr);
         callerPC_ = nullptr;
         break;
@@ -748,7 +736,6 @@ ProfilingFrameIterator::label() const
     //     devtools/client/performance/modules/logic/frame-utils.js
     const char* importJitDescription = "fast FFI trampoline (in asm.js)";
     const char* importInterpDescription = "slow FFI trampoline (in asm.js)";
-    const char* nativeDescription = "native call (in asm.js)";
     const char* trapDescription = "trap handling (in asm.js)";
     const char* debugTrapDescription = "debug trap handling (in asm.js)";
 
@@ -759,8 +746,6 @@ ProfilingFrameIterator::label() const
         return importJitDescription;
       case ExitReason::ImportInterp:
         return importInterpDescription;
-      case ExitReason::Native:
-        return nativeDescription;
       case ExitReason::Trap:
         return trapDescription;
       case ExitReason::DebugTrap:
@@ -776,6 +761,7 @@ ProfilingFrameIterator::label() const
       case CodeRange::DebugTrap:        return debugTrapDescription;
       case CodeRange::Inline:           return "inline stub (in asm.js)";
       case CodeRange::FarJumpIsland:    return "interstitial (in asm.js)";
+      case CodeRange::Throw:            MOZ_CRASH("no frame for throw stubs");
     }
 
     MOZ_CRASH("bad code range kind");
diff --git a/js/src/wasm/WasmFrameIterator.h b/js/src/wasm/WasmFrameIterator.h
index 962b7c9e903c..1f780c73ef96 100644
--- a/js/src/wasm/WasmFrameIterator.h
+++ b/js/src/wasm/WasmFrameIterator.h
@@ -89,7 +89,6 @@ enum class ExitReason : uint32_t
     None,          // default state, the pc is in wasm code
     ImportJit,     // fast-path call directly into JIT code
     ImportInterp,  // slow-path call into C++ Invoke()
-    Native,        // call to native C++ code (e.g., Math.sin, ToInt32(), interrupt)
     Trap,          // call to trap handler for the trap in WasmActivation::trap
     DebugTrap      // call to debug trap handler
 };
@@ -101,12 +100,12 @@ class ProfilingFrameIterator
     const WasmActivation* activation_;
     const Code* code_;
     const CodeRange* codeRange_;
-    uint8_t* callerFP_;
+    void* callerFP_;
     void* callerPC_;
     void* stackAddress_;
     ExitReason exitReason_;
 
-    void initFromFP();
+    void initFromExitFP();
 
   public:
     ProfilingFrameIterator();
diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp
index 2994a96ca416..46e4fa0fe84a 100644
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -623,7 +623,7 @@ ModuleGenerator::finishCodegen()
         return false;
 
     throwStub.offsetBy(offsetInWhole);
-    if (!metadata_->codeRanges.emplaceBack(CodeRange::Inline, throwStub))
+    if (!metadata_->codeRanges.emplaceBack(CodeRange::Throw, throwStub))
         return false;
 
     debugTrapStub.offsetBy(offsetInWhole);
diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp
index fa185f27cc8a..7938395974cc 100644
--- a/js/src/wasm/WasmIonCompile.cpp
+++ b/js/src/wasm/WasmIonCompile.cpp
@@ -1140,7 +1140,7 @@ class FunctionCompiler
         if (inDeadCode())
             return;
 
-        MWasmReturn* ins = MWasmReturn::New(alloc(), operand, tlsPointer_);
+        MWasmReturn* ins = MWasmReturn::New(alloc(), operand);
         curBlock_->end(ins);
         curBlock_ = nullptr;
     }
@@ -1150,7 +1150,7 @@ class FunctionCompiler
         if (inDeadCode())
             return;
 
-        MWasmReturnVoid* ins = MWasmReturnVoid::New(alloc(), tlsPointer_);
+        MWasmReturnVoid* ins = MWasmReturnVoid::New(alloc());
         curBlock_->end(ins);
         curBlock_ = nullptr;
     }
diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp
index 60da82cd7a3b..8c28d98981ac 100644
--- a/js/src/wasm/WasmStubs.cpp
+++ b/js/src/wasm/WasmStubs.cpp
@@ -262,12 +262,25 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe)
         }
     }
 
+    // Set the FramePointer to null for the benefit of debugging.
+    masm.movePtr(ImmWord(0), FramePointer);
+
     // Call into the real function.
     masm.assertStackAlignment(WasmStackAlignment);
     masm.call(CallSiteDesc(CallSiteDesc::Func), fe.funcIndex());
+    masm.assertStackAlignment(WasmStackAlignment);
+
+#ifdef DEBUG
+    // Assert FramePointer was returned to null by the callee.
+    Label ok;
+    masm.branchTestPtr(Assembler::Zero, FramePointer, FramePointer, &ok);
+    masm.breakpoint();
+    masm.bind(&ok);
+#endif
 
     // Recover the stack pointer value before dynamic alignment.
     masm.loadWasmActivationFromTls(scratch);
+    masm.wasmAssertNonExitInvariants(scratch);
     masm.loadStackPtr(Address(scratch, WasmActivation::offsetOfEntrySP()));
     masm.setFramePushed(FramePushedForEntrySP);
 
@@ -704,9 +717,11 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
     masm.callJitNoProfiler(callee);
     AssertStackAlignment(masm, JitStackAlignment, sizeOfRetAddr);
 
-    // Reload the TLS reg which has been clobbered by Ion code. The TLS reg is
-    // non-volatile and so preserved by the native-ABI calls below.
+    // The JIT callee clobbers all registers, including WasmTlsReg and
+    // FrameRegister, so restore those here.
     masm.loadWasmTlsRegFromFrame();
+    masm.moveStackPtrTo(FramePointer);
+    masm.addPtr(Imm32(masm.framePushed()), FramePointer);
 
     {
         // Disable Activation.
@@ -888,11 +903,11 @@ wasm::GenerateTrapExit(MacroAssembler& masm, Trap trap, Label* throwLabel)
 // Generate a stub which is only used by the signal handlers to handle out of
 // bounds access by experimental SIMD.js and Atomics and unaligned accesses on
 // ARM. This stub is executed by direct PC transfer from the faulting memory
-// access and thus the stack depth is unknown. Since WasmActivation::fp is not
-// set before calling the error reporter, the current wasm activation will be
-// lost. This stub should be removed when SIMD.js and Atomics are moved to wasm
-// and given proper traps and when we use a non-faulting strategy for unaligned
-// ARM access.
+// access and thus the stack depth is unknown. Since WasmActivation::exitFP is
+// not set before calling the error reporter, the current wasm activation will
+// be lost. This stub should be removed when SIMD.js and Atomics are moved to
+// wasm and given proper traps and when we use a non-faulting strategy for
+// unaligned ARM access.
 static Offsets
 GenerateGenericMemoryAccessTrap(MacroAssembler& masm, SymbolicAddress reporter, Label* throwLabel)
 {
@@ -1109,16 +1124,7 @@ wasm::GenerateThrowStub(MacroAssembler& masm, Label* throwLabel)
 
     // HandleThrow returns the innermost WasmActivation* in ReturnReg.
     Register act = ReturnReg;
-
-#ifdef DEBUG
-    // We are about to pop all frames in this WasmActivation. Checking if fp is
-    // set to null to maintain the invariant that fp is either null or pointing
-    // to a valid frame.
-    Label ok;
-    masm.branchPtr(Assembler::Equal, Address(act, WasmActivation::offsetOfFP()), ImmWord(0), &ok);
-    masm.breakpoint();
-    masm.bind(&ok);
-#endif
+    masm.wasmAssertNonExitInvariants(act);
 
     masm.setFramePushed(FramePushedForEntrySP);
     masm.loadStackPtr(Address(act, WasmActivation::offsetOfEntrySP()));
diff --git a/js/src/wasm/WasmTypes.cpp b/js/src/wasm/WasmTypes.cpp
index 7f55eacdb7d4..b117f65a530c 100644
--- a/js/src/wasm/WasmTypes.cpp
+++ b/js/src/wasm/WasmTypes.cpp
@@ -174,8 +174,8 @@ WasmHandleThrow()
     MOZ_ASSERT(activation);
 
     // FrameIterator iterates down wasm frames in the activation starting at
-    // WasmActivation::fp. Pass Unwind::True to pop WasmActivation::fp once each
-    // time FrameIterator is incremented, ultimately leaving WasmActivation::fp
+    // WasmActivation::exitFP. Pass Unwind::True to pop WasmActivation::exitFP
+    // once each time FrameIterator is incremented, ultimately leaving exitFP
     // null when the FrameIterator is done(). This is necessary to prevent a
     // DebugFrame from being observed again after we just called onLeaveFrame
     // (which would lead to the frame being re-added to the map of live frames,
diff --git a/js/src/wasm/WasmTypes.h b/js/src/wasm/WasmTypes.h
index 39d11dcb0d25..899c6ae23fbb 100644
--- a/js/src/wasm/WasmTypes.h
+++ b/js/src/wasm/WasmTypes.h
@@ -1458,8 +1458,7 @@ struct Frame
     // effectively the callee's instance.
     TlsData* tls;
 
-    // The value of WasmActivation::fp on entry to the function (before being
-    // overwritten by this Frame's address).
+    // The caller's Frame*.
     uint8_t* callerFP;
 
     // The return address pushed by the call (in the case of ARM/MIPS the return
diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp
index 2ee40057e5b6..769cc6166a29 100644
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -535,6 +535,7 @@ MergeStacksIntoProfile(ProfileBuffer* aBuffer, TickSample* aSample,
       registerState.pc = aSample->pc;
       registerState.sp = aSample->sp;
       registerState.lr = aSample->lr;
+      registerState.fp = aSample->fp;
 
       JS::ProfilingFrameIterator jsIter(pseudoStack->mContext,
                                         registerState,

From 888ae610aa9b987c29cd8b9ba109f7a7d5699a2d Mon Sep 17 00:00:00 2001
From: Luke Wagner 
Date: Wed, 22 Mar 2017 17:26:55 -0500
Subject: [PATCH 31/96] Bug 1334504 - Baldr: move reload of TLS out of bloaty
 out-of-line paths (r=bbouvier)

MozReview-Commit-ID: 5u8qNfxK1fC

--HG--
extra : rebase_source : c8aced29c17b64a59bb6860e488d0e04cdd0e031
---
 js/src/jit-test/tests/wasm/profiling.js |  2 +-
 js/src/jit/MacroAssembler.cpp           |  7 ++++---
 js/src/wasm/WasmGenerator.cpp           | 17 +++++------------
 js/src/wasm/WasmGenerator.h             |  2 +-
 4 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/js/src/jit-test/tests/wasm/profiling.js b/js/src/jit-test/tests/wasm/profiling.js
index 6d81add93492..45b169e70b40 100644
--- a/js/src/jit-test/tests/wasm/profiling.js
+++ b/js/src/jit-test/tests/wasm/profiling.js
@@ -125,7 +125,7 @@ testError(
     (func (export "") (call $foo))
 )`,
 WebAssembly.RuntimeError,
-["", ">", "1,>", "0,1,>", "trap handling,0,1,>", ""]);
+["", ">", "1,>", "0,1,>", "interstitial,0,1,>", "trap handling,0,1,>", ""]);
 
 testError(
 `(module
diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp
index d3f70e1064cd..72723f337bdb 100644
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2934,9 +2934,10 @@ MacroAssembler::wasmEmitTrapOutOfLineCode()
             // To call the trap handler function, we must have the WasmTlsReg
             // filled since this is the normal calling ABI. To avoid requiring
             // every trapping operation to have the TLS register filled for the
-            // rare case that it takes a trap, we instead restore it here on the
-            // out-of-line path.
-            loadWasmTlsRegFromFrame();
+            // rare case that it takes a trap, we restore it from the frame on
+            // the out-of-line path. However, there are millions of out-of-line
+            // paths (viz. for loads/stores), so the load is factored out into
+            // the shared FarJumpIsland generated by patchCallSites.
 
             // Call the trap's exit, using the bytecode offset of the trap site.
             // Note that this code is inside the same CodeRange::Function as the
diff --git a/js/src/wasm/WasmGenerator.cpp b/js/src/wasm/WasmGenerator.cpp
index 46e4fa0fe84a..9cb645c91270 100644
--- a/js/src/wasm/WasmGenerator.cpp
+++ b/js/src/wasm/WasmGenerator.cpp
@@ -309,7 +309,7 @@ JumpRange()
 typedef HashMap, SystemAllocPolicy> OffsetMap;
 
 bool
-ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits)
+ModuleGenerator::patchCallSites()
 {
     masm_.haltingAlign(CodeAlignment);
 
@@ -366,19 +366,12 @@ ModuleGenerator::patchCallSites(TrapExitOffsetArray* maybeTrapExits)
             break;
           }
           case CallSiteDesc::TrapExit: {
-            if (maybeTrapExits) {
-                uint32_t calleeOffset = (*maybeTrapExits)[cs.trap()].begin;
-                MOZ_RELEASE_ASSERT(calleeOffset < INT32_MAX);
-
-                if (uint32_t(abs(int32_t(calleeOffset) - int32_t(callerOffset))) < JumpRange()) {
-                    masm_.patchCall(callerOffset, calleeOffset);
-                    break;
-                }
-            }
-
             if (!existingTrapFarJumps[cs.trap()]) {
+                // See MacroAssembler::wasmEmitTrapOutOfLineCode for why we must
+                // reload the TLS register on this path.
                 Offsets offsets;
                 offsets.begin = masm_.currentOffset();
+                masm_.loadPtr(Address(FramePointer, offsetof(Frame, tls)), WasmTlsReg);
                 masm_.append(TrapFarJump(cs.trap(), masm_.farJumpWithPatch()));
                 offsets.end = masm_.currentOffset();
                 if (masm_.oom())
@@ -640,7 +633,7 @@ ModuleGenerator::finishCodegen()
     // then far jumps. Patching callsites can generate far jumps so there is an
     // ordering dependency.
 
-    if (!patchCallSites(&trapExits))
+    if (!patchCallSites())
         return false;
 
     if (!patchFarJumps(trapExits, debugTrapStub))
diff --git a/js/src/wasm/WasmGenerator.h b/js/src/wasm/WasmGenerator.h
index e9f6595fdae0..6a820525b27a 100644
--- a/js/src/wasm/WasmGenerator.h
+++ b/js/src/wasm/WasmGenerator.h
@@ -257,7 +257,7 @@ class MOZ_STACK_CLASS ModuleGenerator
     bool funcIsCompiled(uint32_t funcIndex) const;
     const CodeRange& funcCodeRange(uint32_t funcIndex) const;
     uint32_t numFuncImports() const;
-    MOZ_MUST_USE bool patchCallSites(TrapExitOffsetArray* maybeTrapExits = nullptr);
+    MOZ_MUST_USE bool patchCallSites();
     MOZ_MUST_USE bool patchFarJumps(const TrapExitOffsetArray& trapExits, const Offsets& debugTrapStub);
     MOZ_MUST_USE bool finishTask(CompileTask* task);
     MOZ_MUST_USE bool finishOutstandingTask();

From 736ff34e7cd38cea61c5c28c95449fa034c496e0 Mon Sep 17 00:00:00 2001
From: Sebastian Hengst 
Date: Wed, 22 Mar 2017 23:47:25 +0100
Subject: [PATCH 32/96] Backed out changeset 421407ec02c0 (bug 1338277) for
 failing its own crashtest. r=backout

---
 dom/xslt/crashtests/1338277.html    | 21 ---------------------
 dom/xslt/crashtests/crashtests.list |  1 -
 dom/xslt/xslt/txExecutionState.cpp  |  4 +---
 3 files changed, 1 insertion(+), 25 deletions(-)
 delete mode 100644 dom/xslt/crashtests/1338277.html

diff --git a/dom/xslt/crashtests/1338277.html b/dom/xslt/crashtests/1338277.html
deleted file mode 100644
index d928819c7572..000000000000
--- a/dom/xslt/crashtests/1338277.html
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
diff --git a/dom/xslt/crashtests/crashtests.list b/dom/xslt/crashtests/crashtests.list
index 8e9a9e72dbdf..5958655d6473 100644
--- a/dom/xslt/crashtests/crashtests.list
+++ b/dom/xslt/crashtests/crashtests.list
@@ -18,4 +18,3 @@ load 667315.xml
 load 1089049.html
 load 1205163.xml
 load 1243337.xml
-load 1338277.html
diff --git a/dom/xslt/xslt/txExecutionState.cpp b/dom/xslt/xslt/txExecutionState.cpp
index f7286a0e5d77..a32fdb0b8065 100644
--- a/dom/xslt/xslt/txExecutionState.cpp
+++ b/dom/xslt/xslt/txExecutionState.cpp
@@ -529,9 +529,7 @@ txExecutionState::bindVariable(const txExpandedName& aName,
 void
 txExecutionState::removeVariable(const txExpandedName& aName)
 {
-    if (mLocalVariables) {
-      mLocalVariables->removeVariable(aName);
-    }
+    mLocalVariables->removeVariable(aName);
 }
 
 nsresult

From 1d35364a0b16df8945de30a2eaba7018ff69742b Mon Sep 17 00:00:00 2001
From: Steve Fink 
Date: Wed, 22 Mar 2017 14:03:53 -0700
Subject: [PATCH 33/96] Bug 1330746 - Disable terminal-style output when
 running within emacs, r=qdot

MozReview-Commit-ID: CgjgL91alUa

--HG--
extra : rebase_source : ba00d397e310d1f3159ff2239ebc3c158184305c
---
 python/mozbuild/mozbuild/mach_commands.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/python/mozbuild/mozbuild/mach_commands.py b/python/mozbuild/mozbuild/mach_commands.py
index 4ae31ba3d79d..6f9323be70fa 100644
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -210,6 +210,8 @@ class BuildOutputManager(LoggingMixin):
         # TODO convert terminal footer to config file setting.
         if not terminal or os.environ.get('MACH_NO_TERMINAL_FOOTER', None):
             return
+        if os.environ.get('INSIDE_EMACS', None):
+            return
 
         self.t = terminal
         self.footer = BuildProgressFooter(terminal, monitor)

From 4d101075eea950f7c6155b0082a5d59112f30d11 Mon Sep 17 00:00:00 2001
From: Stanford Lockhart 
Date: Wed, 1 Mar 2017 08:58:12 -0400
Subject: [PATCH 34/96] Bug 1292051 - Part 2: Add unit tests for properties
 under the box model. r=gl

MozReview-Commit-ID: K99iGuucH1I
---
 .../boxmodel/components/ComputedProperty.js   |   1 +
 .../inspector/boxmodel/test/browser.ini       |   1 +
 .../test/browser_boxmodel_properties.js       | 120 ++++++++++++++++++
 .../client/inspector/boxmodel/test/head.js    |  32 +++++
 devtools/client/inspector/inspector.js        |   8 ++
 5 files changed, 162 insertions(+)
 create mode 100644 devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js

diff --git a/devtools/client/inspector/boxmodel/components/ComputedProperty.js b/devtools/client/inspector/boxmodel/components/ComputedProperty.js
index 87fef1a3d4c2..262258ba6184 100644
--- a/devtools/client/inspector/boxmodel/components/ComputedProperty.js
+++ b/devtools/client/inspector/boxmodel/components/ComputedProperty.js
@@ -28,6 +28,7 @@ module.exports = createClass({
     return dom.div(
       {
         className: "property-view",
+        "data-property-name": name,
         tabIndex: "0",
         ref: container => {
           this.container = container;
diff --git a/devtools/client/inspector/boxmodel/test/browser.ini b/devtools/client/inspector/boxmodel/test/browser.ini
index c9881c903937..ba05da95490b 100644
--- a/devtools/client/inspector/boxmodel/test/browser.ini
+++ b/devtools/client/inspector/boxmodel/test/browser.ini
@@ -22,6 +22,7 @@ support-files =
 [browser_boxmodel_guides.js]
 [browser_boxmodel_navigation.js]
 skip-if = true # Bug 1336198
+[browser_boxmodel_properties.js]
 [browser_boxmodel_rotate-labels-on-sides.js]
 [browser_boxmodel_sync.js]
 [browser_boxmodel_tooltips.js]
diff --git a/devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js b/devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js
new file mode 100644
index 000000000000..95479f756538
--- /dev/null
+++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel_properties.js
@@ -0,0 +1,120 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test that the box model properties list displays the right values
+// and that it updates when the node's style is changed.
+
+const TEST_URI = `
+  
+  
Test Node
+`; + +const res1 = [ + { + property: "box-sizing", + value: "border-box" + }, + { + property: "display", + value: "block" + }, + { + property: "float", + value: "left" + }, + { + property: "line-height", + value: "20px" + }, + { + property: "position", + value: "relative" + }, + { + property: "z-index", + value: 2 + }, +]; + +const res2 = [ + { + property: "box-sizing", + value: "content-box" + }, + { + property: "display", + value: "block" + }, + { + property: "float", + value: "right" + }, + { + property: "line-height", + value: "10px" + }, + { + property: "position", + value: "static" + }, + { + property: "z-index", + value: 5 + }, +]; + +add_task(function* () { + yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI)); + let { inspector, boxmodel, testActor } = yield openLayoutView(); + yield selectNode("div", inspector); + + yield testInitialValues(inspector, boxmodel); + yield testChangingValues(inspector, boxmodel, testActor); +}); + +function* testInitialValues(inspector, boxmodel) { + info("Test that the initial values of the box model are correct"); + let doc = boxmodel.document; + + for (let { property, value } of res1) { + let elt = doc.querySelector(getPropertySelector(property)); + is(elt.textContent, value, property + " has the right value."); + } +} + +function* testChangingValues(inspector, boxmodel, testActor) { + info("Test that changing the document updates the box model"); + let doc = boxmodel.document; + + let onUpdated = waitForUpdate(inspector); + yield testActor.setAttribute("div", "style", + "box-sizing:content-box;float:right;" + + "line-height:10px;position:static;z-index:5;"); + yield onUpdated; + + for (let { property, value } of res2) { + let elt = doc.querySelector(getPropertySelector(property)); + is(elt.textContent, value, property + " has the right value after style update."); + } +} + +function getPropertySelector(propertyName) { + return `.boxmodel-properties-wrapper .property-view` + + `[data-property-name=${propertyName}] .property-value`; +} diff --git a/devtools/client/inspector/boxmodel/test/head.js b/devtools/client/inspector/boxmodel/test/head.js index b842968a5595..4df6e686a28e 100644 --- a/devtools/client/inspector/boxmodel/test/head.js +++ b/devtools/client/inspector/boxmodel/test/head.js @@ -11,8 +11,10 @@ Services.scriptloader.loadSubScript( "chrome://mochitests/content/browser/devtools/client/inspector/test/head.js", this); +Services.prefs.setBoolPref("devtools.layoutview.enabled", true); Services.prefs.setIntPref("devtools.toolbox.footer.height", 350); registerCleanupFunction(() => { + Services.prefs.clearUserPref("devtools.layoutview.enabled"); Services.prefs.clearUserPref("devtools.toolbox.footer.height"); }); @@ -66,6 +68,36 @@ function openBoxModelView() { }); } +/** + * Open the toolbox, with the inspector tool visible, and the layout view + * sidebar tab selected to display the box model view with properties. + * + * @return {Promise} a promise that resolves when the inspector is ready and the box model + * view is visible and ready. + */ +function openLayoutView() { + return openInspectorSidebarTab("layoutview").then(data => { + // The actual highligher show/hide methods are mocked in box model tests. + // The highlighter is tested in devtools/inspector/test. + function mockHighlighter({highlighter}) { + highlighter.showBoxModel = function () { + return promise.resolve(); + }; + highlighter.hideBoxModel = function () { + return promise.resolve(); + }; + } + mockHighlighter(data.toolbox); + + return { + toolbox: data.toolbox, + inspector: data.inspector, + boxmodel: data.inspector.boxmodel, + testActor: data.testActor + }; + }); +} + /** * Wait for the boxmodel-view-updated event. * diff --git a/devtools/client/inspector/inspector.js b/devtools/client/inspector/inspector.js index b58dce429004..349945a49cae 100644 --- a/devtools/client/inspector/inspector.js +++ b/devtools/client/inspector/inspector.js @@ -926,10 +926,18 @@ Inspector.prototype = { this.ruleview.destroy(); } + if (this.boxmodel) { + this.boxmodel.destroy(); + } + if (this.computedview) { this.computedview.destroy(); } + if (this.gridInspector) { + this.gridInspector.destroy(); + } + if (this.layoutview) { this.layoutview.destroy(); } From e9975370e74834d72eb16dd7895b4071f7b53824 Mon Sep 17 00:00:00 2001 From: Sean Stangl Date: Tue, 21 Mar 2017 12:12:15 -0400 Subject: [PATCH 35/96] Bug 1342016 - Fast-path for isObservableSlot(). r=nbp --- js/src/jit/CompileInfo.h | 16 ++++++++++------ js/src/jit/IonAnalysis.cpp | 14 ++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/js/src/jit/CompileInfo.h b/js/src/jit/CompileInfo.h index a73677c14d54..92210679e092 100644 --- a/js/src/jit/CompileInfo.h +++ b/js/src/jit/CompileInfo.h @@ -447,14 +447,18 @@ class CompileInfo // the frame is active on the stack. This implies that these definitions // would have to be executed and that they cannot be removed even if they // are unused. - bool isObservableSlot(uint32_t slot) const { - if (isObservableFrameSlot(slot)) - return true; + inline bool isObservableSlot(uint32_t slot) const { + if (slot >= firstLocalSlot()) { + // The |this| slot for a derived class constructor is a local slot. + if (thisSlotForDerivedClassConstructor_) + return *thisSlotForDerivedClassConstructor_ == slot; + return false; + } - if (isObservableArgumentSlot(slot)) - return true; + if (slot < firstArgSlot()) + return isObservableFrameSlot(slot); - return false; + return isObservableArgumentSlot(slot); } bool isObservableFrameSlot(uint32_t slot) const { diff --git a/js/src/jit/IonAnalysis.cpp b/js/src/jit/IonAnalysis.cpp index 7de6715b4398..28c5460c8a05 100644 --- a/js/src/jit/IonAnalysis.cpp +++ b/js/src/jit/IonAnalysis.cpp @@ -196,6 +196,8 @@ FlagPhiInputsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block, MBasicBl static bool FlagAllOperandsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block) { + const CompileInfo& info = block->info(); + // Flag all instructions operands as having removed uses. MInstructionIterator end = block->end(); for (MInstructionIterator it = block->begin(); it != end; it++) { @@ -210,8 +212,10 @@ FlagAllOperandsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block) if (MResumePoint* rp = ins->resumePoint()) { // Note: no need to iterate over the caller's of the resume point as // this is the same as the entry resume point. - for (size_t i = 0, e = rp->numOperands(); i < e; i++) - rp->getOperand(i)->setUseRemovedUnchecked(); + for (size_t i = 0, e = rp->numOperands(); i < e; i++) { + if (info.isObservableSlot(i)) + rp->getOperand(i)->setUseRemovedUnchecked(); + } } } @@ -221,8 +225,10 @@ FlagAllOperandsAsHavingRemovedUses(MIRGenerator* mir, MBasicBlock* block) if (mir->shouldCancel("FlagAllOperandsAsHavingRemovedUses loop 2")) return false; - for (size_t i = 0, e = rp->numOperands(); i < e; i++) - rp->getOperand(i)->setUseRemovedUnchecked(); + for (size_t i = 0, e = rp->numOperands(); i < e; i++) { + if (info.isObservableSlot(i)) + rp->getOperand(i)->setUseRemovedUnchecked(); + } rp = rp->caller(); } From 9bb7aa8e77a9f1b5fe47159b509c30bb913de7c2 Mon Sep 17 00:00:00 2001 From: Sheldon Roddick Date: Tue, 14 Mar 2017 23:58:53 -0700 Subject: [PATCH 36/96] Bug 1061823 - Allow to edit width and height in the box model. r=gl --- .../boxmodel/components/BoxModelEditable.js | 10 ++-- .../boxmodel/components/BoxModelMain.js | 50 ++++++++++++++----- .../boxmodel/test/browser_boxmodel.js | 16 ++++-- .../boxmodel/test/doc_boxmodel_iframe2.html | 4 +- devtools/client/themes/boxmodel.css | 20 +++++--- 5 files changed, 70 insertions(+), 30 deletions(-) diff --git a/devtools/client/inspector/boxmodel/components/BoxModelEditable.js b/devtools/client/inspector/boxmodel/components/BoxModelEditable.js index f90954d5ffe5..9b20cd560338 100644 --- a/devtools/client/inspector/boxmodel/components/BoxModelEditable.js +++ b/devtools/client/inspector/boxmodel/components/BoxModelEditable.js @@ -16,7 +16,7 @@ module.exports = createClass({ propTypes: { box: PropTypes.string.isRequired, - direction: PropTypes.string.isRequired, + direction: PropTypes.string, property: PropTypes.string.isRequired, textContent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, onShowBoxModelEditor: PropTypes.func.isRequired, @@ -42,13 +42,15 @@ module.exports = createClass({ textContent, } = this.props; - let rotate = (direction == "left" || direction == "right") && + let rotate = direction && + (direction == "left" || direction == "right") && textContent.toString().length > LONG_TEXT_ROTATE_LIMIT; return dom.p( { - className: `boxmodel-${box} boxmodel-${direction} - ${rotate ? "boxmodel-rotate" : ""}`, + className: `boxmodel-${box} + ${direction ? " boxmodel-" + direction : "boxmodel-" + property} + ${rotate ? " boxmodel-rotate" : ""}`, }, dom.span( { diff --git a/devtools/client/inspector/boxmodel/components/BoxModelMain.js b/devtools/client/inspector/boxmodel/components/BoxModelMain.js index 37581a630cae..07a4c84ab4b5 100644 --- a/devtools/client/inspector/boxmodel/components/BoxModelMain.js +++ b/devtools/client/inspector/boxmodel/components/BoxModelMain.js @@ -134,6 +134,41 @@ module.exports = createClass({ height = this.getHeightValue(height); width = this.getWidthValue(width); + let contentBox = layout["box-sizing"] == "content-box" ? + dom.p( + { + className: "boxmodel-size", + }, + BoxModelEditable({ + box: "content", + property: "width", + textContent: width, + onShowBoxModelEditor + }), + dom.span( + {}, + "\u00D7" + ), + BoxModelEditable({ + box: "content", + property: "height", + textContent: height, + onShowBoxModelEditor + }) + ) + : + dom.p( + { + className: "boxmodel-size", + }, + dom.span( + { + title: BOXMODEL_L10N.getStr("boxmodel.content"), + }, + SHARED_L10N.getFormatStr("dimensions", width, height) + ) + ); + return dom.div( { className: "boxmodel-main", @@ -198,7 +233,7 @@ module.exports = createClass({ title: BOXMODEL_L10N.getStr("boxmodel.padding"), }, dom.div({ - className: "boxmodel-content", + className: "boxmodel-contents", "data-box": "content", title: BOXMODEL_L10N.getStr("boxmodel.content"), }) @@ -330,18 +365,7 @@ module.exports = createClass({ textContent: paddingLeft, onShowBoxModelEditor, }), - dom.p( - { - className: "boxmodel-size", - }, - dom.span( - { - "data-box": "content", - title: BOXMODEL_L10N.getStr("boxmodel.content"), - }, - SHARED_L10N.getFormatStr("dimensions", width, height) - ) - ) + contentBox ); }, diff --git a/devtools/client/inspector/boxmodel/test/browser_boxmodel.js b/devtools/client/inspector/boxmodel/test/browser_boxmodel.js index 9e085cafe232..3ad67b4da72d 100644 --- a/devtools/client/inspector/boxmodel/test/browser_boxmodel.js +++ b/devtools/client/inspector/boxmodel/test/browser_boxmodel.js @@ -14,8 +14,12 @@ var res1 = [ value: "160" + "\u00D7" + "160.117" }, { - selector: ".boxmodel-size > span", - value: "100" + "\u00D7" + "100.117" + selector: ".boxmodel-size > .boxmodel-width", + value: "100" + }, + { + selector: ".boxmodel-size > .boxmodel-height", + value: "100.117" }, { selector: ".boxmodel-margin.boxmodel-top > span", @@ -73,8 +77,12 @@ var res2 = [ value: "190" + "\u00D7" + "210" }, { - selector: ".boxmodel-size > span", - value: "100" + "\u00D7" + "150" + selector: ".boxmodel-size > .boxmodel-width", + value: "100" + }, + { + selector: ".boxmodel-size > .boxmodel-height", + value: "150" }, { selector: ".boxmodel-margin.boxmodel-top > span", diff --git a/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html b/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html index 1f1b0463c3d4..0fa6dc02e97d 100644 --- a/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html +++ b/devtools/client/inspector/boxmodel/test/doc_boxmodel_iframe2.html @@ -1,3 +1,3 @@ -

iframe 1

- +

iframe 1

+ diff --git a/devtools/client/themes/boxmodel.css b/devtools/client/themes/boxmodel.css index d8e2b4d31efd..4cef659de5aa 100644 --- a/devtools/client/themes/boxmodel.css +++ b/devtools/client/themes/boxmodel.css @@ -52,7 +52,7 @@ /* Regions are 3 nested elements with wide borders and outlines */ -.boxmodel-content { +.boxmodel-contents { height: 18px; } @@ -84,7 +84,7 @@ border-color: #6a5acd; } -.boxmodel-content { +.boxmodel-contents { background-color: #87ceeb; } @@ -104,7 +104,8 @@ /* Editable region sizes are contained in absolutely positioned

*/ -.boxmodel-main > p { +.boxmodel-main > p, +.boxmodel-size { position: absolute; pointer-events: none; margin: 0; @@ -112,7 +113,8 @@ } .boxmodel-main > p > span, -.boxmodel-main > p > input { +.boxmodel-main > p > input, +.boxmodel-content { vertical-align: middle; pointer-events: auto; } @@ -172,8 +174,8 @@ .boxmodel-position.boxmodel-right, .boxmodel-margin.boxmodel-right, .boxmodel-margin.boxmodel-left, -.boxmodel-border.boxmodel-left, .boxmodel-border.boxmodel-right, +.boxmodel-border.boxmodel-left, .boxmodel-padding.boxmodel-right, .boxmodel-padding.boxmodel-left { width: 21px; @@ -218,6 +220,12 @@ height: 30px; } +.boxmodel-size > p { + display: inline-block; + margin: auto; + line-height: 0; +} + .boxmodel-rotate.boxmodel-right.boxmodel-position:not(.boxmodel-editing) { border-top: none; border-left: 1px solid var(--theme-highlight-purple); @@ -290,8 +298,6 @@ border-bottom-color: hsl(0, 0%, 50%); } -/* Make sure the content size doesn't appear as editable like the other sizes */ - .boxmodel-size > span { cursor: default; } From b98245c5fc0e45c01e757420f9f1ed0ce668ea94 Mon Sep 17 00:00:00 2001 From: sotaro Date: Thu, 23 Mar 2017 11:00:41 +0900 Subject: [PATCH 37/96] Bug 1349476 - Remove LayersBackend::LAYERS_D3D9 type r=mattwoodrow --- .../platforms/wmf/WMFVideoMFTManager.cpp | 23 ++++++++----------- dom/media/platforms/wmf/WMFVideoMFTManager.h | 4 ++-- gfx/layers/LayersTypes.h | 1 - gfx/layers/client/CanvasClient.cpp | 2 -- gfx/layers/client/ClientLayerManager.cpp | 1 - gfx/layers/client/ContentClient.cpp | 1 - gfx/tests/gtest/TestCompositor.cpp | 3 --- widget/GfxInfoBase.cpp | 2 -- widget/windows/nsWindow.cpp | 2 +- 9 files changed, 12 insertions(+), 27 deletions(-) diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp index 48fa812b32e7..5a4a65c77a0d 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp @@ -384,10 +384,9 @@ FindD3D9BlacklistedDLL() class CreateDXVAManagerEvent : public Runnable { public: - CreateDXVAManagerEvent(LayersBackend aBackend, - layers::KnowsCompositor* aKnowsCompositor, + CreateDXVAManagerEvent(layers::KnowsCompositor* aKnowsCompositor, nsCString& aFailureReason) - : mBackend(aBackend) + : mBackend(LayersBackend::LAYERS_D3D11) , mKnowsCompositor(aKnowsCompositor) , mFailureReason(aFailureReason) { @@ -435,7 +434,7 @@ public: }; bool -WMFVideoMFTManager::InitializeDXVA(bool aForceD3D9) +WMFVideoMFTManager::InitializeDXVA() { // If we use DXVA but aren't running with a D3D layer manager then the // readback of decoded video frames from GPU to CPU memory grinds painting @@ -447,17 +446,14 @@ WMFVideoMFTManager::InitializeDXVA(bool aForceD3D9) } MOZ_ASSERT(!mDXVA2Manager); LayersBackend backend = GetCompositorBackendType(mKnowsCompositor); - if (backend != LayersBackend::LAYERS_D3D9 - && backend != LayersBackend::LAYERS_D3D11) { + if (backend != LayersBackend::LAYERS_D3D11) { mDXVAFailureReason.AssignLiteral("Unsupported layers backend"); return false; } // The DXVA manager must be created on the main thread. RefPtr event = - new CreateDXVAManagerEvent(aForceD3D9 ? LayersBackend::LAYERS_D3D9 - : backend, - mKnowsCompositor, + new CreateDXVAManagerEvent(mKnowsCompositor, mDXVAFailureReason); if (NS_IsMainThread()) { @@ -499,7 +495,7 @@ WMFVideoMFTManager::Init() return false; } - bool success = InitInternal(/* aForceD3D9 = */ false); + bool success = InitInternal(); if (success && mDXVA2Manager) { // If we had some failures but eventually made it work, @@ -515,10 +511,10 @@ WMFVideoMFTManager::Init() } bool -WMFVideoMFTManager::InitInternal(bool aForceD3D9) +WMFVideoMFTManager::InitInternal() { mUseHwAccel = false; // default value; changed if D3D setup succeeds. - bool useDxva = InitializeDXVA(aForceD3D9); + bool useDxva = InitializeDXVA(); RefPtr decoder(new MFTDecoder()); @@ -869,8 +865,7 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample, nsIntRect pictureRegion = mVideoInfo.ScaledImageRect(videoWidth, videoHeight); LayersBackend backend = GetCompositorBackendType(mKnowsCompositor); - if (backend != LayersBackend::LAYERS_D3D9 && - backend != LayersBackend::LAYERS_D3D11) { + if (backend != LayersBackend::LAYERS_D3D11) { RefPtr v = VideoData::CreateAndCopyData(mVideoInfo, mImageContainer, diff --git a/dom/media/platforms/wmf/WMFVideoMFTManager.h b/dom/media/platforms/wmf/WMFVideoMFTManager.h index 74cc7857140e..60f51cfa6627 100644 --- a/dom/media/platforms/wmf/WMFVideoMFTManager.h +++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h @@ -69,9 +69,9 @@ public: private: bool ValidateVideoInfo(); - bool InitializeDXVA(bool aForceD3D9); + bool InitializeDXVA(); - bool InitInternal(bool aForceD3D9); + bool InitInternal(); HRESULT ConfigureVideoFrameGeometry(); diff --git a/gfx/layers/LayersTypes.h b/gfx/layers/LayersTypes.h index f9ac335c1c9b..adc70fefb9f3 100644 --- a/gfx/layers/LayersTypes.h +++ b/gfx/layers/LayersTypes.h @@ -46,7 +46,6 @@ enum class LayersBackend : int8_t { LAYERS_NONE = 0, LAYERS_BASIC, LAYERS_OPENGL, - LAYERS_D3D9, LAYERS_D3D11, LAYERS_CLIENT, LAYERS_WR, diff --git a/gfx/layers/client/CanvasClient.cpp b/gfx/layers/client/CanvasClient.cpp index 19683a6c82b3..03d406b5b924 100644 --- a/gfx/layers/client/CanvasClient.cpp +++ b/gfx/layers/client/CanvasClient.cpp @@ -336,9 +336,7 @@ TexClientFromReadback(SharedSurface* src, CompositableForwarder* allocator, // RB_SWAPPED doesn't work with D3D11. (bug 1051010) // RB_SWAPPED doesn't work with Basic. (bug ???????) - // RB_SWAPPED doesn't work with D3D9. (bug ???????) bool layersNeedsManualSwap = layersBackend == LayersBackend::LAYERS_BASIC || - layersBackend == LayersBackend::LAYERS_D3D9 || layersBackend == LayersBackend::LAYERS_D3D11; if (texClient->HasFlags(TextureFlags::RB_SWAPPED) && layersNeedsManualSwap) diff --git a/gfx/layers/client/ClientLayerManager.cpp b/gfx/layers/client/ClientLayerManager.cpp index 9a57682b0b5f..08fe6c4d2b13 100644 --- a/gfx/layers/client/ClientLayerManager.cpp +++ b/gfx/layers/client/ClientLayerManager.cpp @@ -826,7 +826,6 @@ ClientLayerManager::GetBackendName(nsAString& aName) case LayersBackend::LAYERS_NONE: aName.AssignLiteral("None"); return; case LayersBackend::LAYERS_BASIC: aName.AssignLiteral("Basic"); return; case LayersBackend::LAYERS_OPENGL: aName.AssignLiteral("OpenGL"); return; - case LayersBackend::LAYERS_D3D9: aName.AssignLiteral("Direct3D 9"); return; case LayersBackend::LAYERS_D3D11: { #ifdef XP_WIN if (DeviceManagerDx::Get()->IsWARP()) { diff --git a/gfx/layers/client/ContentClient.cpp b/gfx/layers/client/ContentClient.cpp index 69384ae7ebde..1d2840920d84 100644 --- a/gfx/layers/client/ContentClient.cpp +++ b/gfx/layers/client/ContentClient.cpp @@ -61,7 +61,6 @@ ContentClient::CreateContentClient(CompositableForwarder* aForwarder) { LayersBackend backend = aForwarder->GetCompositorBackendType(); if (backend != LayersBackend::LAYERS_OPENGL && - backend != LayersBackend::LAYERS_D3D9 && backend != LayersBackend::LAYERS_D3D11 && backend != LayersBackend::LAYERS_WR && backend != LayersBackend::LAYERS_BASIC) { diff --git a/gfx/tests/gtest/TestCompositor.cpp b/gfx/tests/gtest/TestCompositor.cpp index 816c0d011aee..0a8498bb6988 100644 --- a/gfx/tests/gtest/TestCompositor.cpp +++ b/gfx/tests/gtest/TestCompositor.cpp @@ -63,9 +63,6 @@ static already_AddRefed CreateTestCompositor(LayersBackend backend, } else if (backend == LayersBackend::LAYERS_D3D11) { //compositor = new CompositorD3D11(); MOZ_CRASH(); // No support yet - } else if (backend == LayersBackend::LAYERS_D3D9) { - //compositor = new CompositorD3D9(this, mWidget); - MOZ_CRASH(); // No support yet #endif } nsCString failureReason; diff --git a/widget/GfxInfoBase.cpp b/widget/GfxInfoBase.cpp index cf3974f8f0c9..c0443898d0f3 100644 --- a/widget/GfxInfoBase.cpp +++ b/widget/GfxInfoBase.cpp @@ -1194,8 +1194,6 @@ GetLayersBackendName(layers::LayersBackend aBackend) return "none"; case layers::LayersBackend::LAYERS_OPENGL: return "opengl"; - case layers::LayersBackend::LAYERS_D3D9: - return "d3d9"; case layers::LayersBackend::LAYERS_D3D11: return "d3d11"; case layers::LayersBackend::LAYERS_CLIENT: diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index 3314c75ca2f5..4fbb5b06cc65 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -1833,7 +1833,7 @@ nsWindow::Move(double aX, double aY) // region, some drivers or OSes may incorrectly copy into the clipped-out // area. if (IsPlugin() && - (!mLayerManager || mLayerManager->GetBackendType() == LayersBackend::LAYERS_D3D9) && + !mLayerManager && mClipRects && (mClipRectCount != 1 || !mClipRects[0].IsEqualInterior(LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height)))) { flags |= SWP_NOCOPYBITS; From f088324ed29583f7dcfc94e7c8da46c41f9ed46e Mon Sep 17 00:00:00 2001 From: Timothy Nikkel Date: Thu, 23 Mar 2017 00:02:54 -0500 Subject: [PATCH 38/96] Bug 1347302. Add animated image specific probes for several imagelib telemetry probes. r=aosmond f=bsmedberg --- image/RasterImage.cpp | 13 +++++++++ toolkit/components/telemetry/Histograms.json | 29 ++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index b98744850295..4fbc654c9122 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -107,6 +107,9 @@ RasterImage::~RasterImage() // Record Telemetry. Telemetry::Accumulate(Telemetry::IMAGE_DECODE_COUNT, mDecodeCount); + if (mAnimationState) { + Telemetry::Accumulate(Telemetry::IMAGE_ANIMATED_DECODE_COUNT, mDecodeCount); + } } nsresult @@ -1428,6 +1431,11 @@ RasterImage::Draw(gfxContext* aContext, TimeDuration drawLatency = TimeStamp::Now() - mDrawStartTime; Telemetry::Accumulate(Telemetry::IMAGE_DECODE_ON_DRAW_LATENCY, int32_t(drawLatency.ToMicroseconds())); + if (mAnimationState) { + Telemetry::Accumulate(Telemetry::IMAGE_ANIMATED_DECODE_ON_DRAW_LATENCY, + int32_t(drawLatency.ToMicroseconds())); + + } mDrawStartTime = TimeStamp(); } @@ -1677,6 +1685,11 @@ RasterImage::NotifyDecodeComplete(const DecoderFinalStatus& aStatus, Telemetry::Accumulate(Telemetry::IMAGE_DECODE_TIME, int32_t(aTelemetry.mDecodeTime.ToMicroseconds())); + if (mAnimationState) { + Telemetry::Accumulate(Telemetry::IMAGE_ANIMATED_DECODE_TIME, + int32_t(aTelemetry.mDecodeTime.ToMicroseconds())); + } + if (aTelemetry.mSpeedHistogram) { Telemetry::Accumulate(*aTelemetry.mSpeedHistogram, aTelemetry.Speed()); } diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 023d76f4fb28..6dd3f11dd891 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -1444,6 +1444,16 @@ "n_buckets": 100, "description": "Time spent decoding an image (us)" }, + "IMAGE_ANIMATED_DECODE_TIME": { + "alert_emails": ["gfx-telemetry-alerts@mozilla.com"], + "bug_numbers": [1347302], + "expires_in_version": "57", + "kind": "exponential", + "low": 50, + "high": 50000000, + "n_buckets": 100, + "description": "Time spent decoding an animated image (us)" + }, "IMAGE_DECODE_ON_DRAW_LATENCY": { "expires_in_version": "never", "kind": "exponential", @@ -1452,6 +1462,16 @@ "n_buckets": 100, "description": "Time from starting a decode to it showing up on the screen (us)" }, + "IMAGE_ANIMATED_DECODE_ON_DRAW_LATENCY": { + "alert_emails": ["gfx-telemetry-alerts@mozilla.com"], + "bug_numbers": [1347302], + "expires_in_version": "57", + "kind": "exponential", + "low": 50, + "high": 50000000, + "n_buckets": 100, + "description": "Time from starting a decode of an animated image to it showing up on the screen (us)" + }, "IMAGE_DECODE_CHUNKS": { "expires_in_version": "never", "kind": "exponential", @@ -1466,6 +1486,15 @@ "n_buckets": 50, "description": "Decode count" }, + "IMAGE_ANIMATED_DECODE_COUNT": { + "alert_emails": ["gfx-telemetry-alerts@mozilla.com"], + "bug_numbers": [1347302], + "expires_in_version": "57", + "kind": "exponential", + "high": 500, + "n_buckets": 50, + "description": "Decode count of animated images" + }, "IMAGE_DECODE_SPEED_JPEG": { "expires_in_version": "never", "kind": "exponential", From 3d98a47ed8420db8c438f9c564af1f8e9225d8eb Mon Sep 17 00:00:00 2001 From: Timothy Nikkel Date: Thu, 23 Mar 2017 00:02:54 -0500 Subject: [PATCH 39/96] Bug 1343341. Change GetTimeoutForFrame to return a Maybe, and make all callers deal with a lack of a return value. r=aosmond Do this to allow GetTimeoutForFrame to be called for frames that haven't been decoded yet. Propagate a Maybe result where it makes sense. The remaining callers just bail if they get no return value. Many of them can just assert that they get a return value because they already got the same frame, so the timeout has to be available. The logic is a little tricky because we have "Forever" timeouts that were sort of treated as error cases. --- image/FrameAnimator.cpp | 64 ++++++++++++++++++++++++++++------------- image/FrameAnimator.h | 10 ++++--- 2 files changed, 50 insertions(+), 24 deletions(-) diff --git a/image/FrameAnimator.cpp b/image/FrameAnimator.cpp index a3ed0a4a69e2..736d722d7a04 100644 --- a/image/FrameAnimator.cpp +++ b/image/FrameAnimator.cpp @@ -141,28 +141,33 @@ AnimationState::LoopLength() const // FrameAnimator implementation. /////////////////////////////////////////////////////////////////////////////// -TimeStamp +Maybe FrameAnimator::GetCurrentImgFrameEndTime(AnimationState& aState) const { TimeStamp currentFrameTime = aState.mCurrentAnimationFrameTime; - FrameTimeout timeout = GetTimeoutForFrame(aState.mCurrentAnimationFrameIndex); + Maybe timeout = GetTimeoutForFrame(aState, aState.mCurrentAnimationFrameIndex); - if (timeout == FrameTimeout::Forever()) { + if (timeout.isNothing()) { + MOZ_ASSERT(aState.GetHasBeenDecoded() && !aState.GetIsCurrentlyDecoded()); + return Nothing(); + } + + if (*timeout == FrameTimeout::Forever()) { // We need to return a sentinel value in this case, because our logic // doesn't work correctly if we have an infinitely long timeout. We use one // year in the future as the sentinel because it works with the loop in // RequestRefresh() below. // XXX(seth): It'd be preferable to make our logic work correctly with // infinitely long timeouts. - return TimeStamp::NowLoRes() + - TimeDuration::FromMilliseconds(31536000.0); + return Some(TimeStamp::NowLoRes() + + TimeDuration::FromMilliseconds(31536000.0)); } TimeDuration durationOfTimeout = - TimeDuration::FromMilliseconds(double(timeout.AsMilliseconds())); + TimeDuration::FromMilliseconds(double(timeout->AsMilliseconds())); TimeStamp currentFrameEndTime = currentFrameTime + durationOfTimeout; - return currentFrameEndTime; + return Some(currentFrameEndTime); } RefreshResult @@ -238,7 +243,11 @@ FrameAnimator::AdvanceFrame(AnimationState& aState, TimeStamp aTime) return ret; } - if (GetTimeoutForFrame(nextFrameIndex) == FrameTimeout::Forever()) { + Maybe nextFrameTimeout = GetTimeoutForFrame(aState, nextFrameIndex); + // GetTimeoutForFrame can only return none if frame doesn't exist, + // but we just got it above. + MOZ_ASSERT(nextFrameTimeout.isSome()); + if (*nextFrameTimeout == FrameTimeout::Forever()) { ret.mAnimationFinished = true; } @@ -252,7 +261,9 @@ FrameAnimator::AdvanceFrame(AnimationState& aState, TimeStamp aTime) // something went wrong, move on to next NS_WARNING("FrameAnimator::AdvanceFrame(): Compositing of frame failed"); nextFrame->SetCompositingFailed(true); - aState.mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(aState); + Maybe currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + MOZ_ASSERT(currentFrameEndTime.isSome()); + aState.mCurrentAnimationFrameTime = *currentFrameEndTime; aState.mCurrentAnimationFrameIndex = nextFrameIndex; return ret; @@ -261,7 +272,9 @@ FrameAnimator::AdvanceFrame(AnimationState& aState, TimeStamp aTime) nextFrame->SetCompositingFailed(false); } - aState.mCurrentAnimationFrameTime = GetCurrentImgFrameEndTime(aState); + Maybe currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + MOZ_ASSERT(currentFrameEndTime.isSome()); + aState.mCurrentAnimationFrameTime = *currentFrameEndTime; // If we can get closer to the current time by a multiple of the image's loop // time, we should. We can only do this if we're done decoding; otherwise, we @@ -301,10 +314,18 @@ FrameAnimator::RequestRefresh(AnimationState& aState, const TimeStamp& aTime) // only advance the frame if the current time is greater than or // equal to the current frame's end time. - TimeStamp currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + Maybe currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + if (currentFrameEndTime.isNothing()) { + MOZ_ASSERT(gfxPrefs::ImageMemAnimatedDiscardable()); + MOZ_ASSERT(aState.GetHasBeenDecoded() && !aState.GetIsCurrentlyDecoded()); + MOZ_ASSERT(aState.mCompositedFrameInvalid); + // Nothing we can do but wait for our previous current frame to be decoded + // again so we can determine what to do next. + return ret; + } - while (currentFrameEndTime <= aTime) { - TimeStamp oldFrameEndTime = currentFrameEndTime; + while (*currentFrameEndTime <= aTime) { + TimeStamp oldFrameEndTime = *currentFrameEndTime; RefreshResult frameRes = AdvanceFrame(aState, aTime); @@ -312,17 +333,19 @@ FrameAnimator::RequestRefresh(AnimationState& aState, const TimeStamp& aTime) ret.Accumulate(frameRes); currentFrameEndTime = GetCurrentImgFrameEndTime(aState); + // AdvanceFrame can't advance to a frame that doesn't exist yet. + MOZ_ASSERT(currentFrameEndTime.isSome()); // If we didn't advance a frame, and our frame end time didn't change, // then we need to break out of this loop & wait for the frame(s) // to finish downloading. - if (!frameRes.mFrameAdvanced && (currentFrameEndTime == oldFrameEndTime)) { + if (!frameRes.mFrameAdvanced && (*currentFrameEndTime == oldFrameEndTime)) { break; } } // Advanced to the correct frame, the composited frame is now valid to be drawn. - if (currentFrameEndTime > aTime) { + if (*currentFrameEndTime > aTime) { aState.mCompositedFrameInvalid = false; } @@ -371,17 +394,18 @@ FrameAnimator::GetCompositedFrame(AnimationState& aState) return result; } -FrameTimeout -FrameAnimator::GetTimeoutForFrame(uint32_t aFrameNum) const +Maybe +FrameAnimator::GetTimeoutForFrame(AnimationState& aState, + uint32_t aFrameNum) const { RawAccessFrameRef frame = GetRawFrame(aFrameNum); if (frame) { AnimationData data = frame->GetAnimationData(); - return data.mTimeout; + return Some(data.mTimeout); } - NS_WARNING("No frame; called GetTimeoutForFrame too early?"); - return FrameTimeout::FromRawMilliseconds(100); + MOZ_ASSERT(aState.mHasBeenDecoded && !aState.mIsCurrentlyDecoded); + return Nothing(); } static void diff --git a/image/FrameAnimator.h b/image/FrameAnimator.h index 998a79f66db3..2f1cbe9eacca 100644 --- a/image/FrameAnimator.h +++ b/image/FrameAnimator.h @@ -312,15 +312,17 @@ private: // methods */ RawAccessFrameRef GetRawFrame(uint32_t aFrameNum) const; - /// @return the given frame's timeout. - FrameTimeout GetTimeoutForFrame(uint32_t aFrameNum) const; + /// @return the given frame's timeout if it is available + Maybe GetTimeoutForFrame(AnimationState& aState, + uint32_t aFrameNum) const; /** * Get the time the frame we're currently displaying is supposed to end. * - * In the error case, returns an "infinity" timestamp. + * In the error case (like if the requested frame is not currently + * decoded), returns None(). */ - TimeStamp GetCurrentImgFrameEndTime(AnimationState& aState) const; + Maybe GetCurrentImgFrameEndTime(AnimationState& aState) const; bool DoBlend(gfx::IntRect* aDirtyRect, uint32_t aPrevFrameIndex, From f51576a84def3e4d4cf338026ab784160c3a6da2 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Wed, 22 Mar 2017 22:04:00 -0700 Subject: [PATCH 40/96] Bug 1348584 Default to 1.0 contrast for Skia backends if custom contrast dwrite param isn't supported by skia. r=emk --- gfx/thebes/gfxWindowsPlatform.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 7ad26449ae19..1410fb040298 100755 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -1217,6 +1217,14 @@ gfxWindowsPlatform::SetupClearTypeParams() } } + if (GetDefaultContentBackend() == BackendType::SKIA) { + // Skia doesn't support a contrast value outside of 0-1, so default to 1.0 + if (contrast < 0.0 || contrast > 1.0) { + NS_WARNING("Custom dwrite contrast not supported in Skia. Defaulting to 1.0."); + contrast = 1.0; + } + } + // For parameters that have not been explicitly set, // we copy values from default params (or our overridden value for contrast) if (gamma < 1.0 || gamma > 2.2) { From 15ee5f552de5d5ebb8cf5c6488c776a021504008 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Thu, 23 Mar 2017 07:19:55 +0100 Subject: [PATCH 41/96] Bug 1349572 - FileSystemSync must be able to work also with non nsISeekableStream, r=smaug --- dom/workers/FileReaderSync.cpp | 52 ++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/dom/workers/FileReaderSync.cpp b/dom/workers/FileReaderSync.cpp index 18efcb194c71..3d855aef9fd0 100644 --- a/dom/workers/FileReaderSync.cpp +++ b/dom/workers/FileReaderSync.cpp @@ -20,7 +20,8 @@ #include "nsError.h" #include "nsIConverterInputStream.h" #include "nsIInputStream.h" -#include "nsISeekableStream.h" +#include "nsIMultiplexInputStream.h" +#include "nsStringStream.h" #include "nsISupportsImpl.h" #include "nsNetUtil.h" #include "nsServiceManagerUtils.h" @@ -133,17 +134,23 @@ FileReaderSync::ReadAsText(Blob& aBlob, } nsAutoCString encoding; - unsigned char sniffBuf[3] = { 0, 0, 0 }; - uint32_t numRead; - aRv = stream->Read(reinterpret_cast(sniffBuf), - sizeof(sniffBuf), &numRead); + + nsAutoCString sniffBuf; + if (!sniffBuf.SetLength(3, fallible)) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return; + } + + uint32_t numRead = 0; + aRv = stream->Read(sniffBuf.BeginWriting(), sniffBuf.Length(), &numRead); if (NS_WARN_IF(aRv.Failed())) { return; } // The BOM sniffing is baked into the "decode" part of the Encoding // Standard, which the File API references. - if (!nsContentUtils::CheckForBOM(sniffBuf, numRead, encoding)) { + if (!nsContentUtils::CheckForBOM((const unsigned char*)sniffBuf.BeginReading(), + numRead, encoding)) { // BOM sniffing failed. Try the API argument. if (!aEncoding.WasPassed() || !EncodingUtils::FindEncodingForLabel(aEncoding.Value(), @@ -167,20 +174,35 @@ FileReaderSync::ReadAsText(Blob& aBlob, } } - nsCOMPtr seekable = do_QueryInterface(stream); - if (!seekable) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } + // Let's recreate the full stream using a: + // multiplexStream(stringStream + original stream) + // In theory, we could try to see if the inputStream is a nsISeekableStream, + // but this doesn't work correctly for nsPipe3 - See bug 1349570. - // Seek to 0 because to undo the BOM sniffing advance. UTF-8 and UTF-16 - // decoders will swallow the BOM. - aRv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); + nsCOMPtr stringStream; + aRv = NS_NewCStringInputStream(getter_AddRefs(stringStream), sniffBuf); if (NS_WARN_IF(aRv.Failed())) { return; } - aRv = ConvertStream(stream, encoding.get(), aResult); + nsCOMPtr multiplexStream = + do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1"); + if (NS_WARN_IF(!multiplexStream)) { + aRv.Throw(NS_ERROR_FAILURE); + return; + } + + aRv = multiplexStream->AppendStream(stringStream); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + aRv = multiplexStream->AppendStream(stream); + if (NS_WARN_IF(aRv.Failed())) { + return; + } + + aRv = ConvertStream(multiplexStream, encoding.get(), aResult); if (NS_WARN_IF(aRv.Failed())) { return; } From ad890360000674f8fbfbc842d9400e56157962e2 Mon Sep 17 00:00:00 2001 From: Cervantes Yu Date: Wed, 15 Mar 2017 18:20:30 +0800 Subject: [PATCH 42/96] Bug 1320134 - Part 1: Tracking TLS allocations for diagnosing out-of-TLS-slots crashes on Windows. r=froydnj This tracks TlsAlloc() and TlsFree() calls on Windows for diagnosing crashes when a proces reaches its limit (1088) for TLS slots. Tracking of TLS allocation is done by intercepting TlsAlloc() and TlsFree() in kernel32.dll. After initialization, we start tracking the number of allocated TLS slots. If the number of observed TLS allocations exceeds a high water mark, we record the stack when TlsAlloc() is called, and the recorded stacks gets serialized in a JSON string ready for crash annotation. MozReview-Commit-ID: 5fHVr0eiMy5 --- xpcom/build/TlsAllocationTracker.cpp | 251 +++++++++++++++++++++++++++ xpcom/build/TlsAllocationTracker.h | 27 +++ xpcom/build/moz.build | 2 + 3 files changed, 280 insertions(+) create mode 100644 xpcom/build/TlsAllocationTracker.cpp create mode 100644 xpcom/build/TlsAllocationTracker.h diff --git a/xpcom/build/TlsAllocationTracker.cpp b/xpcom/build/TlsAllocationTracker.cpp new file mode 100644 index 000000000000..5ba031bf0a94 --- /dev/null +++ b/xpcom/build/TlsAllocationTracker.cpp @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "TlsAllocationTracker.h" + +#include + +#include + +#include "mozilla/Atomics.h" +#include "mozilla/JSONWriter.h" +#include "mozilla/Move.h" +#include "mozilla/StackWalk.h" +#include "mozilla/StaticMutex.h" +#include "mozilla/StaticPtr.h" + +#include "nsDebug.h" +#include "nsHashKeys.h" +#include "nsString.h" +#include "nsTArray.h" +#include "nsTHashtable.h" +#include "nsWindowsDllInterceptor.h" + +namespace mozilla { +namespace { + +static StaticAutoPtr sTlsAllocationStacks; + +struct nsCStringWriter : public JSONWriteFunc { + explicit nsCStringWriter(nsCString* aData) + : mData(aData) + { + MOZ_ASSERT(mData); + } + + void Write(const char* aStr) + { + mData->AppendASCII(aStr); + } + + nsCString* mData; +}; + +// Start recording TlsAlloc() call stacks when we observed kStartTrackingTlsAt +// allocations. We choose this value close to the maximum number of TLS indexes +// in a Windows process, which is 1088, in the hope of catching TLS leaks +// without impacting normal users. +const uint32_t kStartTrackingTlsAt = 950; + +using stack_t = nsTArray; + +struct StackEntry : public nsUint32HashKey { + explicit StackEntry(KeyTypePointer aKey) + : nsUint32HashKey(aKey) + { } + + stack_t mStack; +}; + +using stacks_t = nsTHashtable; + +static StaticAutoPtr sRecentTlsAllocationStacks; + +static Atomic sInitialized; +static StaticMutex sMutex; +static Atomic sCurrentTlsSlots{0}; + +using TlsAllocFn = DWORD (WINAPI *)(); +using TlsFreeFn = BOOL (WINAPI *)(DWORD); + +TlsAllocFn gOriginalTlsAlloc; +TlsFreeFn gOriginalTlsFree; + +static void +MaybeRecordCurrentStack(DWORD aTlsIndex) +{ + if (sCurrentTlsSlots < kStartTrackingTlsAt) { + return; + } + + stack_t rawStack; + auto callback = [](uint32_t, void* aPC, void*, void* aClosure) { + auto stack = static_cast(aClosure); + stack->AppendElement(reinterpret_cast(aPC)); + }; + MozStackWalk(callback, /* skip 2 frames */ 2, + /* maxFrames */ 0, &rawStack, 0, nullptr); + + StaticMutexAutoLock lock(sMutex); + if (!sRecentTlsAllocationStacks) { + return; + } + + StackEntry* stack = sRecentTlsAllocationStacks->PutEntry(aTlsIndex); + + MOZ_ASSERT(!stack->mStack.IsEmpty()); + stack->mStack = Move(rawStack); +} + +static void +MaybeDeleteRecordedStack(DWORD aTlsIndex) +{ + StaticMutexAutoLock lock(sMutex); + if (!sRecentTlsAllocationStacks) { + return; + } + + auto entry = sRecentTlsAllocationStacks->GetEntry(aTlsIndex); + if (entry) { + sRecentTlsAllocationStacks->RemoveEntry(aTlsIndex); + } +} + + +static void +AnnotateRecentTlsStacks() +{ + StaticMutexAutoLock lock(sMutex); + if (!sRecentTlsAllocationStacks) { + // Maybe another thread steals the stack vector content and is dumping the + // stacks + return; + } + + // Move the content to prevent further requests to this function. + UniquePtr stacks = MakeUnique(); + sRecentTlsAllocationStacks->SwapElements(*stacks.get()); + sRecentTlsAllocationStacks = nullptr; + + sTlsAllocationStacks = new nsCString(); + JSONWriter output( + MakeUnique(sTlsAllocationStacks.get())); + + output.Start(JSONWriter::SingleLineStyle); + for (auto iter = stacks->Iter(); !iter.Done(); iter.Next()) { + const stack_t& stack = iter.Get()->mStack; + + output.StartArrayElement(); + for (auto pc : stack) { + output.IntElement(pc); + } + output.EndArray(); + } + output.End(); +} + +DWORD WINAPI +InterposedTlsAlloc() +{ + if (!sInitialized) { + // Don't interpose if we didn't fully initialize both hooks or after we + // already shutdown the tracker. + return gOriginalTlsAlloc(); + } + + sCurrentTlsSlots += 1; + + DWORD tlsAllocRv = gOriginalTlsAlloc(); + + MaybeRecordCurrentStack(tlsAllocRv); + + if (tlsAllocRv == TLS_OUT_OF_INDEXES) { + AnnotateRecentTlsStacks(); + } + + return tlsAllocRv; +} + +BOOL WINAPI +InterposedTlsFree(DWORD aTlsIndex) +{ + if (!sInitialized) { + // Don't interpose if we didn't fully initialize both hooks or after we + // already shutdown the tracker. + return gOriginalTlsFree(aTlsIndex); + } + + sCurrentTlsSlots -= 1; + + MaybeDeleteRecordedStack(aTlsIndex); + + return gOriginalTlsFree(aTlsIndex); +} + +} // Anonymous namespace. + +void +InitTlsAllocationTracker() +{ + if (sInitialized) { + return; + } + + sRecentTlsAllocationStacks = new stacks_t(); + + // Windows DLL interceptor + static WindowsDllInterceptor sKernel32DllInterceptor{}; + + // Initialize dll interceptor and add hook. + sKernel32DllInterceptor.Init("kernel32.dll"); + bool succeeded = sKernel32DllInterceptor.AddHook( + "TlsAlloc", + reinterpret_cast(InterposedTlsAlloc), + reinterpret_cast(&gOriginalTlsAlloc)); + + if (!succeeded) { + return; + } + + succeeded = sKernel32DllInterceptor.AddHook( + "TlsFree", + reinterpret_cast(InterposedTlsFree), + reinterpret_cast(&gOriginalTlsFree)); + + if (!succeeded) { + return; + } + + sInitialized = true; +} + +const char* +GetTlsAllocationStacks() +{ + StaticMutexAutoLock lock(sMutex); + + if (!sTlsAllocationStacks) { + return nullptr; + } + + return sTlsAllocationStacks->BeginReading(); +} + +void +ShutdownTlsAllocationTracker() +{ + if (!sInitialized) { + return; + } + sInitialized = false; + + StaticMutexAutoLock lock(sMutex); + + sRecentTlsAllocationStacks = nullptr; + sTlsAllocationStacks = nullptr; +} + +} // namespace mozilla diff --git a/xpcom/build/TlsAllocationTracker.h b/xpcom/build/TlsAllocationTracker.h new file mode 100644 index 000000000000..7476ad4c7f36 --- /dev/null +++ b/xpcom/build/TlsAllocationTracker.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_TlsAllocationTracker_h +#define mozilla_TlsAllocationTracker_h + +#include + +#include "mozilla/Types.h" + +namespace mozilla { + +void +InitTlsAllocationTracker(); + +const char* +GetTlsAllocationStacks(); + +void +ShutdownTlsAllocationTracker(); + +} + +#endif diff --git a/xpcom/build/moz.build b/xpcom/build/moz.build index b84d4340a8fa..5f0a9752e698 100644 --- a/xpcom/build/moz.build +++ b/xpcom/build/moz.build @@ -22,6 +22,7 @@ EXPORTS.mozilla += [ 'PoisonIOInterposer.h', 'ServiceList.h', 'Services.h', + 'TlsAllocationTracker.h', 'XPCOM.h', 'XREAppData.h', ] @@ -33,6 +34,7 @@ if CONFIG['OS_ARCH'] == 'WINNT': 'perfprobe.cpp', 'PoisonIOInterposerBase.cpp', 'PoisonIOInterposerWin.cpp', + 'TlsAllocationTracker.cpp', ] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': UNIFIED_SOURCES += [ From 615a84813f9a92f904cbc3183e378b1c53da10b6 Mon Sep 17 00:00:00 2001 From: Cervantes Yu Date: Thu, 16 Mar 2017 14:06:35 +0800 Subject: [PATCH 43/96] Bug 1320134 - Part 2: Initialize and shutdown the TLS allocation tracker in the content process. r=froydnj MozReview-Commit-ID: 2Pu9r1MV1e4 --- toolkit/xre/nsEmbedFunctions.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 578d67db3bd0..c4fc4819e4c6 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -25,6 +25,7 @@ #ifdef XP_WIN #include #include "mozilla/ipc/WindowsMessageLoop.h" +#include "mozilla/TlsAllocationTracker.h" #endif #include "nsAppDirectoryServiceDefs.h" @@ -358,6 +359,14 @@ XRE_InitChildProcess(int aArgc, #endif #if defined(XP_WIN) +#ifndef DEBUG + // XXX Bug 1320134: added for diagnosing the crashes because we're running out + // of TLS indices on Windows. Remove after the root cause is found. + if (XRE_GetProcessType() == GeckoProcessType_Content) { + mozilla::InitTlsAllocationTracker(); + } +#endif + // From the --attach-console support in nsNativeAppSupportWin.cpp, but // here we are a content child process, so we always attempt to attach // to the parent's (ie, the browser's) console. @@ -697,6 +706,14 @@ XRE_InitChildProcess(int aArgc, } } +#if defined(XP_WIN) && !defined(DEBUG) + // XXX Bug 1320134: added for diagnosing the crashes because we're running out + // of TLS indices on Windows. Remove after the root cause is found. + if (XRE_GetProcessType() == GeckoProcessType_Content) { + mozilla::ShutdownTlsAllocationTracker(); + } +#endif + Telemetry::DestroyStatisticsRecorder(); return XRE_DeinitCommandLine(); } From 0f5d7dafd59c884f37a69a4323641a32ee06a4f4 Mon Sep 17 00:00:00 2001 From: Cervantes Yu Date: Thu, 23 Feb 2017 16:46:27 +0800 Subject: [PATCH 44/96] Bug 1320134 - Part 3: Annotate the crash report with TLS allocation stacks on running out of TLS slots. r=ted MozReview-Commit-ID: 9BEe4G28Txd --- toolkit/crashreporter/nsExceptionHandler.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 3dfe4c60763d..cdba494f180e 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -24,6 +24,10 @@ #include "nsXULAppAPI.h" #include "jsfriendapi.h" +#ifdef XP_WIN +#include "mozilla/TlsAllocationTracker.h" +#endif + #if defined(XP_WIN32) #ifdef WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN @@ -1385,6 +1389,13 @@ PrepareChildExceptionTimeAnnotations() WriteAnnotation(apiData, "TopPendingIPCType", topPendingIPCTypeBuffer); } } + +#ifdef XP_WIN + const char* tlsAllocations = mozilla::GetTlsAllocationStacks(); + if (tlsAllocations) { + WriteAnnotation(apiData, "TlsAllocations", tlsAllocations); + } +#endif } #ifdef XP_WIN From 0341ce9cc9334a64d074e37a187cab50afd0600c Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 23 Mar 2017 03:06:25 -0400 Subject: [PATCH 45/96] Bug 1348095 part 1. Remove the unused reserved slots from the XPCWN xray holder. r=bholley MozReview-Commit-ID: 5IRrE8EmL9A --- js/xpconnect/wrappers/XrayWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 0daf207897f0..6d4d565e059f 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -201,7 +201,7 @@ XPCWrappedNativeXrayTraits::getWN(JSObject* wrapper) } const JSClass XPCWrappedNativeXrayTraits::HolderClass = { - "NativePropertyHolder", JSCLASS_HAS_RESERVED_SLOTS(2) + "NativePropertyHolder" }; From ad63ed3278c6fc20bd140e35167ac32e33ba1ee6 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 23 Mar 2017 03:06:25 -0400 Subject: [PATCH 46/96] Bug 1348095 part 2. Give all the Xray holders a JSClass that has a slot for caching a prototype. r=bholley MozReview-Commit-ID: ID9vMG3iJfZ --- js/xpconnect/wrappers/XrayWrapper.cpp | 7 +++++-- js/xpconnect/wrappers/XrayWrapper.h | 12 ++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 6d4d565e059f..42a4a4ddc3d8 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -201,9 +201,12 @@ XPCWrappedNativeXrayTraits::getWN(JSObject* wrapper) } const JSClass XPCWrappedNativeXrayTraits::HolderClass = { - "NativePropertyHolder" + "NativePropertyHolder", JSCLASS_HAS_RESERVED_SLOTS(HOLDER_SHARED_SLOT_COUNT) }; +const JSClass XrayTraits::HolderClass = { + "XrayHolder", JSCLASS_HAS_RESERVED_SLOTS(HOLDER_SHARED_SLOT_COUNT) +}; const JSClass JSXrayTraits::HolderClass = { "JSXrayHolder", JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT) @@ -1854,7 +1857,7 @@ DOMXrayTraits::preserveWrapper(JSObject* target) JSObject* DOMXrayTraits::createHolder(JSContext* cx, JSObject* wrapper) { - return JS_NewObjectWithGivenProto(cx, nullptr, nullptr); + return JS_NewObjectWithGivenProto(cx, &HolderClass, nullptr); } const JSClass* diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 5630982c28c4..4527e3b0a1f0 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -99,6 +99,12 @@ public: JSObject* ensureExpandoObject(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject target); + // Slots for holder objects. + enum { + HOLDER_SLOT_CACHED_PROTO = 0, + HOLDER_SHARED_SLOT_COUNT + }; + JSObject* getHolder(JSObject* wrapper); JSObject* ensureHolder(JSContext* cx, JS::HandleObject wrapper); virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) = 0; @@ -108,6 +114,8 @@ public: bool cloneExpandoChain(JSContext* cx, JS::HandleObject dst, JS::HandleObject src); protected: + static const JSClass HolderClass; + // Get the JSClass we should use for our expando object. virtual const JSClass* getExpandoClass(JSContext* cx, JS::HandleObject target) const; @@ -301,7 +309,7 @@ public: } enum { - SLOT_PROTOKEY = 0, + SLOT_PROTOKEY = HOLDER_SHARED_SLOT_COUNT, SLOT_ISPROTOTYPE, SLOT_CONSTRUCTOR_FOR, SLOT_COUNT @@ -421,7 +429,7 @@ public: virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) override { - return JS_NewObjectWithGivenProto(cx, nullptr, nullptr); + return JS_NewObjectWithGivenProto(cx, &HolderClass, nullptr); } static OpaqueXrayTraits singleton; From 0660340117afc2ee90ca26e54a251c36fa7c7340 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 23 Mar 2017 03:06:25 -0400 Subject: [PATCH 47/96] Bug 1348095 part 3. Cache the proto of an Xray on its holder, so we don't have to keep re-wrapping it. r=bholley MozReview-Commit-ID: I78AoSB3TNW --- js/xpconnect/wrappers/XrayWrapper.cpp | 33 +++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 42a4a4ddc3d8..45eb0ffa95c9 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -2410,16 +2410,35 @@ XrayWrapper::getPrototype(JSContext* cx, JS::HandleObject wrapper, // only if there's been a set. If there's not an expando, or the expando // slot is |undefined|, hand back the default proto, appropriately wrapped. - RootedValue v(cx); if (expando) { - JSAutoCompartment ac(cx, expando); - v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE); + RootedValue v(cx); + { // Scope for JSAutoCompartment + JSAutoCompartment ac(cx, expando); + v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE); + } + if (!v.isUndefined()) { + protop.set(v.toObjectOrNull()); + return JS_WrapObject(cx, protop); + } } - if (v.isUndefined()) - return getPrototypeHelper(cx, wrapper, target, protop); - protop.set(v.toObjectOrNull()); - return JS_WrapObject(cx, protop); + // Check our holder, and cache there if we don't have it cached already. + RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper)); + if (!holder) + return false; + + Value cached = js::GetReservedSlot(holder, + Traits::HOLDER_SLOT_CACHED_PROTO); + if (cached.isUndefined()) { + if (!getPrototypeHelper(cx, wrapper, target, protop)) + return false; + + js::SetReservedSlot(holder, Traits::HOLDER_SLOT_CACHED_PROTO, + ObjectOrNullValue(protop)); + } else { + protop.set(cached.toObjectOrNull()); + } + return true; } template From 5497e491cbc8291f051ae6d181fbe4bb40c770b5 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 23 Mar 2017 03:06:25 -0400 Subject: [PATCH 48/96] Bug 1349690. Improve dangling-exception logging in AutoJSAPI::InitInternal to deal better with exceptions from a different origin. r=bholley MozReview-Commit-ID: IpvRcBC2d6k --- dom/base/ScriptSettings.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dom/base/ScriptSettings.cpp b/dom/base/ScriptSettings.cpp index a89b3419127a..c9fa9e1f2ba9 100644 --- a/dom/base/ScriptSettings.cpp +++ b/dom/base/ScriptSettings.cpp @@ -376,6 +376,13 @@ AutoJSAPI::InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal, if (exn.isObject()) { JS::Rooted exnObj(aCx, &exn.toObject()); + // Make sure we can actually read things from it. This UncheckedUwrap is + // safe because we're only getting data for a debug printf. In + // particular, we do not expose this data to anyone, which is very + // important; otherwise it could be a cross-origin information leak. + exnObj = js::UncheckedUwrap(exnObj); + JSAutoCompartment ac(aCx, exnObj); + nsAutoJSString stack, filename, name, message; int32_t line; From 660aaef3f5b2df606ea72b96d5d03933be2ec140 Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Wed, 22 Mar 2017 11:18:31 +0100 Subject: [PATCH 49/96] Bug 1345032 - Further cost reductions for ProfileBuffer::FindLastSampleOfThread. r=n.nethercote. ProfileBuffer::FindLastSampleOfThread currently involves a linear search backwards through the sample buffer. Profiling showed that to be the largest profiler cost by far, at least on Linux. Bugs 1344118 and 1344258 significantly improve the situation, collectively reducing the cost by a factor of at least 5 and often much more. But the linear search is still present and still dominant. The worst of it is that it's unnecessary: we could achieve the same by recording the start point of the most recent sample for each thread in that thread's ThreadInfo record. This patch does exactly that, adding the type ProfileBuffer::LastSample to store the start points. LastSample also includes the ID of the thread it pertains to as a read-only field, as that is needed in various places. addTag doesn't check whether we're overwriting buffer entries containing start points. Instead, FindLastSample checks whether the entry pointed to the LastSample it is given still contains a marker. --HG-- extra : rebase_source : 2987ec744a5c16e8b6814abe7efb507fc7280605 --- tools/profiler/core/ProfileBuffer.cpp | 8 +++ tools/profiler/core/ProfileBuffer.h | 31 ++++++++++- tools/profiler/core/ProfileBufferEntry.cpp | 51 +++++++++++-------- tools/profiler/core/ThreadInfo.cpp | 1 + tools/profiler/core/ThreadInfo.h | 8 +++ .../profiler/core/platform-linux-android.cpp | 4 +- tools/profiler/core/platform-macos.cpp | 4 +- tools/profiler/core/platform-win32.cpp | 4 +- tools/profiler/core/platform.cpp | 3 +- 9 files changed, 84 insertions(+), 30 deletions(-) diff --git a/tools/profiler/core/ProfileBuffer.cpp b/tools/profiler/core/ProfileBuffer.cpp index 3ae360420c1a..72604efddeb3 100644 --- a/tools/profiler/core/ProfileBuffer.cpp +++ b/tools/profiler/core/ProfileBuffer.cpp @@ -39,6 +39,14 @@ void ProfileBuffer::addTag(const ProfileBufferEntry& aTag) } } +void ProfileBuffer::addTagThreadId(LastSample& aLS) +{ + // This is the start of a sample, so make a note of its location in |aLS|. + aLS.mGeneration = mGeneration; + aLS.mPos = mWritePos; + addTag(ProfileBufferEntry::ThreadId(aLS.mThreadId)); +} + void ProfileBuffer::addStoredMarker(ProfilerMarker *aStoredMarker) { aStoredMarker->SetGeneration(mGeneration); mStoredMarkers.insert(aStoredMarker); diff --git a/tools/profiler/core/ProfileBuffer.h b/tools/profiler/core/ProfileBuffer.h index 8e7cb522edd7..56445c0d4ef4 100644 --- a/tools/profiler/core/ProfileBuffer.h +++ b/tools/profiler/core/ProfileBuffer.h @@ -19,14 +19,41 @@ public: ~ProfileBuffer(); + // LastSample is used to record the buffer location of the most recent + // sample for each thread. + struct LastSample { + explicit LastSample(int aThreadId) + : mThreadId(aThreadId) + , mGeneration(0) + , mPos(-1) + {} + + // The thread to which this LastSample pertains. + const int mThreadId; + // The profiler-buffer generation number at which the sample was created. + uint32_t mGeneration; + // And its position in the buffer, or -1 meaning "invalid". + int mPos; + }; + + // Add |aTag| to the buffer, ignoring what kind of entry it is. void addTag(const ProfileBufferEntry& aTag); + + // Add to the buffer, a sample start (ThreadId) entry, for the thread that + // |aLS| belongs to, and record the resulting generation and index in |aLS|. + void addTagThreadId(LastSample& aLS); + void StreamSamplesToJSON(SpliceableJSONWriter& aWriter, int aThreadId, double aSinceTime, JSContext* cx, UniqueStacks& aUniqueStacks); void StreamMarkersToJSON(SpliceableJSONWriter& aWriter, int aThreadId, const mozilla::TimeStamp& aStartTime, double aSinceTime, UniqueStacks& aUniqueStacks); - bool DuplicateLastSample(int aThreadId, const mozilla::TimeStamp& aStartTime); + + // Find the most recent sample for the thread denoted by |aLS| and clone it, + // patching in |aStartTime| as appropriate. + bool DuplicateLastSample(const mozilla::TimeStamp& aStartTime, + LastSample& aLS); void addStoredMarker(ProfilerMarker* aStoredMarker); @@ -38,7 +65,7 @@ public: protected: char* processDynamicTag(int readPos, int* tagsConsumed, char* tagBuff); - int FindLastSampleOfThread(int aThreadId); + int FindLastSampleOfThread(const LastSample& aLS); public: // Circular buffer 'Keep One Slot Open' implementation for simplicity diff --git a/tools/profiler/core/ProfileBufferEntry.cpp b/tools/profiler/core/ProfileBufferEntry.cpp index 802d11b21e5f..747f9119bb9e 100644 --- a/tools/profiler/core/ProfileBufferEntry.cpp +++ b/tools/profiler/core/ProfileBufferEntry.cpp @@ -742,40 +742,49 @@ ProfileBuffer::StreamMarkersToJSON(SpliceableJSONWriter& aWriter, } } -int ProfileBuffer::FindLastSampleOfThread(int aThreadId) +int +ProfileBuffer::FindLastSampleOfThread(const LastSample& aLS) { - // We search backwards from mWritePos-1 to mReadPos. - // Adding mEntrySize makes the result of the modulus positive. - int currPos = (mWritePos + mEntrySize - 1) % mEntrySize; - int stopPos = (mReadPos + mEntrySize - 1) % mEntrySize; - while (currPos != stopPos) { - ProfileBufferEntry entry = mEntries[currPos]; - if (entry.isThreadId() && entry.mTagInt == aThreadId) { - return currPos; - } - currPos--; - if (currPos < 0) { - // This almost never happens, so is perfectly predicted, and hence - // almost free. - currPos = mEntrySize - 1; + // |aLS| has a valid generation number if either it matches the buffer's + // generation, or is one behind the buffer's generation, since the buffer's + // generation is incremented on wraparound. There's no ambiguity relative to + // ProfileBuffer::reset, since that increments mGeneration by two. + if (aLS.mGeneration == mGeneration || + (mGeneration > 0 && aLS.mGeneration == mGeneration - 1)) { + int ix = aLS.mPos; + + if (ix == -1) { + // There's no record of |aLS|'s thread ever having recorded a sample in + // the buffer. + return -1; } + + // It might be that the sample has since been overwritten, so check that it + // is still valid. + MOZ_RELEASE_ASSERT(0 <= ix && ix < mEntrySize); + ProfileBufferEntry& entry = mEntries[ix]; + bool isStillValid = entry.isThreadId() && entry.mTagInt == aLS.mThreadId; + return isStillValid ? ix : -1; } - // This is rare. It typically happens after ProfileBuffer::reset() occurs. + // |aLS| denotes a sample which is older than either two wraparounds or one + // call to ProfileBuffer::reset. In either case it is no longer valid. + MOZ_ASSERT(aLS.mGeneration <= mGeneration - 2); return -1; } bool -ProfileBuffer::DuplicateLastSample(int aThreadId, const TimeStamp& aStartTime) +ProfileBuffer::DuplicateLastSample(const TimeStamp& aStartTime, LastSample& aLS) { - int lastSampleStartPos = FindLastSampleOfThread(aThreadId); + int lastSampleStartPos = FindLastSampleOfThread(aLS); if (lastSampleStartPos == -1) { return false; } - MOZ_ASSERT(mEntries[lastSampleStartPos].isThreadId()); + MOZ_ASSERT(mEntries[lastSampleStartPos].isThreadId() && + mEntries[lastSampleStartPos].mTagInt == aLS.mThreadId); - addTag(mEntries[lastSampleStartPos]); + addTagThreadId(aLS); // Go through the whole entry and duplicate it, until we find the next one. for (int readPos = (lastSampleStartPos + 1) % mEntrySize; @@ -794,7 +803,7 @@ ProfileBuffer::DuplicateLastSample(int aThreadId, const TimeStamp& aStartTime) // Don't copy markers break; default: - // Copy anything else we don't know about + // Copy anything else we don't know about. addTag(mEntries[readPos]); break; } diff --git a/tools/profiler/core/ThreadInfo.cpp b/tools/profiler/core/ThreadInfo.cpp index 29724462a9c5..58036bca49cc 100644 --- a/tools/profiler/core/ThreadInfo.cpp +++ b/tools/profiler/core/ThreadInfo.cpp @@ -23,6 +23,7 @@ ThreadInfo::ThreadInfo(const char* aName, int aThreadId, bool aIsMainThread, , mStackTop(aStackTop) , mPendingDelete(false) , mHasProfile(false) + , mLastSample(aThreadId) { MOZ_COUNT_CTOR(ThreadInfo); mThread = NS_GetCurrentThread(); diff --git a/tools/profiler/core/ThreadInfo.h b/tools/profiler/core/ThreadInfo.h index a97715b23836..4d3975fdab2a 100644 --- a/tools/profiler/core/ThreadInfo.h +++ b/tools/profiler/core/ThreadInfo.h @@ -38,6 +38,8 @@ public: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + ProfileBuffer::LastSample& LastSample() { return mLastSample; } + private: mozilla::UniqueFreePtr mName; int mThreadId; @@ -104,6 +106,12 @@ private: mozilla::Maybe mUniqueStacks; ThreadResponsiveness mRespInfo; + + // When sampling, this holds the generation number and offset in the + // ProfileBuffer of the most recent sample for this thread. + // mLastSample.mThreadId duplicates mThreadId in this structure, which + // simplifies some uses of mLastSample. + ProfileBuffer::LastSample mLastSample; }; #endif diff --git a/tools/profiler/core/platform-linux-android.cpp b/tools/profiler/core/platform-linux-android.cpp index 1acb396e701c..a5d567046b86 100644 --- a/tools/profiler/core/platform-linux-android.cpp +++ b/tools/profiler/core/platform-linux-android.cpp @@ -390,8 +390,8 @@ public: } if (info->Stack()->CanDuplicateLastSampleDueToSleep() && - gPS->Buffer(lock)->DuplicateLastSample(info->ThreadId(), - gPS->StartTime(lock))) { + gPS->Buffer(lock)->DuplicateLastSample(gPS->StartTime(lock), + info->LastSample())) { continue; } diff --git a/tools/profiler/core/platform-macos.cpp b/tools/profiler/core/platform-macos.cpp index b514de2c3bdc..0f9f55a5414b 100644 --- a/tools/profiler/core/platform-macos.cpp +++ b/tools/profiler/core/platform-macos.cpp @@ -146,8 +146,8 @@ public: } if (info->Stack()->CanDuplicateLastSampleDueToSleep() && - gPS->Buffer(lock)->DuplicateLastSample(info->ThreadId(), - gPS->StartTime(lock))) { + gPS->Buffer(lock)->DuplicateLastSample(gPS->StartTime(lock), + info->LastSample())) { continue; } diff --git a/tools/profiler/core/platform-win32.cpp b/tools/profiler/core/platform-win32.cpp index eda8bf316fa9..40bdfb36b4a2 100644 --- a/tools/profiler/core/platform-win32.cpp +++ b/tools/profiler/core/platform-win32.cpp @@ -174,8 +174,8 @@ public: } if (info->Stack()->CanDuplicateLastSampleDueToSleep() && - gPS->Buffer(lock)->DuplicateLastSample(info->ThreadId(), - gPS->StartTime(lock))) { + gPS->Buffer(lock)->DuplicateLastSample(gPS->StartTime(lock), + info->LastSample())) { continue; } diff --git a/tools/profiler/core/platform.cpp b/tools/profiler/core/platform.cpp index 769cc6166a29..27fb61ba5a0d 100644 --- a/tools/profiler/core/platform.cpp +++ b/tools/profiler/core/platform.cpp @@ -949,7 +949,8 @@ Tick(PS::LockRef aLock, ProfileBuffer* aBuffer, TickSample* aSample) { ThreadInfo& threadInfo = *aSample->threadInfo; - aBuffer->addTag(ProfileBufferEntry::ThreadId(threadInfo.ThreadId())); + MOZ_ASSERT(threadInfo.LastSample().mThreadId == threadInfo.ThreadId()); + aBuffer->addTagThreadId(threadInfo.LastSample()); mozilla::TimeDuration delta = aSample->timestamp - gPS->StartTime(aLock); aBuffer->addTag(ProfileBufferEntry::Time(delta.ToMilliseconds())); From 0c342448a647754cce8574cdbf9a41f645fc5b7c Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Mon, 20 Mar 2017 12:36:47 +0100 Subject: [PATCH 50/96] Bug 1343007 - Do not insert redundant truncation nodes in constant folding. r=nbp --HG-- extra : rebase_source : b8b3ec8d1f05d02cc0c0a6b94c76f7cec4eaffb8 --- js/src/jit/MIR.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 184fc33ced6e..02ee711a89e6 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -3171,7 +3171,8 @@ MBinaryArithInstruction::foldsTo(TempAllocator& alloc) if (isTruncated()) { if (!folded->block()) block()->insertBefore(this, folded); - return MTruncateToInt32::New(alloc, folded); + if (folded->type() != MIRType::Int32) + return MTruncateToInt32::New(alloc, folded); } return folded; } From 867bbb6b9177a8992329e075c27444ee002bcf14 Mon Sep 17 00:00:00 2001 From: Shawn Huang Date: Wed, 22 Mar 2017 18:12:11 +0800 Subject: [PATCH 51/96] Bug 1348877 - Load test case interfaces.html on https, r=annevk --HG-- rename : testing/web-platform/tests/storage/interfaces.html => testing/web-platform/tests/storage/interfaces.https.html --- testing/web-platform/meta/MANIFEST.json | 8 ++++---- .../storage/{interfaces.html => interfaces.https.html} | 0 2 files changed, 4 insertions(+), 4 deletions(-) rename testing/web-platform/tests/storage/{interfaces.html => interfaces.https.html} (100%) diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 9f8d07bdf355..9aa9e0f41755 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -120882,9 +120882,9 @@ {} ] ], - "storage/interfaces.html": [ + "storage/interfaces.https.html": [ [ - "/storage/interfaces.html", + "/storage/interfaces.https.html", {} ] ], @@ -181322,7 +181322,7 @@ "testharness" ], "html/webappapis/idle-callbacks/callback-removed-frame.html": [ - "79b4a278f0e35646cfdffeebf8f0523e2772bc9b", + "ff034276659407d2dea91d2b0ed0e5919b875904", "testharness" ], "html/webappapis/idle-callbacks/callback-suspended.html": [ @@ -203621,7 +203621,7 @@ "6e5db2d0c2f5d2d8f1e2d04da953a3f2c50bec7a", "testharness" ], - "storage/interfaces.html": [ + "storage/interfaces.https.html": [ "76fa61c3a87485266a7f9d6f66e5d08bb7881ff7", "testharness" ], diff --git a/testing/web-platform/tests/storage/interfaces.html b/testing/web-platform/tests/storage/interfaces.https.html similarity index 100% rename from testing/web-platform/tests/storage/interfaces.html rename to testing/web-platform/tests/storage/interfaces.https.html From 68207654f217ec6b5bcaea88ecf3b7eea96d7c94 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 22 Mar 2017 11:38:17 +0100 Subject: [PATCH 52/96] Bug 1343933 - Renaming Principal classes - part 1 - ExpandedPrincipal, r=qdot --HG-- rename : caps/nsExpandedPrincipal.cpp => caps/ExpandedPrincipal.cpp rename : caps/nsExpandedPrincipal.h => caps/ExpandedPrincipal.h --- caps/BasePrincipal.h | 4 +- ...dedPrincipal.cpp => ExpandedPrincipal.cpp} | 58 +++++++++---------- ...xpandedPrincipal.h => ExpandedPrincipal.h} | 23 ++++---- caps/moz.build | 2 +- caps/nsIPrincipal.idl | 8 +-- dom/base/ScriptSettings.cpp | 2 +- dom/base/nsContentUtils.h | 4 +- ipc/glue/BackgroundUtils.cpp | 6 +- js/xpconnect/idl/xpccomponents.idl | 2 +- js/xpconnect/src/Sandbox.cpp | 6 +- js/xpconnect/src/XPCJSContext.cpp | 2 +- js/xpconnect/src/XPCWrappedNativeScope.cpp | 10 ++-- js/xpconnect/tests/chrome/test_bug996069.xul | 6 +- 13 files changed, 68 insertions(+), 65 deletions(-) rename caps/{nsExpandedPrincipal.cpp => ExpandedPrincipal.cpp} (70%) rename caps/{nsExpandedPrincipal.h => ExpandedPrincipal.h} (76%) diff --git a/caps/BasePrincipal.h b/caps/BasePrincipal.h index 537b1a8e51e9..877060779f7a 100644 --- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -19,7 +19,7 @@ class nsIObjectOutputStream; class nsIObjectInputStream; class nsIURI; -class nsExpandedPrincipal; +class ExpandedPrincipal; namespace mozilla { @@ -283,7 +283,7 @@ protected: // principal would allow the load ignoring any common behavior implemented in // BasePrincipal::CheckMayLoad. virtual bool MayLoadInternal(nsIURI* aURI) = 0; - friend class ::nsExpandedPrincipal; + friend class ::ExpandedPrincipal; // This function should be called as the last step of the initialization of the // principal objects. It's typically called as the last step from the Init() diff --git a/caps/nsExpandedPrincipal.cpp b/caps/ExpandedPrincipal.cpp similarity index 70% rename from caps/nsExpandedPrincipal.cpp rename to caps/ExpandedPrincipal.cpp index 9a06abe874d7..c3e30c23b1ba 100644 --- a/caps/nsExpandedPrincipal.cpp +++ b/caps/ExpandedPrincipal.cpp @@ -4,19 +4,19 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsExpandedPrincipal.h" +#include "ExpandedPrincipal.h" #include "nsIClassInfoImpl.h" using namespace mozilla; -NS_IMPL_CLASSINFO(nsExpandedPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, +NS_IMPL_CLASSINFO(ExpandedPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, NS_EXPANDEDPRINCIPAL_CID) -NS_IMPL_QUERY_INTERFACE_CI(nsExpandedPrincipal, +NS_IMPL_QUERY_INTERFACE_CI(ExpandedPrincipal, nsIPrincipal, nsIExpandedPrincipal) -NS_IMPL_CI_INTERFACE_GETTER(nsExpandedPrincipal, - nsIPrincipal, - nsIExpandedPrincipal) +NS_IMPL_CI_INTERFACE_GETTER(ExpandedPrincipal, + nsIPrincipal, + nsIExpandedPrincipal) struct OriginComparator { @@ -43,11 +43,11 @@ struct OriginComparator } }; -nsExpandedPrincipal::nsExpandedPrincipal(nsTArray> &aWhiteList, - const OriginAttributes& aAttrs) +ExpandedPrincipal::ExpandedPrincipal(nsTArray> &aWhiteList, + const OriginAttributes& aAttrs) : BasePrincipal(eExpandedPrincipal) { - // We force the principals to be sorted by origin so that nsExpandedPrincipal + // We force the principals to be sorted by origin so that ExpandedPrincipal // origins can have a canonical form. OriginComparator c; for (size_t i = 0; i < aWhiteList.Length(); ++i) { @@ -56,33 +56,33 @@ nsExpandedPrincipal::nsExpandedPrincipal(nsTArray> &aWhit mOriginAttributes = aAttrs; } -nsExpandedPrincipal::~nsExpandedPrincipal() +ExpandedPrincipal::~ExpandedPrincipal() { } -already_AddRefed -nsExpandedPrincipal::Create(nsTArray>& aWhiteList, - const OriginAttributes& aAttrs) +already_AddRefed +ExpandedPrincipal::Create(nsTArray>& aWhiteList, + const OriginAttributes& aAttrs) { - RefPtr ep = new nsExpandedPrincipal(aWhiteList, aAttrs); + RefPtr ep = new ExpandedPrincipal(aWhiteList, aAttrs); ep->FinishInit(); return ep.forget(); } NS_IMETHODIMP -nsExpandedPrincipal::GetDomain(nsIURI** aDomain) +ExpandedPrincipal::GetDomain(nsIURI** aDomain) { *aDomain = nullptr; return NS_OK; } NS_IMETHODIMP -nsExpandedPrincipal::SetDomain(nsIURI* aDomain) +ExpandedPrincipal::SetDomain(nsIURI* aDomain) { return NS_OK; } nsresult -nsExpandedPrincipal::GetOriginInternal(nsACString& aOrigin) +ExpandedPrincipal::GetOriginInternal(nsACString& aOrigin) { aOrigin.AssignLiteral("[Expanded Principal ["); for (size_t i = 0; i < mPrincipals.Length(); ++i) { @@ -101,8 +101,8 @@ nsExpandedPrincipal::GetOriginInternal(nsACString& aOrigin) } bool -nsExpandedPrincipal::SubsumesInternal(nsIPrincipal* aOther, - BasePrincipal::DocumentDomainConsideration aConsideration) +ExpandedPrincipal::SubsumesInternal(nsIPrincipal* aOther, + BasePrincipal::DocumentDomainConsideration aConsideration) { // If aOther is an ExpandedPrincipal too, we break it down into its component // nsIPrincipals, and check subsumes on each one. @@ -133,7 +133,7 @@ nsExpandedPrincipal::SubsumesInternal(nsIPrincipal* aOther, } bool -nsExpandedPrincipal::MayLoadInternal(nsIURI* uri) +ExpandedPrincipal::MayLoadInternal(nsIURI* uri) { for (uint32_t i = 0; i < mPrincipals.Length(); ++i){ if (BasePrincipal::Cast(mPrincipals[i])->MayLoadInternal(uri)) { @@ -145,40 +145,40 @@ nsExpandedPrincipal::MayLoadInternal(nsIURI* uri) } NS_IMETHODIMP -nsExpandedPrincipal::GetHashValue(uint32_t* result) +ExpandedPrincipal::GetHashValue(uint32_t* result) { MOZ_CRASH("extended principal should never be used as key in a hash map"); } NS_IMETHODIMP -nsExpandedPrincipal::GetURI(nsIURI** aURI) +ExpandedPrincipal::GetURI(nsIURI** aURI) { *aURI = nullptr; return NS_OK; } NS_IMETHODIMP -nsExpandedPrincipal::GetWhiteList(nsTArray >** aWhiteList) +ExpandedPrincipal::GetWhiteList(nsTArray >** aWhiteList) { *aWhiteList = &mPrincipals; return NS_OK; } NS_IMETHODIMP -nsExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain) +ExpandedPrincipal::GetBaseDomain(nsACString& aBaseDomain) { return NS_ERROR_NOT_AVAILABLE; } NS_IMETHODIMP -nsExpandedPrincipal::GetAddonId(nsAString& aAddonId) +ExpandedPrincipal::GetAddonId(nsAString& aAddonId) { aAddonId.Truncate(); return NS_OK; }; bool -nsExpandedPrincipal::AddonHasPermission(const nsAString& aPerm) +ExpandedPrincipal::AddonHasPermission(const nsAString& aPerm) { for (size_t i = 0; i < mPrincipals.Length(); ++i) { if (BasePrincipal::Cast(mPrincipals[i])->AddonHasPermission(aPerm)) { @@ -189,7 +189,7 @@ nsExpandedPrincipal::AddonHasPermission(const nsAString& aPerm) } nsresult -nsExpandedPrincipal::GetScriptLocation(nsACString& aStr) +ExpandedPrincipal::GetScriptLocation(nsACString& aStr) { aStr.Assign("[Expanded Principal ["); for (size_t i = 0; i < mPrincipals.Length(); ++i) { @@ -213,13 +213,13 @@ nsExpandedPrincipal::GetScriptLocation(nsACString& aStr) ////////////////////////////////////////// NS_IMETHODIMP -nsExpandedPrincipal::Read(nsIObjectInputStream* aStream) +ExpandedPrincipal::Read(nsIObjectInputStream* aStream) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsExpandedPrincipal::Write(nsIObjectOutputStream* aStream) +ExpandedPrincipal::Write(nsIObjectOutputStream* aStream) { return NS_ERROR_NOT_IMPLEMENTED; } diff --git a/caps/nsExpandedPrincipal.h b/caps/ExpandedPrincipal.h similarity index 76% rename from caps/nsExpandedPrincipal.h rename to caps/ExpandedPrincipal.h index 360f83ce65d0..06750a09353e 100644 --- a/caps/nsExpandedPrincipal.h +++ b/caps/ExpandedPrincipal.h @@ -3,8 +3,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef nsExpandedPrincipal_h -#define nsExpandedPrincipal_h +#ifndef ExpandedPrincipal_h +#define ExpandedPrincipal_h #include "nsCOMPtr.h" #include "nsJSPrincipals.h" @@ -12,19 +12,20 @@ #include "nsNetUtil.h" #include "mozilla/BasePrincipal.h" -class nsExpandedPrincipal : public nsIExpandedPrincipal - , public mozilla::BasePrincipal +class ExpandedPrincipal : public nsIExpandedPrincipal + , public mozilla::BasePrincipal { - nsExpandedPrincipal(nsTArray> &aWhiteList, - const mozilla::OriginAttributes& aAttrs); + ExpandedPrincipal(nsTArray> &aWhiteList, + const mozilla::OriginAttributes& aAttrs); public: - static already_AddRefed + static already_AddRefed Create(nsTArray>& aWhiteList, const mozilla::OriginAttributes& aAttrs); NS_DECL_NSIEXPANDEDPRINCIPAL NS_DECL_NSISERIALIZABLE + NS_IMETHOD_(MozExternalRefCountType) AddRef() override { return nsJSPrincipals::AddRef(); }; NS_IMETHOD_(MozExternalRefCountType) Release() override { return nsJSPrincipals::Release(); }; NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; @@ -39,9 +40,11 @@ public: nsresult GetOriginInternal(nsACString& aOrigin) override; protected: - virtual ~nsExpandedPrincipal(); + virtual ~ExpandedPrincipal(); + + bool SubsumesInternal(nsIPrincipal* aOther, + DocumentDomainConsideration aConsideration) override; - bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override; bool MayLoadInternal(nsIURI* aURI) override; private: @@ -53,4 +56,4 @@ private: { 0xe8ee88b0, 0x5571, 0x4086, \ { 0xa4, 0x5b, 0x39, 0xa7, 0x16, 0x90, 0x6b, 0xdb } } -#endif // nsExpandedPrincipal_h +#endif // ExpandedPrincipal_h diff --git a/caps/moz.build b/caps/moz.build index 4a2189bf958e..3d5e52af9710 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -41,7 +41,7 @@ SOURCES += [ UNIFIED_SOURCES += [ 'DomainPolicy.cpp', - 'nsExpandedPrincipal.cpp', + 'ExpandedPrincipal.cpp', 'nsJSPrincipals.cpp', 'nsNullPrincipal.cpp', 'nsNullPrincipalURI.cpp', diff --git a/caps/nsIPrincipal.idl b/caps/nsIPrincipal.idl index 870792527813..a34853e37604 100644 --- a/caps/nsIPrincipal.idl +++ b/caps/nsIPrincipal.idl @@ -358,11 +358,11 @@ interface nsIPrincipal : nsISerializable /** * If nsSystemPrincipal is too risky to use, but we want a principal to access - * more than one origin, nsExpandedPrincipals letting us define an array of - * principals it subsumes. So script with an nsExpandedPrincipals will gain + * more than one origin, ExpandedPrincipals letting us define an array of + * principals it subsumes. So script with an ExpandedPrincipals will gain * same origin access when at least one of its principals it contains gained - * sameorigin acccess. An nsExpandedPrincipal will be subsumed by the system - * principal, and by another nsExpandedPrincipal that has all its principals. + * sameorigin acccess. An ExpandedPrincipal will be subsumed by the system + * principal, and by another ExpandedPrincipal that has all its principals. * It is added for jetpack content-scripts to let them interact with the * content and a well defined set of other domains, without the risk of * leaking out a system principal to the content. See: Bug 734891 diff --git a/dom/base/ScriptSettings.cpp b/dom/base/ScriptSettings.cpp index 7d0e4566b294..a89b3419127a 100644 --- a/dom/base/ScriptSettings.cpp +++ b/dom/base/ScriptSettings.cpp @@ -164,7 +164,7 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry() // If the entry or incumbent global ends up being something that the subject // principal doesn't subsume, we don't want to use it. This never happens on // the web, but can happen with asymmetric privilege relationships (i.e. -// nsExpandedPrincipal and System Principal). +// ExpandedPrincipal and System Principal). // // The most correct thing to use instead would be the topmost global on the // callstack whose principal is subsumed by the subject principal. But that's diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 159343549fe6..3aab08822895 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -1578,12 +1578,12 @@ public: static bool IsSystemPrincipal(nsIPrincipal* aPrincipal); /** - * Returns true if aPrincipal is an nsExpandedPrincipal. + * Returns true if aPrincipal is an ExpandedPrincipal. */ static bool IsExpandedPrincipal(nsIPrincipal* aPrincipal); /** - * Returns true if aPrincipal is the system or an nsExpandedPrincipal. + * Returns true if aPrincipal is the system or an ExpandedPrincipal. */ static bool IsSystemOrExpandedPrincipal(nsIPrincipal* aPrincipal) { diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index 8d6014e4749f..a2936e1cfcc3 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -11,7 +11,7 @@ #include "mozilla/BasePrincipal.h" #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/net/NeckoChannelParams.h" -#include "nsExpandedPrincipal.h" +#include "ExpandedPrincipal.h" #include "nsPrincipal.h" #include "nsIScriptSecurityManager.h" #include "nsIURI.h" @@ -124,8 +124,8 @@ PrincipalInfoToPrincipal(const PrincipalInfo& aPrincipalInfo, whitelist.AppendElement(wlPrincipal); } - RefPtr expandedPrincipal = - nsExpandedPrincipal::Create(whitelist, info.attrs()); + RefPtr expandedPrincipal = + ExpandedPrincipal::Create(whitelist, info.attrs()); if (!expandedPrincipal) { NS_WARNING("could not instantiate expanded principal"); return nullptr; diff --git a/js/xpconnect/idl/xpccomponents.idl b/js/xpconnect/idl/xpccomponents.idl index 711ea4c64238..10c0537c801c 100644 --- a/js/xpconnect/idl/xpccomponents.idl +++ b/js/xpconnect/idl/xpccomponents.idl @@ -693,7 +693,7 @@ interface nsIXPCComponents_Utils : nsISupports * Interface for the 'Components' object. * * The first interface contains things that are available to non-chrome XBL code -* that runs in a scope with an nsExpandedPrincipal. The second interface +* that runs in a scope with an ExpandedPrincipal. The second interface * includes members that are only exposed to chrome. */ diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index d52c408660bc..2a90b7ada490 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -20,7 +20,7 @@ #include "nsJSUtils.h" #include "nsNetUtil.h" #include "nsNullPrincipal.h" -#include "nsExpandedPrincipal.h" +#include "ExpandedPrincipal.h" #include "WrapperFactory.h" #include "xpcprivate.h" #include "xpc_make_class.h" @@ -1439,8 +1439,8 @@ GetExpandedPrincipal(JSContext* cx, HandleObject arrayObj, } } - RefPtr result = - nsExpandedPrincipal::Create(allowedDomains, attrs.ref()); + RefPtr result = + ExpandedPrincipal::Create(allowedDomains, attrs.ref()); result.forget(out); return true; } diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index ed33f230a735..6f72c9db8510 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -342,7 +342,7 @@ PrincipalImmuneToScriptPolicy(nsIPrincipal* aPrincipal) if (nsXPConnect::SecurityManager()->IsSystemPrincipal(aPrincipal)) return true; - // nsExpandedPrincipal gets a free pass. + // ExpandedPrincipal gets a free pass. nsCOMPtr ep = do_QueryInterface(aPrincipal); if (ep) return true; diff --git a/js/xpconnect/src/XPCWrappedNativeScope.cpp b/js/xpconnect/src/XPCWrappedNativeScope.cpp index c3c87d76a795..be86e0878158 100644 --- a/js/xpconnect/src/XPCWrappedNativeScope.cpp +++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp @@ -10,7 +10,7 @@ #include "XPCWrapper.h" #include "nsContentUtils.h" #include "nsCycleCollectionNoteRootCallback.h" -#include "nsExpandedPrincipal.h" +#include "ExpandedPrincipal.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Preferences.h" #include "nsIAddonInterposition.h" @@ -290,14 +290,14 @@ XPCWrappedNativeScope::EnsureContentXBLScope(JSContext* cx) options.proto = global; options.sameZoneAs = global; - // Use an nsExpandedPrincipal to create asymmetric security. + // Use an ExpandedPrincipal to create asymmetric security. nsIPrincipal* principal = GetPrincipal(); MOZ_ASSERT(!nsContentUtils::IsExpandedPrincipal(principal)); nsTArray> principalAsArray(1); principalAsArray.AppendElement(principal); - RefPtr ep = - nsExpandedPrincipal::Create(principalAsArray, - principal->OriginAttributesRef()); + RefPtr ep = + ExpandedPrincipal::Create(principalAsArray, + principal->OriginAttributesRef()); // Create the sandbox. RootedValue v(cx); diff --git a/js/xpconnect/tests/chrome/test_bug996069.xul b/js/xpconnect/tests/chrome/test_bug996069.xul index f61003bb1baa..52e33c2ec10f 100644 --- a/js/xpconnect/tests/chrome/test_bug996069.xul +++ b/js/xpconnect/tests/chrome/test_bug996069.xul @@ -28,15 +28,15 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=996069 ifr.wrappedJSObject.finishTest = function() { // If we got here we did not hit the NS_ReleaseAssert... - ok(true, "nsExpandedPrincipal should not be inherited by content windows"); + ok(true, "ExpandedPrincipal should not be inherited by content windows"); // But let's be sure that the new window does not have nsEP newWin.wrappedJSObject.obj = Cu.evalInSandbox("var obj = { foo: 'bar' }; obj", sb); try { newWin.eval("obj.foo"); - ok(false, "newWin should not have access to object from a scope with nsExpandedPrincipal"); + ok(false, "newWin should not have access to object from a scope with ExpandedPrincipal"); } catch (e) { - ok(/Permission denied/.exec(e.message), "newWin should not have access to object from a scope with nsExpandedPrincipal"); + ok(/Permission denied/.exec(e.message), "newWin should not have access to object from a scope with ExpandedPrincipal"); } newWin.close(); SimpleTest.finish(); From 1fd1bc393577873fc8b9263d83c520811f77514f Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 22 Mar 2017 11:38:40 +0100 Subject: [PATCH 53/96] Bug 1343933 - Renaming Principal classes - part 2 - NullPrincipal, r=qdot --HG-- rename : caps/nsNullPrincipal.cpp => caps/NullPrincipal.cpp rename : caps/nsNullPrincipal.h => caps/NullPrincipal.h rename : caps/nsNullPrincipalURI.cpp => caps/NullPrincipalURI.cpp rename : caps/nsNullPrincipalURI.h => caps/NullPrincipalURI.h --- caps/BasePrincipal.cpp | 8 +- ...{nsNullPrincipal.cpp => NullPrincipal.cpp} | 59 ++++---- caps/{nsNullPrincipal.h => NullPrincipal.h} | 19 +-- ...lPrincipalURI.cpp => NullPrincipalURI.cpp} | 130 +++++++++--------- ...sNullPrincipalURI.h => NullPrincipalURI.h} | 22 +-- caps/moz.build | 10 +- caps/nsScriptSecurityManager.cpp | 4 +- docshell/base/nsDocShell.cpp | 18 +-- dom/base/DOMParser.cpp | 6 +- dom/base/Location.cpp | 4 +- dom/base/nsContentUtils.cpp | 6 +- dom/base/nsDocument.cpp | 4 +- dom/base/nsFrameLoader.cpp | 4 +- dom/base/nsNodeInfoManager.cpp | 4 +- dom/base/nsTreeSanitizer.cpp | 4 +- dom/bindings/SimpleGlobalObject.cpp | 4 +- dom/json/nsJSON.cpp | 4 +- dom/media/MediaManager.cpp | 4 +- dom/media/MediaStreamTrack.h | 2 +- dom/plugins/base/nsPluginHost.cpp | 2 +- .../base/nsPluginStreamListenerPeer.cpp | 2 +- extensions/gio/nsGIOProtocolHandler.cpp | 2 +- gfx/thebes/gfxSVGGlyphs.cpp | 4 +- image/decoders/icon/android/nsIconChannel.cpp | 4 +- image/decoders/icon/gtk/nsIconChannel.cpp | 4 +- ipc/glue/BackgroundUtils.cpp | 4 +- ipc/glue/URIUtils.cpp | 4 +- js/xpconnect/src/Sandbox.cpp | 6 +- layout/build/nsLayoutModule.cpp | 6 +- layout/style/CSSStyleSheet.cpp | 2 +- layout/style/StyleSheet.cpp | 6 +- .../src/peerconnection/PeerConnectionImpl.cpp | 4 +- netwerk/base/LoadInfo.cpp | 8 +- .../protocol/ftp/nsFtpConnectionThread.cpp | 2 +- netwerk/protocol/http/nsCORSListenerProxy.cpp | 4 +- netwerk/protocol/http/nsHttpChannel.cpp | 2 +- .../viewsource/nsViewSourceChannel.cpp | 4 +- parser/html/nsParserUtils.cpp | 4 +- parser/htmlparser/nsExpatDriver.cpp | 4 +- parser/xml/nsSAXXMLReader.cpp | 4 +- rdf/base/nsRDFXMLParser.cpp | 4 +- .../components/places/nsFaviconService.cpp | 6 +- 42 files changed, 205 insertions(+), 203 deletions(-) rename caps/{nsNullPrincipal.cpp => NullPrincipal.cpp} (73%) rename caps/{nsNullPrincipal.h => NullPrincipal.h} (84%) rename caps/{nsNullPrincipalURI.cpp => NullPrincipalURI.cpp} (61%) rename caps/{nsNullPrincipalURI.h => NullPrincipalURI.h} (73%) diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index 466e4994cd0b..8ac83ef0c585 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -19,7 +19,7 @@ #include "nsPrincipal.h" #include "nsNetUtil.h" #include "nsIURIWithPrincipal.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsScriptSecurityManager.h" #include "nsServiceManagerUtils.h" @@ -645,7 +645,7 @@ BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAt nsresult rv = NS_URIChainHasFlags(aURI, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, &inheritsPrincipal); if (NS_FAILED(rv) || inheritsPrincipal) { - return nsNullPrincipal::Create(aAttrs); + return NullPrincipal::Create(aAttrs); } // Check whether the URI knows what its principal is supposed to be. @@ -654,7 +654,7 @@ BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAt nsCOMPtr principal; uriPrinc->GetPrincipal(getter_AddRefs(principal)); if (!principal) { - return nsNullPrincipal::Create(aAttrs); + return NullPrincipal::Create(aAttrs); } RefPtr concrete = Cast(principal); return concrete.forget(); @@ -674,7 +674,7 @@ BasePrincipal::CreateCodebasePrincipal(const nsACString& aOrigin) "CreateCodebasePrincipal does not support System and Expanded principals"); MOZ_ASSERT(!StringBeginsWith(aOrigin, NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME ":")), - "CreateCodebasePrincipal does not support nsNullPrincipal"); + "CreateCodebasePrincipal does not support NullPrincipal"); nsAutoCString originNoSuffix; mozilla::OriginAttributes attrs; diff --git a/caps/nsNullPrincipal.cpp b/caps/NullPrincipal.cpp similarity index 73% rename from caps/nsNullPrincipal.cpp rename to caps/NullPrincipal.cpp index fe846ac25b0c..b3e4c745e63a 100644 --- a/caps/nsNullPrincipal.cpp +++ b/caps/NullPrincipal.cpp @@ -13,8 +13,8 @@ #include "mozilla/ArrayUtils.h" #include "nsDocShell.h" -#include "nsNullPrincipal.h" -#include "nsNullPrincipalURI.h" +#include "NullPrincipal.h" +#include "NullPrincipalURI.h" #include "nsMemory.h" #include "nsIURIWithPrincipal.h" #include "nsIClassInfoImpl.h" @@ -27,40 +27,40 @@ using namespace mozilla; -NS_IMPL_CLASSINFO(nsNullPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, +NS_IMPL_CLASSINFO(NullPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, NS_NULLPRINCIPAL_CID) -NS_IMPL_QUERY_INTERFACE_CI(nsNullPrincipal, +NS_IMPL_QUERY_INTERFACE_CI(NullPrincipal, nsIPrincipal, nsISerializable) -NS_IMPL_CI_INTERFACE_GETTER(nsNullPrincipal, +NS_IMPL_CI_INTERFACE_GETTER(NullPrincipal, nsIPrincipal, nsISerializable) -/* static */ already_AddRefed -nsNullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom) +/* static */ already_AddRefed +NullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom) { - RefPtr nullPrin = new nsNullPrincipal(); + RefPtr nullPrin = new NullPrincipal(); nsresult rv = nullPrin->Init(Cast(aInheritFrom)->OriginAttributesRef()); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); return nullPrin.forget(); } -/* static */ already_AddRefed -nsNullPrincipal::CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty) +/* static */ already_AddRefed +NullPrincipal::CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty) { OriginAttributes attrs = nsDocShell::Cast(aDocShell)->GetOriginAttributes(); attrs.SetFirstPartyDomain(aIsFirstParty, NS_LITERAL_CSTRING(NULL_PRINCIPAL_FIRST_PARTY_DOMAIN)); - RefPtr nullPrin = new nsNullPrincipal(); + RefPtr nullPrin = new NullPrincipal(); nsresult rv = nullPrin->Init(attrs); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); return nullPrin.forget(); } -/* static */ already_AddRefed -nsNullPrincipal::Create(const OriginAttributes& aOriginAttributes, nsIURI* aURI) +/* static */ already_AddRefed +NullPrincipal::Create(const OriginAttributes& aOriginAttributes, nsIURI* aURI) { - RefPtr nullPrin = new nsNullPrincipal(); + RefPtr nullPrin = new NullPrincipal(); nsresult rv = nullPrin->Init(aOriginAttributes, aURI); MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); @@ -68,7 +68,7 @@ nsNullPrincipal::Create(const OriginAttributes& aOriginAttributes, nsIURI* aURI) } nsresult -nsNullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI) +NullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI) { mOriginAttributes = aOriginAttributes; @@ -82,7 +82,7 @@ nsNullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI) mURI = aURI; } else { - mURI = nsNullPrincipalURI::Create(); + mURI = NullPrincipalURI::Create(); NS_ENSURE_TRUE(mURI, NS_ERROR_NOT_AVAILABLE); } @@ -92,7 +92,7 @@ nsNullPrincipal::Init(const OriginAttributes& aOriginAttributes, nsIURI* aURI) } nsresult -nsNullPrincipal::GetScriptLocation(nsACString &aStr) +NullPrincipal::GetScriptLocation(nsACString &aStr) { return mURI->GetSpec(aStr); } @@ -102,14 +102,15 @@ nsNullPrincipal::GetScriptLocation(nsACString &aStr) */ NS_IMETHODIMP -nsNullPrincipal::GetHashValue(uint32_t *aResult) +NullPrincipal::GetHashValue(uint32_t *aResult) { *aResult = (NS_PTR_TO_INT32(this) >> 2); return NS_OK; } NS_IMETHODIMP -nsNullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) { +NullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) +{ // Never destroy an existing CSP on the principal. // This method should only be called in rare cases. @@ -123,19 +124,19 @@ nsNullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) { } NS_IMETHODIMP -nsNullPrincipal::GetURI(nsIURI** aURI) +NullPrincipal::GetURI(nsIURI** aURI) { return NS_EnsureSafeToReturn(mURI, aURI); } NS_IMETHODIMP -nsNullPrincipal::GetDomain(nsIURI** aDomain) +NullPrincipal::GetDomain(nsIURI** aDomain) { return NS_EnsureSafeToReturn(mURI, aDomain); } NS_IMETHODIMP -nsNullPrincipal::SetDomain(nsIURI* aDomain) +NullPrincipal::SetDomain(nsIURI* aDomain) { // I think the right thing to do here is to just throw... Silently failing // seems counterproductive. @@ -143,13 +144,13 @@ nsNullPrincipal::SetDomain(nsIURI* aDomain) } nsresult -nsNullPrincipal::GetOriginInternal(nsACString& aOrigin) +NullPrincipal::GetOriginInternal(nsACString& aOrigin) { return mURI->GetSpec(aOrigin); } bool -nsNullPrincipal::MayLoadInternal(nsIURI* aURI) +NullPrincipal::MayLoadInternal(nsIURI* aURI) { // Also allow the load if we are the principal of the URI being checked. nsCOMPtr uriPrinc = do_QueryInterface(aURI); @@ -166,14 +167,14 @@ nsNullPrincipal::MayLoadInternal(nsIURI* aURI) } NS_IMETHODIMP -nsNullPrincipal::GetBaseDomain(nsACString& aBaseDomain) +NullPrincipal::GetBaseDomain(nsACString& aBaseDomain) { // For a null principal, we use our unique uuid as the base domain. return mURI->GetPath(aBaseDomain); } NS_IMETHODIMP -nsNullPrincipal::GetAddonId(nsAString& aAddonId) +NullPrincipal::GetAddonId(nsAString& aAddonId) { aAddonId.Truncate(); return NS_OK; @@ -183,9 +184,9 @@ nsNullPrincipal::GetAddonId(nsAString& aAddonId) * nsISerializable implementation */ NS_IMETHODIMP -nsNullPrincipal::Read(nsIObjectInputStream* aStream) +NullPrincipal::Read(nsIObjectInputStream* aStream) { - // Note - nsNullPrincipal use NS_GENERIC_FACTORY_CONSTRUCTOR_INIT, which means + // Note - NullPrincipal use NS_GENERIC_FACTORY_CONSTRUCTOR_INIT, which means // that the Init() method has already been invoked by the time we deserialize. // This is in contrast to nsPrincipal, which uses NS_GENERIC_FACTORY_CONSTRUCTOR, // in which case ::Read needs to invoke Init(). @@ -210,7 +211,7 @@ nsNullPrincipal::Read(nsIObjectInputStream* aStream) } NS_IMETHODIMP -nsNullPrincipal::Write(nsIObjectOutputStream* aStream) +NullPrincipal::Write(nsIObjectOutputStream* aStream) { NS_ENSURE_STATE(mURI); diff --git a/caps/nsNullPrincipal.h b/caps/NullPrincipal.h similarity index 84% rename from caps/nsNullPrincipal.h rename to caps/NullPrincipal.h index 653029258f4b..b036d0c3b220 100644 --- a/caps/nsNullPrincipal.h +++ b/caps/NullPrincipal.h @@ -9,8 +9,8 @@ * same-origin with anything but themselves. */ -#ifndef nsNullPrincipal_h__ -#define nsNullPrincipal_h__ +#ifndef NullPrincipal_h +#define NullPrincipal_h #include "nsIPrincipal.h" #include "nsJSPrincipals.h" @@ -30,13 +30,13 @@ class nsIURI; #define NS_NULLPRINCIPAL_SCHEME "moz-nullprincipal" -class nsNullPrincipal final : public mozilla::BasePrincipal +class NullPrincipal final : public mozilla::BasePrincipal { public: // This should only be used by deserialization, and the factory constructor. // Other consumers should use the Create and CreateWithInheritedAttributes // methods. - nsNullPrincipal() + NullPrincipal() : BasePrincipal(eNullPrincipal) { } @@ -53,15 +53,16 @@ public: NS_IMETHOD GetAddonId(nsAString& aAddonId) override; nsresult GetOriginInternal(nsACString& aOrigin) override; - static already_AddRefed CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom); + static already_AddRefed CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom); // Create NullPrincipal with origin attributes from docshell. // If aIsFirstParty is true, and the pref 'privacy.firstparty.isolate' is also // enabled, the mFirstPartyDomain value of the origin attributes will be set // to NULL_PRINCIPAL_FIRST_PARTY_DOMAIN. - static already_AddRefed CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty = false); + static already_AddRefed + CreateWithInheritedAttributes(nsIDocShell* aDocShell, bool aIsFirstParty = false); - static already_AddRefed + static already_AddRefed Create(const mozilla::OriginAttributes& aOriginAttributes = mozilla::OriginAttributes(), nsIURI* aURI = nullptr); @@ -71,7 +72,7 @@ public: virtual nsresult GetScriptLocation(nsACString &aStr) override; protected: - virtual ~nsNullPrincipal() {} + virtual ~NullPrincipal() = default; bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override { @@ -83,4 +84,4 @@ public: nsCOMPtr mURI; }; -#endif // nsNullPrincipal_h__ +#endif // NullPrincipal_h__ diff --git a/caps/nsNullPrincipalURI.cpp b/caps/NullPrincipalURI.cpp similarity index 61% rename from caps/nsNullPrincipalURI.cpp rename to caps/NullPrincipalURI.cpp index f8b86716066b..17d98a488faf 100644 --- a/caps/nsNullPrincipalURI.cpp +++ b/caps/NullPrincipalURI.cpp @@ -4,7 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsNullPrincipalURI.h" +#include "NullPrincipalURI.h" #include "mozilla/DebugOnly.h" #include "mozilla/MemoryReporting.h" @@ -16,21 +16,21 @@ #include "nsIUUIDGenerator.h" //////////////////////////////////////////////////////////////////////////////// -//// nsNullPrincipalURI +//// NullPrincipalURI -nsNullPrincipalURI::nsNullPrincipalURI() +NullPrincipalURI::NullPrincipalURI() : mPath(mPathBytes, ArrayLength(mPathBytes), ArrayLength(mPathBytes) - 1) { } -nsNullPrincipalURI::nsNullPrincipalURI(const nsNullPrincipalURI& aOther) +NullPrincipalURI::NullPrincipalURI(const NullPrincipalURI& aOther) : mPath(mPathBytes, ArrayLength(mPathBytes), ArrayLength(mPathBytes) - 1) { mPath.Assign(aOther.mPath); } nsresult -nsNullPrincipalURI::Init() +NullPrincipalURI::Init() { // FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant. nsCOMPtr uuidgen = services::GetUUIDGenerator(); @@ -51,10 +51,10 @@ nsNullPrincipalURI::Init() } /* static */ -already_AddRefed -nsNullPrincipalURI::Create() +already_AddRefed +NullPrincipalURI::Create() { - RefPtr uri = new nsNullPrincipalURI(); + RefPtr uri = new NullPrincipalURI(); nsresult rv = uri->Init(); NS_ENSURE_SUCCESS(rv, nullptr); return uri.forget(); @@ -63,13 +63,13 @@ nsNullPrincipalURI::Create() static NS_DEFINE_CID(kNullPrincipalURIImplementationCID, NS_NULLPRINCIPALURI_IMPLEMENTATION_CID); -NS_IMPL_ADDREF(nsNullPrincipalURI) -NS_IMPL_RELEASE(nsNullPrincipalURI) +NS_IMPL_ADDREF(NullPrincipalURI) +NS_IMPL_RELEASE(NullPrincipalURI) -NS_INTERFACE_MAP_BEGIN(nsNullPrincipalURI) +NS_INTERFACE_MAP_BEGIN(NullPrincipalURI) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIURI) if (aIID.Equals(kNullPrincipalURIImplementationCID)) - foundInterface = static_cast(this); + foundInterface = static_cast(this); else NS_INTERFACE_MAP_ENTRY(nsIURI) NS_INTERFACE_MAP_ENTRY(nsISizeOf) @@ -80,23 +80,23 @@ NS_INTERFACE_MAP_END //// nsIURI NS_IMETHODIMP -nsNullPrincipalURI::GetAsciiHost(nsACString &_host) +NullPrincipalURI::GetAsciiHost(nsACString& _host) { _host.Truncate(); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::GetAsciiHostPort(nsACString &_hostport) +NullPrincipalURI::GetAsciiHostPort(nsACString& _hostport) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetAsciiSpec(nsACString &_spec) +NullPrincipalURI::GetAsciiSpec(nsACString& _spec) { nsAutoCString buffer; - // Ignore the return value -- nsNullPrincipalURI::GetSpec() is infallible. + // Ignore the return value -- NullPrincipalURI::GetSpec() is infallible. Unused << GetSpec(buffer); // This uses the infallible version of |NS_EscapeURL| as |GetSpec| is // already infallible. @@ -105,141 +105,141 @@ nsNullPrincipalURI::GetAsciiSpec(nsACString &_spec) } NS_IMETHODIMP -nsNullPrincipalURI::GetHost(nsACString &_host) +NullPrincipalURI::GetHost(nsACString& _host) { _host.Truncate(); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SetHost(const nsACString &aHost) +NullPrincipalURI::SetHost(const nsACString& aHost) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetHostPort(nsACString &_host) +NullPrincipalURI::GetHostPort(nsACString& _host) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetHostPort(const nsACString &aHost) +NullPrincipalURI::SetHostPort(const nsACString& aHost) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetHostAndPort(const nsACString &aHost) +NullPrincipalURI::SetHostAndPort(const nsACString& aHost) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetOriginCharset(nsACString &_charset) +NullPrincipalURI::GetOriginCharset(nsACString& _charset) { _charset.Truncate(); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::GetPassword(nsACString &_password) +NullPrincipalURI::GetPassword(nsACString& _password) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetPassword(const nsACString &aPassword) +NullPrincipalURI::SetPassword(const nsACString& aPassword) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetPath(nsACString &_path) +NullPrincipalURI::GetPath(nsACString& _path) { _path = mPath; return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SetPath(const nsACString &aPath) +NullPrincipalURI::SetPath(const nsACString& aPath) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetFilePath(nsACString &aFilePath) +NullPrincipalURI::GetFilePath(nsACString& aFilePath) { aFilePath.Truncate(); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetFilePath(const nsACString &aFilePath) +NullPrincipalURI::SetFilePath(const nsACString& aFilePath) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetQuery(nsACString &aQuery) +NullPrincipalURI::GetQuery(nsACString& aQuery) { aQuery.Truncate(); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetQuery(const nsACString &aQuery) +NullPrincipalURI::SetQuery(const nsACString& aQuery) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetRef(nsACString &_ref) +NullPrincipalURI::GetRef(nsACString& _ref) { _ref.Truncate(); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetRef(const nsACString &aRef) +NullPrincipalURI::SetRef(const nsACString& aRef) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetPrePath(nsACString &_prePath) +NullPrincipalURI::GetPrePath(nsACString& _prePath) { _prePath = NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME ":"); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::GetPort(int32_t *_port) +NullPrincipalURI::GetPort(int32_t* _port) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetPort(int32_t aPort) +NullPrincipalURI::SetPort(int32_t aPort) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetScheme(nsACString &_scheme) +NullPrincipalURI::GetScheme(nsACString& _scheme) { _scheme = NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SetScheme(const nsACString &aScheme) +NullPrincipalURI::SetScheme(const nsACString& aScheme) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetSpec(nsACString &_spec) +NullPrincipalURI::GetSpec(nsACString& _spec) { _spec = NS_LITERAL_CSTRING(NS_NULLPRINCIPAL_SCHEME ":") + mPath; return NS_OK; @@ -247,77 +247,77 @@ nsNullPrincipalURI::GetSpec(nsACString &_spec) // result may contain unescaped UTF-8 characters NS_IMETHODIMP -nsNullPrincipalURI::GetSpecIgnoringRef(nsACString &result) +NullPrincipalURI::GetSpecIgnoringRef(nsACString& _result) { - return GetSpec(result); + return GetSpec(_result); } NS_IMETHODIMP -nsNullPrincipalURI::GetHasRef(bool *result) +NullPrincipalURI::GetHasRef(bool* _result) { - *result = false; + *_result = false; return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SetSpec(const nsACString &aSpec) +NullPrincipalURI::SetSpec(const nsACString& aSpec) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetUsername(nsACString &_username) +NullPrincipalURI::GetUsername(nsACString& _username) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetUsername(const nsACString &aUsername) +NullPrincipalURI::SetUsername(const nsACString& aUsername) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::GetUserPass(nsACString &_userPass) +NullPrincipalURI::GetUserPass(nsACString& _userPass) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::SetUserPass(const nsACString &aUserPass) +NullPrincipalURI::SetUserPass(const nsACString& aUserPass) { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsNullPrincipalURI::Clone(nsIURI **_newURI) +NullPrincipalURI::Clone(nsIURI** _newURI) { - nsCOMPtr uri = new nsNullPrincipalURI(*this); + nsCOMPtr uri = new NullPrincipalURI(*this); uri.forget(_newURI); return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::CloneIgnoringRef(nsIURI **_newURI) +NullPrincipalURI::CloneIgnoringRef(nsIURI** _newURI) { - // GetRef/SetRef not supported by nsNullPrincipalURI, so + // GetRef/SetRef not supported by NullPrincipalURI, so // CloneIgnoringRef() is the same as Clone(). return Clone(_newURI); } NS_IMETHODIMP -nsNullPrincipalURI::CloneWithNewRef(const nsACString& newRef, nsIURI **_newURI) +NullPrincipalURI::CloneWithNewRef(const nsACString& newRef, nsIURI** _newURI) { - // GetRef/SetRef not supported by nsNullPrincipalURI, so + // GetRef/SetRef not supported by NullPrincipalURI, so // CloneWithNewRef() is the same as Clone(). return Clone(_newURI); } NS_IMETHODIMP -nsNullPrincipalURI::Equals(nsIURI *aOther, bool *_equals) +NullPrincipalURI::Equals(nsIURI* aOther, bool* _equals) { *_equals = false; - RefPtr otherURI; + RefPtr otherURI; nsresult rv = aOther->QueryInterface(kNullPrincipalURIImplementationCID, getter_AddRefs(otherURI)); if (NS_SUCCEEDED(rv)) { @@ -327,23 +327,23 @@ nsNullPrincipalURI::Equals(nsIURI *aOther, bool *_equals) } NS_IMETHODIMP -nsNullPrincipalURI::EqualsExceptRef(nsIURI *aOther, bool *_equals) +NullPrincipalURI::EqualsExceptRef(nsIURI* aOther, bool* _equals) { - // GetRef/SetRef not supported by nsNullPrincipalURI, so + // GetRef/SetRef not supported by NullPrincipalURI, so // EqualsExceptRef() is the same as Equals(). return Equals(aOther, _equals); } NS_IMETHODIMP -nsNullPrincipalURI::Resolve(const nsACString &aRelativePath, - nsACString &_resolvedURI) +NullPrincipalURI::Resolve(const nsACString& aRelativePath, + nsACString& _resolvedURI) { _resolvedURI = aRelativePath; return NS_OK; } NS_IMETHODIMP -nsNullPrincipalURI::SchemeIs(const char *aScheme, bool *_schemeIs) +NullPrincipalURI::SchemeIs(const char* aScheme, bool* _schemeIs) { *_schemeIs = (0 == nsCRT::strcasecmp(NS_NULLPRINCIPAL_SCHEME, aScheme)); return NS_OK; @@ -353,13 +353,13 @@ nsNullPrincipalURI::SchemeIs(const char *aScheme, bool *_schemeIs) //// nsIIPCSerializableURI void -nsNullPrincipalURI::Serialize(mozilla::ipc::URIParams &aParams) +NullPrincipalURI::Serialize(mozilla::ipc::URIParams& aParams) { aParams = mozilla::ipc::NullPrincipalURIParams(); } bool -nsNullPrincipalURI::Deserialize(const mozilla::ipc::URIParams &aParams) +NullPrincipalURI::Deserialize(const mozilla::ipc::URIParams& aParams) { if (aParams.type() != mozilla::ipc::URIParams::TNullPrincipalURIParams) { MOZ_ASSERT_UNREACHABLE("unexpected URIParams type"); @@ -376,13 +376,13 @@ nsNullPrincipalURI::Deserialize(const mozilla::ipc::URIParams &aParams) //// nsISizeOf size_t -nsNullPrincipalURI::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const +NullPrincipalURI::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { return mPath.SizeOfExcludingThisIfUnshared(aMallocSizeOf); } size_t -nsNullPrincipalURI::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const { +NullPrincipalURI::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const +{ return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); } - diff --git a/caps/nsNullPrincipalURI.h b/caps/NullPrincipalURI.h similarity index 73% rename from caps/nsNullPrincipalURI.h rename to caps/NullPrincipalURI.h index 63d7221c2832..fb4c60c0b4cb 100644 --- a/caps/nsNullPrincipalURI.h +++ b/caps/NullPrincipalURI.h @@ -8,8 +8,8 @@ * This wraps nsSimpleURI so that all calls to it are done on the main thread. */ -#ifndef __nsNullPrincipalURI_h__ -#define __nsNullPrincipalURI_h__ +#ifndef __NullPrincipalURI_h__ +#define __NullPrincipalURI_h__ #include "nsIURI.h" #include "nsISizeOf.h" @@ -17,7 +17,7 @@ #include "mozilla/Attributes.h" #include "nsIIPCSerializableURI.h" #include "mozilla/MemoryReporting.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsID.h" // {51fcd543-3b52-41f7-b91b-6b54102236e6} @@ -25,9 +25,9 @@ {0x51fcd543, 0x3b52, 0x41f7, \ {0xb9, 0x1b, 0x6b, 0x54, 0x10, 0x22, 0x36, 0xe6} } -class nsNullPrincipalURI final : public nsIURI - , public nsISizeOf - , public nsIIPCSerializableURI +class NullPrincipalURI final : public nsIURI + , public nsISizeOf + , public nsIIPCSerializableURI { public: NS_DECL_THREADSAFE_ISUPPORTS @@ -40,15 +40,15 @@ public: // NB: This constructor exists only for deserialization. Everyone // else should call Create. - nsNullPrincipalURI(); + NullPrincipalURI(); // Returns null on failure. - static already_AddRefed Create(); + static already_AddRefed Create(); private: - nsNullPrincipalURI(const nsNullPrincipalURI& aOther); + NullPrincipalURI(const NullPrincipalURI& aOther); - ~nsNullPrincipalURI() {} + ~NullPrincipalURI() {} nsresult Init(); @@ -56,4 +56,4 @@ private: nsFixedCString mPath; }; -#endif // __nsNullPrincipalURI_h__ +#endif // __NullPrincipalURI_h__ diff --git a/caps/moz.build b/caps/moz.build index 3d5e52af9710..3da5ffbdce63 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -25,8 +25,8 @@ XPIDL_MODULE = 'caps' EXPORTS += [ 'nsJSPrincipals.h', - 'nsNullPrincipal.h', - 'nsNullPrincipalURI.h', + 'NullPrincipal.h', + 'NullPrincipalURI.h', ] EXPORTS.mozilla = [ @@ -35,7 +35,7 @@ EXPORTS.mozilla = [ SOURCES += [ # Compile this separately since nsExceptionHandler.h conflicts - # with something from nsNullPrincipal.cpp. + # with something from NullPrincipal.cpp. 'BasePrincipal.cpp', ] @@ -43,11 +43,11 @@ UNIFIED_SOURCES += [ 'DomainPolicy.cpp', 'ExpandedPrincipal.cpp', 'nsJSPrincipals.cpp', - 'nsNullPrincipal.cpp', - 'nsNullPrincipalURI.cpp', 'nsPrincipal.cpp', 'nsScriptSecurityManager.cpp', 'nsSystemPrincipal.cpp', + 'NullPrincipal.cpp', + 'NullPrincipalURI.cpp', ] LOCAL_INCLUDES += [ diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index a3874ab22ce0..52b60331126c 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -22,7 +22,7 @@ #include "mozilla/BasePrincipal.h" #include "nsSystemPrincipal.h" #include "nsPrincipal.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "DomainPolicy.h" #include "nsXPIDLString.h" #include "nsCRT.h" @@ -1141,7 +1141,7 @@ nsScriptSecurityManager::CreateNullPrincipal(JS::Handle aOriginAttrib if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) { return NS_ERROR_INVALID_ARG; } - nsCOMPtr prin = nsNullPrincipal::Create(attrs); + nsCOMPtr prin = NullPrincipal::Create(attrs); prin.forget(aPrincipal); return NS_OK; } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 04fa021fcb79..6ed2909fb70e 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -120,7 +120,7 @@ #include "nsITimer.h" #include "nsISHistoryInternal.h" #include "nsIPrincipal.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsISHEntry.h" #include "nsIWindowWatcher.h" #include "nsIPromptFactory.h" @@ -1501,7 +1501,7 @@ nsDocShell::LoadURI(nsIURI* aURI, // // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't // have origin attributes. - principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this); + principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this); inheritPrincipal = false; } } @@ -1514,7 +1514,7 @@ nsDocShell::LoadURI(nsIURI* aURI, inheritPrincipal = false; // If aFirstParty is true and the pref 'privacy.firstparty.isolate' is // enabled, we will set firstPartyDomain on the origin attributes. - principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this, aFirstParty); + principalToInherit = NullPrincipal::CreateWithInheritedAttributes(this, aFirstParty); } // If the triggeringPrincipal is not passed explicitly, we first try to create @@ -8127,9 +8127,9 @@ nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal, nsCOMPtr principal; if (mSandboxFlags & SANDBOXED_ORIGIN) { if (aPrincipal) { - principal = nsNullPrincipal::CreateWithInheritedAttributes(aPrincipal); + principal = NullPrincipal::CreateWithInheritedAttributes(aPrincipal); } else { - principal = nsNullPrincipal::CreateWithInheritedAttributes(this); + principal = NullPrincipal::CreateWithInheritedAttributes(this); } } else { principal = aPrincipal; @@ -12409,13 +12409,13 @@ nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel, if (!principalToInherit) { if (loadInfo->GetLoadingSandboxed()) { if (loadInfo->LoadingPrincipal()) { - principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes( + principalToInherit = NullPrincipal::CreateWithInheritedAttributes( loadInfo->LoadingPrincipal()); } else { // get the OriginAttributes OriginAttributes attrs; loadInfo->GetOriginAttributes(&attrs); - principalToInherit = nsNullPrincipal::Create(attrs); + principalToInherit = NullPrincipal::Create(attrs); } } else { principalToInherit = loadInfo->PrincipalToInherit(); @@ -12606,7 +12606,7 @@ nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType) // Ensure that we have a triggeringPrincipal. Otherwise javascript: // URIs will pick it up from the about:blank page we just loaded, // and we don't really want even that in this case. - triggeringPrincipal = nsNullPrincipal::CreateWithInheritedAttributes(this); + triggeringPrincipal = NullPrincipal::CreateWithInheritedAttributes(this); } } @@ -14378,7 +14378,7 @@ nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview) // we QI the mContentViewer if the current URI is either about:blank // or about:printpreview. Stop(nsIWebNavigation::STOP_ALL); - nsCOMPtr principal = nsNullPrincipal::CreateWithInheritedAttributes(this); + nsCOMPtr principal = NullPrincipal::CreateWithInheritedAttributes(this); nsCOMPtr uri; NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:printpreview")); nsresult rv = CreateAboutBlankContentViewer(principal, uri); diff --git a/dom/base/DOMParser.cpp b/dom/base/DOMParser.cpp index 3d063369a49b..da81cfc6b672 100644 --- a/dom/base/DOMParser.cpp +++ b/dom/base/DOMParser.cpp @@ -18,7 +18,7 @@ #include "nsDOMJSUtils.h" #include "nsError.h" #include "nsPIDOMWindow.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/LoadInfo.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/ScriptSettings.h" @@ -345,7 +345,7 @@ DOMParser::Init(nsIPrincipal* principal, nsIURI* documentURI, // Don't give DOMParsers the system principal. Use a null // principal instead. mOriginalPrincipalWasSystem = true; - mPrincipal = nsNullPrincipal::Create(); + mPrincipal = NullPrincipal::Create(); if (!mDocumentURI) { rv = mPrincipal->GetURI(getter_AddRefs(mDocumentURI)); @@ -456,7 +456,7 @@ DOMParser::SetUpDocument(DocumentFlavor aFlavor, nsIDOMDocument** aResult) NS_ENSURE_TRUE(!mAttemptedInit, NS_ERROR_NOT_INITIALIZED); AttemptedInitMarker marker(&mAttemptedInit); - nsCOMPtr prin = nsNullPrincipal::Create(); + nsCOMPtr prin = NullPrincipal::Create(); rv = Init(prin, nullptr, nullptr, scriptHandlingObject); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/dom/base/Location.cpp b/dom/base/Location.cpp index d93dee5f3f52..6a269fe631e4 100644 --- a/dom/base/Location.cpp +++ b/dom/base/Location.cpp @@ -31,7 +31,7 @@ #include "nsGlobalWindow.h" #include "mozilla/Likely.h" #include "nsCycleCollectionParticipant.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "ScriptSettings.h" #include "mozilla/Unused.h" #include "mozilla/dom/LocationBinding.h" @@ -164,7 +164,7 @@ Location::CheckURL(nsIURI* aURI, nsIDocShellLoadInfo** aLoadInfo) sourceURI = docCurrentURI; } else { - // Use principalURI as long as it is not an nsNullPrincipalURI. We + // Use principalURI as long as it is not an NullPrincipalURI. We // could add a method such as GetReferrerURI to principals to make this // cleaner, but given that we need to start using Source Browsing // Context for referrer (see Bug 960639) this may be wasted effort at diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index f7e0c1c9b96e..d3fa869985d8 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -182,7 +182,7 @@ #include "nsNetCID.h" #include "nsNetUtil.h" #include "nsNodeInfoManager.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsParserCIID.h" #include "nsParserConstants.h" #include "nsPIDOMWindow.h" @@ -514,7 +514,7 @@ nsContentUtils::Init() sSecurityManager->GetSystemPrincipal(&sSystemPrincipal); MOZ_ASSERT(sSystemPrincipal); - RefPtr nullPrincipal = nsNullPrincipal::Create(); + RefPtr nullPrincipal = NullPrincipal::Create(); if (!nullPrincipal) { return NS_ERROR_FAILURE; } @@ -4790,7 +4790,7 @@ nsContentUtils::ConvertToPlainText(const nsAString& aSourceBuffer, { nsCOMPtr uri; NS_NewURI(getter_AddRefs(uri), "about:blank"); - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); nsCOMPtr domDocument; nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument), EmptyString(), diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index b05ad121f579..22da15285c34 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -106,7 +106,7 @@ #include "nsIScriptSecurityManager.h" #include "nsIPermissionManager.h" #include "nsIPrincipal.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIDOMWindow.h" #include "nsPIDOMWindow.h" @@ -2723,7 +2723,7 @@ nsDocument::InitCSP(nsIChannel* aChannel) if (cspSandboxFlags & SANDBOXED_ORIGIN) { // If the new CSP sandbox flags do not have the allow-same-origin flag // reset the document principal to a null principal - principal = nsNullPrincipal::Create(); + principal = NullPrincipal::Create(); SetPrincipal(principal); } diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 0217c97ffa54..052f77ab6df9 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -50,7 +50,7 @@ #include "nsIEditor.h" #include "nsIMozBrowserFrame.h" #include "nsISHistory.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIScriptError.h" #include "nsGlobalWindow.h" #include "nsPIWindowRoot.h" @@ -831,7 +831,7 @@ nsFrameLoader::ReallyStartLoadingInternal() NS_ENSURE_SUCCESS(rv, rv); } - // Use referrer as long as it is not an nsNullPrincipalURI. + // Use referrer as long as it is not an NullPrincipalURI. // We could add a method such as GetReferrerURI to principals to make this // cleaner, but given that we need to start using Source Browsing Context for // referrer (see Bug 960639) this may be wasted effort at this stage. diff --git a/dom/base/nsNodeInfoManager.cpp b/dom/base/nsNodeInfoManager.cpp index 66c8c84cfd31..b0169b82ba0e 100644 --- a/dom/base/nsNodeInfoManager.cpp +++ b/dom/base/nsNodeInfoManager.cpp @@ -30,7 +30,7 @@ #include "nsCCUncollectableMarker.h" #include "nsNameSpaceManager.h" #include "nsDocument.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" using namespace mozilla; using mozilla::dom::NodeInfo; @@ -182,7 +182,7 @@ nsNodeInfoManager::Init(nsIDocument *aDocument) NS_PRECONDITION(!mPrincipal, "Being inited when we already have a principal?"); - mPrincipal = nsNullPrincipal::Create(); + mPrincipal = NullPrincipal::Create(); if (aDocument) { mBindingManager = new nsBindingManager(aDocument); diff --git a/dom/base/nsTreeSanitizer.cpp b/dom/base/nsTreeSanitizer.cpp index c234a15301ba..b9dd8e4e1db0 100644 --- a/dom/base/nsTreeSanitizer.cpp +++ b/dom/base/nsTreeSanitizer.cpp @@ -19,7 +19,7 @@ #include "nsIScriptSecurityManager.h" #include "nsNetUtil.h" #include "nsComponentManagerUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsContentUtils.h" #include "nsIParserUtils.h" #include "nsIDocument.h" @@ -1522,7 +1522,7 @@ nsTreeSanitizer::InitializeStatics() sAttributesMathML->PutEntry(*kAttributesMathML[i]); } - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); principal.forget(&sNullPrincipal); } diff --git a/dom/bindings/SimpleGlobalObject.cpp b/dom/bindings/SimpleGlobalObject.cpp index 5659138c852f..2a9f5656c532 100644 --- a/dom/bindings/SimpleGlobalObject.cpp +++ b/dom/bindings/SimpleGlobalObject.cpp @@ -10,7 +10,7 @@ #include "js/Class.h" #include "nsJSPrincipals.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsThreadUtils.h" #include "nsContentUtils.h" @@ -113,7 +113,7 @@ SimpleGlobalObject::Create(GlobalType globalType, JS::Handle proto) .setSystemZone(); if (NS_IsMainThread()) { - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); options.creationOptions().setTrace(xpc::TraceXPCGlobal); global = xpc::CreateGlobalObject(cx, js::Jsvalify(&SimpleGlobalClass), nsJSPrincipals::get(principal), diff --git a/dom/json/nsJSON.cpp b/dom/json/nsJSON.cpp index 4a6503fb8eaf..2884c7bc96f3 100644 --- a/dom/json/nsJSON.cpp +++ b/dom/json/nsJSON.cpp @@ -22,7 +22,7 @@ #include "nsIScriptError.h" #include "nsCRTGlue.h" #include "nsIScriptSecurityManager.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/Maybe.h" #include @@ -407,7 +407,7 @@ nsJSON::DecodeInternal(JSContext* cx, } nsresult rv; - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); // The ::Decode function is deprecated [Bug 675797] and the following // channel is never openend, so it does not matter what securityFlags diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 7a81f835a086..0fa7b7fd81d0 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -54,7 +54,7 @@ #include "VideoUtils.h" #include "Latency.h" #include "nsProxyRelease.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsVariant.h" // For snprintf @@ -1155,7 +1155,7 @@ public: nsCOMPtr principal; if (mPeerIdentity) { - principal = nsNullPrincipal::CreateWithInheritedAttributes(window->GetExtantDoc()->NodePrincipal()); + principal = NullPrincipal::CreateWithInheritedAttributes(window->GetExtantDoc()->NodePrincipal()); } else { principal = window->GetExtantDoc()->NodePrincipal(); } diff --git a/dom/media/MediaStreamTrack.h b/dom/media/MediaStreamTrack.h index cb11e919ac2e..c433f1a5656c 100644 --- a/dom/media/MediaStreamTrack.h +++ b/dom/media/MediaStreamTrack.h @@ -97,7 +97,7 @@ public: * This is used in WebRTC. A peerIdentity constrained MediaStreamTrack cannot * be sent across the network to anything other than a peer with the provided * identity. If this is set, then GetPrincipal() should return an instance of - * nsNullPrincipal. + * NullPrincipal. * * A track's PeerIdentity is immutable and will not change during the track's * lifetime. diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 24816654569f..3b8ace19e1ee 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -94,7 +94,7 @@ #include "nsIImageLoadingContent.h" #include "mozilla/Preferences.h" #include "nsVersionComparator.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #if defined(XP_WIN) #include "nsIWindowMediator.h" diff --git a/dom/plugins/base/nsPluginStreamListenerPeer.cpp b/dom/plugins/base/nsPluginStreamListenerPeer.cpp index 283f1da7e277..a6d0634fbdfc 100644 --- a/dom/plugins/base/nsPluginStreamListenerPeer.cpp +++ b/dom/plugins/base/nsPluginStreamListenerPeer.cpp @@ -33,7 +33,7 @@ #include "GeckoProfiler.h" #include "nsPluginInstanceOwner.h" #include "nsDataHashtable.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #define BYTERANGE_REQUEST_CONTEXT 0x01020304 diff --git a/extensions/gio/nsGIOProtocolHandler.cpp b/extensions/gio/nsGIOProtocolHandler.cpp index 793f80267014..eae6e1da0fe5 100644 --- a/extensions/gio/nsGIOProtocolHandler.cpp +++ b/extensions/gio/nsGIOProtocolHandler.cpp @@ -24,7 +24,7 @@ #include "nsIChannel.h" #include "nsIInputStream.h" #include "nsIProtocolHandler.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/Monitor.h" #include "plstr.h" #include "prtime.h" diff --git a/gfx/thebes/gfxSVGGlyphs.cpp b/gfx/thebes/gfxSVGGlyphs.cpp index 21e88212deab..6276e882ddf7 100644 --- a/gfx/thebes/gfxSVGGlyphs.cpp +++ b/gfx/thebes/gfxSVGGlyphs.cpp @@ -16,7 +16,7 @@ #include "nsServiceManagerUtils.h" #include "nsIPresShell.h" #include "nsNetUtil.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIInputStream.h" #include "nsStringStream.h" #include "nsStreamUtils.h" @@ -359,7 +359,7 @@ gfxSVGGlyphsDocument::ParseDocument(const uint8_t *aBuffer, uint32_t aBufLen) rv = NS_NewURI(getter_AddRefs(uri), mSVGGlyphsDocumentURI); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); nsCOMPtr domDoc; rv = NS_NewDOMDocument(getter_AddRefs(domDoc), diff --git a/image/decoders/icon/android/nsIconChannel.cpp b/image/decoders/icon/android/nsIconChannel.cpp index 5670bf2f9540..11d58ea20a89 100644 --- a/image/decoders/icon/android/nsIconChannel.cpp +++ b/image/decoders/icon/android/nsIconChannel.cpp @@ -13,7 +13,7 @@ #include "nsIStringStream.h" #include "nsNetUtil.h" #include "nsComponentManagerUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" NS_IMPL_ISUPPORTS(nsIconChannel, nsIRequest, @@ -115,7 +115,7 @@ moz_icon_to_channel(nsIURI* aURI, const nsACString& aFileExt, // nsIconProtocolHandler::NewChannel2 will provide the correct loadInfo for // this iconChannel. Use the most restrictive security settings for the // temporary loadInfo to make sure the channel can not be openend. - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); return NS_NewInputStreamChannel(aChannel, aURI, stream, diff --git a/image/decoders/icon/gtk/nsIconChannel.cpp b/image/decoders/icon/gtk/nsIconChannel.cpp index 3d3820e72465..c050a37ce93d 100644 --- a/image/decoders/icon/gtk/nsIconChannel.cpp +++ b/image/decoders/icon/gtk/nsIconChannel.cpp @@ -27,7 +27,7 @@ #include "nsComponentManagerUtils.h" #include "nsIStringStream.h" #include "nsServiceManagerUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIURL.h" #include "prlink.h" @@ -107,7 +107,7 @@ moz_gdk_pixbuf_to_channel(GdkPixbuf* aPixbuf, nsIURI* aURI, // nsIconProtocolHandler::NewChannel2 will provide the correct loadInfo for // this iconChannel. Use the most restrictive security settings for the // temporary loadInfo to make sure the channel can not be openend. - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); return NS_NewInputStreamChannel(aChannel, aURI, stream, diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index a2936e1cfcc3..8ec75c5e026b 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -17,7 +17,7 @@ #include "nsIURI.h" #include "nsNetUtil.h" #include "mozilla/LoadInfo.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsServiceManagerUtils.h" #include "nsString.h" #include "nsTArray.h" @@ -70,7 +70,7 @@ PrincipalInfoToPrincipal(const PrincipalInfo& aPrincipalInfo, return nullptr; } - principal = nsNullPrincipal::Create(info.attrs(), uri); + principal = NullPrincipal::Create(info.attrs(), uri); return principal.forget(); } diff --git a/ipc/glue/URIUtils.cpp b/ipc/glue/URIUtils.cpp index ec7656d74e8c..b961310d33bb 100644 --- a/ipc/glue/URIUtils.cpp +++ b/ipc/glue/URIUtils.cpp @@ -16,7 +16,7 @@ #include "nsJARURI.h" #include "nsIIconURI.h" #include "nsHostObjectURI.h" -#include "nsNullPrincipalURI.h" +#include "NullPrincipalURI.h" #include "nsJSProtocolHandler.h" #include "nsNetCID.h" #include "nsSimpleNestedURI.h" @@ -100,7 +100,7 @@ DeserializeURI(const URIParams& aParams) break; case URIParams::TNullPrincipalURIParams: - serializable = new nsNullPrincipalURI(); + serializable = new NullPrincipalURI(); break; case URIParams::TSimpleNestedURIParams: diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 2a90b7ada490..4c1d884c3725 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -19,7 +19,7 @@ #include "nsIURI.h" #include "nsJSUtils.h" #include "nsNetUtil.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "ExpandedPrincipal.h" #include "WrapperFactory.h" #include "xpcprivate.h" @@ -1049,7 +1049,7 @@ xpc::CreateSandboxObject(JSContext* cx, MutableHandleValue vp, nsISupports* prin if (sop) { principal = sop->GetPrincipal(); } else { - RefPtr nullPrin = nsNullPrincipal::Create(); + RefPtr nullPrin = NullPrincipal::Create(); principal = nullPrin; } } @@ -1784,7 +1784,7 @@ nsXPCComponents_utils_Sandbox::CallOrConstruct(nsIXPConnectWrappedNative* wrappe } } else if (args[0].isNull()) { // Null means that we just pass prinOrSop = nullptr, and get an - // nsNullPrincipal. + // NullPrincipal. ok = true; } diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 064a0a2e184d..705642aaf3d1 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -133,7 +133,7 @@ using mozilla::dom::AudioChannelAgent; #include "nsScriptSecurityManager.h" #include "nsPrincipal.h" #include "nsSystemPrincipal.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsNetCID.h" #ifndef MOZ_WIDGET_GONK #if defined(MOZ_WIDGET_ANDROID) @@ -593,7 +593,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsMixedContentBlocker) NS_GENERIC_FACTORY_CONSTRUCTOR(nsPrincipal) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemPrincipal, nsScriptSecurityManager::SystemPrincipalSingletonConstructor) -NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsNullPrincipal, Init) +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NullPrincipal, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsStructuredCloneContainer) NS_GENERIC_FACTORY_CONSTRUCTOR(OSFileConstantsService) @@ -1029,7 +1029,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kNS_SCRIPTSECURITYMANAGER_CID, false, nullptr, Construct_nsIScriptSecurityManager }, { &kNS_PRINCIPAL_CID, false, nullptr, nsPrincipalConstructor }, { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, nsSystemPrincipalConstructor }, - { &kNS_NULLPRINCIPAL_CID, false, nullptr, nsNullPrincipalConstructor }, + { &kNS_NULLPRINCIPAL_CID, false, nullptr, NullPrincipalConstructor }, { &kNS_DEVICE_SENSORS_CID, false, nullptr, nsDeviceSensorsConstructor }, #ifndef MOZ_WIDGET_GONK #if defined(ANDROID) diff --git a/layout/style/CSSStyleSheet.cpp b/layout/style/CSSStyleSheet.cpp index 84d0f7c9f476..6b1444c9e7d7 100644 --- a/layout/style/CSSStyleSheet.cpp +++ b/layout/style/CSSStyleSheet.cpp @@ -43,7 +43,7 @@ #include "nsDOMClassInfoID.h" #include "mozilla/Likely.h" #include "nsComponentManagerUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/RuleProcessorCache.h" #include "nsIStyleSheetLinkingElement.h" #include "nsDOMWindowUtils.h" diff --git a/layout/style/StyleSheet.cpp b/layout/style/StyleSheet.cpp index fdb901eb2e80..c0cc593b51dc 100644 --- a/layout/style/StyleSheet.cpp +++ b/layout/style/StyleSheet.cpp @@ -15,7 +15,7 @@ #include "mozAutoDocUpdate.h" #include "nsMediaList.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" namespace mozilla { @@ -202,7 +202,7 @@ StyleSheet::SetEnabled(bool aEnabled) StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy, const dom::SRIMetadata& aIntegrity) - : mPrincipal(nsNullPrincipal::Create()) + : mPrincipal(NullPrincipal::Create()) , mCORSMode(aCORSMode) , mReferrerPolicy(aReferrerPolicy) , mIntegrity(aIntegrity) @@ -212,7 +212,7 @@ StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode, #endif { if (!mPrincipal) { - NS_RUNTIMEABORT("nsNullPrincipal::Init failed"); + NS_RUNTIMEABORT("NullPrincipal::Init failed"); } } diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index 2ee486e90188..d65ceda2ec6b 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -74,7 +74,7 @@ #include "nsIURLParser.h" #include "nsIDOMDataChannel.h" #include "nsIDOMLocation.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/PeerIdentity.h" #include "mozilla/dom/RTCCertificate.h" #include "mozilla/dom/RTCConfigurationBinding.h" @@ -1877,7 +1877,7 @@ PeerConnectionImpl::CreateNewRemoteTracks(RefPtr& aPco) } else { // we're either certain that we need isolation for the streams, OR // we're not sure and we can fix the stream in SetDtlsConnected - principal = nsNullPrincipal::CreateWithInheritedAttributes(doc->NodePrincipal()); + principal = NullPrincipal::CreateWithInheritedAttributes(doc->NodePrincipal()); } // We need to select unique ids, just use max + 1 diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index a11a35c3c314..c9992f812346 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -21,7 +21,7 @@ #include "nsContentUtils.h" #include "nsDocShell.h" #include "nsGlobalWindow.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" using namespace mozilla::dom; @@ -465,10 +465,10 @@ LoadInfo::GetSandboxedLoadingPrincipal(nsIPrincipal** aPrincipal) if (!mSandboxedLoadingPrincipal) { if (mLoadingPrincipal) { mSandboxedLoadingPrincipal = - nsNullPrincipal::CreateWithInheritedAttributes(mLoadingPrincipal); + NullPrincipal::CreateWithInheritedAttributes(mLoadingPrincipal); } else { OriginAttributes attrs(mOriginAttributes); - mSandboxedLoadingPrincipal = nsNullPrincipal::Create(attrs); + mSandboxedLoadingPrincipal = NullPrincipal::Create(attrs); } } MOZ_ASSERT(mSandboxedLoadingPrincipal); @@ -717,7 +717,7 @@ LoadInfo::ResetPrincipalsToNullPrincipal() // take the originAttributes from the LoadInfo and create // a new NullPrincipal using those origin attributes. nsCOMPtr newNullPrincipal = - nsNullPrincipal::Create(mOriginAttributes); + NullPrincipal::Create(mOriginAttributes); MOZ_ASSERT(mInternalContentPolicyType != nsIContentPolicy::TYPE_DOCUMENT || !mLoadingPrincipal, diff --git a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp index 61c9d7fc1b1f..d120890338a1 100644 --- a/netwerk/protocol/ftp/nsFtpConnectionThread.cpp +++ b/netwerk/protocol/ftp/nsFtpConnectionThread.cpp @@ -41,7 +41,7 @@ #include "nsISocketTransportService.h" #include "nsIURI.h" #include "nsILoadInfo.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIAuthPrompt2.h" #include "nsIFTPChannelParentInternal.h" diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index d6579e14858e..69e61bbbcc41 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -39,7 +39,7 @@ #include "nsIDOMWindowUtils.h" #include "nsIDOMWindow.h" #include "nsINetworkInterceptController.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsICorsPreflightCallback.h" #include "nsISupportsImpl.h" #include "mozilla/LoadInfo.h" @@ -762,7 +762,7 @@ nsCORSListenerProxy::AsyncOnChannelRedirect(nsIChannel *aOldChannel, if (NS_SUCCEEDED(rv) && !equal) { // Spec says to set our source origin to a unique origin. mOriginHeaderPrincipal = - nsNullPrincipal::CreateWithInheritedAttributes(oldChannelPrincipal); + NullPrincipal::CreateWithInheritedAttributes(oldChannelPrincipal); } } diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index f6ce07f4d8ac..3d466d63799b 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -92,7 +92,7 @@ #include "nsIHttpPushListener.h" #include "nsIX509Cert.h" #include "ScopedNSSTypes.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIDeprecationWarner.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" diff --git a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp index 324aae069e5a..cfa4eceff625 100644 --- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp +++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp @@ -11,7 +11,7 @@ #include "nsContentUtils.h" #include "nsIHttpHeaderVisitor.h" #include "nsContentSecurityManager.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsServiceManagerUtils.h" #include "nsIInputStreamChannel.h" #include "mozilla/DebugOnly.h" @@ -67,7 +67,7 @@ nsViewSourceChannel::Init(nsIURI* uri) // Until then we follow the principal of least privilege and use // nullPrincipal as the loadingPrincipal and the least permissive // securityflag. - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); rv = pService->NewChannel2(path, nullptr, // aOriginCharset diff --git a/parser/html/nsParserUtils.cpp b/parser/html/nsParserUtils.cpp index 6e9b9c296fb0..bf4ca6546b6f 100644 --- a/parser/html/nsParserUtils.cpp +++ b/parser/html/nsParserUtils.cpp @@ -36,7 +36,7 @@ #include "nsTreeSanitizer.h" #include "nsHtml5Module.h" #include "mozilla/dom/DocumentFragment.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #define XHTML_DIV_TAG "div xmlns=\"http://www.w3.org/1999/xhtml\"" @@ -76,7 +76,7 @@ nsParserUtils::Sanitize(const nsAString& aFromStr, { nsCOMPtr uri; NS_NewURI(getter_AddRefs(uri), "about:blank"); - nsCOMPtr principal = nsNullPrincipal::Create(); + nsCOMPtr principal = NullPrincipal::Create(); nsCOMPtr domDocument; nsresult rv = NS_NewDOMDocument(getter_AddRefs(domDocument), EmptyString(), diff --git a/parser/htmlparser/nsExpatDriver.cpp b/parser/htmlparser/nsExpatDriver.cpp index df4bfbb96052..eb3e16ce83ec 100644 --- a/parser/htmlparser/nsExpatDriver.cpp +++ b/parser/htmlparser/nsExpatDriver.cpp @@ -27,7 +27,7 @@ #include "nsXPCOMCIDInternal.h" #include "nsUnicharInputStream.h" #include "nsContentUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "mozilla/Logging.h" #include "mozilla/SizePrintfMacros.h" @@ -793,7 +793,7 @@ nsExpatDriver::OpenInputStreamFromExternalDTD(const char16_t* aFPIStr, } } if (!loadingPrincipal) { - loadingPrincipal = nsNullPrincipal::Create(); + loadingPrincipal = NullPrincipal::Create(); } rv = NS_NewChannel(getter_AddRefs(channel), uri, diff --git a/parser/xml/nsSAXXMLReader.cpp b/parser/xml/nsSAXXMLReader.cpp index a84e0d63ba91..363f7bfea2e2 100644 --- a/parser/xml/nsSAXXMLReader.cpp +++ b/parser/xml/nsSAXXMLReader.cpp @@ -6,7 +6,7 @@ #include "nsIInputStream.h" #include "nsNetCID.h" #include "nsNetUtil.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" #include "nsIParser.h" #include "nsParserCIID.h" #include "nsStreamUtils.h" @@ -496,7 +496,7 @@ nsSAXXMLReader::ParseFromStream(nsIInputStream *aStream, rv = EnsureBaseURI(); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); // The following channel is never openend, so it does not matter what // securityFlags we pass; let's follow the principle of least privilege. diff --git a/rdf/base/nsRDFXMLParser.cpp b/rdf/base/nsRDFXMLParser.cpp index f8237356bd3b..6975522ef0c4 100644 --- a/rdf/base/nsRDFXMLParser.cpp +++ b/rdf/base/nsRDFXMLParser.cpp @@ -13,7 +13,7 @@ #include "nsParserCIID.h" #include "nsStringStream.h" #include "nsNetUtil.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" static NS_DEFINE_CID(kParserCID, NS_PARSER_CID); @@ -113,7 +113,7 @@ nsRDFXMLParser::ParseString(nsIRDFDataSource* aSink, nsIURI* aBaseURI, const nsA rv = NS_NewCStringInputStream(getter_AddRefs(stream), aString); if (NS_FAILED(rv)) return rv; - nsCOMPtr nullPrincipal = nsNullPrincipal::Create(); + nsCOMPtr nullPrincipal = NullPrincipal::Create(); // The following channel is never openend, so it does not matter what // securityFlags we pass; let's follow the principle of least privilege. diff --git a/toolkit/components/places/nsFaviconService.cpp b/toolkit/components/places/nsFaviconService.cpp index 42526b285724..2bf6672d17c4 100644 --- a/toolkit/components/places/nsFaviconService.cpp +++ b/toolkit/components/places/nsFaviconService.cpp @@ -31,7 +31,7 @@ #include "nsILoadInfo.h" #include "nsIContentPolicy.h" #include "nsContentUtils.h" -#include "nsNullPrincipal.h" +#include "NullPrincipal.h" // For large favicons optimization. #include "imgITools.h" @@ -240,7 +240,7 @@ nsFaviconService::SetAndFetchFaviconForPage(nsIURI* aPageURI, nsContentUtils::eNECKO_PROPERTIES, "APIDeprecationWarning", params, ArrayLength(params)); - loadingPrincipal = nsNullPrincipal::Create(); + loadingPrincipal = NullPrincipal::Create(); } NS_ENSURE_TRUE(loadingPrincipal, NS_ERROR_FAILURE); @@ -402,7 +402,7 @@ nsFaviconService::ReplaceFaviconDataFromDataURL(nsIURI* aFaviconURI, "APIDeprecationWarning", params, ArrayLength(params)); - loadingPrincipal = nsNullPrincipal::Create(); + loadingPrincipal = NullPrincipal::Create(); } NS_ENSURE_TRUE(loadingPrincipal, NS_ERROR_FAILURE); From f91cb666bbf7d1a40aff2af620db0c9f46b0d7d4 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 22 Mar 2017 11:39:08 +0100 Subject: [PATCH 54/96] Bug 1343933 - Renaming Principal classes - part 3 - SystemPrincipal, r=qdot --HG-- rename : caps/nsSystemPrincipal.cpp => caps/SystemPrincipal.cpp rename : caps/nsSystemPrincipal.h => caps/SystemPrincipal.h --- ...ystemPrincipal.cpp => SystemPrincipal.cpp} | 48 +++++++++---------- ...{nsSystemPrincipal.h => SystemPrincipal.h} | 17 +++---- caps/moz.build | 2 +- caps/nsIPrincipal.idl | 2 +- caps/nsScriptSecurityManager.cpp | 8 ++-- caps/nsScriptSecurityManager.h | 4 +- layout/build/nsLayoutModule.cpp | 6 +-- 7 files changed, 44 insertions(+), 43 deletions(-) rename caps/{nsSystemPrincipal.cpp => SystemPrincipal.cpp} (66%) rename caps/{nsSystemPrincipal.h => SystemPrincipal.h} (82%) diff --git a/caps/nsSystemPrincipal.cpp b/caps/SystemPrincipal.cpp similarity index 66% rename from caps/nsSystemPrincipal.cpp rename to caps/SystemPrincipal.cpp index b1c33553ac8d..0f03793c552c 100644 --- a/caps/nsSystemPrincipal.cpp +++ b/caps/SystemPrincipal.cpp @@ -6,7 +6,7 @@ /* The privileged system principal. */ #include "nscore.h" -#include "nsSystemPrincipal.h" +#include "SystemPrincipal.h" #include "nsIComponentManager.h" #include "nsIServiceManager.h" #include "nsIURL.h" @@ -19,28 +19,28 @@ #include "nsIScriptSecurityManager.h" #include "pratom.h" -NS_IMPL_CLASSINFO(nsSystemPrincipal, nullptr, +NS_IMPL_CLASSINFO(SystemPrincipal, nullptr, nsIClassInfo::SINGLETON | nsIClassInfo::MAIN_THREAD_ONLY, NS_SYSTEMPRINCIPAL_CID) -NS_IMPL_QUERY_INTERFACE_CI(nsSystemPrincipal, +NS_IMPL_QUERY_INTERFACE_CI(SystemPrincipal, nsIPrincipal, nsISerializable) -NS_IMPL_CI_INTERFACE_GETTER(nsSystemPrincipal, +NS_IMPL_CI_INTERFACE_GETTER(SystemPrincipal, nsIPrincipal, nsISerializable) #define SYSTEM_PRINCIPAL_SPEC "[System Principal]" -already_AddRefed -nsSystemPrincipal::Create() +already_AddRefed +SystemPrincipal::Create() { - RefPtr sp = new nsSystemPrincipal(); + RefPtr sp = new SystemPrincipal(); sp->FinishInit(); return sp.forget(); } nsresult -nsSystemPrincipal::GetScriptLocation(nsACString &aStr) +SystemPrincipal::GetScriptLocation(nsACString &aStr) { aStr.AssignLiteral(SYSTEM_PRINCIPAL_SPEC); return NS_OK; @@ -51,35 +51,35 @@ nsSystemPrincipal::GetScriptLocation(nsACString &aStr) /////////////////////////////////////// NS_IMETHODIMP -nsSystemPrincipal::GetHashValue(uint32_t *result) +SystemPrincipal::GetHashValue(uint32_t *result) { *result = NS_PTR_TO_INT32(this); return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetURI(nsIURI** aURI) +SystemPrincipal::GetURI(nsIURI** aURI) { *aURI = nullptr; return NS_OK; } nsresult -nsSystemPrincipal::GetOriginInternal(nsACString& aOrigin) +SystemPrincipal::GetOriginInternal(nsACString& aOrigin) { aOrigin.AssignLiteral(SYSTEM_PRINCIPAL_SPEC); return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) +SystemPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp) { *aCsp = nullptr; return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) +SystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) { // Never destroy an existing CSP on the principal. // This method should only be called in rare cases. @@ -88,50 +88,50 @@ nsSystemPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp) } NS_IMETHODIMP -nsSystemPrincipal::EnsureCSP(nsIDOMDocument* aDocument, - nsIContentSecurityPolicy** aCSP) +SystemPrincipal::EnsureCSP(nsIDOMDocument* aDocument, + nsIContentSecurityPolicy** aCSP) { // CSP on a system principal makes no sense return NS_ERROR_FAILURE; } NS_IMETHODIMP -nsSystemPrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) +SystemPrincipal::GetPreloadCsp(nsIContentSecurityPolicy** aPreloadCSP) { *aPreloadCSP = nullptr; return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument, - nsIContentSecurityPolicy** aPreloadCSP) +SystemPrincipal::EnsurePreloadCSP(nsIDOMDocument* aDocument, + nsIContentSecurityPolicy** aPreloadCSP) { // CSP on a system principal makes no sense return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetDomain(nsIURI** aDomain) +SystemPrincipal::GetDomain(nsIURI** aDomain) { *aDomain = nullptr; return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::SetDomain(nsIURI* aDomain) +SystemPrincipal::SetDomain(nsIURI* aDomain) { return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetBaseDomain(nsACString& aBaseDomain) +SystemPrincipal::GetBaseDomain(nsACString& aBaseDomain) { // No base domain for chrome. return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::GetAddonId(nsAString& aAddonId) +SystemPrincipal::GetAddonId(nsAString& aAddonId) { aAddonId.Truncate(); return NS_OK; @@ -142,14 +142,14 @@ nsSystemPrincipal::GetAddonId(nsAString& aAddonId) ////////////////////////////////////////// NS_IMETHODIMP -nsSystemPrincipal::Read(nsIObjectInputStream* aStream) +SystemPrincipal::Read(nsIObjectInputStream* aStream) { // no-op: CID is sufficient to identify the mSystemPrincipal singleton return NS_OK; } NS_IMETHODIMP -nsSystemPrincipal::Write(nsIObjectOutputStream* aStream) +SystemPrincipal::Write(nsIObjectOutputStream* aStream) { // no-op: CID is sufficient to identify the mSystemPrincipal singleton return NS_OK; diff --git a/caps/nsSystemPrincipal.h b/caps/SystemPrincipal.h similarity index 82% rename from caps/nsSystemPrincipal.h rename to caps/SystemPrincipal.h index 0e67ce45e490..d542f578ef5b 100644 --- a/caps/nsSystemPrincipal.h +++ b/caps/SystemPrincipal.h @@ -6,8 +6,8 @@ /* The privileged system principal. */ -#ifndef nsSystemPrincipal_h__ -#define nsSystemPrincipal_h__ +#ifndef SystemPrincipal_h +#define SystemPrincipal_h #include "nsIPrincipal.h" #include "nsJSPrincipals.h" @@ -20,15 +20,15 @@ #define NS_SYSTEMPRINCIPAL_CONTRACTID "@mozilla.org/systemprincipal;1" -class nsSystemPrincipal final : public mozilla::BasePrincipal +class SystemPrincipal final : public mozilla::BasePrincipal { - nsSystemPrincipal() + SystemPrincipal() : BasePrincipal(eSystemPrincipal) { } public: - static already_AddRefed Create(); + static already_AddRefed Create(); NS_DECL_NSISERIALIZABLE NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override; @@ -48,9 +48,10 @@ public: virtual nsresult GetScriptLocation(nsACString &aStr) override; protected: - virtual ~nsSystemPrincipal(void) {} + virtual ~SystemPrincipal(void) {} - bool SubsumesInternal(nsIPrincipal *aOther, DocumentDomainConsideration aConsideration) override + bool SubsumesInternal(nsIPrincipal *aOther, + DocumentDomainConsideration aConsideration) override { return true; } @@ -61,4 +62,4 @@ protected: } }; -#endif // nsSystemPrincipal_h__ +#endif // SystemPrincipal_h diff --git a/caps/moz.build b/caps/moz.build index 3da5ffbdce63..e15b1fa44323 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -45,9 +45,9 @@ UNIFIED_SOURCES += [ 'nsJSPrincipals.cpp', 'nsPrincipal.cpp', 'nsScriptSecurityManager.cpp', - 'nsSystemPrincipal.cpp', 'NullPrincipal.cpp', 'NullPrincipalURI.cpp', + 'SystemPrincipal.cpp', ] LOCAL_INCLUDES += [ diff --git a/caps/nsIPrincipal.idl b/caps/nsIPrincipal.idl index a34853e37604..258aa384a9f5 100644 --- a/caps/nsIPrincipal.idl +++ b/caps/nsIPrincipal.idl @@ -357,7 +357,7 @@ interface nsIPrincipal : nsISerializable }; /** - * If nsSystemPrincipal is too risky to use, but we want a principal to access + * If SystemPrincipal is too risky to use, but we want a principal to access * more than one origin, ExpandedPrincipals letting us define an array of * principals it subsumes. So script with an ExpandedPrincipals will gain * same origin access when at least one of its principals it contains gained diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 52b60331126c..daa7e2bd7911 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -20,7 +20,7 @@ #include "nspr.h" #include "nsJSPrincipals.h" #include "mozilla/BasePrincipal.h" -#include "nsSystemPrincipal.h" +#include "SystemPrincipal.h" #include "nsPrincipal.h" #include "NullPrincipal.h" #include "DomainPolicy.h" @@ -1335,7 +1335,7 @@ nsresult nsScriptSecurityManager::Init() NS_ENSURE_SUCCESS(rv, rv); // Create our system principal singleton - RefPtr system = nsSystemPrincipal::Create(); + RefPtr system = SystemPrincipal::Create(); mSystemPrincipal = system; @@ -1407,13 +1407,13 @@ nsScriptSecurityManager::InitStatics() // Currently this nsGenericFactory constructor is used only from FastLoad // (XPCOM object deserialization) code, when "creating" the system principal // singleton. -nsSystemPrincipal * +SystemPrincipal * nsScriptSecurityManager::SystemPrincipalSingletonConstructor() { nsIPrincipal *sysprin = nullptr; if (gScriptSecMan) NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal); - return static_cast(sysprin); + return static_cast(sysprin); } struct IsWhitespace { diff --git a/caps/nsScriptSecurityManager.h b/caps/nsScriptSecurityManager.h index da20441dd60a..d633c9a4a941 100644 --- a/caps/nsScriptSecurityManager.h +++ b/caps/nsScriptSecurityManager.h @@ -24,7 +24,7 @@ class nsCString; class nsIIOService; class nsIStringBundle; -class nsSystemPrincipal; +class SystemPrincipal; namespace mozilla { class OriginAttributes; @@ -55,7 +55,7 @@ public: // Invoked exactly once, by XPConnect. static void InitStatics(); - static nsSystemPrincipal* + static SystemPrincipal* SystemPrincipalSingletonConstructor(); /** diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 705642aaf3d1..f440939b98b9 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -132,7 +132,7 @@ using mozilla::dom::AudioChannelAgent; #include "nsScriptSecurityManager.h" #include "nsPrincipal.h" -#include "nsSystemPrincipal.h" +#include "SystemPrincipal.h" #include "NullPrincipal.h" #include "nsNetCID.h" #ifndef MOZ_WIDGET_GONK @@ -591,7 +591,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(CSPService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMixedContentBlocker) NS_GENERIC_FACTORY_CONSTRUCTOR(nsPrincipal) -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSystemPrincipal, +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemPrincipal, nsScriptSecurityManager::SystemPrincipalSingletonConstructor) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NullPrincipal, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(nsStructuredCloneContainer) @@ -1028,7 +1028,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kNS_CHILDPROCESSMESSAGEMANAGER_CID, false, nullptr, CreateChildMessageManager }, { &kNS_SCRIPTSECURITYMANAGER_CID, false, nullptr, Construct_nsIScriptSecurityManager }, { &kNS_PRINCIPAL_CID, false, nullptr, nsPrincipalConstructor }, - { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, nsSystemPrincipalConstructor }, + { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, SystemPrincipalConstructor }, { &kNS_NULLPRINCIPAL_CID, false, nullptr, NullPrincipalConstructor }, { &kNS_DEVICE_SENSORS_CID, false, nullptr, nsDeviceSensorsConstructor }, #ifndef MOZ_WIDGET_GONK From 507c00cb9f7a480bba832a10cd4155c02f5541ae Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 22 Mar 2017 11:39:31 +0100 Subject: [PATCH 55/96] Bug 1343933 - Renaming Principal classes - part 4 - ContentPrincipal, r=qdot --HG-- rename : caps/nsPrincipal.cpp => caps/ContentPrincipal.cpp rename : caps/nsPrincipal.h => caps/ContentPrincipal.h --- caps/BasePrincipal.cpp | 4 +- .../{nsPrincipal.cpp => ContentPrincipal.cpp} | 47 ++++++++++--------- caps/{nsPrincipal.h => ContentPrincipal.h} | 15 +++--- caps/NullPrincipal.cpp | 4 +- caps/moz.build | 2 +- caps/nsScriptSecurityManager.cpp | 1 - dom/base/nsFrameLoader.cpp | 2 +- dom/ipc/TabParent.cpp | 2 +- dom/media/MediaManager.cpp | 1 - dom/security/nsCSPService.cpp | 1 - ipc/glue/BackgroundUtils.cpp | 2 +- layout/build/nsLayoutModule.cpp | 6 +-- layout/build/nsLayoutStatics.cpp | 4 +- netwerk/base/nsIURI.idl | 2 +- netwerk/ipc/NeckoParent.cpp | 2 +- .../mozprofile/mozprofile/permissions.py | 7 +-- xpfe/appshell/nsContentTreeOwner.cpp | 2 +- 17 files changed, 53 insertions(+), 51 deletions(-) rename caps/{nsPrincipal.cpp => ContentPrincipal.cpp} (92%) rename caps/{nsPrincipal.h => ContentPrincipal.h} (85%) diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index 8ac83ef0c585..f2a008208f09 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -16,7 +16,7 @@ #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "nsNetUtil.h" #include "nsIURIWithPrincipal.h" #include "NullPrincipal.h" @@ -661,7 +661,7 @@ BasePrincipal::CreateCodebasePrincipal(nsIURI* aURI, const OriginAttributes& aAt } // Mint a codebase principal. - RefPtr codebase = new nsPrincipal(); + RefPtr codebase = new ContentPrincipal(); rv = codebase->Init(aURI, aAttrs); NS_ENSURE_SUCCESS(rv, nullptr); return codebase.forget(); diff --git a/caps/nsPrincipal.cpp b/caps/ContentPrincipal.cpp similarity index 92% rename from caps/nsPrincipal.cpp rename to caps/ContentPrincipal.cpp index 80a03b9476b7..127f6ce37f10 100644 --- a/caps/nsPrincipal.cpp +++ b/caps/ContentPrincipal.cpp @@ -4,7 +4,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "mozIThirdPartyUtil.h" #include "nscore.h" @@ -19,6 +19,8 @@ #include "nsJSPrincipals.h" #include "nsIEffectiveTLDService.h" #include "nsIClassInfoImpl.h" +#include "nsIObjectInputStream.h" +#include "nsIObjectOutputStream.h" #include "nsIProtocolHandler.h" #include "nsError.h" #include "nsIContentSecurityPolicy.h" @@ -58,25 +60,25 @@ GetAddonPolicyService(nsresult* aRv) return addonPolicyService; } -NS_IMPL_CLASSINFO(nsPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, +NS_IMPL_CLASSINFO(ContentPrincipal, nullptr, nsIClassInfo::MAIN_THREAD_ONLY, NS_PRINCIPAL_CID) -NS_IMPL_QUERY_INTERFACE_CI(nsPrincipal, +NS_IMPL_QUERY_INTERFACE_CI(ContentPrincipal, nsIPrincipal, nsISerializable) -NS_IMPL_CI_INTERFACE_GETTER(nsPrincipal, +NS_IMPL_CI_INTERFACE_GETTER(ContentPrincipal, nsIPrincipal, nsISerializable) // Called at startup: /* static */ void -nsPrincipal::InitializeStatics() +ContentPrincipal::InitializeStatics() { Preferences::AddBoolVarCache(&gCodeBasePrincipalSupport, "signed.applets.codebase_principal_support", false); } -nsPrincipal::nsPrincipal() +ContentPrincipal::ContentPrincipal() : BasePrincipal(eCodebasePrincipal) , mCodebaseImmutable(false) , mDomainImmutable(false) @@ -84,7 +86,7 @@ nsPrincipal::nsPrincipal() { } -nsPrincipal::~nsPrincipal() +ContentPrincipal::~ContentPrincipal() { // let's clear the principal within the csp to avoid a tangling pointer if (mCSP) { @@ -93,7 +95,8 @@ nsPrincipal::~nsPrincipal() } nsresult -nsPrincipal::Init(nsIURI *aCodebase, const OriginAttributes& aOriginAttributes) +ContentPrincipal::Init(nsIURI *aCodebase, + const OriginAttributes& aOriginAttributes) { NS_ENSURE_STATE(!mInitialized); NS_ENSURE_ARG(aCodebase); @@ -123,13 +126,13 @@ nsPrincipal::Init(nsIURI *aCodebase, const OriginAttributes& aOriginAttributes) } nsresult -nsPrincipal::GetScriptLocation(nsACString &aStr) +ContentPrincipal::GetScriptLocation(nsACString &aStr) { return mCodebase->GetSpec(aStr); } nsresult -nsPrincipal::GetOriginInternal(nsACString& aOrigin) +ContentPrincipal::GetOriginInternal(nsACString& aOrigin) { if (!mCodebase) { return NS_ERROR_FAILURE; @@ -249,12 +252,12 @@ nsPrincipal::GetOriginInternal(nsACString& aOrigin) } bool -nsPrincipal::SubsumesInternal(nsIPrincipal* aOther, - BasePrincipal::DocumentDomainConsideration aConsideration) +ContentPrincipal::SubsumesInternal(nsIPrincipal* aOther, + BasePrincipal::DocumentDomainConsideration aConsideration) { MOZ_ASSERT(aOther); - // For nsPrincipal, Subsumes is equivalent to Equals. + // For ContentPrincipal, Subsumes is equivalent to Equals. if (aOther == this) { return true; } @@ -286,7 +289,7 @@ nsPrincipal::SubsumesInternal(nsIPrincipal* aOther, } NS_IMETHODIMP -nsPrincipal::GetURI(nsIURI** aURI) +ContentPrincipal::GetURI(nsIURI** aURI) { if (mCodebaseImmutable) { NS_ADDREF(*aURI = mCodebase); @@ -302,7 +305,7 @@ nsPrincipal::GetURI(nsIURI** aURI) } bool -nsPrincipal::MayLoadInternal(nsIURI* aURI) +ContentPrincipal::MayLoadInternal(nsIURI* aURI) { // See if aURI is something like a Blob URI that is actually associated with // a principal. @@ -338,7 +341,7 @@ nsPrincipal::MayLoadInternal(nsIURI* aURI) } NS_IMETHODIMP -nsPrincipal::GetHashValue(uint32_t* aValue) +ContentPrincipal::GetHashValue(uint32_t* aValue) { NS_PRECONDITION(mCodebase, "Need a codebase"); @@ -347,7 +350,7 @@ nsPrincipal::GetHashValue(uint32_t* aValue) } NS_IMETHODIMP -nsPrincipal::GetDomain(nsIURI** aDomain) +ContentPrincipal::GetDomain(nsIURI** aDomain) { if (!mDomain) { *aDomain = nullptr; @@ -363,7 +366,7 @@ nsPrincipal::GetDomain(nsIURI** aDomain) } NS_IMETHODIMP -nsPrincipal::SetDomain(nsIURI* aDomain) +ContentPrincipal::SetDomain(nsIURI* aDomain) { mDomain = NS_TryToMakeImmutable(aDomain); mDomainImmutable = URIIsImmutable(mDomain); @@ -384,7 +387,7 @@ nsPrincipal::SetDomain(nsIURI* aDomain) } NS_IMETHODIMP -nsPrincipal::GetBaseDomain(nsACString& aBaseDomain) +ContentPrincipal::GetBaseDomain(nsACString& aBaseDomain) { // For a file URI, we return the file path. if (NS_URIIsLocalFile(mCodebase)) { @@ -419,7 +422,7 @@ nsPrincipal::GetBaseDomain(nsACString& aBaseDomain) } NS_IMETHODIMP -nsPrincipal::GetAddonId(nsAString& aAddonId) +ContentPrincipal::GetAddonId(nsAString& aAddonId) { if (mAddonIdCache.isSome()) { aAddonId.Assign(mAddonIdCache.ref()); @@ -448,7 +451,7 @@ nsPrincipal::GetAddonId(nsAString& aAddonId) }; NS_IMETHODIMP -nsPrincipal::Read(nsIObjectInputStream* aStream) +ContentPrincipal::Read(nsIObjectInputStream* aStream) { nsCOMPtr supports; nsCOMPtr codebase; @@ -494,7 +497,7 @@ nsPrincipal::Read(nsIObjectInputStream* aStream) } NS_IMETHODIMP -nsPrincipal::Write(nsIObjectOutputStream* aStream) +ContentPrincipal::Write(nsIObjectOutputStream* aStream) { NS_ENSURE_STATE(mCodebase); nsresult rv = NS_WriteOptionalCompoundObject(aStream, mCodebase, NS_GET_IID(nsIURI), diff --git a/caps/nsPrincipal.h b/caps/ContentPrincipal.h similarity index 85% rename from caps/nsPrincipal.h rename to caps/ContentPrincipal.h index f65dc81823d4..1acdafeda51d 100644 --- a/caps/nsPrincipal.h +++ b/caps/ContentPrincipal.h @@ -3,8 +3,8 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef nsPrincipal_h__ -#define nsPrincipal_h__ +#ifndef ContentPrincipal_h +#define ContentPrincipal_h #include "nsCOMPtr.h" #include "nsJSPrincipals.h" @@ -15,7 +15,7 @@ #include "nsScriptSecurityManager.h" #include "mozilla/BasePrincipal.h" -class nsPrincipal final : public mozilla::BasePrincipal +class ContentPrincipal final : public mozilla::BasePrincipal { public: NS_DECL_NSISERIALIZABLE @@ -29,7 +29,7 @@ public: bool IsCodebasePrincipal() const override { return true; } nsresult GetOriginInternal(nsACString& aOrigin) override; - nsPrincipal(); + ContentPrincipal(); // Init() must be called before the principal is in a usable state. nsresult Init(nsIURI* aCodebase, @@ -50,9 +50,10 @@ public: bool mInitialized; protected: - virtual ~nsPrincipal(); + virtual ~ContentPrincipal(); - bool SubsumesInternal(nsIPrincipal* aOther, DocumentDomainConsideration aConsideration) override; + bool SubsumesInternal(nsIPrincipal* aOther, + DocumentDomainConsideration aConsideration) override; bool MayLoadInternal(nsIURI* aURI) override; private: @@ -64,4 +65,4 @@ private: { 0x653e0e4d, 0x3ee4, 0x45fa, \ { 0xb2, 0x72, 0x97, 0xc2, 0x0b, 0xc0, 0x1e, 0xb8 } } -#endif // nsPrincipal_h__ +#endif // ContentPrincipal_h diff --git a/caps/NullPrincipal.cpp b/caps/NullPrincipal.cpp index b3e4c745e63a..8fff3211eb93 100644 --- a/caps/NullPrincipal.cpp +++ b/caps/NullPrincipal.cpp @@ -21,7 +21,7 @@ #include "nsNetCID.h" #include "nsError.h" #include "nsIScriptSecurityManager.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "nsScriptSecurityManager.h" #include "pratom.h" @@ -188,7 +188,7 @@ NullPrincipal::Read(nsIObjectInputStream* aStream) { // Note - NullPrincipal use NS_GENERIC_FACTORY_CONSTRUCTOR_INIT, which means // that the Init() method has already been invoked by the time we deserialize. - // This is in contrast to nsPrincipal, which uses NS_GENERIC_FACTORY_CONSTRUCTOR, + // This is in contrast to ContentPrincipal, which uses NS_GENERIC_FACTORY_CONSTRUCTOR, // in which case ::Read needs to invoke Init(). nsAutoCString spec; diff --git a/caps/moz.build b/caps/moz.build index e15b1fa44323..2f3d6614cdf5 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -40,10 +40,10 @@ SOURCES += [ ] UNIFIED_SOURCES += [ + 'ContentPrincipal.cpp', 'DomainPolicy.cpp', 'ExpandedPrincipal.cpp', 'nsJSPrincipals.cpp', - 'nsPrincipal.cpp', 'nsScriptSecurityManager.cpp', 'NullPrincipal.cpp', 'NullPrincipalURI.cpp', diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index daa7e2bd7911..0d587f8115a3 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -21,7 +21,6 @@ #include "nsJSPrincipals.h" #include "mozilla/BasePrincipal.h" #include "SystemPrincipal.h" -#include "nsPrincipal.h" #include "NullPrincipal.h" #include "DomainPolicy.h" #include "nsXPIDLString.h" diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 052f77ab6df9..e261b1860f41 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -98,7 +98,7 @@ #include "mozilla/dom/Promise.h" #include "mozilla/dom/PromiseNativeHandler.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #ifdef XP_WIN #include "mozilla/plugins/PPluginWidgetParent.h" diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 06b69a77a49a..87163e1bcb91 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -58,7 +58,6 @@ #include "nsIDOMWindowUtils.h" #include "nsIInterfaceRequestorUtils.h" #include "nsILoadInfo.h" -#include "nsPrincipal.h" #include "nsIPromptFactory.h" #include "nsIURI.h" #include "nsIWindowWatcher.h" @@ -69,6 +68,7 @@ #include "nsViewManager.h" #include "nsVariant.h" #include "nsIWidget.h" +#include "nsNetUtil.h" #ifndef XP_WIN #include "nsJARProtocolHandler.h" #endif diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 0fa7b7fd81d0..2e3763325484 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -28,7 +28,6 @@ #include "nsIIDNService.h" #include "nsNetCID.h" #include "nsNetUtil.h" -#include "nsPrincipal.h" #include "nsICryptoHash.h" #include "nsICryptoHMAC.h" #include "nsIKeyModule.h" diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp index b5bb2109f28e..3aa3e0ed0e38 100644 --- a/dom/security/nsCSPService.cpp +++ b/dom/security/nsCSPService.cpp @@ -20,7 +20,6 @@ #include "nsIScriptError.h" #include "nsContentUtils.h" #include "nsContentPolicyUtils.h" -#include "nsPrincipal.h" using namespace mozilla; diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index 8ec75c5e026b..d7a99677b47e 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -12,11 +12,11 @@ #include "mozilla/ipc/PBackgroundSharedTypes.h" #include "mozilla/net/NeckoChannelParams.h" #include "ExpandedPrincipal.h" -#include "nsPrincipal.h" #include "nsIScriptSecurityManager.h" #include "nsIURI.h" #include "nsNetUtil.h" #include "mozilla/LoadInfo.h" +#include "ContentPrincipal.h" #include "NullPrincipal.h" #include "nsServiceManagerUtils.h" #include "nsString.h" diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index f440939b98b9..d6413ace24ea 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -131,7 +131,7 @@ using mozilla::dom::AudioChannelAgent; #include "nsTextServicesCID.h" #include "nsScriptSecurityManager.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "SystemPrincipal.h" #include "NullPrincipal.h" #include "nsNetCID.h" @@ -590,7 +590,7 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsCSPContext) NS_GENERIC_FACTORY_CONSTRUCTOR(CSPService) NS_GENERIC_FACTORY_CONSTRUCTOR(nsMixedContentBlocker) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsPrincipal) +NS_GENERIC_FACTORY_CONSTRUCTOR(ContentPrincipal) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SystemPrincipal, nsScriptSecurityManager::SystemPrincipalSingletonConstructor) NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NullPrincipal, Init) @@ -1027,7 +1027,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kNS_PARENTPROCESSMESSAGEMANAGER_CID, false, nullptr, CreateParentMessageManager }, { &kNS_CHILDPROCESSMESSAGEMANAGER_CID, false, nullptr, CreateChildMessageManager }, { &kNS_SCRIPTSECURITYMANAGER_CID, false, nullptr, Construct_nsIScriptSecurityManager }, - { &kNS_PRINCIPAL_CID, false, nullptr, nsPrincipalConstructor }, + { &kNS_PRINCIPAL_CID, false, nullptr, ContentPrincipalConstructor }, { &kNS_SYSTEMPRINCIPAL_CID, false, nullptr, SystemPrincipalConstructor }, { &kNS_NULLPRINCIPAL_CID, false, nullptr, NullPrincipalConstructor }, { &kNS_DEVICE_SENSORS_CID, false, nullptr, nsDeviceSensorsConstructor }, diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 3247ed29bb8e..e8e4826efb52 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -32,7 +32,7 @@ #include "nsImageFrame.h" #include "nsLayoutStylesheetCache.h" #include "mozilla/RuleProcessorCache.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "nsRange.h" #include "nsRegion.h" #include "nsRepeatService.h" @@ -270,7 +270,7 @@ nsLayoutStatics::Initialize() nsLayoutUtils::Initialize(); nsIPresShell::InitializeStatics(); TouchManager::InitializeStatics(); - nsPrincipal::InitializeStatics(); + ContentPrincipal::InitializeStatics(); nsCORSListenerProxy::Startup(); diff --git a/netwerk/base/nsIURI.idl b/netwerk/base/nsIURI.idl index ef163813aa37..2b903141921e 100644 --- a/netwerk/base/nsIURI.idl +++ b/netwerk/base/nsIURI.idl @@ -63,7 +63,7 @@ * old (pre-gecko6) nsIURI IID and swap in the current IID instead, in order * for sessionstore to work after an upgrade. If this IID is revved further, * we will need to add additional checks there for all intermediate IIDs, until - * nsPrincipal is fixed to serialize its URIs as nsISupports (bug 662693). + * ContentPrincipal is fixed to serialize its URIs as nsISupports (bug 662693). */ [scriptable, uuid(92073a54-6d78-4f30-913a-b871813208c6)] interface nsIURI : nsISupports diff --git a/netwerk/ipc/NeckoParent.cpp b/netwerk/ipc/NeckoParent.cpp index b9aabe3fd05e..3047860eae81 100644 --- a/netwerk/ipc/NeckoParent.cpp +++ b/netwerk/ipc/NeckoParent.cpp @@ -40,7 +40,7 @@ #include "SerializedLoadContext.h" #include "nsAuthInformationHolder.h" #include "nsIAuthPromptCallback.h" -#include "nsPrincipal.h" +#include "ContentPrincipal.h" #include "nsINetworkPredictor.h" #include "nsINetworkPredictorVerifier.h" #include "nsISpeculativeConnect.h" diff --git a/testing/mozbase/mozprofile/mozprofile/permissions.py b/testing/mozbase/mozprofile/mozprofile/permissions.py index ea13d96f021c..2a0754c1be0a 100644 --- a/testing/mozbase/mozprofile/mozprofile/permissions.py +++ b/testing/mozbase/mozprofile/mozprofile/permissions.py @@ -274,9 +274,10 @@ class Permissions(object): permission_type = 2 if using_origin: - # This is a crude approximation of the origin generation logic from - # nsPrincipal and nsStandardURL. It should suffice for the permissions - # which the test runners will want to insert into the system. + # This is a crude approximation of the origin generation + # logic from ContentPrincipal and nsStandardURL. It should + # suffice for the permissions which the test runners will + # want to insert into the system. origin = location.scheme + "://" + location.host if (location.scheme != 'http' or location.port != '80') and \ (location.scheme != 'https' or location.port != '443'): diff --git a/xpfe/appshell/nsContentTreeOwner.cpp b/xpfe/appshell/nsContentTreeOwner.cpp index ff2524b8ab78..155d30551801 100644 --- a/xpfe/appshell/nsContentTreeOwner.cpp +++ b/xpfe/appshell/nsContentTreeOwner.cpp @@ -763,7 +763,7 @@ NS_IMETHODIMP nsContentTreeOwner::SetTitle(const char16_t* aTitle) // // location bar is turned off, find the browser location // - // use the document's nsPrincipal to find the true owner + // use the document's ContentPrincipal to find the true owner // in case of javascript: or data: documents // nsCOMPtr dsitem; From 02a0f210fae1343ea70749658ddb70eb252974d4 Mon Sep 17 00:00:00 2001 From: Olli Pettay Date: Wed, 22 Mar 2017 12:19:20 +0200 Subject: [PATCH 56/96] Bug 1346654, follow the COM rules in nsTextInputSelectionImpl, r=ehsan --HG-- extra : rebase_source : 15f1e22fe3e814c34332b4f9e2ff1f889e3a264d --- dom/html/nsTextEditorState.cpp | 74 ++++++++++++++++++++++------------ 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/dom/html/nsTextEditorState.cpp b/dom/html/nsTextEditorState.cpp index b574cb5946ef..7c98e1e2696a 100644 --- a/dom/html/nsTextEditorState.cpp +++ b/dom/html/nsTextEditorState.cpp @@ -379,9 +379,10 @@ nsTextInputSelectionImpl::ScrollSelectionIntoView( if (!mFrameSelection) return NS_ERROR_FAILURE; - return mFrameSelection->ScrollSelectionIntoView( - ToSelectionType(aRawSelectionType), - aRegion, aFlags); + RefPtr frameSelection = mFrameSelection; + return frameSelection->ScrollSelectionIntoView( + ToSelectionType(aRawSelectionType), + aRegion, aFlags); } NS_IMETHODIMP @@ -390,7 +391,8 @@ nsTextInputSelectionImpl::RepaintSelection(RawSelectionType aRawSelectionType) if (!mFrameSelection) return NS_ERROR_FAILURE; - return mFrameSelection->RepaintSelection(ToSelectionType(aRawSelectionType)); + RefPtr frameSelection = mFrameSelection; + return frameSelection->RepaintSelection(ToSelectionType(aRawSelectionType)); } nsresult @@ -400,7 +402,8 @@ nsTextInputSelectionImpl::RepaintSelection(nsPresContext* aPresContext, if (!mFrameSelection) return NS_ERROR_FAILURE; - return mFrameSelection->RepaintSelection(aSelectionType); + RefPtr frameSelection = mFrameSelection; + return frameSelection->RepaintSelection(aSelectionType); } NS_IMETHODIMP @@ -487,48 +490,60 @@ NS_IMETHODIMP nsTextInputSelectionImpl::PhysicalMove(int16_t aDirection, int16_t aAmount, bool aExtend) { - if (mFrameSelection) - return mFrameSelection->PhysicalMove(aDirection, aAmount, aExtend); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->PhysicalMove(aDirection, aAmount, aExtend); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::CharacterMove(bool aForward, bool aExtend) { - if (mFrameSelection) - return mFrameSelection->CharacterMove(aForward, aExtend); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->CharacterMove(aForward, aExtend); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::CharacterExtendForDelete() { - if (mFrameSelection) - return mFrameSelection->CharacterExtendForDelete(); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->CharacterExtendForDelete(); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::CharacterExtendForBackspace() { - if (mFrameSelection) - return mFrameSelection->CharacterExtendForBackspace(); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->CharacterExtendForBackspace(); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::WordMove(bool aForward, bool aExtend) { - if (mFrameSelection) - return mFrameSelection->WordMove(aForward, aExtend); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->WordMove(aForward, aExtend); + } return NS_ERROR_NULL_POINTER; } NS_IMETHODIMP nsTextInputSelectionImpl::WordExtendForDelete(bool aForward) { - if (mFrameSelection) - return mFrameSelection->WordExtendForDelete(aForward); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->WordExtendForDelete(aForward); + } return NS_ERROR_NULL_POINTER; } @@ -537,7 +552,8 @@ nsTextInputSelectionImpl::LineMove(bool aForward, bool aExtend) { if (mFrameSelection) { - nsresult result = mFrameSelection->LineMove(aForward, aExtend); + RefPtr frameSelection = mFrameSelection; + nsresult result = frameSelection->LineMove(aForward, aExtend); if (NS_FAILED(result)) result = CompleteMove(aForward,aExtend); return result; @@ -549,8 +565,10 @@ nsTextInputSelectionImpl::LineMove(bool aForward, bool aExtend) NS_IMETHODIMP nsTextInputSelectionImpl::IntraLineMove(bool aForward, bool aExtend) { - if (mFrameSelection) - return mFrameSelection->IntraLineMove(aForward, aExtend); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->IntraLineMove(aForward, aExtend); + } return NS_ERROR_NULL_POINTER; } @@ -562,7 +580,8 @@ nsTextInputSelectionImpl::PageMove(bool aForward, bool aExtend) // and to remain relative position of the caret in view. see Bug 4302. if (mScrollFrame) { - mFrameSelection->CommonPageMove(aForward, aExtend, mScrollFrame); + RefPtr frameSelection = mFrameSelection; + frameSelection->CommonPageMove(aForward, aExtend, mScrollFrame); } // After ScrollSelectionIntoView(), the pending notifications might be // flushed and PresShell/PresContext/Frames may be dead. See bug 418470. @@ -590,8 +609,11 @@ nsTextInputSelectionImpl::CompleteScroll(bool aForward) NS_IMETHODIMP nsTextInputSelectionImpl::CompleteMove(bool aForward, bool aExtend) { + NS_ENSURE_STATE(mFrameSelection); + RefPtr frameSelection = mFrameSelection; + // grab the parent / root DIV for this text widget - nsIContent* parentDIV = mFrameSelection->GetLimiter(); + nsIContent* parentDIV = frameSelection->GetLimiter(); if (!parentDIV) return NS_ERROR_UNEXPECTED; @@ -617,7 +639,7 @@ nsTextInputSelectionImpl::CompleteMove(bool aForward, bool aExtend) } } - mFrameSelection->HandleClick(parentDIV, offset, offset, aExtend, + frameSelection->HandleClick(parentDIV, offset, offset, aExtend, false, hint); // if we got this far, attempt to scroll no matter what the above result is @@ -672,8 +694,10 @@ nsTextInputSelectionImpl::ScrollCharacter(bool aRight) NS_IMETHODIMP nsTextInputSelectionImpl::SelectAll() { - if (mFrameSelection) - return mFrameSelection->SelectAll(); + if (mFrameSelection) { + RefPtr frameSelection = mFrameSelection; + return frameSelection->SelectAll(); + } return NS_ERROR_NULL_POINTER; } From 2232d1fd5c1baefbb3e2493c11b5f43f140c206c Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Wed, 22 Mar 2017 12:13:38 +0100 Subject: [PATCH 57/96] Bug 1348660 - Part 1: Convert nsIQuotaUsageRequest result related attributes to a new structure nsIQuotaUsageResult and expose it using a new result attribute of type nsIVariant; r=btseng --- browser/base/content/pageinfo/permissions.js | 5 +- .../preferences/SiteDataManager.jsm | 2 +- .../tests/browser_advanced_siteData.js | 2 +- .../mochitest/test_cache_orphaned_body.html | 3 +- .../mochitest/test_cache_orphaned_cache.html | 3 +- .../test/mochitest/test_cache_shrink.html | 3 +- dom/indexedDB/test/file.js | 2 +- .../test/unit/test_idle_maintenance.js | 10 ++-- .../test/unit/xpcshell-head-parent-process.js | 2 +- dom/quota/ActorsChild.cpp | 12 +++-- dom/quota/QuotaRequests.cpp | 44 +++------------ dom/quota/QuotaRequests.h | 8 +-- dom/quota/QuotaResults.cpp | 54 +++++++++++++++++++ dom/quota/QuotaResults.h | 40 ++++++++++++++ dom/quota/StorageManager.cpp | 22 +++++--- dom/quota/moz.build | 2 + dom/quota/nsIQuotaRequests.idl | 11 ++-- dom/quota/nsIQuotaResults.idl | 17 ++++++ dom/quota/test/unit/head.js | 2 +- 19 files changed, 174 insertions(+), 70 deletions(-) create mode 100644 dom/quota/QuotaResults.cpp create mode 100644 dom/quota/QuotaResults.h create mode 100644 dom/quota/nsIQuotaResults.idl diff --git a/browser/base/content/pageinfo/permissions.js b/browser/base/content/pageinfo/permissions.js index 16a0af7318db..7b8487c0df3e 100644 --- a/browser/base/content/pageinfo/permissions.js +++ b/browser/base/content/pageinfo/permissions.js @@ -218,7 +218,8 @@ function onIndexedDBUsageCallback(request) { throw new Error("Callback received for bad URI: " + uri); } - if (request.usage) { + let usage = request.result.usage; + if (usage) { if (!("DownloadUtils" in window)) { Components.utils.import("resource://gre/modules/DownloadUtils.jsm"); } @@ -228,7 +229,7 @@ function onIndexedDBUsageCallback(request) { status.value = gBundle.getFormattedString("indexedDBUsage", - DownloadUtils.convertByteUnits(request.usage)); + DownloadUtils.convertByteUnits(usage)); status.removeAttribute("hidden"); button.removeAttribute("hidden"); } diff --git a/browser/components/preferences/SiteDataManager.jsm b/browser/components/preferences/SiteDataManager.jsm index 2f1ba38e5b39..b48faac12c9b 100644 --- a/browser/components/preferences/SiteDataManager.jsm +++ b/browser/components/preferences/SiteDataManager.jsm @@ -83,7 +83,7 @@ this.SiteDataManager = { promises.push(new Promise(resolve => { let callback = { onUsageResult(request) { - site.quotaUsage = request.usage; + site.quotaUsage = request.result.usage; resolve(); } }; diff --git a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js index 759ba2aeac8b..0d1f5062df32 100644 --- a/browser/components/preferences/in-content/tests/browser_advanced_siteData.js +++ b/browser/components/preferences/in-content/tests/browser_advanced_siteData.js @@ -132,7 +132,7 @@ function getQuotaUsage(origin) { return new Promise(resolve => { let uri = NetUtil.newURI(origin); let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {}); - Services.qms.getUsageForPrincipal(principal, request => resolve(request.usage)); + Services.qms.getUsageForPrincipal(principal, request => resolve(request.result.usage)); }); } diff --git a/dom/cache/test/mochitest/test_cache_orphaned_body.html b/dom/cache/test/mochitest/test_cache_orphaned_body.html index a806cb30005f..049a97a79421 100644 --- a/dom/cache/test/mochitest/test_cache_orphaned_body.html +++ b/dom/cache/test/mochitest/test_cache_orphaned_body.html @@ -37,7 +37,8 @@ function storageUsage() { var qms = SpecialPowers.Services.qms; var principal = SpecialPowers.wrap(document).nodePrincipal; var cb = SpecialPowers.wrapCallback(function(request) { - resolve(request.usage, request.fileUsage); + var result = request.result; + resolve(result.usage, result.fileUsage); }); qms.getUsageForPrincipal(principal, cb); }); diff --git a/dom/cache/test/mochitest/test_cache_orphaned_cache.html b/dom/cache/test/mochitest/test_cache_orphaned_cache.html index c797da7b2f75..c6086e4877fc 100644 --- a/dom/cache/test/mochitest/test_cache_orphaned_cache.html +++ b/dom/cache/test/mochitest/test_cache_orphaned_cache.html @@ -37,7 +37,8 @@ function storageUsage() { var qms = SpecialPowers.Services.qms; var principal = SpecialPowers.wrap(document).nodePrincipal; var cb = SpecialPowers.wrapCallback(function(request) { - resolve(request.usage, request.fileUsage); + var result = request.result; + resolve(result.usage, result.fileUsage); }); qms.getUsageForPrincipal(principal, cb); }); diff --git a/dom/cache/test/mochitest/test_cache_shrink.html b/dom/cache/test/mochitest/test_cache_shrink.html index e6b362eb2215..b7136cb750f4 100644 --- a/dom/cache/test/mochitest/test_cache_shrink.html +++ b/dom/cache/test/mochitest/test_cache_shrink.html @@ -37,7 +37,8 @@ function storageUsage() { var qms = SpecialPowers.Services.qms; var principal = SpecialPowers.wrap(document).nodePrincipal; var cb = SpecialPowers.wrapCallback(function(request) { - resolve(request.usage, request.fileUsage); + var result = request.result; + resolve(result.usage, result.fileUsage); }); qms.getUsageForPrincipal(principal, cb); }); diff --git a/dom/indexedDB/test/file.js b/dom/indexedDB/test/file.js index 6c70eff1be25..ac574e254644 100644 --- a/dom/indexedDB/test/file.js +++ b/dom/indexedDB/test/file.js @@ -220,7 +220,7 @@ function verifyWasmModule(module1, module2) function grabFileUsageAndContinueHandler(request) { - testGenerator.next(request.fileUsage); + testGenerator.next(request.result.fileUsage); } function getUsage(usageHandler) diff --git a/dom/indexedDB/test/unit/test_idle_maintenance.js b/dom/indexedDB/test/unit/test_idle_maintenance.js index 51bcf0b11c93..a0cf01fd778d 100644 --- a/dom/indexedDB/test/unit/test_idle_maintenance.js +++ b/dom/indexedDB/test/unit/test_idle_maintenance.js @@ -122,8 +122,9 @@ function* testSteps() let usageBeforeMaintenance; quotaManagerService.getUsageForPrincipal(principal, (request) => { - ok(request.usage > 0, "Usage is non-zero"); - usageBeforeMaintenance = request.usage; + let usage = request.result.usage; + ok(usage > 0, "Usage is non-zero"); + usageBeforeMaintenance = usage; continueToNextStep(); }); yield undefined; @@ -155,8 +156,9 @@ function* testSteps() let usageAfterMaintenance; quotaManagerService.getUsageForPrincipal(principal, (request) => { - ok(request.usage > 0, "Usage is non-zero"); - usageAfterMaintenance = request.usage; + let usage = request.result.usage; + ok(usage > 0, "Usage is non-zero"); + usageAfterMaintenance = usage; continueToNextStep(); }); yield undefined; diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js index d56e8269cf8a..0f45fac88df3 100644 --- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js +++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js @@ -516,7 +516,7 @@ function verifyWasmModule(module1, module2) function grabFileUsageAndContinueHandler(request) { - testGenerator.next(request.fileUsage); + testGenerator.next(request.result.fileUsage); } function getUsage(usageHandler) diff --git a/dom/quota/ActorsChild.cpp b/dom/quota/ActorsChild.cpp index ab900dc39e6e..c9a44d8f0aba 100644 --- a/dom/quota/ActorsChild.cpp +++ b/dom/quota/ActorsChild.cpp @@ -9,6 +9,7 @@ #include "nsVariant.h" #include "QuotaManagerService.h" #include "QuotaRequests.h" +#include "QuotaResults.h" namespace mozilla { namespace dom { @@ -146,9 +147,14 @@ QuotaUsageRequestChild::HandleResponse(const UsageResponse& aResponse) AssertIsOnOwningThread(); MOZ_ASSERT(mRequest); - mRequest->SetResult(aResponse.usage(), - aResponse.fileUsage(), - aResponse.limit()); + RefPtr result = new UsageResult(aResponse.usage(), + aResponse.fileUsage(), + aResponse.limit()); + + RefPtr variant = new nsVariant(); + variant->SetAsInterface(NS_GET_IID(nsIQuotaUsageResult), result); + + mRequest->SetResult(variant); } void diff --git a/dom/quota/QuotaRequests.cpp b/dom/quota/QuotaRequests.cpp index 10b36b04078d..1f53b9aa50d5 100644 --- a/dom/quota/QuotaRequests.cpp +++ b/dom/quota/QuotaRequests.cpp @@ -95,9 +95,6 @@ UsageRequest::UsageRequest(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback) : RequestBase(aPrincipal) , mCallback(aCallback) - , mUsage(0) - , mFileUsage(0) - , mLimit(0) , mBackgroundActor(nullptr) , mCanceled(false) { @@ -126,14 +123,14 @@ UsageRequest::SetBackgroundActor(QuotaUsageRequestChild* aBackgroundActor) } void -UsageRequest::SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit) +UsageRequest::SetResult(nsIVariant* aResult) { AssertIsOnOwningThread(); + MOZ_ASSERT(aResult); MOZ_ASSERT(!mHaveResultOrErrorCode); - mUsage = aUsage; - mFileUsage = aFileUsage; - mLimit = aLimit; + mResult = aResult; + mHaveResultOrErrorCode = true; FireCallback(); @@ -149,43 +146,18 @@ NS_IMPL_ADDREF_INHERITED(UsageRequest, RequestBase) NS_IMPL_RELEASE_INHERITED(UsageRequest, RequestBase) NS_IMETHODIMP -UsageRequest::GetUsage(uint64_t* aUsage) +UsageRequest::GetResult(nsIVariant** aResult) { AssertIsOnOwningThread(); + MOZ_ASSERT(aResult); if (!mHaveResultOrErrorCode) { return NS_ERROR_FAILURE; } - *aUsage = mUsage; - return NS_OK; -} + MOZ_ASSERT(mResult); -NS_IMETHODIMP -UsageRequest::GetFileUsage(uint64_t* aFileUsage) -{ - AssertIsOnOwningThread(); - MOZ_ASSERT(aFileUsage); - - if (!mHaveResultOrErrorCode) { - return NS_ERROR_FAILURE; - } - - *aFileUsage = mFileUsage; - return NS_OK; -} - -NS_IMETHODIMP -UsageRequest::GetLimit(uint64_t* aLimit) -{ - AssertIsOnOwningThread(); - MOZ_ASSERT(aLimit); - - if (!mHaveResultOrErrorCode) { - return NS_ERROR_FAILURE; - } - - *aLimit = mLimit; + NS_ADDREF(*aResult = mResult); return NS_OK; } diff --git a/dom/quota/QuotaRequests.h b/dom/quota/QuotaRequests.h index 37c276039278..0fc2f096a43e 100644 --- a/dom/quota/QuotaRequests.h +++ b/dom/quota/QuotaRequests.h @@ -72,11 +72,7 @@ class UsageRequest final { nsCOMPtr mCallback; - uint64_t mUsage; - uint64_t mFileUsage; - - // Group Limit. - uint64_t mLimit; + nsCOMPtr mResult; QuotaUsageRequestChild* mBackgroundActor; @@ -98,7 +94,7 @@ public: } void - SetResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit); + SetResult(nsIVariant* aResult); NS_DECL_ISUPPORTS_INHERITED NS_FORWARD_NSIQUOTAREQUESTBASE(RequestBase::) diff --git a/dom/quota/QuotaResults.cpp b/dom/quota/QuotaResults.cpp new file mode 100644 index 000000000000..55a1dd9332dc --- /dev/null +++ b/dom/quota/QuotaResults.cpp @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "QuotaResults.h" + +namespace mozilla { +namespace dom { +namespace quota { + +UsageResult::UsageResult(uint64_t aUsage, + uint64_t aFileUsage, + uint64_t aLimit) + : mUsage(aUsage) + , mFileUsage(aFileUsage) + , mLimit(aLimit) +{ +} + +NS_IMPL_ISUPPORTS(UsageResult, + nsIQuotaUsageResult) + +NS_IMETHODIMP +UsageResult::GetUsage(uint64_t* aUsage) +{ + MOZ_ASSERT(aUsage); + + *aUsage = mUsage; + return NS_OK; +} + +NS_IMETHODIMP +UsageResult::GetFileUsage(uint64_t* aFileUsage) +{ + MOZ_ASSERT(aFileUsage); + + *aFileUsage = mFileUsage; + return NS_OK; +} + +NS_IMETHODIMP +UsageResult::GetLimit(uint64_t* aLimit) +{ + MOZ_ASSERT(aLimit); + + *aLimit = mLimit; + return NS_OK; +} + +} // namespace quota +} // namespace dom +} // namespace mozilla diff --git a/dom/quota/QuotaResults.h b/dom/quota/QuotaResults.h new file mode 100644 index 000000000000..d32e245faa57 --- /dev/null +++ b/dom/quota/QuotaResults.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_quota_QuotaResults_h +#define mozilla_dom_quota_QuotaResults_h + +#include "nsIQuotaResults.h" + +namespace mozilla { +namespace dom { +namespace quota { + +class UsageResult + : public nsIQuotaUsageResult +{ + uint64_t mUsage; + uint64_t mFileUsage; + uint64_t mLimit; + +public: + UsageResult(uint64_t aUsage, + uint64_t aFileUsage, + uint64_t aLimit); + +private: + virtual ~UsageResult() + { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIQUOTAUSAGERESULT +}; + +} // namespace quota +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_quota_QuotaResults_h diff --git a/dom/quota/StorageManager.cpp b/dom/quota/StorageManager.cpp index 988fac57409c..1a4773825b66 100644 --- a/dom/quota/StorageManager.cpp +++ b/dom/quota/StorageManager.cpp @@ -133,20 +133,30 @@ GetStorageEstimate(nsIQuotaUsageRequest* aRequest, { MOZ_ASSERT(aRequest); - uint64_t usage; - nsresult rv = aRequest->GetUsage(&usage); + nsCOMPtr result; + nsresult rv = aRequest->GetResult(getter_AddRefs(result)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - uint64_t limit; - rv = aRequest->GetLimit(&limit); + nsID* iid; + nsCOMPtr supports; + rv = result->GetAsInterface(&iid, getter_AddRefs(supports)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } - aStorageEstimate.mUsage.Construct() = usage; - aStorageEstimate.mQuota.Construct() = limit; + free(iid); + + nsCOMPtr usageResult = do_QueryInterface(supports); + MOZ_ASSERT(usageResult); + + MOZ_ALWAYS_SUCCEEDS( + usageResult->GetUsage(&aStorageEstimate.mUsage.Construct())); + + MOZ_ALWAYS_SUCCEEDS( + usageResult->GetLimit(&aStorageEstimate.mQuota.Construct())); + return NS_OK; } diff --git a/dom/quota/moz.build b/dom/quota/moz.build index dca28101d3db..33c465666d4b 100644 --- a/dom/quota/moz.build +++ b/dom/quota/moz.build @@ -15,6 +15,7 @@ XPIDL_SOURCES += [ 'nsIQuotaCallbacks.idl', 'nsIQuotaManagerService.idl', 'nsIQuotaRequests.idl', + 'nsIQuotaResults.idl', ] XPIDL_MODULE = 'dom_quota' @@ -43,6 +44,7 @@ UNIFIED_SOURCES += [ 'FileStreams.cpp', 'QuotaManagerService.cpp', 'QuotaRequests.cpp', + 'QuotaResults.cpp', 'StorageManager.cpp', ] diff --git a/dom/quota/nsIQuotaRequests.idl b/dom/quota/nsIQuotaRequests.idl index 4a3d8547ae11..c8d39c3ed2a0 100644 --- a/dom/quota/nsIQuotaRequests.idl +++ b/dom/quota/nsIQuotaRequests.idl @@ -22,11 +22,9 @@ interface nsIQuotaRequestBase : nsISupports [scriptable, uuid(166e28e6-cf6d-4927-a6d7-b51bca9d3469)] interface nsIQuotaUsageRequest : nsIQuotaRequestBase { - [must_use] readonly attribute unsigned long long usage; - - [must_use] readonly attribute unsigned long long fileUsage; - - [must_use] readonly attribute unsigned long long limit; + // The result can contain one of these types: + // nsIQuotaUsageResult + [must_use] readonly attribute nsIVariant result; attribute nsIQuotaUsageCallback callback; @@ -37,6 +35,9 @@ interface nsIQuotaUsageRequest : nsIQuotaRequestBase [scriptable, uuid(22890e3e-ff25-4372-9684-d901060e2f6c)] interface nsIQuotaRequest : nsIQuotaRequestBase { + // The result can contain one of these types: + // void + // bool [must_use] readonly attribute nsIVariant result; attribute nsIQuotaCallback callback; diff --git a/dom/quota/nsIQuotaResults.idl b/dom/quota/nsIQuotaResults.idl new file mode 100644 index 000000000000..e8d05a20e640 --- /dev/null +++ b/dom/quota/nsIQuotaResults.idl @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +[scriptable, function, uuid(96df03d2-116a-493f-bb0b-118c212a6b32)] +interface nsIQuotaUsageResult : nsISupports +{ + readonly attribute unsigned long long usage; + + readonly attribute unsigned long long fileUsage; + + readonly attribute unsigned long long limit; +}; diff --git a/dom/quota/test/unit/head.js b/dom/quota/test/unit/head.js index e3606c47dece..879c2cb7fc1f 100644 --- a/dom/quota/test/unit/head.js +++ b/dom/quota/test/unit/head.js @@ -263,7 +263,7 @@ function getPersistedFromMetadata(readBuffer) function grabUsageAndContinueHandler(request) { - testGenerator.next(request.usage); + testGenerator.next(request.result.usage); } function getUsage(usageHandler) From 4221505b788fab82519bea72f971302b4fe375c5 Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Wed, 22 Mar 2017 12:13:48 +0100 Subject: [PATCH 58/96] Bug 1348660 - Part 2: Rename usage related methods and structures to express the relation to a concrete origin; r=btseng --- dom/indexedDB/test/file.js | 2 +- dom/indexedDB/test/test_file_os_delete.html | 8 ++-- .../test/unit/test_view_put_get_values.js | 2 +- .../test/unit/xpcshell-head-parent-process.js | 2 +- dom/quota/ActorsChild.cpp | 15 ++++--- dom/quota/ActorsChild.h | 2 +- dom/quota/ActorsParent.cpp | 44 +++++++++---------- dom/quota/PQuota.ipdl | 4 +- dom/quota/PQuotaUsageRequest.ipdl | 4 +- dom/quota/QuotaManagerService.cpp | 2 +- dom/quota/QuotaResults.cpp | 16 +++---- dom/quota/QuotaResults.h | 14 +++--- dom/quota/StorageManager.cpp | 9 ++-- dom/quota/nsIQuotaRequests.idl | 2 +- dom/quota/nsIQuotaResults.idl | 2 +- dom/quota/test/unit/head.js | 2 +- dom/quota/test/unit/test_basics.js | 4 +- dom/quota/test/unit/test_unknownFiles.js | 6 +-- 18 files changed, 71 insertions(+), 69 deletions(-) diff --git a/dom/indexedDB/test/file.js b/dom/indexedDB/test/file.js index ac574e254644..744a92b33a0c 100644 --- a/dom/indexedDB/test/file.js +++ b/dom/indexedDB/test/file.js @@ -223,7 +223,7 @@ function grabFileUsageAndContinueHandler(request) testGenerator.next(request.result.fileUsage); } -function getUsage(usageHandler) +function getCurrentUsage(usageHandler) { let qms = SpecialPowers.Services.qms; let principal = SpecialPowers.wrap(document).nodePrincipal; diff --git a/dom/indexedDB/test/test_file_os_delete.html b/dom/indexedDB/test/test_file_os_delete.html index e5acf079c420..81c8fd1a8c50 100644 --- a/dom/indexedDB/test/test_file_os_delete.html +++ b/dom/indexedDB/test/test_file_os_delete.html @@ -18,7 +18,7 @@ const objectStoreName = "Blobs"; - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); let startUsage = yield undefined; const fileData1 = { @@ -61,7 +61,7 @@ is(event.type, "success", "Got correct event type"); - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); let usage = yield undefined; is(usage, startUsage + fileData1.obj.file.size + fileData2.obj.file.size, @@ -74,7 +74,7 @@ is(event.type, "complete", "Got correct event type"); - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); usage = yield undefined; is(usage, startUsage + fileData1.obj.file.size + fileData2.obj.file.size, @@ -90,7 +90,7 @@ // Flush pending file deletions before checking usage. flushPendingFileDeletions(); - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); let endUsage = yield undefined; is(endUsage, startUsage, "OS files deleted"); diff --git a/dom/indexedDB/test/unit/test_view_put_get_values.js b/dom/indexedDB/test/unit/test_view_put_get_values.js index 2dad2f64c653..2b4b8bf060ce 100644 --- a/dom/indexedDB/test/unit/test_view_put_get_values.js +++ b/dom/indexedDB/test/unit/test_view_put_get_values.js @@ -80,7 +80,7 @@ function* testSteps() verifyView(request.result, viewData.view); yield undefined; - getUsage(grabFileUsageAndContinueHandler); + getCurrentUsage(grabFileUsageAndContinueHandler); let fileUsage = yield undefined; if (external) { diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js index 0f45fac88df3..ba757ba9a248 100644 --- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js +++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js @@ -519,7 +519,7 @@ function grabFileUsageAndContinueHandler(request) testGenerator.next(request.result.fileUsage); } -function getUsage(usageHandler) +function getCurrentUsage(usageHandler) { let qms = Cc["@mozilla.org/dom/quota-manager-service;1"] .getService(Ci.nsIQuotaManagerService); diff --git a/dom/quota/ActorsChild.cpp b/dom/quota/ActorsChild.cpp index c9a44d8f0aba..ffb35104a857 100644 --- a/dom/quota/ActorsChild.cpp +++ b/dom/quota/ActorsChild.cpp @@ -142,17 +142,18 @@ QuotaUsageRequestChild::HandleResponse(nsresult aResponse) } void -QuotaUsageRequestChild::HandleResponse(const UsageResponse& aResponse) +QuotaUsageRequestChild::HandleResponse(const OriginUsageResponse& aResponse) { AssertIsOnOwningThread(); MOZ_ASSERT(mRequest); - RefPtr result = new UsageResult(aResponse.usage(), - aResponse.fileUsage(), - aResponse.limit()); + RefPtr result = + new OriginUsageResult(aResponse.usage(), + aResponse.fileUsage(), + aResponse.limit()); RefPtr variant = new nsVariant(); - variant->SetAsInterface(NS_GET_IID(nsIQuotaUsageResult), result); + variant->SetAsInterface(NS_GET_IID(nsIQuotaOriginUsageResult), result); mRequest->SetResult(variant); } @@ -181,8 +182,8 @@ QuotaUsageRequestChild::Recv__delete__(const UsageRequestResponse& aResponse) HandleResponse(aResponse.get_nsresult()); break; - case UsageRequestResponse::TUsageResponse: - HandleResponse(aResponse.get_UsageResponse()); + case UsageRequestResponse::TOriginUsageResponse: + HandleResponse(aResponse.get_OriginUsageResponse()); break; default: diff --git a/dom/quota/ActorsChild.h b/dom/quota/ActorsChild.h index 90a952e3b65e..4bc5e85a5f29 100644 --- a/dom/quota/ActorsChild.h +++ b/dom/quota/ActorsChild.h @@ -98,7 +98,7 @@ private: HandleResponse(nsresult aResponse); void - HandleResponse(const UsageResponse& aResponse); + HandleResponse(const OriginUsageResponse& aResponse); // IPDL methods are only called by IPDL. virtual void diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 22a3559d39bb..68459c1d0a3d 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -1042,7 +1042,7 @@ private: RecvStopIdleMaintenance() override; }; -class GetUsageOp final +class GetOriginUsageOp final : public NormalOriginOperationBase , public PQuotaUsageRequestParent { @@ -1051,19 +1051,19 @@ class GetUsageOp final // limit. UsageInfo mUsageInfo; - const UsageParams mParams; + const OriginUsageParams mParams; nsCString mSuffix; nsCString mGroup; bool mGetGroupUsage; public: - explicit GetUsageOp(const UsageRequestParams& aParams); + explicit GetOriginUsageOp(const UsageRequestParams& aParams); MOZ_IS_CLASS_INIT bool Init(Quota* aQuota); private: - ~GetUsageOp() + ~GetOriginUsageOp() { } MOZ_IS_CLASS_INIT virtual nsresult @@ -6230,7 +6230,7 @@ Quota::ActorDestroy(ActorDestroyReason aWhy) PQuotaUsageRequestParent* Quota::AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams) { - RefPtr actor = new GetUsageOp(aParams); + RefPtr actor = new GetOriginUsageOp(aParams); // Transfer ownership to IPDL. return actor.forget().take(); @@ -6244,7 +6244,7 @@ Quota::RecvPQuotaUsageRequestConstructor(PQuotaUsageRequestParent* aActor, MOZ_ASSERT(aActor); MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None); - auto* op = static_cast(aActor); + auto* op = static_cast(aActor); if (NS_WARN_IF(!op->Init(this))) { return IPC_FAIL_NO_REASON(this); @@ -6261,8 +6261,8 @@ Quota::DeallocPQuotaUsageRequestParent(PQuotaUsageRequestParent* aActor) MOZ_ASSERT(aActor); // Transfer ownership back from IPDL. - RefPtr actor = - dont_AddRef(static_cast(aActor)); + RefPtr actor = + dont_AddRef(static_cast(aActor)); return true; } @@ -6414,19 +6414,19 @@ Quota::RecvStopIdleMaintenance() return IPC_OK(); } -GetUsageOp::GetUsageOp(const UsageRequestParams& aParams) +GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams) : NormalOriginOperationBase(Nullable(), OriginScope::FromNull(), /* aExclusive */ false) - , mParams(aParams.get_UsageParams()) - , mGetGroupUsage(aParams.get_UsageParams().getGroupUsage()) + , mParams(aParams.get_OriginUsageParams()) + , mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage()) { AssertIsOnOwningThread(); - MOZ_ASSERT(aParams.type() == UsageRequestParams::TUsageParams); + MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams); } bool -GetUsageOp::Init(Quota* aQuota) +GetOriginUsageOp::Init(Quota* aQuota) { AssertIsOnOwningThread(); MOZ_ASSERT(aQuota); @@ -6438,7 +6438,7 @@ GetUsageOp::Init(Quota* aQuota) } nsresult -GetUsageOp::DoInitOnMainThread() +GetOriginUsageOp::DoInitOnMainThread() { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(GetState() == State_Initializing); @@ -6467,8 +6467,8 @@ GetUsageOp::DoInitOnMainThread() } nsresult -GetUsageOp::AddToUsage(QuotaManager* aQuotaManager, - PersistenceType aPersistenceType) +GetOriginUsageOp::AddToUsage(QuotaManager* aQuotaManager, + PersistenceType aPersistenceType) { AssertIsOnIOThread(); @@ -6580,12 +6580,12 @@ GetUsageOp::AddToUsage(QuotaManager* aQuotaManager, } nsresult -GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) +GetOriginUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) { AssertIsOnIOThread(); MOZ_ASSERT(mUsageInfo.TotalUsage() == 0); - PROFILER_LABEL("Quota", "GetUsageOp::DoDirectoryWork", + PROFILER_LABEL("Quota", "GetOriginUsageOp::DoDirectoryWork", js::ProfileEntry::Category::OTHER); nsresult rv; @@ -6621,7 +6621,7 @@ GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) } void -GetUsageOp::SendResults() +GetOriginUsageOp::SendResults() { AssertIsOnOwningThread(); @@ -6637,7 +6637,7 @@ GetUsageOp::SendResults() UsageRequestResponse response; if (NS_SUCCEEDED(mResultCode)) { - UsageResponse usageResponse; + OriginUsageResponse usageResponse; // We'll get the group usage when mGetGroupUsage is true and get the // origin usage when mGetGroupUsage is false. @@ -6659,7 +6659,7 @@ GetUsageOp::SendResults() } void -GetUsageOp::ActorDestroy(ActorDestroyReason aWhy) +GetOriginUsageOp::ActorDestroy(ActorDestroyReason aWhy) { AssertIsOnOwningThread(); @@ -6667,7 +6667,7 @@ GetUsageOp::ActorDestroy(ActorDestroyReason aWhy) } mozilla::ipc::IPCResult -GetUsageOp::RecvCancel() +GetOriginUsageOp::RecvCancel() { AssertIsOnOwningThread(); diff --git a/dom/quota/PQuota.ipdl b/dom/quota/PQuota.ipdl index 88333e5bee6b..29ec3ae3e546 100644 --- a/dom/quota/PQuota.ipdl +++ b/dom/quota/PQuota.ipdl @@ -27,7 +27,7 @@ struct InitOriginParams PersistenceType persistenceType; }; -struct UsageParams +struct OriginUsageParams { PrincipalInfo principalInfo; bool getGroupUsage; @@ -35,7 +35,7 @@ struct UsageParams union UsageRequestParams { - UsageParams; + OriginUsageParams; }; struct ClearOriginParams diff --git a/dom/quota/PQuotaUsageRequest.ipdl b/dom/quota/PQuotaUsageRequest.ipdl index fbf7941c15d1..682222204fa2 100644 --- a/dom/quota/PQuotaUsageRequest.ipdl +++ b/dom/quota/PQuotaUsageRequest.ipdl @@ -8,7 +8,7 @@ namespace mozilla { namespace dom { namespace quota { -struct UsageResponse +struct OriginUsageResponse { uint64_t usage; uint64_t fileUsage; @@ -18,7 +18,7 @@ struct UsageResponse union UsageRequestResponse { nsresult; - UsageResponse; + OriginUsageResponse; }; protocol PQuotaUsageRequest diff --git a/dom/quota/QuotaManagerService.cpp b/dom/quota/QuotaManagerService.cpp index 659d87a9e102..9d495591ff0d 100644 --- a/dom/quota/QuotaManagerService.cpp +++ b/dom/quota/QuotaManagerService.cpp @@ -596,7 +596,7 @@ QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, RefPtr request = new UsageRequest(aPrincipal, aCallback); - UsageParams params; + OriginUsageParams params; nsresult rv = CheckedPrincipalToPrincipalInfo(aPrincipal, params.principalInfo()); diff --git a/dom/quota/QuotaResults.cpp b/dom/quota/QuotaResults.cpp index 55a1dd9332dc..be02691579e0 100644 --- a/dom/quota/QuotaResults.cpp +++ b/dom/quota/QuotaResults.cpp @@ -10,20 +10,20 @@ namespace mozilla { namespace dom { namespace quota { -UsageResult::UsageResult(uint64_t aUsage, - uint64_t aFileUsage, - uint64_t aLimit) +OriginUsageResult::OriginUsageResult(uint64_t aUsage, + uint64_t aFileUsage, + uint64_t aLimit) : mUsage(aUsage) , mFileUsage(aFileUsage) , mLimit(aLimit) { } -NS_IMPL_ISUPPORTS(UsageResult, - nsIQuotaUsageResult) +NS_IMPL_ISUPPORTS(OriginUsageResult, + nsIQuotaOriginUsageResult) NS_IMETHODIMP -UsageResult::GetUsage(uint64_t* aUsage) +OriginUsageResult::GetUsage(uint64_t* aUsage) { MOZ_ASSERT(aUsage); @@ -32,7 +32,7 @@ UsageResult::GetUsage(uint64_t* aUsage) } NS_IMETHODIMP -UsageResult::GetFileUsage(uint64_t* aFileUsage) +OriginUsageResult::GetFileUsage(uint64_t* aFileUsage) { MOZ_ASSERT(aFileUsage); @@ -41,7 +41,7 @@ UsageResult::GetFileUsage(uint64_t* aFileUsage) } NS_IMETHODIMP -UsageResult::GetLimit(uint64_t* aLimit) +OriginUsageResult::GetLimit(uint64_t* aLimit) { MOZ_ASSERT(aLimit); diff --git a/dom/quota/QuotaResults.h b/dom/quota/QuotaResults.h index d32e245faa57..4d38d6d8d578 100644 --- a/dom/quota/QuotaResults.h +++ b/dom/quota/QuotaResults.h @@ -13,24 +13,24 @@ namespace mozilla { namespace dom { namespace quota { -class UsageResult - : public nsIQuotaUsageResult +class OriginUsageResult + : public nsIQuotaOriginUsageResult { uint64_t mUsage; uint64_t mFileUsage; uint64_t mLimit; public: - UsageResult(uint64_t aUsage, - uint64_t aFileUsage, - uint64_t aLimit); + OriginUsageResult(uint64_t aUsage, + uint64_t aFileUsage, + uint64_t aLimit); private: - virtual ~UsageResult() + virtual ~OriginUsageResult() { } NS_DECL_ISUPPORTS - NS_DECL_NSIQUOTAUSAGERESULT + NS_DECL_NSIQUOTAORIGINUSAGERESULT }; } // namespace quota diff --git a/dom/quota/StorageManager.cpp b/dom/quota/StorageManager.cpp index 1a4773825b66..4e9f0cf8c6b2 100644 --- a/dom/quota/StorageManager.cpp +++ b/dom/quota/StorageManager.cpp @@ -148,14 +148,15 @@ GetStorageEstimate(nsIQuotaUsageRequest* aRequest, free(iid); - nsCOMPtr usageResult = do_QueryInterface(supports); - MOZ_ASSERT(usageResult); + nsCOMPtr originUsageResult = + do_QueryInterface(supports); + MOZ_ASSERT(originUsageResult); MOZ_ALWAYS_SUCCEEDS( - usageResult->GetUsage(&aStorageEstimate.mUsage.Construct())); + originUsageResult->GetUsage(&aStorageEstimate.mUsage.Construct())); MOZ_ALWAYS_SUCCEEDS( - usageResult->GetLimit(&aStorageEstimate.mQuota.Construct())); + originUsageResult->GetLimit(&aStorageEstimate.mQuota.Construct())); return NS_OK; } diff --git a/dom/quota/nsIQuotaRequests.idl b/dom/quota/nsIQuotaRequests.idl index c8d39c3ed2a0..e30a6ebbbfbb 100644 --- a/dom/quota/nsIQuotaRequests.idl +++ b/dom/quota/nsIQuotaRequests.idl @@ -23,7 +23,7 @@ interface nsIQuotaRequestBase : nsISupports interface nsIQuotaUsageRequest : nsIQuotaRequestBase { // The result can contain one of these types: - // nsIQuotaUsageResult + // nsIQuotaOriginUsageResult [must_use] readonly attribute nsIVariant result; attribute nsIQuotaUsageCallback callback; diff --git a/dom/quota/nsIQuotaResults.idl b/dom/quota/nsIQuotaResults.idl index e8d05a20e640..1c787009dcd0 100644 --- a/dom/quota/nsIQuotaResults.idl +++ b/dom/quota/nsIQuotaResults.idl @@ -7,7 +7,7 @@ #include "nsISupports.idl" [scriptable, function, uuid(96df03d2-116a-493f-bb0b-118c212a6b32)] -interface nsIQuotaUsageResult : nsISupports +interface nsIQuotaOriginUsageResult : nsISupports { readonly attribute unsigned long long usage; diff --git a/dom/quota/test/unit/head.js b/dom/quota/test/unit/head.js index 879c2cb7fc1f..89df227644c1 100644 --- a/dom/quota/test/unit/head.js +++ b/dom/quota/test/unit/head.js @@ -266,7 +266,7 @@ function grabUsageAndContinueHandler(request) testGenerator.next(request.result.usage); } -function getUsage(usageHandler) +function getCurrentUsage(usageHandler) { let principal = Cc["@mozilla.org/systemprincipal;1"] .createInstance(Ci.nsIPrincipal); diff --git a/dom/quota/test/unit/test_basics.js b/dom/quota/test/unit/test_basics.js index f23898c45abc..29aadf1fe11c 100644 --- a/dom/quota/test/unit/test_basics.js +++ b/dom/quota/test/unit/test_basics.js @@ -38,7 +38,7 @@ function* testSteps() info("Getting usage"); - getUsage(grabUsageAndContinueHandler); + getCurrentUsage(grabUsageAndContinueHandler); let usage = yield undefined; ok(usage == 0, "Usage is zero"); @@ -53,7 +53,7 @@ function* testSteps() info("Getting usage"); - getUsage(grabUsageAndContinueHandler); + getCurrentUsage(grabUsageAndContinueHandler); usage = yield undefined; ok(usage > 0, "Usage is not zero"); diff --git a/dom/quota/test/unit/test_unknownFiles.js b/dom/quota/test/unit/test_unknownFiles.js index 8eef05b83024..e14af9695cdf 100644 --- a/dom/quota/test/unit/test_unknownFiles.js +++ b/dom/quota/test/unit/test_unknownFiles.js @@ -131,7 +131,7 @@ function* testSteps() info("Getting usage"); - request = getUsage(continueToNextStepSync); + request = getCurrentUsage(continueToNextStepSync); yield undefined; ok(request.resultCode == NS_ERROR_UNEXPECTED, "Get usage failed"); @@ -140,7 +140,7 @@ function* testSteps() info("Getting usage"); - request = getUsage(continueToNextStepSync); + request = getCurrentUsage(continueToNextStepSync); yield undefined; ok(request.resultCode == NS_OK, "Get usage succeeded"); @@ -156,7 +156,7 @@ function* testSteps() info("Getting usage"); - request = getUsage(continueToNextStepSync); + request = getCurrentUsage(continueToNextStepSync); yield undefined; ok(request.resultCode == NS_OK, "Get usage succeeded"); From ae1ee28451c88243dff8bc349547600099744999 Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Wed, 22 Mar 2017 12:13:54 +0100 Subject: [PATCH 59/96] Bug 1348660 - Part 3: Separate the canceled state out of UsageInfo; r=btseng --- dom/asmjscache/AsmJSCache.cpp | 10 ++++++++-- dom/cache/QuotaClient.cpp | 20 ++++++++++++-------- dom/indexedDB/ActorsParent.cpp | 30 ++++++++++++++++++++---------- dom/quota/ActorsParent.cpp | 19 +++++++++++++------ dom/quota/Client.h | 4 ++++ dom/quota/UsageInfo.h | 23 +++-------------------- 6 files changed, 60 insertions(+), 46 deletions(-) diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp index 3c2c959ca8f5..e8f657bff0cf 100644 --- a/dom/asmjscache/AsmJSCache.cpp +++ b/dom/asmjscache/AsmJSCache.cpp @@ -1623,18 +1623,24 @@ public: InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override { if (!aUsageInfo) { return NS_OK; } - return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aUsageInfo); + return GetUsageForOrigin(aPersistenceType, + aGroup, + aOrigin, + aCanceled, + aUsageInfo); } nsresult GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override { QuotaManager* qm = QuotaManager::Get(); @@ -1658,7 +1664,7 @@ public: bool hasMore; while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && - hasMore && !aUsageInfo->Canceled()) { + hasMore && !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/cache/QuotaClient.cpp b/dom/cache/QuotaClient.cpp index b33fa8c34a31..5641c953c6c0 100644 --- a/dom/cache/QuotaClient.cpp +++ b/dom/cache/QuotaClient.cpp @@ -16,6 +16,7 @@ namespace { +using mozilla::Atomic; using mozilla::dom::ContentParentId; using mozilla::dom::cache::Manager; using mozilla::dom::quota::Client; @@ -25,7 +26,8 @@ using mozilla::dom::quota::UsageInfo; using mozilla::ipc::AssertIsOnBackgroundThread; static nsresult -GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo) +GetBodyUsage(nsIFile* aDir, const Atomic& aCanceled, + UsageInfo* aUsageInfo) { nsCOMPtr entries; nsresult rv = aDir->GetDirectoryEntries(getter_AddRefs(entries)); @@ -33,7 +35,7 @@ GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo) bool hasMore; while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore && - !aUsageInfo->Canceled()) { + !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -45,7 +47,7 @@ GetBodyUsage(nsIFile* aDir, UsageInfo* aUsageInfo) if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } if (isDir) { - rv = GetBodyUsage(file, aUsageInfo); + rv = GetBodyUsage(file, aCanceled, aUsageInfo); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } continue; } @@ -72,7 +74,8 @@ public: virtual nsresult InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, - const nsACString& aOrigin, UsageInfo* aUsageInfo) override + const nsACString& aOrigin, const AtomicBool& aCanceled, + UsageInfo* aUsageInfo) override { // The QuotaManager passes a nullptr UsageInfo if there is no quota being // enforced against the origin. @@ -80,12 +83,13 @@ public: return NS_OK; } - return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aUsageInfo); + return GetUsageForOrigin(aPersistenceType, aGroup, aOrigin, aCanceled, + aUsageInfo); } virtual nsresult GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, - const nsACString& aOrigin, + const nsACString& aOrigin, const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override { MOZ_DIAGNOSTIC_ASSERT(aUsageInfo); @@ -107,7 +111,7 @@ public: bool hasMore; while (NS_SUCCEEDED(rv = entries->HasMoreElements(&hasMore)) && hasMore && - !aUsageInfo->Canceled()) { + !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -124,7 +128,7 @@ public: if (isDir) { if (leafName.EqualsLiteral("morgue")) { - rv = GetBodyUsage(file, aUsageInfo); + rv = GetBodyUsage(file, aCanceled, aUsageInfo); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } } else { NS_WARNING("Unknown Cache directory found!"); diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index d30f58e8d456..feaabc9d49f9 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -9347,12 +9347,14 @@ public: InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override; nsresult GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) override; void @@ -9394,13 +9396,14 @@ private: nsresult GetDatabaseFilenames(nsIFile* aDirectory, - UsageInfo* aUsageInfo, + const AtomicBool& aCanceled, bool aForUpgrade, nsTArray& aSubdirsToProcess, nsTHashtable& aDatabaseFilename); nsresult GetUsageForDirectoryInternal(nsIFile* aDirectory, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo, bool aDatabaseFiles); @@ -17828,10 +17831,11 @@ QuotaClient::UpgradeStorageFrom1_0To2_0(nsIFile* aDirectory) AssertIsOnIOThread(); MOZ_ASSERT(aDirectory); + AtomicBool dummy(false); AutoTArray subdirsToProcess; nsTHashtable databaseFilenames(20); nsresult rv = GetDatabaseFilenames(aDirectory, - nullptr, + /* aCanceled */ dummy, /* aForUpgrade */ true, subdirsToProcess, databaseFilenames); @@ -17924,6 +17928,7 @@ nsresult QuotaClient::InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) { AssertIsOnIOThread(); @@ -17942,7 +17947,7 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType, AutoTArray subdirsToProcess; nsTHashtable databaseFilenames(20); rv = GetDatabaseFilenames(directory, - aUsageInfo, + aCanceled, /* aForUpgrade */ false, subdirsToProcess, databaseFilenames); @@ -17974,7 +17979,9 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType, const NS_ConvertASCIItoUTF16 walSuffix(kSQLiteWALSuffix, LiteralStringLength(kSQLiteWALSuffix)); - for (auto iter = databaseFilenames.ConstIter(); !iter.Done(); iter.Next()) { + for (auto iter = databaseFilenames.ConstIter(); + !iter.Done() && !aCanceled; + iter.Next()) { auto& databaseFilename = iter.Get()->GetKey(); nsCOMPtr fmDirectory; @@ -18022,7 +18029,7 @@ QuotaClient::InitOrigin(PersistenceType aPersistenceType, return rv; } - if (aUsageInfo && !aUsageInfo->Canceled()) { + if (aUsageInfo) { int64_t fileSize; rv = databaseFile->GetFileSize(&fileSize); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -18059,6 +18066,7 @@ nsresult QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) { AssertIsOnIOThread(); @@ -18071,7 +18079,7 @@ QuotaClient::GetUsageForOrigin(PersistenceType aPersistenceType, return rv; } - rv = GetUsageForDirectoryInternal(directory, aUsageInfo, true); + rv = GetUsageForDirectoryInternal(directory, aCanceled, aUsageInfo, true); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -18260,12 +18268,13 @@ QuotaClient::GetDirectory(PersistenceType aPersistenceType, nsresult QuotaClient::GetDatabaseFilenames( nsIFile* aDirectory, - UsageInfo* aUsageInfo, + const AtomicBool& aCanceled, bool aForUpgrade, nsTArray& aSubdirsToProcess, nsTHashtable& aDatabaseFilenames) { AssertIsOnIOThread(); + MOZ_ASSERT(aDirectory); nsCOMPtr entries; nsresult rv = aDirectory->GetDirectoryEntries(getter_AddRefs(entries)); @@ -18286,7 +18295,7 @@ QuotaClient::GetDatabaseFilenames( bool hasMore; while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore && - (!aUsageInfo || !aUsageInfo->Canceled())) { + !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -18362,6 +18371,7 @@ QuotaClient::GetDatabaseFilenames( nsresult QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo, bool aDatabaseFiles) { @@ -18388,7 +18398,7 @@ QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory, bool hasMore; while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && hasMore && - !aUsageInfo->Canceled()) { + !aCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -18423,7 +18433,7 @@ QuotaClient::GetUsageForDirectoryInternal(nsIFile* aDirectory, if (isDirectory) { if (aDatabaseFiles) { - rv = GetUsageForDirectoryInternal(file, aUsageInfo, false); + rv = GetUsageForDirectoryInternal(file, aCanceled, aUsageInfo, false); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 68459c1d0a3d..9a7223c33beb 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -915,6 +915,7 @@ class NormalOriginOperationBase protected: Nullable mPersistenceType; OriginScope mOriginScope; + mozilla::Atomic mCanceled; const bool mExclusive; public: @@ -4196,7 +4197,11 @@ QuotaManager::InitializeOrigin(PersistenceType aPersistenceType, return NS_ERROR_UNEXPECTED; } - rv = mClients[clientType]->InitOrigin(aPersistenceType, aGroup, aOrigin, + Atomic dummy(false); + rv = mClients[clientType]->InitOrigin(aPersistenceType, + aGroup, + aOrigin, + /* aCanceled */ dummy, usageInfo); NS_ENSURE_SUCCESS(rv, rv); } @@ -6484,7 +6489,7 @@ GetOriginUsageOp::AddToUsage(QuotaManager* aQuotaManager, // If the directory exists then enumerate all the files inside, adding up // the sizes to get the final usage statistic. - if (exists && !mUsageInfo.Canceled()) { + if (exists && !mCanceled) { bool initialized; if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) { @@ -6500,7 +6505,7 @@ GetOriginUsageOp::AddToUsage(QuotaManager* aQuotaManager, bool hasMore; while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && - hasMore && !mUsageInfo.Canceled()) { + hasMore && !mCanceled) { nsCOMPtr entry; rv = entries->GetNext(getter_AddRefs(entry)); NS_ENSURE_SUCCESS(rv, rv); @@ -6564,12 +6569,14 @@ GetOriginUsageOp::AddToUsage(QuotaManager* aQuotaManager, rv = client->GetUsageForOrigin(aPersistenceType, mGroup, mOriginScope.GetOrigin(), + mCanceled, &mUsageInfo); } else { rv = client->InitOrigin(aPersistenceType, mGroup, mOriginScope.GetOrigin(), + mCanceled, &mUsageInfo); } NS_ENSURE_SUCCESS(rv, rv); @@ -6630,7 +6637,7 @@ GetOriginUsageOp::SendResults() mResultCode = NS_ERROR_FAILURE; } } else { - if (mUsageInfo.Canceled()) { + if (mCanceled) { mResultCode = NS_ERROR_FAILURE; } @@ -6671,8 +6678,8 @@ GetOriginUsageOp::RecvCancel() { AssertIsOnOwningThread(); - nsresult rv = mUsageInfo.Cancel(); - if (NS_WARN_IF(NS_FAILED(rv))) { + if (mCanceled.exchange(true)) { + NS_WARNING("Canceled more than once?!"); return IPC_FAIL_NO_REASON(this); } diff --git a/dom/quota/Client.h b/dom/quota/Client.h index b70d3e606914..4ee5ed228646 100644 --- a/dom/quota/Client.h +++ b/dom/quota/Client.h @@ -31,6 +31,8 @@ class UsageInfo; class Client { public: + typedef mozilla::Atomic AtomicBool; + NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING enum Type { @@ -100,12 +102,14 @@ public: InitOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) = 0; virtual nsresult GetUsageForOrigin(PersistenceType aPersistenceType, const nsACString& aGroup, const nsACString& aOrigin, + const AtomicBool& aCanceled, UsageInfo* aUsageInfo) = 0; virtual void diff --git a/dom/quota/UsageInfo.h b/dom/quota/UsageInfo.h index 688e168707fa..67b73195b54a 100644 --- a/dom/quota/UsageInfo.h +++ b/dom/quota/UsageInfo.h @@ -18,28 +18,14 @@ class UsageInfo { public: UsageInfo() - : mCanceled(false), mDatabaseUsage(0), mFileUsage(0), mLimit(0) + : mDatabaseUsage(0) + , mFileUsage(0) + , mLimit(0) { } virtual ~UsageInfo() { } - bool - Canceled() - { - return mCanceled; - } - - nsresult - Cancel() - { - if (mCanceled.exchange(true)) { - NS_WARNING("Canceled more than once?!"); - return NS_ERROR_UNEXPECTED; - } - return NS_OK; - } - void AppendToDatabaseUsage(uint64_t aUsage) { @@ -104,9 +90,6 @@ public: } } -protected: - mozilla::Atomic mCanceled; - private: uint64_t mDatabaseUsage; uint64_t mFileUsage; From 84e0671a2cd59f787104cdfe1014e221bd0e8527 Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Wed, 22 Mar 2017 12:13:58 +0100 Subject: [PATCH 60/96] Bug 1348660 - Part 4: Extract common code from GetOriginUsageOp to a new base class QuotaUsageRequestBase; r=btseng --- dom/quota/ActorsParent.cpp | 320 +++++++++++++++++++++++-------------- dom/quota/UsageInfo.h | 7 + 2 files changed, 204 insertions(+), 123 deletions(-) diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 9a7223c33beb..46f59713121d 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -1043,9 +1043,48 @@ private: RecvStopIdleMaintenance() override; }; -class GetOriginUsageOp final +class QuotaUsageRequestBase : public NormalOriginOperationBase , public PQuotaUsageRequestParent +{ +public: + // May be overridden by subclasses if they need to perform work on the + // background thread before being run. + virtual bool + Init(Quota* aQuota); + +protected: + QuotaUsageRequestBase() + : NormalOriginOperationBase(Nullable(), + OriginScope::FromNull(), + /* aExclusive */ false) + { } + + nsresult + GetUsageForOrigin(QuotaManager* aQuotaManager, + PersistenceType aPersistenceType, + const nsACString& aGroup, + const nsACString& aOrigin, + UsageInfo* aUsageInfo); + + // Subclasses use this override to set the IPDL response value. + virtual void + GetResponse(UsageRequestResponse& aResponse) = 0; + +private: + void + SendResults() override; + + // IPDL methods. + void + ActorDestroy(ActorDestroyReason aWhy) override; + + mozilla::ipc::IPCResult + RecvCancel() override; +}; + +class GetOriginUsageOp final + : public QuotaUsageRequestBase { // If mGetGroupUsage is false, we use mUsageInfo to record the origin usage // and the file usage. Otherwise, we use it to record the group usage and the @@ -1061,7 +1100,7 @@ public: explicit GetOriginUsageOp(const UsageRequestParams& aParams); MOZ_IS_CLASS_INIT bool - Init(Quota* aQuota); + Init(Quota* aQuota) override; private: ~GetOriginUsageOp() @@ -1070,22 +1109,11 @@ private: MOZ_IS_CLASS_INIT virtual nsresult DoInitOnMainThread() override; - nsresult - AddToUsage(QuotaManager* aQuotaManager, - PersistenceType aPersistenceType); - virtual nsresult DoDirectoryWork(QuotaManager* aQuotaManager) override; - virtual void - SendResults() override; - - // IPDL methods. - virtual void - ActorDestroy(ActorDestroyReason aWhy) override; - - virtual mozilla::ipc::IPCResult - RecvCancel() override; + void + GetResponse(UsageRequestResponse& aResponse) override; }; class QuotaRequestBase @@ -6235,7 +6263,21 @@ Quota::ActorDestroy(ActorDestroyReason aWhy) PQuotaUsageRequestParent* Quota::AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams) { - RefPtr actor = new GetOriginUsageOp(aParams); + AssertIsOnBackgroundThread(); + MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None); + + RefPtr actor; + + switch (aParams.type()) { + case UsageRequestParams::TOriginUsageParams: + actor = new GetOriginUsageOp(aParams); + break; + + default: + MOZ_CRASH("Should never get here!"); + } + + MOZ_ASSERT(actor); // Transfer ownership to IPDL. return actor.forget().take(); @@ -6249,7 +6291,7 @@ Quota::RecvPQuotaUsageRequestConstructor(PQuotaUsageRequestParent* aActor, MOZ_ASSERT(aActor); MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None); - auto* op = static_cast(aActor); + auto* op = static_cast(aActor); if (NS_WARN_IF(!op->Init(this))) { return IPC_FAIL_NO_REASON(this); @@ -6266,8 +6308,8 @@ Quota::DeallocPQuotaUsageRequestParent(PQuotaUsageRequestParent* aActor) MOZ_ASSERT(aActor); // Transfer ownership back from IPDL. - RefPtr actor = - dont_AddRef(static_cast(aActor)); + RefPtr actor = + dont_AddRef(static_cast(aActor)); return true; } @@ -6341,6 +6383,7 @@ Quota::RecvPQuotaRequestConstructor(PQuotaRequestParent* aActor, MOZ_ASSERT(aParams.type() != RequestParams::T__None); auto* op = static_cast(aActor); + if (NS_WARN_IF(!op->Init(this))) { return IPC_FAIL_NO_REASON(this); } @@ -6419,67 +6462,32 @@ Quota::RecvStopIdleMaintenance() return IPC_OK(); } -GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams) - : NormalOriginOperationBase(Nullable(), - OriginScope::FromNull(), - /* aExclusive */ false) - , mParams(aParams.get_OriginUsageParams()) - , mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage()) -{ - AssertIsOnOwningThread(); - MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams); -} - bool -GetOriginUsageOp::Init(Quota* aQuota) +QuotaUsageRequestBase::Init(Quota* aQuota) { AssertIsOnOwningThread(); MOZ_ASSERT(aQuota); - mNeedsMainThreadInit = true; mNeedsQuotaManagerInit = true; return true; } nsresult -GetOriginUsageOp::DoInitOnMainThread() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(GetState() == State_Initializing); - MOZ_ASSERT(mNeedsMainThreadInit); - - const PrincipalInfo& principalInfo = mParams.principalInfo(); - - nsresult rv; - nsCOMPtr principal = - PrincipalInfoToPrincipal(principalInfo, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - // Figure out which origin we're dealing with. - nsCString origin; - rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup, - &origin); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - mOriginScope.SetFromOrigin(origin); - - return NS_OK; -} - -nsresult -GetOriginUsageOp::AddToUsage(QuotaManager* aQuotaManager, - PersistenceType aPersistenceType) +QuotaUsageRequestBase::GetUsageForOrigin(QuotaManager* aQuotaManager, + PersistenceType aPersistenceType, + const nsACString& aGroup, + const nsACString& aOrigin, + UsageInfo* aUsageInfo) { AssertIsOnIOThread(); + MOZ_ASSERT(aQuotaManager); + MOZ_ASSERT(aUsageInfo); + MOZ_ASSERT(aUsageInfo->TotalUsage() == 0); nsCOMPtr directory; nsresult rv = aQuotaManager->GetDirectoryForOrigin(aPersistenceType, - mOriginScope.GetOrigin(), + aOrigin, getter_AddRefs(directory)); NS_ENSURE_SUCCESS(rv, rv); @@ -6493,8 +6501,7 @@ GetOriginUsageOp::AddToUsage(QuotaManager* aQuotaManager, bool initialized; if (aPersistenceType == PERSISTENCE_TYPE_PERSISTENT) { - initialized = - aQuotaManager->IsOriginInitialized(mOriginScope.GetOrigin()); + initialized = aQuotaManager->IsOriginInitialized(aOrigin); } else { initialized = aQuotaManager->IsTemporaryStorageInitialized(); } @@ -6567,17 +6574,17 @@ GetOriginUsageOp::AddToUsage(QuotaManager* aQuotaManager, if (initialized) { rv = client->GetUsageForOrigin(aPersistenceType, - mGroup, - mOriginScope.GetOrigin(), + aGroup, + aOrigin, mCanceled, - &mUsageInfo); + aUsageInfo); } else { rv = client->InitOrigin(aPersistenceType, - mGroup, - mOriginScope.GetOrigin(), + aGroup, + aOrigin, mCanceled, - &mUsageInfo); + aUsageInfo); } NS_ENSURE_SUCCESS(rv, rv); } @@ -6586,6 +6593,105 @@ GetOriginUsageOp::AddToUsage(QuotaManager* aQuotaManager, return NS_OK; } +void +QuotaUsageRequestBase::SendResults() +{ + AssertIsOnOwningThread(); + + if (IsActorDestroyed()) { + if (NS_SUCCEEDED(mResultCode)) { + mResultCode = NS_ERROR_FAILURE; + } + } else { + if (mCanceled) { + mResultCode = NS_ERROR_FAILURE; + } + + UsageRequestResponse response; + + if (NS_SUCCEEDED(mResultCode)) { + GetResponse(response); + } else { + response = mResultCode; + } + + Unused << PQuotaUsageRequestParent::Send__delete__(this, response); + } +} + +void +QuotaUsageRequestBase::ActorDestroy(ActorDestroyReason aWhy) +{ + AssertIsOnOwningThread(); + + NoteActorDestroyed(); +} + +mozilla::ipc::IPCResult +QuotaUsageRequestBase::RecvCancel() +{ + AssertIsOnOwningThread(); + + if (mCanceled.exchange(true)) { + NS_WARNING("Canceled more than once?!"); + return IPC_FAIL_NO_REASON(this); + } + + return IPC_OK(); +} + +GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams) + : mParams(aParams.get_OriginUsageParams()) + , mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage()) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams); +} + +bool +GetOriginUsageOp::Init(Quota* aQuota) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aQuota); + + if (NS_WARN_IF(!QuotaUsageRequestBase::Init(aQuota))) { + return false; + } + + mNeedsMainThreadInit = true; + + return true; +} + +nsresult +GetOriginUsageOp::DoInitOnMainThread() +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(GetState() == State_Initializing); + MOZ_ASSERT(mNeedsMainThreadInit); + + const PrincipalInfo& principalInfo = mParams.principalInfo(); + + nsresult rv; + nsCOMPtr principal = + PrincipalInfoToPrincipal(principalInfo, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + // Figure out which origin we're dealing with. + nsCString origin; + rv = QuotaManager::GetInfoFromPrincipal(principal, &mSuffix, &mGroup, + &origin); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mOriginScope.SetFromOrigin(origin); + + return NS_OK; +} + nsresult GetOriginUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) { @@ -6618,72 +6724,40 @@ GetOriginUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) // Add all the persistent/temporary/default storage files we care about. for (const PersistenceType type : kAllPersistenceTypes) { - rv = AddToUsage(aQuotaManager, type); + UsageInfo usageInfo; + rv = GetUsageForOrigin(aQuotaManager, + type, + mGroup, + mOriginScope.GetOrigin(), + &usageInfo); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } + + mUsageInfo.Append(usageInfo); } return NS_OK; } void -GetOriginUsageOp::SendResults() +GetOriginUsageOp::GetResponse(UsageRequestResponse& aResponse) { AssertIsOnOwningThread(); - if (IsActorDestroyed()) { - if (NS_SUCCEEDED(mResultCode)) { - mResultCode = NS_ERROR_FAILURE; - } + OriginUsageResponse usageResponse; + + // We'll get the group usage when mGetGroupUsage is true and get the + // origin usage when mGetGroupUsage is false. + usageResponse.usage() = mUsageInfo.TotalUsage(); + + if (mGetGroupUsage) { + usageResponse.limit() = mUsageInfo.Limit(); } else { - if (mCanceled) { - mResultCode = NS_ERROR_FAILURE; - } - - UsageRequestResponse response; - - if (NS_SUCCEEDED(mResultCode)) { - OriginUsageResponse usageResponse; - - // We'll get the group usage when mGetGroupUsage is true and get the - // origin usage when mGetGroupUsage is false. - usageResponse.usage() = mUsageInfo.TotalUsage(); - - if (mGetGroupUsage) { - usageResponse.limit() = mUsageInfo.Limit(); - } else { - usageResponse.fileUsage() = mUsageInfo.FileUsage(); - } - - response = usageResponse; - } else { - response = mResultCode; - } - - Unused << PQuotaUsageRequestParent::Send__delete__(this, response); - } -} - -void -GetOriginUsageOp::ActorDestroy(ActorDestroyReason aWhy) -{ - AssertIsOnOwningThread(); - - NoteActorDestroyed(); -} - -mozilla::ipc::IPCResult -GetOriginUsageOp::RecvCancel() -{ - AssertIsOnOwningThread(); - - if (mCanceled.exchange(true)) { - NS_WARNING("Canceled more than once?!"); - return IPC_FAIL_NO_REASON(this); + usageResponse.fileUsage() = mUsageInfo.FileUsage(); } - return IPC_OK(); + aResponse = usageResponse; } bool diff --git a/dom/quota/UsageInfo.h b/dom/quota/UsageInfo.h index 67b73195b54a..9d34f1bff61e 100644 --- a/dom/quota/UsageInfo.h +++ b/dom/quota/UsageInfo.h @@ -26,6 +26,13 @@ public: virtual ~UsageInfo() { } + void + Append(const UsageInfo& aUsageInfo) + { + IncrementUsage(&mDatabaseUsage, aUsageInfo.mDatabaseUsage); + IncrementUsage(&mFileUsage, aUsageInfo.mFileUsage); + } + void AppendToDatabaseUsage(uint64_t aUsage) { From 08e526c841bd05bef7eb1836579ddaed0bbf9d2a Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Wed, 22 Mar 2017 12:14:04 +0100 Subject: [PATCH 61/96] Bug 1348660 - Part 5: Implement a method to retrieve usage data for all origins at once; r=btseng --- dom/quota/ActorsChild.cpp | 40 +++++ dom/quota/ActorsChild.h | 3 + dom/quota/ActorsParent.cpp | 205 +++++++++++++++++++++++ dom/quota/PQuota.ipdl | 6 + dom/quota/PQuotaUsageRequest.ipdl | 13 ++ dom/quota/QuotaManagerService.cpp | 25 +++ dom/quota/QuotaRequests.cpp | 9 + dom/quota/QuotaRequests.h | 2 + dom/quota/QuotaResults.cpp | 37 ++++ dom/quota/QuotaResults.h | 20 +++ dom/quota/nsIQuotaManagerService.idl | 15 ++ dom/quota/nsIQuotaRequests.idl | 1 + dom/quota/nsIQuotaResults.idl | 10 ++ dom/quota/test/unit/getUsage_profile.zip | Bin 0 -> 24717 bytes dom/quota/test/unit/head.js | 12 ++ dom/quota/test/unit/test_getUsage.js | 127 ++++++++++++++ dom/quota/test/unit/xpcshell.ini | 2 + 17 files changed, 527 insertions(+) create mode 100644 dom/quota/test/unit/getUsage_profile.zip create mode 100644 dom/quota/test/unit/test_getUsage.js diff --git a/dom/quota/ActorsChild.cpp b/dom/quota/ActorsChild.cpp index ffb35104a857..364896c54695 100644 --- a/dom/quota/ActorsChild.cpp +++ b/dom/quota/ActorsChild.cpp @@ -141,6 +141,42 @@ QuotaUsageRequestChild::HandleResponse(nsresult aResponse) mRequest->SetError(aResponse); } +void +QuotaUsageRequestChild::HandleResponse(const nsTArray& aResponse) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(mRequest); + + RefPtr variant = new nsVariant(); + + if (aResponse.IsEmpty()) { + variant->SetAsEmptyArray(); + } else { + nsTArray> usageResults; + + const uint32_t count = aResponse.Length(); + + usageResults.SetCapacity(count); + + for (uint32_t index = 0; index < count; index++) { + auto& originUsage = aResponse[index]; + + RefPtr usageResult = new UsageResult(originUsage.origin(), + originUsage.persisted(), + originUsage.usage()); + + usageResults.AppendElement(usageResult.forget()); + } + + variant->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS, + &NS_GET_IID(nsIQuotaUsageResult), + usageResults.Length(), + static_cast(usageResults.Elements())); + } + + mRequest->SetResult(variant); +} + void QuotaUsageRequestChild::HandleResponse(const OriginUsageResponse& aResponse) { @@ -182,6 +218,10 @@ QuotaUsageRequestChild::Recv__delete__(const UsageRequestResponse& aResponse) HandleResponse(aResponse.get_nsresult()); break; + case UsageRequestResponse::TAllUsageResponse: + HandleResponse(aResponse.get_AllUsageResponse().originUsages()); + break; + case UsageRequestResponse::TOriginUsageResponse: HandleResponse(aResponse.get_OriginUsageResponse()); break; diff --git a/dom/quota/ActorsChild.h b/dom/quota/ActorsChild.h index 4bc5e85a5f29..fe1abf1094d0 100644 --- a/dom/quota/ActorsChild.h +++ b/dom/quota/ActorsChild.h @@ -97,6 +97,9 @@ private: void HandleResponse(nsresult aResponse); + void + HandleResponse(const nsTArray& aResponse); + void HandleResponse(const OriginUsageResponse& aResponse); diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index 46f59713121d..b503738c0ae3 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -1083,6 +1083,32 @@ private: RecvCancel() override; }; +class GetUsageOp final + : public QuotaUsageRequestBase +{ + nsTArray mOriginUsages; + nsDataHashtable mOriginUsagesIndex; + + bool mGetAll; + +public: + explicit GetUsageOp(const UsageRequestParams& aParams); + +private: + ~GetUsageOp() + { } + + nsresult + TraverseRepository(QuotaManager* aQuotaManager, + PersistenceType aPersistenceType); + + nsresult + DoDirectoryWork(QuotaManager* aQuotaManager) override; + + void + GetResponse(UsageRequestResponse& aResponse) override; +}; + class GetOriginUsageOp final : public QuotaUsageRequestBase { @@ -6269,6 +6295,10 @@ Quota::AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams) RefPtr actor; switch (aParams.type()) { + case UsageRequestParams::TAllUsageParams: + actor = new GetUsageOp(aParams); + break; + case UsageRequestParams::TOriginUsageParams: actor = new GetOriginUsageOp(aParams); break; @@ -6640,6 +6670,181 @@ QuotaUsageRequestBase::RecvCancel() return IPC_OK(); } +GetUsageOp::GetUsageOp(const UsageRequestParams& aParams) + : mGetAll(aParams.get_AllUsageParams().getAll()) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams); +} + +nsresult +GetUsageOp::TraverseRepository(QuotaManager* aQuotaManager, + PersistenceType aPersistenceType) +{ + AssertIsOnIOThread(); + MOZ_ASSERT(aQuotaManager); + + nsresult rv; + + nsCOMPtr directory = + do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool exists; + rv = directory->Exists(&exists); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!exists) { + return NS_OK; + } + + nsCOMPtr entries; + rv = directory->GetDirectoryEntries(getter_AddRefs(entries)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + bool persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT; + + bool hasMore; + while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) && + hasMore && !mCanceled) { + nsCOMPtr entry; + rv = entries->GetNext(getter_AddRefs(entry)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr originDir = do_QueryInterface(entry); + MOZ_ASSERT(originDir); + + bool isDirectory; + rv = originDir->IsDirectory(&isDirectory); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!isDirectory) { + nsString leafName; + rv = originDir->GetLeafName(leafName); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!IsOSMetadata(leafName)) { + UNKNOWN_FILE_WARNING(leafName); + } + continue; + } + + int64_t timestamp; + bool persisted; + nsCString suffix; + nsCString group; + nsCString origin; + rv = aQuotaManager->GetDirectoryMetadata2WithRestore(originDir, + persistent, + ×tamp, + &persisted, + suffix, + group, + origin); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!mGetAll && + aQuotaManager->IsOriginWhitelistedForPersistentStorage(origin)) { + continue; + } + + OriginUsage* originUsage; + + // We can't store pointers to OriginUsage objects in the hashtable + // since AppendElement() reallocates its internal array buffer as number + // of elements grows. + uint32_t index; + if (mOriginUsagesIndex.Get(origin, &index)) { + originUsage = &mOriginUsages[index]; + } else { + index = mOriginUsages.Length(); + + originUsage = mOriginUsages.AppendElement(); + + originUsage->origin() = origin; + originUsage->persisted() = false; + originUsage->usage() = 0; + + mOriginUsagesIndex.Put(origin, index); + } + + if (aPersistenceType == PERSISTENCE_TYPE_DEFAULT) { + originUsage->persisted() = persisted; + } + + UsageInfo usageInfo; + rv = GetUsageForOrigin(aQuotaManager, + aPersistenceType, + group, + origin, + &usageInfo); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + originUsage->usage() = originUsage->usage() + usageInfo.TotalUsage(); + } + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + return NS_OK; +} + +nsresult +GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager) +{ + AssertIsOnIOThread(); + + PROFILER_LABEL("Quota", "GetUsageOp::DoDirectoryWork", + js::ProfileEntry::Category::OTHER); + + nsresult rv; + + for (const PersistenceType type : kAllPersistenceTypes) { + rv = TraverseRepository(aQuotaManager, type); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + return NS_OK; +} + +void +GetUsageOp::GetResponse(UsageRequestResponse& aResponse) +{ + AssertIsOnOwningThread(); + + aResponse = AllUsageResponse(); + + if (!mOriginUsages.IsEmpty()) { + nsTArray& originUsages = + aResponse.get_AllUsageResponse().originUsages(); + + mOriginUsages.SwapElements(originUsages); + } +} + GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams) : mParams(aParams.get_OriginUsageParams()) , mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage()) diff --git a/dom/quota/PQuota.ipdl b/dom/quota/PQuota.ipdl index 29ec3ae3e546..566cb02eef76 100644 --- a/dom/quota/PQuota.ipdl +++ b/dom/quota/PQuota.ipdl @@ -27,6 +27,11 @@ struct InitOriginParams PersistenceType persistenceType; }; +struct AllUsageParams +{ + bool getAll; +}; + struct OriginUsageParams { PrincipalInfo principalInfo; @@ -35,6 +40,7 @@ struct OriginUsageParams union UsageRequestParams { + AllUsageParams; OriginUsageParams; }; diff --git a/dom/quota/PQuotaUsageRequest.ipdl b/dom/quota/PQuotaUsageRequest.ipdl index 682222204fa2..16994e627d1b 100644 --- a/dom/quota/PQuotaUsageRequest.ipdl +++ b/dom/quota/PQuotaUsageRequest.ipdl @@ -8,6 +8,18 @@ namespace mozilla { namespace dom { namespace quota { +struct OriginUsage +{ + nsCString origin; + bool persisted; + uint64_t usage; +}; + +struct AllUsageResponse +{ + OriginUsage[] originUsages; +}; + struct OriginUsageResponse { uint64_t usage; @@ -18,6 +30,7 @@ struct OriginUsageResponse union UsageRequestResponse { nsresult; + AllUsageResponse; OriginUsageResponse; }; diff --git a/dom/quota/QuotaManagerService.cpp b/dom/quota/QuotaManagerService.cpp index 9d495591ff0d..01be3f87e203 100644 --- a/dom/quota/QuotaManagerService.cpp +++ b/dom/quota/QuotaManagerService.cpp @@ -584,6 +584,31 @@ QuotaManagerService::InitStoragesForPrincipal( return NS_OK; } +NS_IMETHODIMP +QuotaManagerService::GetUsage(nsIQuotaUsageCallback* aCallback, + bool aGetAll, + nsIQuotaUsageRequest** _retval) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aCallback); + + RefPtr request = new UsageRequest(aCallback); + + AllUsageParams params; + + params.getAll() = aGetAll; + + nsAutoPtr info(new UsageRequestInfo(request, params)); + + nsresult rv = InitiateRequest(info); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + request.forget(_retval); + return NS_OK; +} + NS_IMETHODIMP QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback, diff --git a/dom/quota/QuotaRequests.cpp b/dom/quota/QuotaRequests.cpp index 1f53b9aa50d5..c9c1cbff6764 100644 --- a/dom/quota/QuotaRequests.cpp +++ b/dom/quota/QuotaRequests.cpp @@ -91,6 +91,15 @@ RequestBase::GetResultCode(nsresult* aResultCode) return NS_OK; } +UsageRequest::UsageRequest(nsIQuotaUsageCallback* aCallback) + : mCallback(aCallback) + , mBackgroundActor(nullptr) + , mCanceled(false) +{ + AssertIsOnOwningThread(); + MOZ_ASSERT(aCallback); +} + UsageRequest::UsageRequest(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback) : RequestBase(aPrincipal) diff --git a/dom/quota/QuotaRequests.h b/dom/quota/QuotaRequests.h index 0fc2f096a43e..9a51a382085b 100644 --- a/dom/quota/QuotaRequests.h +++ b/dom/quota/QuotaRequests.h @@ -79,6 +79,8 @@ class UsageRequest final bool mCanceled; public: + explicit UsageRequest(nsIQuotaUsageCallback* aCallback); + UsageRequest(nsIPrincipal* aPrincipal, nsIQuotaUsageCallback* aCallback); diff --git a/dom/quota/QuotaResults.cpp b/dom/quota/QuotaResults.cpp index be02691579e0..f5dbbd657e2a 100644 --- a/dom/quota/QuotaResults.cpp +++ b/dom/quota/QuotaResults.cpp @@ -10,6 +10,43 @@ namespace mozilla { namespace dom { namespace quota { +UsageResult::UsageResult(const nsACString& aOrigin, + bool aPersisted, + uint64_t aUsage) + : mOrigin(aOrigin) + , mUsage(aUsage) + , mPersisted(aPersisted) +{ +} + +NS_IMPL_ISUPPORTS(UsageResult, + nsIQuotaUsageResult) + +NS_IMETHODIMP +UsageResult::GetOrigin(nsACString& aOrigin) +{ + aOrigin = mOrigin; + return NS_OK; +} + +NS_IMETHODIMP +UsageResult::GetPersisted(bool* aPersisted) +{ + MOZ_ASSERT(aPersisted); + + *aPersisted = mPersisted; + return NS_OK; +} + +NS_IMETHODIMP +UsageResult::GetUsage(uint64_t* aUsage) +{ + MOZ_ASSERT(aUsage); + + *aUsage = mUsage; + return NS_OK; +} + OriginUsageResult::OriginUsageResult(uint64_t aUsage, uint64_t aFileUsage, uint64_t aLimit) diff --git a/dom/quota/QuotaResults.h b/dom/quota/QuotaResults.h index 4d38d6d8d578..73fe6b790174 100644 --- a/dom/quota/QuotaResults.h +++ b/dom/quota/QuotaResults.h @@ -13,6 +13,26 @@ namespace mozilla { namespace dom { namespace quota { +class UsageResult + : public nsIQuotaUsageResult +{ + nsCString mOrigin; + uint64_t mUsage; + bool mPersisted; + +public: + UsageResult(const nsACString& aOrigin, + bool aPersisted, + uint64_t aUsage); + +private: + virtual ~UsageResult() + { } + + NS_DECL_ISUPPORTS + NS_DECL_NSIQUOTAUSAGERESULT +}; + class OriginUsageResult : public nsIQuotaOriginUsageResult { diff --git a/dom/quota/nsIQuotaManagerService.idl b/dom/quota/nsIQuotaManagerService.idl index 99a44476c6ec..b5c1869a9b68 100644 --- a/dom/quota/nsIQuotaManagerService.idl +++ b/dom/quota/nsIQuotaManagerService.idl @@ -41,6 +41,21 @@ interface nsIQuotaManagerService : nsISupports initStoragesForPrincipal(in nsIPrincipal aPrincipal, in ACString aPersistenceType); + /** + * Schedules an asynchronous callback that will inspect all origins and + * return the total amount of disk space being used by storages for each + * origin separately. + * + * @param aCallback + * The callback that will be called when the usage is available. + * @param aGetAll + * An optional boolean to indicate inspection of all origins, + * including internal ones. + */ + [must_use] nsIQuotaUsageRequest + getUsage(in nsIQuotaUsageCallback aCallback, + [optional] in boolean aGetAll); + /** * Schedules an asynchronous callback that will return the total amount of * disk space being used by storages for the given origin. diff --git a/dom/quota/nsIQuotaRequests.idl b/dom/quota/nsIQuotaRequests.idl index e30a6ebbbfbb..5d7cff3b9350 100644 --- a/dom/quota/nsIQuotaRequests.idl +++ b/dom/quota/nsIQuotaRequests.idl @@ -23,6 +23,7 @@ interface nsIQuotaRequestBase : nsISupports interface nsIQuotaUsageRequest : nsIQuotaRequestBase { // The result can contain one of these types: + // array of nsIQuotaUsageResult // nsIQuotaOriginUsageResult [must_use] readonly attribute nsIVariant result; diff --git a/dom/quota/nsIQuotaResults.idl b/dom/quota/nsIQuotaResults.idl index 1c787009dcd0..cd7ffd3a02c6 100644 --- a/dom/quota/nsIQuotaResults.idl +++ b/dom/quota/nsIQuotaResults.idl @@ -6,6 +6,16 @@ #include "nsISupports.idl" +[scriptable, function, uuid(d8c9328b-9aa8-4f5d-90e6-482de4a6d5b8)] +interface nsIQuotaUsageResult : nsISupports +{ + readonly attribute ACString origin; + + readonly attribute boolean persisted; + + readonly attribute unsigned long long usage; +}; + [scriptable, function, uuid(96df03d2-116a-493f-bb0b-118c212a6b32)] interface nsIQuotaOriginUsageResult : nsISupports { diff --git a/dom/quota/test/unit/getUsage_profile.zip b/dom/quota/test/unit/getUsage_profile.zip new file mode 100644 index 0000000000000000000000000000000000000000..5144112bde351703f42ab87f817421af09cdae53 GIT binary patch literal 24717 zcmeHPc|26@`&QbON_(P`eVeitBFVlB(L#2zjO?<#EtFIgl0pfI2o2e?B+5?qow8-m z5~1ODjxjT5hQsv!-ao#7n9t{_(MR`nJ@<2;`#SeI_wy*plCRlB27YRk6lCVU%>S{0 z>;Rdy4bn=-$N-_Hx{-`LEdQm(5HM^VD9Bc=`L&9SY|T#Kca>l*P(dtM8d#a@SQuE? zENct2xqp4a=cMCPZLBz=ap(wKP z=w|n!nO(OO6_hmklEk*M-5q$p%h+kZhv-A&XE)i?sG8|HMp`8)q-!agbtF~1hg`yo z(^mi9Inn0Oz|^~bRbks#U(^lSTcYc3J#*ZV|B=`GvF@8AH}h?D?#UXv(|#R3ZdJ?? z*&-+2=T#-7qifybdbGMhwK`1x(34II2|4xS9}S|AYa^Rtgw@sfC7E)sqSLfbn!Y^i zcKw8Vj96>ZDy4%gs|Bgom8v|?=s_ko+I28(`pBv8mhrvx!P#u}dQ+F*p*@j)#*$Tj z*K~f@hcy{B>P@rNii;(*znbCG39q}Etjo`*_x4;T?~7A8w>2fJZ@m0MGu8Lzv05wp zXV#m(FRN4PPZSraJmuJF^r1a2g)O~xFpTY$Q%;+XI_d%4R0a3C2PoODyI=?Ao1k8%4W~~C3 z9kW#Grj{~86wjiLfq?@o6(xSzIjygnnb;W2E!NFjg&N=>S}Y36u>y8!HK`&*p**|t zQNzo+m-Y26m6R?6pIf?3|7?t7C)dcLja-MgdPVXhLA-Hau_TDtZFpdWzJZ~Rt=W9E z>D(yP00$8?K63eqEI}jJ#=zVXxC*QsF_CKm*Z~KuEq}lrpeL}OeGpdot3c1#3TZxn zVNC*F0mmXHF&+j@{+W)5-VNBK0S4VtCOORwY;^Q>Y;@+l4r5#I@~^besjoxSn#Q8kI~E5dL4eR9;mQWoZOQ!_L`cl zuSCxEc;(7{Vf4=!JF=yFABfQKRaXcaUrR`?qrJSx>1Ip+K0cFxO4`fFcs;%B+256R z)w{>g%xj9e?H{-SLyTRV#Z9wHUZS)i_?6)!r<^T1Cepv}Z4=!__a}+-p83z(ch+XX zdnRkWZ%%m9Bh032AL|Qx zbjWN94ZJD#((gh3*Tepva^7}={V_Fz@8w2VQpLtiG7tH(bEvc+BK>G7uZ>)Gr^+bR zlgaCUtL1j;be5&7L5)2r=Dwx& z@zepuR^ggHlkbC%#$$?-`*TbbP9%R2thv;`=b)5|E>h81GpTQPidNg1;gYiEtG6N^q|CB4aBAZ^zs}!%=(BPHm6Od8D^0NE@!r%E+ zQD%6|o$y`X`g&zg`k2)D*gafLGjKUmeeJJ!RpnTxaGwE}cdQH}7j)e!6)yK`?c+s%ITEWz3LX z0au+gFQPBqeiPz;Ra@_Yibqvz)|UICryh54`F}rZJf``gLXTIz|6~vK7ZiPHWw2I} z=Np~4n^`KYXTo!v)4wxVpDRpq_{hzsV{47z4;=f(ogTvxThL$OAbZIrI?x;4-7NB0 z%;Sn3^{dkJhTU}GUsKnw^Ljz87Hj%ml3yZ9HGE(FF7)o|!2xz@&tRH_tnIJkrX3u0 z<(bY^mTDra1!4+L3zth$50xG;kpG3etDcdSh51k%u z^&fjYd$&yEOL=2#R3IPEr;cRB*hX`8`QWX>+#04P_r1E!N{x+-#oUBB>g;{%whoQD zk^_kZ`253Waz86~!ga^*J(zzWyT~EkGk!av+BjF=L-VAOVP1J@{oszU@svsnE}hQN zR{I%Yw3LIvta6rRdzJ$Bf3+|O&CZ)-7w#LH9saWwV=un$C+_R-<-g9(0yk;U&)ZBl zNLqhPB#1{A&A-MrHkNE`Y-UJ39W!I3^}KTb0TL`YV3RCpys@Y>`3Qgy3KctP#tB6d z1_dLM2{YROku*|pwbE6PaJ{KEo>E=geO_s15GI))2i~Dk0Rhb3v4{8dqkUo31g6Wpjqn$hA9D6EmILN1e z8F$olMwd^YP?bBc7~cPYB0;>T>mdKZmftQj-KmY92>$?-Td6DmXyur9g7%pm*|U;H z=Ax+&8q9v5Ae(kmse^F8t z<#$r+JWoU%HQmkP=Xt)u^E}J$<`e#TM=uCm?W=ljQ`pGXo*NmQYP(~!v?)a7&XZ?Z zb?qesg=-6aMZ4le6t|nibyL@7b4xT_>Q4REXU4}~^F2Ax;jrm_Tq$l- zvFKYB!5Jx!V$AZJ*Bgd?&NSyQMmBt}7{3}vsdzu_xH6JE6Q{_H27S`(wV7OwAuSTFerDSX>WWyZ)zqiA9k^Ew5_4&F2=c#Q4~$XO(Bd9F8JMoKO%xjF zH6@oxSi~o%pjv{J9~BjiP!!c`2JA@_QgL?b(XKo5>3#l>ljC=vF@LD4H8^M6`ds}H z8{0_UOB8#^OvoqA)*OepV-hS!dJi^vs3Q(Zj@HX09OQ98l=p;$94-yne6Rh&qx>GN zOGTk?zQu^et7zx>b!0e=tQ}P^L^*up=2o^H<>cQt-o>33v!&hdM8t4F+BL(UzHN>} zah-QU6&h_V-mOChOY)>moI-Awdvhhx(b`haPe%Ny+R3j-rGe63zeg7@`KMEaPF?ek zyj^4Cz#AM?@>$0#_}v};v5%kA1tl~qn;YLfx_JH(VkeWLlQ!+%nl_{20PR_`Lhg9C z(7aX|!y^uPkue5=C7=BRYqofKHFn203&&cW-7L&iXT0~ryh!d{yyV;gNFg|2QA6jbu7x)lmg~4AbG*=4El|pl+(EML6G+z;EEc8t${;esr)Z7Co4LFF@22A#t zWDA;vmYUEvoeNA7YATHF<%&%Z5n60Q)e9aGE1%1PE?#aDdk*@ha{(w$Dq+CzQb}wU z`o?ilv!qGn61ezPgO;5CA6$qu!r-nHohwD>O3}GebpG!Zoy7SU`rs0ue;3q3b0y(k zKo-HVq%=ayPUxG?C5#h_Bn%3^+#}&lCpb%J;R$`yNeU6Hb}q|h`O=fv;m|joOHjcn zDhvg9MTNd+Tn2zNZC!!^UR$B%=YPWhqOvdyRtnIS0(7MST`55SmkUrjph+D24ix+w zs<%W>9t|9H%q`6fIQ5X`nD)&q&q57w!0Ih%TzyttiUBap2@I&-E@7NdZ(&eCy;bJz zmK6ayi|nt6>sp8^L~B{Oa{93O&G#0uZ-Vp|fmCv($wlY^8iK%pDlREhu!_4ZoBeGH zu~Nkx`O?+0rDbca+~>QC9*WPkdv5}uf#zc(r$aS&2{Jg%g&~30Tw(yI;w=L}n&vLS z0He7e19J5O&7eiPi~cv`nVdfuk4VPaiE$UWe0z12`-rpXokJV8&z#@M$v#{ggK6SbL{B`V z%aLH$vAuYgouYO&bLMA*wpSKs(*qZ_j0ZD2&^m(w_0NxFjWYhTRdQnRkxlo^h%++J ztnbU07?laksgZKT$s;u@5&+Up&S*gJ9e^087* z<-1P$$biB#ubimO?NrTepE6DcH63Z>2?&t(*v&i?pmx`L>ZD`*X-}>8V|k|y#o|uV ztCreqeJgEWVLF;Y-u*82lTpkSbqB`t5ubbe=?k36efu@KZYFv{;uegJHnw zxPA26bXLj?R;fysU8>(d^}o)Is=QpW(LTzn_ejK{T6i=Xol)lRd$6pCHK}Vvqd-K4ZG8vZH6OZ9(?;b2Qq1+u&jY@9 z$|nGAFEw>u3TJ0CKOxL%Ci;F}d^5V^m%7>;!EW+n6bg)vC&VTS=*2X4ZO$DY8_>&m zOgG5MQkLfYMIpE=+`1@TuQ|_k@*#a5KY!l2UFjCr`_?Mt3hmm$!<2t0>(svBd--;u zDFXsM9p+DB`6!0Eo&~y*l~u*O_j9^LzE<{COor6xiTcJM`b{MxDg}ax9kPXYr8Kr@ zzRj#65A@h#vWKPoD`l6d|2cavgX%QNk-$MCWtNZ&yPVkURtF6Fdwq5+6Q)l8*wS8_ z#>zir_EJ*$MFiccuxuQhr>?&TlkeNqv8tR_PPkM<<-{Yjv8RPc$Ld? zQsRz@vWWE#wR%X191=tISm|uz`NOW%llhcxJY?*CyXK?v9xbh+hnOy2MLHE{Q&}OS zL7CLu2nR#X7>mJ9#xP;$&jCqMyiYFeM@F$RJ)Nv_YeDOs(0?rvY0(>F@?KGFf3VYw ztPN?(Uj+dwuc+}~4=($4W_G?yX`UEacJ%}TpP%VT z7XW*EdrouYH4`&49ZsZ`5k`4)0o4Tutnz{Yotsc0EC4 zkS57Xu)s(%I8`QV*22(vN&fFxKx7$)1@ORGp%L6#^Nfs9sX=SA!4-F#ZKq|!c@ld| zH26)f2c3Ff)pI~HJDP>7<5csBjb6cADY7z%amw`hy)|+!?$YT&j04B)`j3B{U2T#c z%`oM9=1%9R;Fm05tdYGl!Y|&e+wr14+H`j+qG=~1<1NI-?Q0Hy*0#<`b)0!><2^7+ zH#-$EA*?EwpX+P)WwP#uC3>iD>svJM#B_h`Z@r$*F_B6Uc{JaoY5&%iH9x=oXbKFl zXw`nw!+D+q{nICj(&naGqa<&MF3|J4#obU%Ml~WnReIN4&#!;7Ds3mw^V<*h{2t~> zPZ0O3;Hz(W$@Q?u?o}S;__F~I@ytW^1p>|N`9ROF-$W5x#O;g_A&t;8al=5*Z@^d6 ztsDHUgPTn&2Kq}xa3tcO?{lcR-p#Gcn%C#VSN`E|zi{Fa+C0zJPMRXi`w_54mA zrDmP$`K@SV8_10eO0{jb26}$u#EVO``@eSCeOujGaA=hOIg@u{?P#oN+rA^6Z%6xo z+SX7rnrg7%I*3!0`9FDxbr&Ig*t$Wffn8yV@~{`{+80A0mm95d-a7G$AJI zM09v2ct4#ycsJ0Nn2$LD&KKEqp@q7SV|>(` zfh8f0HS@KAEyX2-4c*`yO-fRv_-bh^rM`>h9x@}rE)9$%`7K~JON3oK>d-OJ>}t4q?G^y_YybsCr( z+jjYV*6!_nXn1mC$i$4sgT2u$eC)xzF*VX>!ko5_?H1*KbH4EkrNup!C@IuCrYVl- zX3an!DmFGXI@9iBPzWS;~sCtW75zmF&IaTM}LT3I9v3-jel|<*1Oau#KjFNqjb(mR? z`M%d}ymhvH@*w7?%OAeszW!PM>nwK1&b(c+i!QT};*5t#n^_>q8o&8;{s}a(c+NeC z?f{e-97O5_>H#JbgAh=4=K325LVbq8!YLu?`V5kCV!pDM8E^}z&%FPN6jq^^<+Yzg zfhJxKXph#i%Yl<<7&>@~CWcY?o7safq>1zrJn*3b73u$y2Slb}c&y0uicGJ_^omUX z56kqb)wJZ8r>F~0TiH9W=-bE!M8U84vscz)&R$ud$ne&v$e`9vL#*LdM@@ApyO@N& z@Dvt|U2sFwKi3}se-fU_0$5z+JQgKckSWIE!oxzaOhJn$fa62v=Z!l$1hBctu^||n z7+)?t2Lx+#8(FsKJG@QEsUU#WMNb65`*h)%AW*A+AXf1&g6Dj?=;2TI^(FQg4S~mQECq$Rhx&U6VFHNySH;8my#y%OAA+Zk$x5cXwhB!_{lEZw~qw^!}L9AK)67fyY5IpBy3xO zB8pIuG&LL|HgsV@7xyOG zSO)kNgXUU118~Li|1|?hK*BP>IGK1`(_sQ1lmgcZHq&AQa`8O7=vFoSRS3dBy9QZt zFyKU4_K^TX7^EcNL9;9e0bcxH;bFsdk^O1V+dpDYGTN0kzYac z(ELh=b2}Ks?n{{`3|KC25+t z!2U}x!oc<<9c+ml3CYv2Y%qbnu;UTxZwlaOUlLY$nad0k*syFc3qjo1Lbwnte6Va5 zzR?7NJ9p{eUf68}o%&tU!3YC<8PtUhMNm{4ph*nI;lxwKp<;s^Y%f~$T3+0@Yy=4v zMLIAp&|zn~IG`K>;NIgT&vcpaf&@D(BTTR_>?MNwKIA`R1PORpMi?IvzrbZ7@KN4L zypQnDgy(gfI3DJ*Ysbc{|Bjwx={cC literal 0 HcmV?d00001 diff --git a/dom/quota/test/unit/head.js b/dom/quota/test/unit/head.js index 89df227644c1..8413ffc9efb3 100644 --- a/dom/quota/test/unit/head.js +++ b/dom/quota/test/unit/head.js @@ -261,11 +261,23 @@ function getPersistedFromMetadata(readBuffer) return !!view[persistedPosition]; } +function grabResultAndContinueHandler(request) +{ + testGenerator.next(request.result); +} + function grabUsageAndContinueHandler(request) { testGenerator.next(request.result.usage); } +function getUsage(usageHandler, getAll) +{ + let request = SpecialPowers._getQuotaManager().getUsage(usageHandler, getAll); + + return request; +} + function getCurrentUsage(usageHandler) { let principal = Cc["@mozilla.org/systemprincipal;1"] diff --git a/dom/quota/test/unit/test_getUsage.js b/dom/quota/test/unit/test_getUsage.js new file mode 100644 index 000000000000..37d9d197a47b --- /dev/null +++ b/dom/quota/test/unit/test_getUsage.js @@ -0,0 +1,127 @@ +/** + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +var testGenerator = testSteps(); + +function* testSteps() +{ + const origins = [ + { + origin: "http://example.com", + persisted: false, + usage: 49152 + }, + + { + origin: "http://localhost", + persisted: false, + usage: 147456 + }, + + { + origin: "http://www.mozilla.org", + persisted: true, + usage: 98304 + } + ]; + + const allOrigins = [ + { + origin: "chrome", + persisted: false, + usage: 147456 + }, + + { + origin: "http://example.com", + persisted: false, + usage: 49152 + }, + + { + origin: "http://localhost", + persisted: false, + usage: 147456 + }, + + { + origin: "http://www.mozilla.org", + persisted: true, + usage: 98304 + } + ]; + + function verifyResult(result, origins) { + ok(result instanceof Array, "Got an array object"); + ok(result.length == origins.length, "Correct number of elements"); + + info("Sorting elements"); + + result.sort(function(a, b) { + let originA = a.origin + let originB = b.origin + + if (originA < originB) { + return -1; + } + if (originA > originB) { + return 1; + } + return 0; + }); + + info("Verifying elements"); + + for (let i = 0; i < result.length; i++) { + let a = result[i]; + let b = origins[i]; + ok(a.origin == b.origin, "Origin equals"); + ok(a.persisted == b.persisted, "Persisted equals"); + ok(a.usage == b.usage, "Usage equals"); + } + } + + info("Clearing"); + + clear(continueToNextStepSync); + yield undefined; + + info("Getting usage"); + + getUsage(grabResultAndContinueHandler, /* getAll */ true); + let result = yield undefined; + + info("Verifying result"); + + verifyResult(result, []); + + info("Installing package"); + + // The profile contains IndexedDB databases placed across the repositories. + // The file create_db.js in the package was run locally, specifically it was + // temporarily added to xpcshell.ini and then executed: + // mach xpcshell-test --interactive dom/quota/test/unit/create_db.js + installPackage("getUsage_profile"); + + info("Getting usage"); + + getUsage(grabResultAndContinueHandler, /* getAll */ false); + result = yield undefined; + + info("Verifying result"); + + verifyResult(result, origins); + + info("Getting usage"); + + getUsage(grabResultAndContinueHandler, /* getAll */ true); + result = yield undefined; + + info("Verifying result"); + + verifyResult(result, allOrigins); + + finishTest(); +} diff --git a/dom/quota/test/unit/xpcshell.ini b/dom/quota/test/unit/xpcshell.ini index 1ad1b8ff0edb..fc825a035c30 100644 --- a/dom/quota/test/unit/xpcshell.ini +++ b/dom/quota/test/unit/xpcshell.ini @@ -7,6 +7,7 @@ head = head.js support-files = basics_profile.zip defaultStorageUpgrade_profile.zip + getUsage_profile.zip idbSubdirUpgrade1_profile.zip idbSubdirUpgrade2_profile.zip morgueCleanup_profile.zip @@ -18,6 +19,7 @@ support-files = [test_basics.js] [test_defaultStorageUpgrade.js] +[test_getUsage.js] [test_idbSubdirUpgrade.js] [test_morgueCleanup.js] [test_obsoleteOriginAttributesUpgrade.js] From ee8bdbeba61447b04ccf24d923aab82abe5e5ccf Mon Sep 17 00:00:00 2001 From: Jan Varga Date: Wed, 22 Mar 2017 12:14:09 +0100 Subject: [PATCH 62/96] Bug 1348660 - Part 6: Rename QuotaManager::IsOriginWhitelistedForPersistentStorage() to QuotaManager::IsOriginInternal(); r=btseng --- dom/indexedDB/ActorsParent.cpp | 5 ++--- dom/quota/ActorsParent.cpp | 17 ++++++----------- dom/quota/QuotaManager.h | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index feaabc9d49f9..083810be7723 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -21246,8 +21246,7 @@ FactoryOp::CheckPermission(ContentParent* aContentParent, if (State::Initial == mState) { QuotaManager::GetInfoForChrome(&mSuffix, &mGroup, &mOrigin); - MOZ_ASSERT( - QuotaManager::IsOriginWhitelistedForPersistentStorage(mOrigin)); + MOZ_ASSERT(QuotaManager::IsOriginInternal(mOrigin)); mEnforcingQuota = false; } @@ -21279,7 +21278,7 @@ FactoryOp::CheckPermission(ContentParent* aContentParent, PermissionRequestBase::PermissionValue permission; if (persistenceType == PERSISTENCE_TYPE_PERSISTENT) { - if (QuotaManager::IsOriginWhitelistedForPersistentStorage(origin)) { + if (QuotaManager::IsOriginInternal(origin)) { permission = PermissionRequestBase::kPermissionAllowed; } else { #ifdef IDB_MOBILE diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp index b503738c0ae3..9e2bceee0044 100644 --- a/dom/quota/ActorsParent.cpp +++ b/dom/quota/ActorsParent.cpp @@ -5355,10 +5355,9 @@ QuotaManager::GetInfoForChrome(nsACString* aSuffix, // static bool -QuotaManager::IsOriginWhitelistedForPersistentStorage(const nsACString& aOrigin) +QuotaManager::IsOriginInternal(const nsACString& aOrigin) { - // The first prompt and quota tracking is not required for these origins in - // persistent storage. + // The first prompt is not required for these origins. if (aOrigin.EqualsLiteral(kChromeOrigin) || StringBeginsWith(aOrigin, nsDependentCString(kAboutHomeOriginPrefix)) || StringBeginsWith(aOrigin, nsDependentCString(kIndexedDBOriginPrefix)) || @@ -6762,8 +6761,7 @@ GetUsageOp::TraverseRepository(QuotaManager* aQuotaManager, return rv; } - if (!mGetAll && - aQuotaManager->IsOriginWhitelistedForPersistentStorage(origin)) { + if (!mGetAll && aQuotaManager->IsOriginInternal(origin)) { continue; } @@ -8471,9 +8469,7 @@ CreateOrUpgradeDirectoryMetadataHelper::CreateOrUpgradeMetadataFiles() } } else { - bool persistent = - QuotaManager::IsOriginWhitelistedForPersistentStorage( - originProps.mSpec); + bool persistent = QuotaManager::IsOriginInternal(originProps.mSpec); originProps.mTimestamp = GetLastModifiedTime(originDir, persistent); } @@ -8617,9 +8613,8 @@ CreateOrUpgradeDirectoryMetadataHelper::ProcessOriginDirectory( return rv; } - // Move whitelisted origins to new persistent storage. - if (QuotaManager::IsOriginWhitelistedForPersistentStorage( - aOriginProps.mSpec)) { + // Move internal origins to new persistent storage. + if (QuotaManager::IsOriginInternal(aOriginProps.mSpec)) { if (!mPermanentStorageDir) { mPermanentStorageDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv); diff --git a/dom/quota/QuotaManager.h b/dom/quota/QuotaManager.h index 176ec5c3fe33..2d4c893cf1ce 100644 --- a/dom/quota/QuotaManager.h +++ b/dom/quota/QuotaManager.h @@ -398,7 +398,7 @@ public: nsACString* aOrigin); static bool - IsOriginWhitelistedForPersistentStorage(const nsACString& aOrigin); + IsOriginInternal(const nsACString& aOrigin); static void ChromeOrigin(nsACString& aOrigin); From a1da2be4c34016efac58b9fa6dc589caf3564b17 Mon Sep 17 00:00:00 2001 From: Jorg K Date: Tue, 21 Mar 2017 08:52:00 +0100 Subject: [PATCH 63/96] Bug 1346916 - Skip test_reload.js:test_reloading_a_temp_addon() for Thunderbird. a=aswan --HG-- extra : rebase_source : b011c81ad7252ce614d021728517a08a7139760d --- toolkit/mozapps/extensions/test/xpcshell/test_reload.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_reload.js b/toolkit/mozapps/extensions/test/xpcshell/test_reload.js index 85211fdd6db2..95e68c956ea1 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_reload.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_reload.js @@ -1,6 +1,7 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ +Components.utils.import("resource://gre/modules/AppConstants.jsm"); createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42"); @@ -44,6 +45,8 @@ function* tearDownAddon(addon) { } add_task(function* test_reloading_a_temp_addon() { + if (AppConstants.MOZ_APP_NAME == "thunderbird") + return; yield promiseRestartManager(); yield AddonManager.installTemporaryAddon(do_get_addon(sampleAddon.name)); const addon = yield promiseAddonByID(sampleAddon.id) From 0974e1801c3b2c04f0e89247bdf1e8fdddd5dbe3 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Wed, 22 Mar 2017 10:23:46 +0800 Subject: [PATCH 64/96] Bug 1348931 - remove dead code. r=gerald --HG-- extra : rebase_source : a4c837715d44a9ecf04defdd4feeaca118041f79 --- dom/media/mediasink/DecodedAudioDataSink.cpp | 21 -------------------- 1 file changed, 21 deletions(-) diff --git a/dom/media/mediasink/DecodedAudioDataSink.cpp b/dom/media/mediasink/DecodedAudioDataSink.cpp index d6e91cbdebc4..5e8ae205b738 100644 --- a/dom/media/mediasink/DecodedAudioDataSink.cpp +++ b/dom/media/mediasink/DecodedAudioDataSink.cpp @@ -260,27 +260,6 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames) AudioDataValue* const mData; }; - class SilentChunk : public AudioStream::Chunk { - public: - SilentChunk(uint32_t aFrames, uint32_t aChannels, uint32_t aRate) - : mFrames(aFrames) - , mChannels(aChannels) - , mRate(aRate) - , mData(MakeUnique(aChannels * aFrames)) { - memset(mData.get(), 0, aChannels * aFrames * sizeof(AudioDataValue)); - } - const AudioDataValue* Data() const { return mData.get(); } - uint32_t Frames() const { return mFrames; } - uint32_t Channels() const { return mChannels; } - uint32_t Rate() const { return mRate; } - AudioDataValue* GetWritable() const { return mData.get(); } - private: - const uint32_t mFrames; - const uint32_t mChannels; - const uint32_t mRate; - UniquePtr mData; - }; - bool needPopping = false; if (!mCurrentData) { // No data in the queue. Return an empty chunk. From f49ee1fdca7594bda4bc906a9f9527fe2381850a Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Wed, 22 Mar 2017 13:04:02 +0100 Subject: [PATCH 65/96] Bug 1316305 - Explicilty call .close() for websocket in test. r=baku --- dom/security/test/csp/file_upgrade_insecure.html | 1 + dom/security/test/csp/file_upgrade_insecure_meta.html | 1 + 2 files changed, 2 insertions(+) diff --git a/dom/security/test/csp/file_upgrade_insecure.html b/dom/security/test/csp/file_upgrade_insecure.html index 0daaa853ebb2..e3243c1bbe9c 100644 --- a/dom/security/test/csp/file_upgrade_insecure.html +++ b/dom/security/test/csp/file_upgrade_insecure.html @@ -57,6 +57,7 @@ else { window.parent.postMessage({result: "websocket-error"}, "*"); } + mySocket.close(); }; mySocket.onerror = function(e) { // debug information for Bug 1316305 diff --git a/dom/security/test/csp/file_upgrade_insecure_meta.html b/dom/security/test/csp/file_upgrade_insecure_meta.html index 5f65e78ec30b..15f565a6b8a7 100644 --- a/dom/security/test/csp/file_upgrade_insecure_meta.html +++ b/dom/security/test/csp/file_upgrade_insecure_meta.html @@ -58,6 +58,7 @@ else { window.parent.postMessage({result: "websocket-error"}, "*"); } + mySocket.close(); }; mySocket.onerror = function(e) { window.parent.postMessage({result: "websocket-unexpected-error"}, "*"); From 1a157c53f31259ec98959422b83a6b52dd2fe2b6 Mon Sep 17 00:00:00 2001 From: Shawn Huang Date: Wed, 22 Mar 2017 20:14:52 +0800 Subject: [PATCH 66/96] Bug 1319306 - Change onreadystatechange assertion to a minimum of 2 rather than 10, r=annevk --- .../tests/XMLHttpRequest/event-readystatechange-loaded.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/web-platform/tests/XMLHttpRequest/event-readystatechange-loaded.htm b/testing/web-platform/tests/XMLHttpRequest/event-readystatechange-loaded.htm index de6debe6babc..452efafae9f7 100644 --- a/testing/web-platform/tests/XMLHttpRequest/event-readystatechange-loaded.htm +++ b/testing/web-platform/tests/XMLHttpRequest/event-readystatechange-loaded.htm @@ -24,7 +24,7 @@ test.step(function() { } if (client.readyState === 4) { - assert_equals(countedLoading, 10, "LOADING state change may be emitted multiple times"); + assert_greater_than(countedLoading, 1, "LOADING state change may be emitted multiple times"); test.done(); } From d9a31ef1f2b9877e9191677a845dc613ac5548ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A3o=20Gottwald?= Date: Wed, 22 Mar 2017 13:28:58 +0100 Subject: [PATCH 67/96] Bug 1349501 - Let _beginRemoveTab skip the whole permitUnload block for tabs that don't have content attached. r=kevinhowjones --- browser/base/content/tabbrowser.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 5335b574d71a..48ecdbcccefc 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -2630,13 +2630,15 @@ var browser = this.getBrowserForTab(aTab); - if (!aTab._pendingPermitUnload && !aAdoptedByTab && !aSkipPermitUnload) { + if (!aTab._pendingPermitUnload && + !aSkipPermitUnload && + aTab.linkedPanel && + !aAdoptedByTab) { // We need to block while calling permitUnload() because it // processes the event queue and may lead to another removeTab() // call before permitUnload() returns. aTab._pendingPermitUnload = true; - let {permitUnload, timedOut} = aTab.linkedPanel ? - browser.permitUnload() : {permitUnload: true, timedOut: false}; + let {permitUnload, timedOut} = browser.permitUnload(); delete aTab._pendingPermitUnload; // If we were closed during onbeforeunload, we return false now // so we don't (try to) close the same tab again. Of course, we From 51e127dbcedfbac1049625d0f9c8565f0ea7138e Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Wed, 22 Mar 2017 13:30:05 +0100 Subject: [PATCH 68/96] Backed out changeset 6bfcef53d382 (bug 1348877) for failing web-platform-test /storage/interfaces.https.html. r=backout --HG-- rename : testing/web-platform/tests/storage/interfaces.https.html => testing/web-platform/tests/storage/interfaces.html --- testing/web-platform/meta/MANIFEST.json | 8 ++++---- .../storage/{interfaces.https.html => interfaces.html} | 0 2 files changed, 4 insertions(+), 4 deletions(-) rename testing/web-platform/tests/storage/{interfaces.https.html => interfaces.html} (100%) diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 9aa9e0f41755..9f8d07bdf355 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -120882,9 +120882,9 @@ {} ] ], - "storage/interfaces.https.html": [ + "storage/interfaces.html": [ [ - "/storage/interfaces.https.html", + "/storage/interfaces.html", {} ] ], @@ -181322,7 +181322,7 @@ "testharness" ], "html/webappapis/idle-callbacks/callback-removed-frame.html": [ - "ff034276659407d2dea91d2b0ed0e5919b875904", + "79b4a278f0e35646cfdffeebf8f0523e2772bc9b", "testharness" ], "html/webappapis/idle-callbacks/callback-suspended.html": [ @@ -203621,7 +203621,7 @@ "6e5db2d0c2f5d2d8f1e2d04da953a3f2c50bec7a", "testharness" ], - "storage/interfaces.https.html": [ + "storage/interfaces.html": [ "76fa61c3a87485266a7f9d6f66e5d08bb7881ff7", "testharness" ], diff --git a/testing/web-platform/tests/storage/interfaces.https.html b/testing/web-platform/tests/storage/interfaces.html similarity index 100% rename from testing/web-platform/tests/storage/interfaces.https.html rename to testing/web-platform/tests/storage/interfaces.html From cbf46adaef7180817ff772458c4f538f359e98ed Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Wed, 22 Mar 2017 09:05:36 -0400 Subject: [PATCH 69/96] Bug 1343499 - Expose native image sizes to imagelib users. r=tnikkel --- image/DynamicImage.cpp | 6 ++ image/DynamicImage.h | 1 + image/FrameTimeout.h | 119 ++++++++++++++++++++++ image/ImageMetadata.h | 13 ++- image/ImageOps.cpp | 110 ++++++++++++++++++-- image/ImageOps.h | 61 ++++++++++- image/ImageWrapper.cpp | 6 ++ image/ImageWrapper.h | 1 + image/OrientedImage.cpp | 16 +++ image/OrientedImage.h | 1 + image/RasterImage.cpp | 19 ++++ image/RasterImage.h | 2 + image/VectorImage.cpp | 7 ++ image/VectorImage.h | 1 + image/decoders/nsICODecoder.cpp | 2 + image/imgFrame.h | 101 +----------------- image/imgIContainer.idl | 4 + image/moz.build | 2 + image/test/gtest/Common.cpp | 6 ++ image/test/gtest/Common.h | 2 + image/test/gtest/TestDecodeToSurface.cpp | 84 +++++++++++++-- image/test/gtest/TestDecoders.cpp | 84 +++++++++++++++ image/test/gtest/green-multiple-sizes.ico | Bin 0 -> 14144 bytes image/test/gtest/moz.build | 1 + 24 files changed, 530 insertions(+), 119 deletions(-) create mode 100644 image/FrameTimeout.h create mode 100644 image/test/gtest/green-multiple-sizes.ico diff --git a/image/DynamicImage.cpp b/image/DynamicImage.cpp index d6444066a9e9..47c920944c3e 100644 --- a/image/DynamicImage.cpp +++ b/image/DynamicImage.cpp @@ -127,6 +127,12 @@ DynamicImage::GetHeight(int32_t* aHeight) return NS_OK; } +nsresult +DynamicImage::GetNativeSizes(nsTArray& aNativeSizes) const +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP DynamicImage::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/DynamicImage.h b/image/DynamicImage.h index a39a29b8e37e..09c6ed550a25 100644 --- a/image/DynamicImage.h +++ b/image/DynamicImage.h @@ -31,6 +31,7 @@ public: } // Inherited methods from Image. + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual already_AddRefed GetProgressTracker() override; virtual size_t SizeOfSourceWithComputedFallback( MallocSizeOf aMallocSizeOf) const override; diff --git a/image/FrameTimeout.h b/image/FrameTimeout.h new file mode 100644 index 000000000000..4070bba65b2b --- /dev/null +++ b/image/FrameTimeout.h @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_image_FrameTimeout_h +#define mozilla_image_FrameTimeout_h + +#include +#include "mozilla/Assertions.h" + +namespace mozilla { +namespace image { + +/** + * FrameTimeout wraps a frame timeout value (measured in milliseconds) after + * first normalizing it. This normalization is necessary because some tools + * generate incorrect frame timeout values which we nevertheless have to + * support. For this reason, code that deals with frame timeouts should always + * use a FrameTimeout value rather than the raw value from the image header. + */ +struct FrameTimeout +{ + /** + * @return a FrameTimeout of zero. This should be used only for math + * involving FrameTimeout values. You can't obtain a zero FrameTimeout from + * FromRawMilliseconds(). + */ + static FrameTimeout Zero() { return FrameTimeout(0); } + + /// @return an infinite FrameTimeout. + static FrameTimeout Forever() { return FrameTimeout(-1); } + + /// @return a FrameTimeout obtained by normalizing a raw timeout value. + static FrameTimeout FromRawMilliseconds(int32_t aRawMilliseconds) + { + // Normalize all infinite timeouts to the same value. + if (aRawMilliseconds < 0) { + return FrameTimeout::Forever(); + } + + // Very small timeout values are problematic for two reasons: we don't want + // to burn energy redrawing animated images extremely fast, and broken tools + // generate these values when they actually want a "default" value, so such + // images won't play back right without normalization. For some context, + // see bug 890743, bug 125137, bug 139677, and bug 207059. The historical + // behavior of IE and Opera was: + // IE 6/Win: + // 10 - 50ms is normalized to 100ms. + // >50ms is used unnormalized. + // Opera 7 final/Win: + // 10ms is normalized to 100ms. + // >10ms is used unnormalized. + if (aRawMilliseconds >= 0 && aRawMilliseconds <= 10 ) { + return FrameTimeout(100); + } + + // The provided timeout value is OK as-is. + return FrameTimeout(aRawMilliseconds); + } + + bool operator==(const FrameTimeout& aOther) const + { + return mTimeout == aOther.mTimeout; + } + + bool operator!=(const FrameTimeout& aOther) const { return !(*this == aOther); } + + FrameTimeout operator+(const FrameTimeout& aOther) + { + if (*this == Forever() || aOther == Forever()) { + return Forever(); + } + + return FrameTimeout(mTimeout + aOther.mTimeout); + } + + FrameTimeout& operator+=(const FrameTimeout& aOther) + { + *this = *this + aOther; + return *this; + } + + /** + * @return this FrameTimeout's value in milliseconds. Illegal to call on a + * an infinite FrameTimeout value. + */ + uint32_t AsMilliseconds() const + { + if (*this == Forever()) { + MOZ_ASSERT_UNREACHABLE("Calling AsMilliseconds() on an infinite FrameTimeout"); + return 100; // Fail to something sane. + } + + return uint32_t(mTimeout); + } + + /** + * @return this FrameTimeout value encoded so that non-negative values + * represent a timeout in milliseconds, and -1 represents an infinite + * timeout. + * + * XXX(seth): This is a backwards compatibility hack that should be removed. + */ + int32_t AsEncodedValueDeprecated() const { return mTimeout; } + +private: + explicit FrameTimeout(int32_t aTimeout) + : mTimeout(aTimeout) + { } + + int32_t mTimeout; +}; + +} // namespace image +} // namespace mozilla + +#endif // mozilla_image_FrameTimeout_h diff --git a/image/ImageMetadata.h b/image/ImageMetadata.h index 05f5729802c7..b1a2edfb03fd 100644 --- a/image/ImageMetadata.h +++ b/image/ImageMetadata.h @@ -11,12 +11,11 @@ #include "mozilla/Maybe.h" #include "nsSize.h" #include "Orientation.h" +#include "FrameTimeout.h" namespace mozilla { namespace image { -class RasterImage; - // The metadata about an image that decoders accumulate as they decode. class ImageMetadata { @@ -64,6 +63,13 @@ public: nsIntSize GetSize() const { return *mSize; } bool HasSize() const { return mSize.isSome(); } + void AddNativeSize(const nsIntSize& aSize) + { + mNativeSizes.AppendElement(aSize); + } + + const nsTArray& GetNativeSizes() const { return mNativeSizes; } + Orientation GetOrientation() const { return *mOrientation; } bool HasOrientation() const { return mOrientation.isSome(); } @@ -90,6 +96,9 @@ private: Maybe mSize; Maybe mOrientation; + // Sizes the image can natively decode to. + nsTArray mNativeSizes; + bool mHasAnimation : 1; }; diff --git a/image/ImageOps.cpp b/image/ImageOps.cpp index d1d5da283642..fb4fc8fb7075 100644 --- a/image/ImageOps.cpp +++ b/image/ImageOps.cpp @@ -14,6 +14,7 @@ #include "FrozenImage.h" #include "IDecodingTask.h" #include "Image.h" +#include "ImageMetadata.h" #include "imgIContainer.h" #include "mozilla/gfx/2D.h" #include "nsStreamUtils.h" @@ -79,10 +80,27 @@ ImageOps::CreateFromDrawable(gfxDrawable* aDrawable) return drawableImage.forget(); } -/* static */ already_AddRefed -ImageOps::DecodeToSurface(nsIInputStream* aInputStream, - const nsACString& aMimeType, - uint32_t aFlags) +class ImageOps::ImageBufferImpl final : public ImageOps::ImageBuffer { +public: + ImageBufferImpl(already_AddRefed aSourceBuffer) + : mSourceBuffer(aSourceBuffer) + { } + +protected: + ~ImageBufferImpl() override { } + + virtual already_AddRefed GetSourceBuffer() + { + RefPtr sourceBuffer = mSourceBuffer; + return sourceBuffer.forget(); + } + +private: + RefPtr mSourceBuffer; +}; + +/* static */ already_AddRefed +ImageOps::CreateImageBuffer(nsIInputStream* aInputStream) { MOZ_ASSERT(aInputStream); @@ -107,7 +125,7 @@ ImageOps::DecodeToSurface(nsIInputStream* aInputStream, } // Write the data into a SourceBuffer. - NotNull> sourceBuffer = WrapNotNull(new SourceBuffer()); + RefPtr sourceBuffer = new SourceBuffer(); sourceBuffer->ExpectLength(length); rv = sourceBuffer->AppendFromInputStream(inputStream, length); if (NS_FAILED(rv)) { @@ -122,12 +140,90 @@ ImageOps::DecodeToSurface(nsIInputStream* aInputStream, } sourceBuffer->Complete(NS_OK); + RefPtr imageBuffer = new ImageBufferImpl(sourceBuffer.forget()); + return imageBuffer.forget(); +} + +/* static */ nsresult +ImageOps::DecodeMetadata(nsIInputStream* aInputStream, + const nsACString& aMimeType, + ImageMetadata& aMetadata) +{ + RefPtr buffer = CreateImageBuffer(aInputStream); + return DecodeMetadata(buffer, aMimeType, aMetadata); +} + +/* static */ nsresult +ImageOps::DecodeMetadata(ImageBuffer* aBuffer, + const nsACString& aMimeType, + ImageMetadata& aMetadata) +{ + if (!aBuffer) { + return NS_ERROR_FAILURE; + } + + RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); + if (NS_WARN_IF(!sourceBuffer)) { + return NS_ERROR_FAILURE; + } + // Create a decoder. DecoderType decoderType = DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); RefPtr decoder = - DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, - Nothing(), ToSurfaceFlags(aFlags)); + DecoderFactory::CreateAnonymousMetadataDecoder(decoderType, + WrapNotNull(sourceBuffer)); + if (!decoder) { + return NS_ERROR_FAILURE; + } + + // Run the decoder synchronously. + RefPtr task = new AnonymousDecodingTask(WrapNotNull(decoder)); + task->Run(); + if (!decoder->GetDecodeDone() || decoder->HasError()) { + return NS_ERROR_FAILURE; + } + + aMetadata = decoder->GetImageMetadata(); + if (aMetadata.GetNativeSizes().IsEmpty() && aMetadata.HasSize()) { + aMetadata.AddNativeSize(aMetadata.GetSize()); + } + + return NS_OK; +} + +/* static */ already_AddRefed +ImageOps::DecodeToSurface(nsIInputStream* aInputStream, + const nsACString& aMimeType, + uint32_t aFlags, + Maybe aSize /* = Nothing() */) +{ + RefPtr buffer = CreateImageBuffer(aInputStream); + return DecodeToSurface(buffer, aMimeType, aFlags, aSize); +} + +/* static */ already_AddRefed +ImageOps::DecodeToSurface(ImageBuffer* aBuffer, + const nsACString& aMimeType, + uint32_t aFlags, + Maybe aSize /* = Nothing() */) +{ + if (!aBuffer) { + return nullptr; + } + + RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); + if (NS_WARN_IF(!sourceBuffer)) { + return nullptr; + } + + // Create a decoder. + DecoderType decoderType = + DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); + RefPtr decoder = + DecoderFactory::CreateAnonymousDecoder(decoderType, + WrapNotNull(sourceBuffer), + aSize, ToSurfaceFlags(aFlags)); if (!decoder) { return nullptr; } diff --git a/image/ImageOps.h b/image/ImageOps.h index 7a8e19be3441..5a089fd16b03 100644 --- a/image/ImageOps.h +++ b/image/ImageOps.h @@ -9,6 +9,7 @@ #include "nsCOMPtr.h" #include "nsRect.h" +#include "ImageMetadata.h" class gfxDrawable; class imgIContainer; @@ -24,10 +25,23 @@ namespace image { class Image; struct Orientation; +class SourceBuffer; class ImageOps { public: + class ImageBuffer { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageOps::ImageBuffer); + protected: + friend class ImageOps; + + ImageBuffer() { } + virtual ~ImageBuffer() { } + + virtual already_AddRefed GetSourceBuffer() = 0; + }; + /** * Creates a version of an existing image which does not animate and is frozen * at the first frame. @@ -74,6 +88,39 @@ public: static already_AddRefed CreateFromDrawable(gfxDrawable* aDrawable); + /** + * Create a buffer to be used with DecodeMetadata and DecodeToSurface. Reusing + * an ImageBuffer representing the given input stream is more efficient if one + * has multiple Decode* calls to make on that stream. + * + * @param aInputStream An input stream containing an encoded image. + * @return An image buffer derived from the input stream. + */ + static already_AddRefed + CreateImageBuffer(nsIInputStream* aInputStream); + + /** + * Decodes an image's metadata from an nsIInputStream into the given + * structure. This function may be called off-main-thread. + * + * @param aInputStream An input stream containing an encoded image. + * @param aMimeType The MIME type of the image. + * @param aMetadata Where the image metadata is stored upon success. + * @return The status of the operation. + */ + static nsresult + DecodeMetadata(nsIInputStream* aInputStream, + const nsACString& aMimeType, + ImageMetadata& aMetadata); + + /** + * Same as above but takes an ImageBuffer instead of nsIInputStream. + */ + static nsresult + DecodeMetadata(ImageBuffer* aBuffer, + const nsACString& aMimeType, + ImageMetadata& aMetadata); + /** * Decodes an image from an nsIInputStream directly into a SourceSurface, * without ever creating an Image or imgIContainer (which are mostly @@ -89,9 +136,21 @@ public: static already_AddRefed DecodeToSurface(nsIInputStream* aInputStream, const nsACString& aMimeType, - uint32_t aFlags); + uint32_t aFlags, + Maybe aSize = Nothing()); + + /** + * Same as above but takes an ImageBuffer instead of nsIInputStream. + */ + static already_AddRefed + DecodeToSurface(ImageBuffer* aBuffer, + const nsACString& aMimeType, + uint32_t aFlags, + Maybe aSize = Nothing()); private: + class ImageBufferImpl; + // This is a static utility class, so disallow instantiation. virtual ~ImageOps() = 0; }; diff --git a/image/ImageWrapper.cpp b/image/ImageWrapper.cpp index dfc76641fd6f..852479904567 100644 --- a/image/ImageWrapper.cpp +++ b/image/ImageWrapper.cpp @@ -139,6 +139,12 @@ ImageWrapper::GetHeight(int32_t* aHeight) return mInnerImage->GetHeight(aHeight); } +nsresult +ImageWrapper::GetNativeSizes(nsTArray& aNativeSizes) const +{ + return mInnerImage->GetNativeSizes(aNativeSizes); +} + NS_IMETHODIMP ImageWrapper::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/ImageWrapper.h b/image/ImageWrapper.h index 94cf0948b537..19e9cb858232 100644 --- a/image/ImageWrapper.h +++ b/image/ImageWrapper.h @@ -22,6 +22,7 @@ public: NS_DECL_IMGICONTAINER // Inherited methods from Image. + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual already_AddRefed GetProgressTracker() override; virtual size_t diff --git a/image/OrientedImage.cpp b/image/OrientedImage.cpp index 951b0acbc94d..79767e2a796a 100644 --- a/image/OrientedImage.cpp +++ b/image/OrientedImage.cpp @@ -46,6 +46,22 @@ OrientedImage::GetHeight(int32_t* aHeight) } } +nsresult +OrientedImage::GetNativeSizes(nsTArray& aNativeSizes) const +{ + nsresult rv = InnerImage()->GetNativeSizes(aNativeSizes); + + if (mOrientation.SwapsWidthAndHeight()) { + auto i = aNativeSizes.Length(); + while (i > 0) { + --i; + swap(aNativeSizes[i].width, aNativeSizes[i].height); + } + } + + return rv; +} + NS_IMETHODIMP OrientedImage::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/OrientedImage.h b/image/OrientedImage.h index 2edf05de9f50..d1291ea74b20 100644 --- a/image/OrientedImage.h +++ b/image/OrientedImage.h @@ -30,6 +30,7 @@ public: NS_IMETHOD GetWidth(int32_t* aWidth) override; NS_IMETHOD GetHeight(int32_t* aHeight) override; + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override; NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override; NS_IMETHOD_(already_AddRefed) diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index b98744850295..b3da4ff3697e 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -220,6 +220,24 @@ RasterImage::GetHeight(int32_t* aHeight) return NS_OK; } +//****************************************************************************** +nsresult +RasterImage::GetNativeSizes(nsTArray& aNativeSizes) const +{ + if (mError) { + return NS_ERROR_FAILURE; + } + + if (mNativeSizes.IsEmpty()) { + aNativeSizes.Clear(); + aNativeSizes.AppendElement(mSize); + } else { + aNativeSizes = mNativeSizes; + } + + return NS_OK; +} + //****************************************************************************** NS_IMETHODIMP RasterImage::GetIntrinsicSize(nsSize* aSize) @@ -703,6 +721,7 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata, // Set the size and flag that we have it. mSize = size; mOrientation = orientation; + mNativeSizes = aMetadata.GetNativeSizes(); mHasSize = true; } diff --git a/image/RasterImage.h b/image/RasterImage.h index 09fa18b4df65..023985669a7a 100644 --- a/image/RasterImage.h +++ b/image/RasterImage.h @@ -160,6 +160,7 @@ public: NS_DECL_IMGICONTAINERDEBUG #endif + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual nsresult StartAnimation() override; virtual nsresult StopAnimation() override; @@ -380,6 +381,7 @@ private: private: // data nsIntSize mSize; + nsTArray mNativeSizes; Orientation mOrientation; /// If this has a value, we're waiting for SetSize() to send the load event. diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index fa3ecb8bc049..7c650fc7545c 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -520,6 +520,13 @@ VectorImage::GetWidth(int32_t* aWidth) return NS_OK; } +//****************************************************************************** +nsresult +VectorImage::GetNativeSizes(nsTArray& aNativeSizes) const +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + //****************************************************************************** NS_IMETHODIMP_(void) VectorImage::RequestRefresh(const TimeStamp& aTime) diff --git a/image/VectorImage.h b/image/VectorImage.h index cb55e057753c..a05c92f3cf38 100644 --- a/image/VectorImage.h +++ b/image/VectorImage.h @@ -34,6 +34,7 @@ public: // (no public constructor - use ImageFactory) // Methods inherited from Image + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; virtual void CollectSizeOfSurfaces(nsTArray& aCounters, diff --git a/image/decoders/nsICODecoder.cpp b/image/decoders/nsICODecoder.cpp index 85b3c139b0d7..d8171431ea83 100644 --- a/image/decoders/nsICODecoder.cpp +++ b/image/decoders/nsICODecoder.cpp @@ -242,6 +242,8 @@ nsICODecoder::ReadDirEntry(const char* aData) } } + mImageMetadata.AddNativeSize(entrySize); + if (desiredSize) { // Calculate the delta between this resource's size and the desired size, so // we can see if it is better than our current-best option. In the case of diff --git a/image/imgFrame.h b/image/imgFrame.h index 77ff3507b177..bd858e088dcf 100644 --- a/image/imgFrame.h +++ b/image/imgFrame.h @@ -11,6 +11,7 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/Monitor.h" #include "mozilla/Move.h" +#include "FrameTimeout.h" #include "gfxDrawable.h" #include "imgIContainer.h" #include "MainThreadUtils.h" @@ -46,106 +47,6 @@ enum class Opacity : uint8_t { SOME_TRANSPARENCY }; -/** - * FrameTimeout wraps a frame timeout value (measured in milliseconds) after - * first normalizing it. This normalization is necessary because some tools - * generate incorrect frame timeout values which we nevertheless have to - * support. For this reason, code that deals with frame timeouts should always - * use a FrameTimeout value rather than the raw value from the image header. - */ -struct FrameTimeout -{ - /** - * @return a FrameTimeout of zero. This should be used only for math - * involving FrameTimeout values. You can't obtain a zero FrameTimeout from - * FromRawMilliseconds(). - */ - static FrameTimeout Zero() { return FrameTimeout(0); } - - /// @return an infinite FrameTimeout. - static FrameTimeout Forever() { return FrameTimeout(-1); } - - /// @return a FrameTimeout obtained by normalizing a raw timeout value. - static FrameTimeout FromRawMilliseconds(int32_t aRawMilliseconds) - { - // Normalize all infinite timeouts to the same value. - if (aRawMilliseconds < 0) { - return FrameTimeout::Forever(); - } - - // Very small timeout values are problematic for two reasons: we don't want - // to burn energy redrawing animated images extremely fast, and broken tools - // generate these values when they actually want a "default" value, so such - // images won't play back right without normalization. For some context, - // see bug 890743, bug 125137, bug 139677, and bug 207059. The historical - // behavior of IE and Opera was: - // IE 6/Win: - // 10 - 50ms is normalized to 100ms. - // >50ms is used unnormalized. - // Opera 7 final/Win: - // 10ms is normalized to 100ms. - // >10ms is used unnormalized. - if (aRawMilliseconds >= 0 && aRawMilliseconds <= 10 ) { - return FrameTimeout(100); - } - - // The provided timeout value is OK as-is. - return FrameTimeout(aRawMilliseconds); - } - - bool operator==(const FrameTimeout& aOther) const - { - return mTimeout == aOther.mTimeout; - } - - bool operator!=(const FrameTimeout& aOther) const { return !(*this == aOther); } - - FrameTimeout operator+(const FrameTimeout& aOther) - { - if (*this == Forever() || aOther == Forever()) { - return Forever(); - } - - return FrameTimeout(mTimeout + aOther.mTimeout); - } - - FrameTimeout& operator+=(const FrameTimeout& aOther) - { - *this = *this + aOther; - return *this; - } - - /** - * @return this FrameTimeout's value in milliseconds. Illegal to call on a - * an infinite FrameTimeout value. - */ - uint32_t AsMilliseconds() const - { - if (*this == Forever()) { - MOZ_ASSERT_UNREACHABLE("Calling AsMilliseconds() on an infinite FrameTimeout"); - return 100; // Fail to something sane. - } - - return uint32_t(mTimeout); - } - - /** - * @return this FrameTimeout value encoded so that non-negative values - * represent a timeout in milliseconds, and -1 represents an infinite - * timeout. - * - * XXX(seth): This is a backwards compatibility hack that should be removed. - */ - int32_t AsEncodedValueDeprecated() const { return mTimeout; } - -private: - explicit FrameTimeout(int32_t aTimeout) - : mTimeout(aTimeout) - { } - - int32_t mTimeout; -}; - /** * AnimationData contains all of the information necessary for using an imgFrame * as part of an animation. diff --git a/image/imgIContainer.idl b/image/imgIContainer.idl index 640eae352558..eed28e2668d9 100644 --- a/image/imgIContainer.idl +++ b/image/imgIContainer.idl @@ -90,6 +90,10 @@ interface imgIContainer : nsISupports */ readonly attribute int32_t height; + %{C++ + virtual nsresult GetNativeSizes(nsTArray& aNativeSizes) const = 0; + %} + /** * The intrinsic size of this image in appunits. If the image has no intrinsic * size in a dimension, -1 will be returned for that dimension. In the case of diff --git a/image/moz.build b/image/moz.build index c3a3a610fd8e..8ccb30247e91 100644 --- a/image/moz.build +++ b/image/moz.build @@ -37,8 +37,10 @@ XPIDL_MODULE = 'imglib2' EXPORTS += [ 'DrawResult.h', + 'FrameTimeout.h', 'ImageCacheKey.h', 'ImageLogging.h', + 'ImageMetadata.h', 'ImageOps.h', 'ImageRegion.h', 'imgLoader.h', diff --git a/image/test/gtest/Common.cpp b/image/test/gtest/Common.cpp index 4be34461c71c..4bc7fce1c32e 100644 --- a/image/test/gtest/Common.cpp +++ b/image/test/gtest/Common.cpp @@ -679,5 +679,11 @@ ImageTestCase TruncatedSmallGIFTestCase() return ImageTestCase("green-1x1-truncated.gif", "image/gif", IntSize(1, 1)); } +ImageTestCase GreenMultipleSizesICOTestCase() +{ + return ImageTestCase("green-multiple-sizes.ico", "image/x-icon", + IntSize(256, 256)); +} + } // namespace image } // namespace mozilla diff --git a/image/test/gtest/Common.h b/image/test/gtest/Common.h index 33fc26e750f8..63b8b9b70026 100644 --- a/image/test/gtest/Common.h +++ b/image/test/gtest/Common.h @@ -414,6 +414,8 @@ ImageTestCase DownscaledTransparentICOWithANDMaskTestCase(); ImageTestCase TruncatedSmallGIFTestCase(); +ImageTestCase GreenMultipleSizesICOTestCase(); + } // namespace image } // namespace mozilla diff --git a/image/test/gtest/TestDecodeToSurface.cpp b/image/test/gtest/TestDecodeToSurface.cpp index dd22d4308d9b..b4b011528d97 100644 --- a/image/test/gtest/TestDecodeToSurface.cpp +++ b/image/test/gtest/TestDecodeToSurface.cpp @@ -27,9 +27,11 @@ class DecodeToSurfaceRunnable : public Runnable public: DecodeToSurfaceRunnable(RefPtr& aSurface, nsIInputStream* aInputStream, + ImageOps::ImageBuffer* aImageBuffer, const ImageTestCase& aTestCase) : mSurface(aSurface) , mInputStream(aInputStream) + , mImageBuffer(aImageBuffer) , mTestCase(aTestCase) { } @@ -41,16 +43,35 @@ public: void Go() { - mSurface = - ImageOps::DecodeToSurface(mInputStream, - nsDependentCString(mTestCase.mMimeType), - imgIContainer::DECODE_FLAGS_DEFAULT); + Maybe outputSize; + if (mTestCase.mOutputSize != mTestCase.mSize) { + outputSize.emplace(mTestCase.mOutputSize); + } + + if (mImageBuffer) { + mSurface = + ImageOps::DecodeToSurface(mImageBuffer, + nsDependentCString(mTestCase.mMimeType), + imgIContainer::DECODE_FLAGS_DEFAULT, + outputSize); + } else { + mSurface = + ImageOps::DecodeToSurface(mInputStream, + nsDependentCString(mTestCase.mMimeType), + imgIContainer::DECODE_FLAGS_DEFAULT, + outputSize); + } ASSERT_TRUE(mSurface != nullptr); EXPECT_TRUE(mSurface->IsDataSourceSurface()); EXPECT_TRUE(mSurface->GetFormat() == SurfaceFormat::B8G8R8X8 || mSurface->GetFormat() == SurfaceFormat::B8G8R8A8); - EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); + + if (outputSize) { + EXPECT_EQ(*outputSize, mSurface->GetSize()); + } else { + EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); + } EXPECT_TRUE(IsSolidColor(mSurface, BGRAColor::Green(), mTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0)); @@ -59,14 +80,19 @@ public: private: RefPtr& mSurface; nsCOMPtr mInputStream; + RefPtr mImageBuffer; ImageTestCase mTestCase; }; static void -RunDecodeToSurface(const ImageTestCase& aTestCase) +RunDecodeToSurface(const ImageTestCase& aTestCase, + ImageOps::ImageBuffer* aImageBuffer = nullptr) { - nsCOMPtr inputStream = LoadFile(aTestCase.mPath); - ASSERT_TRUE(inputStream != nullptr); + nsCOMPtr inputStream; + if (!aImageBuffer) { + inputStream = LoadFile(aTestCase.mPath); + ASSERT_TRUE(inputStream != nullptr); + } nsCOMPtr thread; nsresult rv = @@ -77,7 +103,7 @@ RunDecodeToSurface(const ImageTestCase& aTestCase) // DecodeToSurface doesn't require any main-thread-only code. RefPtr surface; nsCOMPtr runnable = - new DecodeToSurfaceRunnable(surface, inputStream, aTestCase); + new DecodeToSurfaceRunnable(surface, inputStream, aImageBuffer, aTestCase); thread->Dispatch(runnable, nsIThread::DISPATCH_SYNC); thread->Shutdown(); @@ -122,3 +148,43 @@ TEST_F(ImageDecodeToSurface, Corrupt) imgIContainer::DECODE_FLAGS_DEFAULT); EXPECT_TRUE(surface == nullptr); } + +TEST_F(ImageDecodeToSurface, ICOMultipleSizes) +{ + ImageTestCase testCase = GreenMultipleSizesICOTestCase(); + + nsCOMPtr inputStream = LoadFile(testCase.mPath); + ASSERT_TRUE(inputStream != nullptr); + + RefPtr buffer = + ImageOps::CreateImageBuffer(inputStream); + ASSERT_TRUE(buffer != nullptr); + + ImageMetadata metadata; + nsresult rv = ImageOps::DecodeMetadata(buffer, + nsDependentCString(testCase.mMimeType), + metadata); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(metadata.HasSize()); + EXPECT_EQ(testCase.mSize, metadata.GetSize()); + + const nsTArray& nativeSizes = metadata.GetNativeSizes(); + ASSERT_EQ(6, nativeSizes.Length()); + + IntSize expectedSizes[] = { + IntSize(16, 16), + IntSize(32, 32), + IntSize(64, 64), + IntSize(128, 128), + IntSize(256, 256), + IntSize(256, 128), + }; + + for (int i = 0; i < 6; ++i) { + EXPECT_EQ(expectedSizes[i], nativeSizes[i]); + + // Request decoding at native size + testCase.mOutputSize = nativeSizes[i]; + RunDecodeToSurface(testCase, buffer); + } +} diff --git a/image/test/gtest/TestDecoders.cpp b/image/test/gtest/TestDecoders.cpp index d39b8e404a60..43fd36b0d1bf 100644 --- a/image/test/gtest/TestDecoders.cpp +++ b/image/test/gtest/TestDecoders.cpp @@ -672,3 +672,87 @@ TEST_F(ImageDecoders, TruncatedSmallGIFSingleChunk) { CheckDecoderSingleChunk(TruncatedSmallGIFTestCase()); } + +TEST_F(ImageDecoders, MultipleSizesICOSingleChunk) +{ + ImageTestCase testCase = GreenMultipleSizesICOTestCase(); + + // Create an image. + RefPtr image = + ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType)); + ASSERT_TRUE(!image->HasError()); + + nsCOMPtr inputStream = LoadFile(testCase.mPath); + ASSERT_TRUE(inputStream); + + // Figure out how much data we have. + uint64_t length; + nsresult rv = inputStream->Available(&length); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + // Write the data into the image. + rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0, + static_cast(length)); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + // Let the image know we've sent all the data. + rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + RefPtr tracker = image->GetProgressTracker(); + tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE); + + // Use GetFrame() to force a sync decode of the image. + RefPtr surface = + image->GetFrame(imgIContainer::FRAME_CURRENT, + imgIContainer::FLAG_SYNC_DECODE); + + // Ensure that the image's metadata meets our expectations. + IntSize imageSize(0, 0); + rv = image->GetWidth(&imageSize.width); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + rv = image->GetHeight(&imageSize.height); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + + EXPECT_EQ(testCase.mSize.width, imageSize.width); + EXPECT_EQ(testCase.mSize.height, imageSize.height); + + nsTArray nativeSizes; + rv = image->GetNativeSizes(nativeSizes); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_EQ(6, nativeSizes.Length()); + + IntSize expectedSizes[] = { + IntSize(16, 16), + IntSize(32, 32), + IntSize(64, 64), + IntSize(128, 128), + IntSize(256, 256), + IntSize(256, 128) + }; + + for (int i = 0; i < 6; ++i) { + EXPECT_EQ(expectedSizes[i], nativeSizes[i]); + } + + RefPtr image90 = + ImageOps::Orient(image, Orientation(Angle::D90, Flip::Unflipped)); + rv = image90->GetNativeSizes(nativeSizes); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_EQ(6, nativeSizes.Length()); + + for (int i = 0; i < 5; ++i) { + EXPECT_EQ(expectedSizes[i], nativeSizes[i]); + } + EXPECT_EQ(IntSize(128, 256), nativeSizes[5]); + + RefPtr image180 = + ImageOps::Orient(image, Orientation(Angle::D180, Flip::Unflipped)); + rv = image180->GetNativeSizes(nativeSizes); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_EQ(6, nativeSizes.Length()); + + for (int i = 0; i < 6; ++i) { + EXPECT_EQ(expectedSizes[i], nativeSizes[i]); + } +} diff --git a/image/test/gtest/green-multiple-sizes.ico b/image/test/gtest/green-multiple-sizes.ico new file mode 100644 index 0000000000000000000000000000000000000000..b9463d0c897117204b2edacfa6cbfc4f5f61d771 GIT binary patch literal 14144 zcmeI$u}Z^09LMorsuU?iGF5aj4uYeb;1s1*3sS3eaC9mnh?}dy&3ACb06tZ(!iOf<#;`kn$9d6k7uQwnw00` zaUxyT{R2m&RA=t*nr^D^Qz==H);#5cg;n_hP}ZY(wYf8)+x>!>Ikgv!B;X9iE3tM2N({eIg8WY>=`o{tYb zv)pNI^-teFUZdEfx8di(`TWMvmqon9E8ga6@%BCpJMC`kVf*AdR5C+V;zwm7l&;4? wWulUxM*sl?5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0;O_{00SHw$wg3PC literal 0 HcmV?d00001 diff --git a/image/test/gtest/moz.build b/image/test/gtest/moz.build index ad69e098518c..3e37573dba04 100644 --- a/image/test/gtest/moz.build +++ b/image/test/gtest/moz.build @@ -47,6 +47,7 @@ TEST_HARNESS_FILES.gtest += [ 'first-frame-green.png', 'first-frame-padding.gif', 'green-1x1-truncated.gif', + 'green-multiple-sizes.ico', 'green.bmp', 'green.gif', 'green.ico', From 9f71f348c1b56db8d1a0a1e1e8c54297a10719a2 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Wed, 22 Mar 2017 09:19:05 -0400 Subject: [PATCH 70/96] Backed out changeset 0b797601dc36 (bug 1343499) for build bustages. r=backout --- image/DynamicImage.cpp | 6 -- image/DynamicImage.h | 1 - image/FrameTimeout.h | 119 ---------------------- image/ImageMetadata.h | 13 +-- image/ImageOps.cpp | 110 ++------------------ image/ImageOps.h | 61 +---------- image/ImageWrapper.cpp | 6 -- image/ImageWrapper.h | 1 - image/OrientedImage.cpp | 16 --- image/OrientedImage.h | 1 - image/RasterImage.cpp | 19 ---- image/RasterImage.h | 2 - image/VectorImage.cpp | 7 -- image/VectorImage.h | 1 - image/decoders/nsICODecoder.cpp | 2 - image/imgFrame.h | 101 +++++++++++++++++- image/imgIContainer.idl | 4 - image/moz.build | 2 - image/test/gtest/Common.cpp | 6 -- image/test/gtest/Common.h | 2 - image/test/gtest/TestDecodeToSurface.cpp | 84 ++------------- image/test/gtest/TestDecoders.cpp | 84 --------------- image/test/gtest/green-multiple-sizes.ico | Bin 14144 -> 0 bytes image/test/gtest/moz.build | 1 - 24 files changed, 119 insertions(+), 530 deletions(-) delete mode 100644 image/FrameTimeout.h delete mode 100644 image/test/gtest/green-multiple-sizes.ico diff --git a/image/DynamicImage.cpp b/image/DynamicImage.cpp index 47c920944c3e..d6444066a9e9 100644 --- a/image/DynamicImage.cpp +++ b/image/DynamicImage.cpp @@ -127,12 +127,6 @@ DynamicImage::GetHeight(int32_t* aHeight) return NS_OK; } -nsresult -DynamicImage::GetNativeSizes(nsTArray& aNativeSizes) const -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - NS_IMETHODIMP DynamicImage::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/DynamicImage.h b/image/DynamicImage.h index 09c6ed550a25..a39a29b8e37e 100644 --- a/image/DynamicImage.h +++ b/image/DynamicImage.h @@ -31,7 +31,6 @@ public: } // Inherited methods from Image. - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual already_AddRefed GetProgressTracker() override; virtual size_t SizeOfSourceWithComputedFallback( MallocSizeOf aMallocSizeOf) const override; diff --git a/image/FrameTimeout.h b/image/FrameTimeout.h deleted file mode 100644 index 4070bba65b2b..000000000000 --- a/image/FrameTimeout.h +++ /dev/null @@ -1,119 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_image_FrameTimeout_h -#define mozilla_image_FrameTimeout_h - -#include -#include "mozilla/Assertions.h" - -namespace mozilla { -namespace image { - -/** - * FrameTimeout wraps a frame timeout value (measured in milliseconds) after - * first normalizing it. This normalization is necessary because some tools - * generate incorrect frame timeout values which we nevertheless have to - * support. For this reason, code that deals with frame timeouts should always - * use a FrameTimeout value rather than the raw value from the image header. - */ -struct FrameTimeout -{ - /** - * @return a FrameTimeout of zero. This should be used only for math - * involving FrameTimeout values. You can't obtain a zero FrameTimeout from - * FromRawMilliseconds(). - */ - static FrameTimeout Zero() { return FrameTimeout(0); } - - /// @return an infinite FrameTimeout. - static FrameTimeout Forever() { return FrameTimeout(-1); } - - /// @return a FrameTimeout obtained by normalizing a raw timeout value. - static FrameTimeout FromRawMilliseconds(int32_t aRawMilliseconds) - { - // Normalize all infinite timeouts to the same value. - if (aRawMilliseconds < 0) { - return FrameTimeout::Forever(); - } - - // Very small timeout values are problematic for two reasons: we don't want - // to burn energy redrawing animated images extremely fast, and broken tools - // generate these values when they actually want a "default" value, so such - // images won't play back right without normalization. For some context, - // see bug 890743, bug 125137, bug 139677, and bug 207059. The historical - // behavior of IE and Opera was: - // IE 6/Win: - // 10 - 50ms is normalized to 100ms. - // >50ms is used unnormalized. - // Opera 7 final/Win: - // 10ms is normalized to 100ms. - // >10ms is used unnormalized. - if (aRawMilliseconds >= 0 && aRawMilliseconds <= 10 ) { - return FrameTimeout(100); - } - - // The provided timeout value is OK as-is. - return FrameTimeout(aRawMilliseconds); - } - - bool operator==(const FrameTimeout& aOther) const - { - return mTimeout == aOther.mTimeout; - } - - bool operator!=(const FrameTimeout& aOther) const { return !(*this == aOther); } - - FrameTimeout operator+(const FrameTimeout& aOther) - { - if (*this == Forever() || aOther == Forever()) { - return Forever(); - } - - return FrameTimeout(mTimeout + aOther.mTimeout); - } - - FrameTimeout& operator+=(const FrameTimeout& aOther) - { - *this = *this + aOther; - return *this; - } - - /** - * @return this FrameTimeout's value in milliseconds. Illegal to call on a - * an infinite FrameTimeout value. - */ - uint32_t AsMilliseconds() const - { - if (*this == Forever()) { - MOZ_ASSERT_UNREACHABLE("Calling AsMilliseconds() on an infinite FrameTimeout"); - return 100; // Fail to something sane. - } - - return uint32_t(mTimeout); - } - - /** - * @return this FrameTimeout value encoded so that non-negative values - * represent a timeout in milliseconds, and -1 represents an infinite - * timeout. - * - * XXX(seth): This is a backwards compatibility hack that should be removed. - */ - int32_t AsEncodedValueDeprecated() const { return mTimeout; } - -private: - explicit FrameTimeout(int32_t aTimeout) - : mTimeout(aTimeout) - { } - - int32_t mTimeout; -}; - -} // namespace image -} // namespace mozilla - -#endif // mozilla_image_FrameTimeout_h diff --git a/image/ImageMetadata.h b/image/ImageMetadata.h index b1a2edfb03fd..05f5729802c7 100644 --- a/image/ImageMetadata.h +++ b/image/ImageMetadata.h @@ -11,11 +11,12 @@ #include "mozilla/Maybe.h" #include "nsSize.h" #include "Orientation.h" -#include "FrameTimeout.h" namespace mozilla { namespace image { +class RasterImage; + // The metadata about an image that decoders accumulate as they decode. class ImageMetadata { @@ -63,13 +64,6 @@ public: nsIntSize GetSize() const { return *mSize; } bool HasSize() const { return mSize.isSome(); } - void AddNativeSize(const nsIntSize& aSize) - { - mNativeSizes.AppendElement(aSize); - } - - const nsTArray& GetNativeSizes() const { return mNativeSizes; } - Orientation GetOrientation() const { return *mOrientation; } bool HasOrientation() const { return mOrientation.isSome(); } @@ -96,9 +90,6 @@ private: Maybe mSize; Maybe mOrientation; - // Sizes the image can natively decode to. - nsTArray mNativeSizes; - bool mHasAnimation : 1; }; diff --git a/image/ImageOps.cpp b/image/ImageOps.cpp index fb4fc8fb7075..d1d5da283642 100644 --- a/image/ImageOps.cpp +++ b/image/ImageOps.cpp @@ -14,7 +14,6 @@ #include "FrozenImage.h" #include "IDecodingTask.h" #include "Image.h" -#include "ImageMetadata.h" #include "imgIContainer.h" #include "mozilla/gfx/2D.h" #include "nsStreamUtils.h" @@ -80,27 +79,10 @@ ImageOps::CreateFromDrawable(gfxDrawable* aDrawable) return drawableImage.forget(); } -class ImageOps::ImageBufferImpl final : public ImageOps::ImageBuffer { -public: - ImageBufferImpl(already_AddRefed aSourceBuffer) - : mSourceBuffer(aSourceBuffer) - { } - -protected: - ~ImageBufferImpl() override { } - - virtual already_AddRefed GetSourceBuffer() - { - RefPtr sourceBuffer = mSourceBuffer; - return sourceBuffer.forget(); - } - -private: - RefPtr mSourceBuffer; -}; - -/* static */ already_AddRefed -ImageOps::CreateImageBuffer(nsIInputStream* aInputStream) +/* static */ already_AddRefed +ImageOps::DecodeToSurface(nsIInputStream* aInputStream, + const nsACString& aMimeType, + uint32_t aFlags) { MOZ_ASSERT(aInputStream); @@ -125,7 +107,7 @@ ImageOps::CreateImageBuffer(nsIInputStream* aInputStream) } // Write the data into a SourceBuffer. - RefPtr sourceBuffer = new SourceBuffer(); + NotNull> sourceBuffer = WrapNotNull(new SourceBuffer()); sourceBuffer->ExpectLength(length); rv = sourceBuffer->AppendFromInputStream(inputStream, length); if (NS_FAILED(rv)) { @@ -140,90 +122,12 @@ ImageOps::CreateImageBuffer(nsIInputStream* aInputStream) } sourceBuffer->Complete(NS_OK); - RefPtr imageBuffer = new ImageBufferImpl(sourceBuffer.forget()); - return imageBuffer.forget(); -} - -/* static */ nsresult -ImageOps::DecodeMetadata(nsIInputStream* aInputStream, - const nsACString& aMimeType, - ImageMetadata& aMetadata) -{ - RefPtr buffer = CreateImageBuffer(aInputStream); - return DecodeMetadata(buffer, aMimeType, aMetadata); -} - -/* static */ nsresult -ImageOps::DecodeMetadata(ImageBuffer* aBuffer, - const nsACString& aMimeType, - ImageMetadata& aMetadata) -{ - if (!aBuffer) { - return NS_ERROR_FAILURE; - } - - RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); - if (NS_WARN_IF(!sourceBuffer)) { - return NS_ERROR_FAILURE; - } - // Create a decoder. DecoderType decoderType = DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); RefPtr decoder = - DecoderFactory::CreateAnonymousMetadataDecoder(decoderType, - WrapNotNull(sourceBuffer)); - if (!decoder) { - return NS_ERROR_FAILURE; - } - - // Run the decoder synchronously. - RefPtr task = new AnonymousDecodingTask(WrapNotNull(decoder)); - task->Run(); - if (!decoder->GetDecodeDone() || decoder->HasError()) { - return NS_ERROR_FAILURE; - } - - aMetadata = decoder->GetImageMetadata(); - if (aMetadata.GetNativeSizes().IsEmpty() && aMetadata.HasSize()) { - aMetadata.AddNativeSize(aMetadata.GetSize()); - } - - return NS_OK; -} - -/* static */ already_AddRefed -ImageOps::DecodeToSurface(nsIInputStream* aInputStream, - const nsACString& aMimeType, - uint32_t aFlags, - Maybe aSize /* = Nothing() */) -{ - RefPtr buffer = CreateImageBuffer(aInputStream); - return DecodeToSurface(buffer, aMimeType, aFlags, aSize); -} - -/* static */ already_AddRefed -ImageOps::DecodeToSurface(ImageBuffer* aBuffer, - const nsACString& aMimeType, - uint32_t aFlags, - Maybe aSize /* = Nothing() */) -{ - if (!aBuffer) { - return nullptr; - } - - RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); - if (NS_WARN_IF(!sourceBuffer)) { - return nullptr; - } - - // Create a decoder. - DecoderType decoderType = - DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); - RefPtr decoder = - DecoderFactory::CreateAnonymousDecoder(decoderType, - WrapNotNull(sourceBuffer), - aSize, ToSurfaceFlags(aFlags)); + DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, + Nothing(), ToSurfaceFlags(aFlags)); if (!decoder) { return nullptr; } diff --git a/image/ImageOps.h b/image/ImageOps.h index 5a089fd16b03..7a8e19be3441 100644 --- a/image/ImageOps.h +++ b/image/ImageOps.h @@ -9,7 +9,6 @@ #include "nsCOMPtr.h" #include "nsRect.h" -#include "ImageMetadata.h" class gfxDrawable; class imgIContainer; @@ -25,23 +24,10 @@ namespace image { class Image; struct Orientation; -class SourceBuffer; class ImageOps { public: - class ImageBuffer { - public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageOps::ImageBuffer); - protected: - friend class ImageOps; - - ImageBuffer() { } - virtual ~ImageBuffer() { } - - virtual already_AddRefed GetSourceBuffer() = 0; - }; - /** * Creates a version of an existing image which does not animate and is frozen * at the first frame. @@ -88,39 +74,6 @@ public: static already_AddRefed CreateFromDrawable(gfxDrawable* aDrawable); - /** - * Create a buffer to be used with DecodeMetadata and DecodeToSurface. Reusing - * an ImageBuffer representing the given input stream is more efficient if one - * has multiple Decode* calls to make on that stream. - * - * @param aInputStream An input stream containing an encoded image. - * @return An image buffer derived from the input stream. - */ - static already_AddRefed - CreateImageBuffer(nsIInputStream* aInputStream); - - /** - * Decodes an image's metadata from an nsIInputStream into the given - * structure. This function may be called off-main-thread. - * - * @param aInputStream An input stream containing an encoded image. - * @param aMimeType The MIME type of the image. - * @param aMetadata Where the image metadata is stored upon success. - * @return The status of the operation. - */ - static nsresult - DecodeMetadata(nsIInputStream* aInputStream, - const nsACString& aMimeType, - ImageMetadata& aMetadata); - - /** - * Same as above but takes an ImageBuffer instead of nsIInputStream. - */ - static nsresult - DecodeMetadata(ImageBuffer* aBuffer, - const nsACString& aMimeType, - ImageMetadata& aMetadata); - /** * Decodes an image from an nsIInputStream directly into a SourceSurface, * without ever creating an Image or imgIContainer (which are mostly @@ -136,21 +89,9 @@ public: static already_AddRefed DecodeToSurface(nsIInputStream* aInputStream, const nsACString& aMimeType, - uint32_t aFlags, - Maybe aSize = Nothing()); - - /** - * Same as above but takes an ImageBuffer instead of nsIInputStream. - */ - static already_AddRefed - DecodeToSurface(ImageBuffer* aBuffer, - const nsACString& aMimeType, - uint32_t aFlags, - Maybe aSize = Nothing()); + uint32_t aFlags); private: - class ImageBufferImpl; - // This is a static utility class, so disallow instantiation. virtual ~ImageOps() = 0; }; diff --git a/image/ImageWrapper.cpp b/image/ImageWrapper.cpp index 852479904567..dfc76641fd6f 100644 --- a/image/ImageWrapper.cpp +++ b/image/ImageWrapper.cpp @@ -139,12 +139,6 @@ ImageWrapper::GetHeight(int32_t* aHeight) return mInnerImage->GetHeight(aHeight); } -nsresult -ImageWrapper::GetNativeSizes(nsTArray& aNativeSizes) const -{ - return mInnerImage->GetNativeSizes(aNativeSizes); -} - NS_IMETHODIMP ImageWrapper::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/ImageWrapper.h b/image/ImageWrapper.h index 19e9cb858232..94cf0948b537 100644 --- a/image/ImageWrapper.h +++ b/image/ImageWrapper.h @@ -22,7 +22,6 @@ public: NS_DECL_IMGICONTAINER // Inherited methods from Image. - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual already_AddRefed GetProgressTracker() override; virtual size_t diff --git a/image/OrientedImage.cpp b/image/OrientedImage.cpp index 79767e2a796a..951b0acbc94d 100644 --- a/image/OrientedImage.cpp +++ b/image/OrientedImage.cpp @@ -46,22 +46,6 @@ OrientedImage::GetHeight(int32_t* aHeight) } } -nsresult -OrientedImage::GetNativeSizes(nsTArray& aNativeSizes) const -{ - nsresult rv = InnerImage()->GetNativeSizes(aNativeSizes); - - if (mOrientation.SwapsWidthAndHeight()) { - auto i = aNativeSizes.Length(); - while (i > 0) { - --i; - swap(aNativeSizes[i].width, aNativeSizes[i].height); - } - } - - return rv; -} - NS_IMETHODIMP OrientedImage::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/OrientedImage.h b/image/OrientedImage.h index d1291ea74b20..2edf05de9f50 100644 --- a/image/OrientedImage.h +++ b/image/OrientedImage.h @@ -30,7 +30,6 @@ public: NS_IMETHOD GetWidth(int32_t* aWidth) override; NS_IMETHOD GetHeight(int32_t* aHeight) override; - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override; NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override; NS_IMETHOD_(already_AddRefed) diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index b3da4ff3697e..b98744850295 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -220,24 +220,6 @@ RasterImage::GetHeight(int32_t* aHeight) return NS_OK; } -//****************************************************************************** -nsresult -RasterImage::GetNativeSizes(nsTArray& aNativeSizes) const -{ - if (mError) { - return NS_ERROR_FAILURE; - } - - if (mNativeSizes.IsEmpty()) { - aNativeSizes.Clear(); - aNativeSizes.AppendElement(mSize); - } else { - aNativeSizes = mNativeSizes; - } - - return NS_OK; -} - //****************************************************************************** NS_IMETHODIMP RasterImage::GetIntrinsicSize(nsSize* aSize) @@ -721,7 +703,6 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata, // Set the size and flag that we have it. mSize = size; mOrientation = orientation; - mNativeSizes = aMetadata.GetNativeSizes(); mHasSize = true; } diff --git a/image/RasterImage.h b/image/RasterImage.h index 023985669a7a..09fa18b4df65 100644 --- a/image/RasterImage.h +++ b/image/RasterImage.h @@ -160,7 +160,6 @@ public: NS_DECL_IMGICONTAINERDEBUG #endif - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual nsresult StartAnimation() override; virtual nsresult StopAnimation() override; @@ -381,7 +380,6 @@ private: private: // data nsIntSize mSize; - nsTArray mNativeSizes; Orientation mOrientation; /// If this has a value, we're waiting for SetSize() to send the load event. diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index 7c650fc7545c..fa3ecb8bc049 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -520,13 +520,6 @@ VectorImage::GetWidth(int32_t* aWidth) return NS_OK; } -//****************************************************************************** -nsresult -VectorImage::GetNativeSizes(nsTArray& aNativeSizes) const -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - //****************************************************************************** NS_IMETHODIMP_(void) VectorImage::RequestRefresh(const TimeStamp& aTime) diff --git a/image/VectorImage.h b/image/VectorImage.h index a05c92f3cf38..cb55e057753c 100644 --- a/image/VectorImage.h +++ b/image/VectorImage.h @@ -34,7 +34,6 @@ public: // (no public constructor - use ImageFactory) // Methods inherited from Image - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; virtual void CollectSizeOfSurfaces(nsTArray& aCounters, diff --git a/image/decoders/nsICODecoder.cpp b/image/decoders/nsICODecoder.cpp index d8171431ea83..85b3c139b0d7 100644 --- a/image/decoders/nsICODecoder.cpp +++ b/image/decoders/nsICODecoder.cpp @@ -242,8 +242,6 @@ nsICODecoder::ReadDirEntry(const char* aData) } } - mImageMetadata.AddNativeSize(entrySize); - if (desiredSize) { // Calculate the delta between this resource's size and the desired size, so // we can see if it is better than our current-best option. In the case of diff --git a/image/imgFrame.h b/image/imgFrame.h index bd858e088dcf..77ff3507b177 100644 --- a/image/imgFrame.h +++ b/image/imgFrame.h @@ -11,7 +11,6 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/Monitor.h" #include "mozilla/Move.h" -#include "FrameTimeout.h" #include "gfxDrawable.h" #include "imgIContainer.h" #include "MainThreadUtils.h" @@ -47,6 +46,106 @@ enum class Opacity : uint8_t { SOME_TRANSPARENCY }; +/** + * FrameTimeout wraps a frame timeout value (measured in milliseconds) after + * first normalizing it. This normalization is necessary because some tools + * generate incorrect frame timeout values which we nevertheless have to + * support. For this reason, code that deals with frame timeouts should always + * use a FrameTimeout value rather than the raw value from the image header. + */ +struct FrameTimeout +{ + /** + * @return a FrameTimeout of zero. This should be used only for math + * involving FrameTimeout values. You can't obtain a zero FrameTimeout from + * FromRawMilliseconds(). + */ + static FrameTimeout Zero() { return FrameTimeout(0); } + + /// @return an infinite FrameTimeout. + static FrameTimeout Forever() { return FrameTimeout(-1); } + + /// @return a FrameTimeout obtained by normalizing a raw timeout value. + static FrameTimeout FromRawMilliseconds(int32_t aRawMilliseconds) + { + // Normalize all infinite timeouts to the same value. + if (aRawMilliseconds < 0) { + return FrameTimeout::Forever(); + } + + // Very small timeout values are problematic for two reasons: we don't want + // to burn energy redrawing animated images extremely fast, and broken tools + // generate these values when they actually want a "default" value, so such + // images won't play back right without normalization. For some context, + // see bug 890743, bug 125137, bug 139677, and bug 207059. The historical + // behavior of IE and Opera was: + // IE 6/Win: + // 10 - 50ms is normalized to 100ms. + // >50ms is used unnormalized. + // Opera 7 final/Win: + // 10ms is normalized to 100ms. + // >10ms is used unnormalized. + if (aRawMilliseconds >= 0 && aRawMilliseconds <= 10 ) { + return FrameTimeout(100); + } + + // The provided timeout value is OK as-is. + return FrameTimeout(aRawMilliseconds); + } + + bool operator==(const FrameTimeout& aOther) const + { + return mTimeout == aOther.mTimeout; + } + + bool operator!=(const FrameTimeout& aOther) const { return !(*this == aOther); } + + FrameTimeout operator+(const FrameTimeout& aOther) + { + if (*this == Forever() || aOther == Forever()) { + return Forever(); + } + + return FrameTimeout(mTimeout + aOther.mTimeout); + } + + FrameTimeout& operator+=(const FrameTimeout& aOther) + { + *this = *this + aOther; + return *this; + } + + /** + * @return this FrameTimeout's value in milliseconds. Illegal to call on a + * an infinite FrameTimeout value. + */ + uint32_t AsMilliseconds() const + { + if (*this == Forever()) { + MOZ_ASSERT_UNREACHABLE("Calling AsMilliseconds() on an infinite FrameTimeout"); + return 100; // Fail to something sane. + } + + return uint32_t(mTimeout); + } + + /** + * @return this FrameTimeout value encoded so that non-negative values + * represent a timeout in milliseconds, and -1 represents an infinite + * timeout. + * + * XXX(seth): This is a backwards compatibility hack that should be removed. + */ + int32_t AsEncodedValueDeprecated() const { return mTimeout; } + +private: + explicit FrameTimeout(int32_t aTimeout) + : mTimeout(aTimeout) + { } + + int32_t mTimeout; +}; + /** * AnimationData contains all of the information necessary for using an imgFrame * as part of an animation. diff --git a/image/imgIContainer.idl b/image/imgIContainer.idl index eed28e2668d9..640eae352558 100644 --- a/image/imgIContainer.idl +++ b/image/imgIContainer.idl @@ -90,10 +90,6 @@ interface imgIContainer : nsISupports */ readonly attribute int32_t height; - %{C++ - virtual nsresult GetNativeSizes(nsTArray& aNativeSizes) const = 0; - %} - /** * The intrinsic size of this image in appunits. If the image has no intrinsic * size in a dimension, -1 will be returned for that dimension. In the case of diff --git a/image/moz.build b/image/moz.build index 8ccb30247e91..c3a3a610fd8e 100644 --- a/image/moz.build +++ b/image/moz.build @@ -37,10 +37,8 @@ XPIDL_MODULE = 'imglib2' EXPORTS += [ 'DrawResult.h', - 'FrameTimeout.h', 'ImageCacheKey.h', 'ImageLogging.h', - 'ImageMetadata.h', 'ImageOps.h', 'ImageRegion.h', 'imgLoader.h', diff --git a/image/test/gtest/Common.cpp b/image/test/gtest/Common.cpp index 4bc7fce1c32e..4be34461c71c 100644 --- a/image/test/gtest/Common.cpp +++ b/image/test/gtest/Common.cpp @@ -679,11 +679,5 @@ ImageTestCase TruncatedSmallGIFTestCase() return ImageTestCase("green-1x1-truncated.gif", "image/gif", IntSize(1, 1)); } -ImageTestCase GreenMultipleSizesICOTestCase() -{ - return ImageTestCase("green-multiple-sizes.ico", "image/x-icon", - IntSize(256, 256)); -} - } // namespace image } // namespace mozilla diff --git a/image/test/gtest/Common.h b/image/test/gtest/Common.h index 63b8b9b70026..33fc26e750f8 100644 --- a/image/test/gtest/Common.h +++ b/image/test/gtest/Common.h @@ -414,8 +414,6 @@ ImageTestCase DownscaledTransparentICOWithANDMaskTestCase(); ImageTestCase TruncatedSmallGIFTestCase(); -ImageTestCase GreenMultipleSizesICOTestCase(); - } // namespace image } // namespace mozilla diff --git a/image/test/gtest/TestDecodeToSurface.cpp b/image/test/gtest/TestDecodeToSurface.cpp index b4b011528d97..dd22d4308d9b 100644 --- a/image/test/gtest/TestDecodeToSurface.cpp +++ b/image/test/gtest/TestDecodeToSurface.cpp @@ -27,11 +27,9 @@ class DecodeToSurfaceRunnable : public Runnable public: DecodeToSurfaceRunnable(RefPtr& aSurface, nsIInputStream* aInputStream, - ImageOps::ImageBuffer* aImageBuffer, const ImageTestCase& aTestCase) : mSurface(aSurface) , mInputStream(aInputStream) - , mImageBuffer(aImageBuffer) , mTestCase(aTestCase) { } @@ -43,35 +41,16 @@ public: void Go() { - Maybe outputSize; - if (mTestCase.mOutputSize != mTestCase.mSize) { - outputSize.emplace(mTestCase.mOutputSize); - } - - if (mImageBuffer) { - mSurface = - ImageOps::DecodeToSurface(mImageBuffer, - nsDependentCString(mTestCase.mMimeType), - imgIContainer::DECODE_FLAGS_DEFAULT, - outputSize); - } else { - mSurface = - ImageOps::DecodeToSurface(mInputStream, - nsDependentCString(mTestCase.mMimeType), - imgIContainer::DECODE_FLAGS_DEFAULT, - outputSize); - } + mSurface = + ImageOps::DecodeToSurface(mInputStream, + nsDependentCString(mTestCase.mMimeType), + imgIContainer::DECODE_FLAGS_DEFAULT); ASSERT_TRUE(mSurface != nullptr); EXPECT_TRUE(mSurface->IsDataSourceSurface()); EXPECT_TRUE(mSurface->GetFormat() == SurfaceFormat::B8G8R8X8 || mSurface->GetFormat() == SurfaceFormat::B8G8R8A8); - - if (outputSize) { - EXPECT_EQ(*outputSize, mSurface->GetSize()); - } else { - EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); - } + EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); EXPECT_TRUE(IsSolidColor(mSurface, BGRAColor::Green(), mTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0)); @@ -80,19 +59,14 @@ public: private: RefPtr& mSurface; nsCOMPtr mInputStream; - RefPtr mImageBuffer; ImageTestCase mTestCase; }; static void -RunDecodeToSurface(const ImageTestCase& aTestCase, - ImageOps::ImageBuffer* aImageBuffer = nullptr) +RunDecodeToSurface(const ImageTestCase& aTestCase) { - nsCOMPtr inputStream; - if (!aImageBuffer) { - inputStream = LoadFile(aTestCase.mPath); - ASSERT_TRUE(inputStream != nullptr); - } + nsCOMPtr inputStream = LoadFile(aTestCase.mPath); + ASSERT_TRUE(inputStream != nullptr); nsCOMPtr thread; nsresult rv = @@ -103,7 +77,7 @@ RunDecodeToSurface(const ImageTestCase& aTestCase, // DecodeToSurface doesn't require any main-thread-only code. RefPtr surface; nsCOMPtr runnable = - new DecodeToSurfaceRunnable(surface, inputStream, aImageBuffer, aTestCase); + new DecodeToSurfaceRunnable(surface, inputStream, aTestCase); thread->Dispatch(runnable, nsIThread::DISPATCH_SYNC); thread->Shutdown(); @@ -148,43 +122,3 @@ TEST_F(ImageDecodeToSurface, Corrupt) imgIContainer::DECODE_FLAGS_DEFAULT); EXPECT_TRUE(surface == nullptr); } - -TEST_F(ImageDecodeToSurface, ICOMultipleSizes) -{ - ImageTestCase testCase = GreenMultipleSizesICOTestCase(); - - nsCOMPtr inputStream = LoadFile(testCase.mPath); - ASSERT_TRUE(inputStream != nullptr); - - RefPtr buffer = - ImageOps::CreateImageBuffer(inputStream); - ASSERT_TRUE(buffer != nullptr); - - ImageMetadata metadata; - nsresult rv = ImageOps::DecodeMetadata(buffer, - nsDependentCString(testCase.mMimeType), - metadata); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - ASSERT_TRUE(metadata.HasSize()); - EXPECT_EQ(testCase.mSize, metadata.GetSize()); - - const nsTArray& nativeSizes = metadata.GetNativeSizes(); - ASSERT_EQ(6, nativeSizes.Length()); - - IntSize expectedSizes[] = { - IntSize(16, 16), - IntSize(32, 32), - IntSize(64, 64), - IntSize(128, 128), - IntSize(256, 256), - IntSize(256, 128), - }; - - for (int i = 0; i < 6; ++i) { - EXPECT_EQ(expectedSizes[i], nativeSizes[i]); - - // Request decoding at native size - testCase.mOutputSize = nativeSizes[i]; - RunDecodeToSurface(testCase, buffer); - } -} diff --git a/image/test/gtest/TestDecoders.cpp b/image/test/gtest/TestDecoders.cpp index 43fd36b0d1bf..d39b8e404a60 100644 --- a/image/test/gtest/TestDecoders.cpp +++ b/image/test/gtest/TestDecoders.cpp @@ -672,87 +672,3 @@ TEST_F(ImageDecoders, TruncatedSmallGIFSingleChunk) { CheckDecoderSingleChunk(TruncatedSmallGIFTestCase()); } - -TEST_F(ImageDecoders, MultipleSizesICOSingleChunk) -{ - ImageTestCase testCase = GreenMultipleSizesICOTestCase(); - - // Create an image. - RefPtr image = - ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType)); - ASSERT_TRUE(!image->HasError()); - - nsCOMPtr inputStream = LoadFile(testCase.mPath); - ASSERT_TRUE(inputStream); - - // Figure out how much data we have. - uint64_t length; - nsresult rv = inputStream->Available(&length); - ASSERT_TRUE(NS_SUCCEEDED(rv)); - - // Write the data into the image. - rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0, - static_cast(length)); - ASSERT_TRUE(NS_SUCCEEDED(rv)); - - // Let the image know we've sent all the data. - rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true); - ASSERT_TRUE(NS_SUCCEEDED(rv)); - - RefPtr tracker = image->GetProgressTracker(); - tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE); - - // Use GetFrame() to force a sync decode of the image. - RefPtr surface = - image->GetFrame(imgIContainer::FRAME_CURRENT, - imgIContainer::FLAG_SYNC_DECODE); - - // Ensure that the image's metadata meets our expectations. - IntSize imageSize(0, 0); - rv = image->GetWidth(&imageSize.width); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - rv = image->GetHeight(&imageSize.height); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - - EXPECT_EQ(testCase.mSize.width, imageSize.width); - EXPECT_EQ(testCase.mSize.height, imageSize.height); - - nsTArray nativeSizes; - rv = image->GetNativeSizes(nativeSizes); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - ASSERT_EQ(6, nativeSizes.Length()); - - IntSize expectedSizes[] = { - IntSize(16, 16), - IntSize(32, 32), - IntSize(64, 64), - IntSize(128, 128), - IntSize(256, 256), - IntSize(256, 128) - }; - - for (int i = 0; i < 6; ++i) { - EXPECT_EQ(expectedSizes[i], nativeSizes[i]); - } - - RefPtr image90 = - ImageOps::Orient(image, Orientation(Angle::D90, Flip::Unflipped)); - rv = image90->GetNativeSizes(nativeSizes); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - ASSERT_EQ(6, nativeSizes.Length()); - - for (int i = 0; i < 5; ++i) { - EXPECT_EQ(expectedSizes[i], nativeSizes[i]); - } - EXPECT_EQ(IntSize(128, 256), nativeSizes[5]); - - RefPtr image180 = - ImageOps::Orient(image, Orientation(Angle::D180, Flip::Unflipped)); - rv = image180->GetNativeSizes(nativeSizes); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - ASSERT_EQ(6, nativeSizes.Length()); - - for (int i = 0; i < 6; ++i) { - EXPECT_EQ(expectedSizes[i], nativeSizes[i]); - } -} diff --git a/image/test/gtest/green-multiple-sizes.ico b/image/test/gtest/green-multiple-sizes.ico deleted file mode 100644 index b9463d0c897117204b2edacfa6cbfc4f5f61d771..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14144 zcmeI$u}Z^09LMorsuU?iGF5aj4uYeb;1s1*3sS3eaC9mnh?}dy&3ACb06tZ(!iOf<#;`kn$9d6k7uQwnw00` zaUxyT{R2m&RA=t*nr^D^Qz==H);#5cg;n_hP}ZY(wYf8)+x>!>Ikgv!B;X9iE3tM2N({eIg8WY>=`o{tYb zv)pNI^-teFUZdEfx8di(`TWMvmqon9E8ga6@%BCpJMC`kVf*AdR5C+V;zwm7l&;4? wWulUxM*sl?5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0;O_{00SHw$wg3PC diff --git a/image/test/gtest/moz.build b/image/test/gtest/moz.build index 3e37573dba04..ad69e098518c 100644 --- a/image/test/gtest/moz.build +++ b/image/test/gtest/moz.build @@ -47,7 +47,6 @@ TEST_HARNESS_FILES.gtest += [ 'first-frame-green.png', 'first-frame-padding.gif', 'green-1x1-truncated.gif', - 'green-multiple-sizes.ico', 'green.bmp', 'green.gif', 'green.ico', From bb7321907a289d2aef396c7c5095bf4bd13831b4 Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Wed, 22 Mar 2017 13:42:26 +0000 Subject: [PATCH 71/96] Bug 1331662 part 1 - Reimplement EvaluateString using the ExecutionContext class. r=bz --- dom/base/nsJSUtils.cpp | 251 ++++++++++++++++++++++++++++------------- dom/base/nsJSUtils.h | 90 +++++++++++++++ 2 files changed, 262 insertions(+), 79 deletions(-) diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index 98b367b663a4..5c8802487b85 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -123,6 +123,164 @@ nsJSUtils::CompileFunction(AutoJSAPI& jsapi, return NS_OK; } +static nsresult +EvaluationExceptionToNSResult(JSContext* aCx) +{ + if (JS_IsExceptionPending(aCx)) { + return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW; + } + return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE; +} + +nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx, + JS::Handle aGlobal) + : mSamplerRAII("nsJSUtils::ExecutionContext", /* PROFILER_LABEL */ + js::ProfileEntry::Category::JS, __LINE__) + , mCx(aCx) + , mCompartment(aCx, aGlobal) + , mRetValue(aCx) + , mScopeChain(aCx) + , mRv(NS_OK) + , mSkip(false) + , mCoerceToString(false) +#ifdef DEBUG + , mWantsReturnValue(false) + , mExpectScopeChain(false) +#endif +{ + MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(nsContentUtils::IsInMicroTask()); + MOZ_ASSERT(mRetValue.isUndefined()); + + MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aGlobal) == aGlobal); + if (MOZ_UNLIKELY(!xpc::Scriptability::Get(aGlobal).Allowed())) { + mSkip = true; + mRv = NS_OK; + } +} + +void +nsJSUtils::ExecutionContext::SetScopeChain( + const JS::AutoObjectVector& aScopeChain) +{ + if (mSkip) { + return; + } + +#ifdef DEBUG + mExpectScopeChain = true; +#endif + // Now make sure to wrap the scope chain into the right compartment. + if (!mScopeChain.reserve(aScopeChain.length())) { + mSkip = true; + mRv = NS_ERROR_OUT_OF_MEMORY; + return; + } + + for (size_t i = 0; i < aScopeChain.length(); ++i) { + JS::ExposeObjectToActiveJS(aScopeChain[i]); + mScopeChain.infallibleAppend(aScopeChain[i]); + if (!JS_WrapObject(mCx, mScopeChain[i])) { + mSkip = true; + mRv = NS_ERROR_OUT_OF_MEMORY; + return; + } + } +} + +nsresult +nsJSUtils::ExecutionContext::SyncAndExec(void **aOffThreadToken, + JS::MutableHandle aScript) +{ + if (mSkip) { + return mRv; + } + + MOZ_ASSERT(!mWantsReturnValue); + MOZ_ASSERT(!mExpectScopeChain); + aScript.set(JS::FinishOffThreadScript(mCx, *aOffThreadToken)); + *aOffThreadToken = nullptr; // Mark the token as having been finished. + if (!aScript || !JS_ExecuteScript(mCx, mScopeChain, aScript)) { + mSkip = true; + mRv = EvaluationExceptionToNSResult(mCx); + return mRv; + } + + return NS_OK; +} + +nsresult +nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions, + JS::SourceBufferHolder& aSrcBuf) +{ + if (mSkip) { + return mRv; + } + + MOZ_ASSERT_IF(aCompileOptions.versionSet, + aCompileOptions.version != JSVERSION_UNKNOWN); + MOZ_ASSERT(aSrcBuf.get()); + MOZ_ASSERT(mRetValue.isUndefined()); +#ifdef DEBUG + mWantsReturnValue = !aCompileOptions.noScriptRval; +#endif + MOZ_ASSERT(!mCoerceToString || mWantsReturnValue); + if (!JS::Evaluate(mCx, mScopeChain, aCompileOptions, aSrcBuf, &mRetValue)) { + mSkip = true; + mRv = EvaluationExceptionToNSResult(mCx); + return mRv; + } + + return NS_OK; +} + +nsresult +nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions, + const nsAString& aScript) +{ + if (mSkip) { + return mRv; + } + + const nsPromiseFlatString& flatScript = PromiseFlatString(aScript); + JS::SourceBufferHolder srcBuf(flatScript.get(), aScript.Length(), + JS::SourceBufferHolder::NoOwnership); + return CompileAndExec(aCompileOptions, srcBuf); +} + +nsresult +nsJSUtils::ExecutionContext::ExtractReturnValue(JS::MutableHandle aRetValue) +{ + MOZ_ASSERT(aRetValue.isUndefined()); + if (mSkip) { + // Repeat earlier result, as NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW are not + // failures cases. +#ifdef DEBUG + mWantsReturnValue = false; +#endif + return mRv; + } + + MOZ_ASSERT(mWantsReturnValue); +#ifdef DEBUG + mWantsReturnValue = false; +#endif + if (mCoerceToString && !mRetValue.isUndefined()) { + JSString* str = JS::ToString(mCx, mRetValue); + if (!str) { + // ToString can be a function call, so an exception can be raised while + // executing the function. + mSkip = true; + return EvaluationExceptionToNSResult(mCx); + } + mRetValue.set(JS::StringValue(str)); + } + + aRetValue.set(mRetValue); + return NS_OK; +} + nsresult nsJSUtils::EvaluateString(JSContext* aCx, const nsAString& aScript, @@ -147,92 +305,27 @@ nsJSUtils::EvaluateString(JSContext* aCx, JS::MutableHandle aRetValue, void **aOffThreadToken) { - PROFILER_LABEL("nsJSUtils", "EvaluateString", - js::ProfileEntry::Category::JS); - - MOZ_ASSERT_IF(aCompileOptions.versionSet, - aCompileOptions.version != JSVERSION_UNKNOWN); - MOZ_ASSERT_IF(aEvaluateOptions.coerceToString, !aCompileOptions.noScriptRval); - MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); - MOZ_ASSERT(aSrcBuf.get()); - MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aEvaluationGlobal) == - aEvaluationGlobal); - MOZ_ASSERT_IF(aOffThreadToken, aCompileOptions.noScriptRval); - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(nsContentUtils::IsInMicroTask()); - - // Unfortunately, the JS engine actually compiles scripts with a return value - // in a different, less efficient way. Furthermore, it can't JIT them in many - // cases. So we need to be explicitly told whether the caller cares about the - // return value. Callers can do this by calling the other overload of - // EvaluateString() which calls this function with - // aCompileOptions.noScriptRval set to true. - aRetValue.setUndefined(); + ExecutionContext exec(aCx, aEvaluationGlobal); + exec.SetReturnValue(aCompileOptions) + .SetCoerceToString(aEvaluateOptions.coerceToString); + exec.SetScopeChain(aEvaluateOptions.scopeChain); nsresult rv = NS_OK; - - NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK); - - bool ok = true; - // Scope the JSAutoCompartment so that we can later wrap the return value - // into the caller's cx. - { - JSAutoCompartment ac(aCx, aEvaluationGlobal); - - // Now make sure to wrap the scope chain into the right compartment. - JS::AutoObjectVector scopeChain(aCx); - if (!scopeChain.reserve(aEvaluateOptions.scopeChain.length())) { - return NS_ERROR_OUT_OF_MEMORY; - } - - for (size_t i = 0; i < aEvaluateOptions.scopeChain.length(); ++i) { - JS::ExposeObjectToActiveJS(aEvaluateOptions.scopeChain[i]); - scopeChain.infallibleAppend(aEvaluateOptions.scopeChain[i]); - if (!JS_WrapObject(aCx, scopeChain[i])) { - ok = false; - break; - } - } - - if (ok && aOffThreadToken) { - JS::Rooted - script(aCx, JS::FinishOffThreadScript(aCx, *aOffThreadToken)); - *aOffThreadToken = nullptr; // Mark the token as having been finished. - if (script) { - ok = JS_ExecuteScript(aCx, scopeChain, script); - } else { - ok = false; - } - } else if (ok) { - ok = JS::Evaluate(aCx, scopeChain, aCompileOptions, aSrcBuf, aRetValue); - } - - if (ok && aEvaluateOptions.coerceToString && !aRetValue.isUndefined()) { - JS::Rooted value(aCx, aRetValue); - JSString* str = JS::ToString(aCx, value); - ok = !!str; - aRetValue.set(ok ? JS::StringValue(str) : JS::UndefinedValue()); - } + if (aOffThreadToken) { + JS::Rooted script(aCx); + rv = exec.SyncAndExec(aOffThreadToken, &script); + } else { + rv = exec.CompileAndExec(aCompileOptions, aSrcBuf); } - if (!ok) { - if (JS_IsExceptionPending(aCx)) { - rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW; - } else { - rv = NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE; - } - - if (!aCompileOptions.noScriptRval) { - aRetValue.setUndefined(); - } + if (NS_FAILED(rv)) { + return rv; } - // Wrap the return value into whatever compartment aCx was in. - if (ok && !aCompileOptions.noScriptRval) { - if (!JS_WrapValue(aCx, aRetValue)) { - return NS_ERROR_OUT_OF_MEMORY; - } + if (!aCompileOptions.noScriptRval) { + return exec.ExtractReturnValue(aRetValue); } + return rv; } diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h index 4affab2d3644..71c313a71416 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -16,6 +16,7 @@ #include "mozilla/Assertions.h" +#include "GeckoProfiler.h" #include "jsapi.h" #include "jsfriendapi.h" #include "js/Conversions.h" @@ -64,6 +65,95 @@ public: const nsAString& aBody, JSObject** aFunctionObject); + + // ExecutionContext is used to switch compartment. + class MOZ_STACK_CLASS ExecutionContext { + // Register stack annotations for the Gecko profiler. + mozilla::SamplerStackFrameRAII mSamplerRAII; + + JSContext* mCx; + + // Handles switching to our global's compartment. + JSAutoCompartment mCompartment; + + // Set to a valid handle if a return value is expected. + JS::Rooted mRetValue; + + // Scope chain in which the execution takes place. + JS::AutoObjectVector mScopeChain; + + // returned value forwarded when we have to interupt the execution eagerly + // with mSkip. + nsresult mRv; + + // Used to skip upcoming phases in case of a failure. In such case the + // result is carried by mRv. + bool mSkip; + + // Should the result be serialized before being returned. + bool mCoerceToString; + +#ifdef DEBUG + // Should we set the return value. + bool mWantsReturnValue; + + bool mExpectScopeChain; +#endif + + public: + + // Enter compartment in which the code would be executed. The JSContext + // must come from an AutoEntryScript that has had + // TakeOwnershipOfErrorReporting() called on it. + ExecutionContext(JSContext* aCx, JS::Handle aGlobal); + + ExecutionContext(const ExecutionContext&) = delete; + ExecutionContext(ExecutionContext&&) = delete; + + ~ExecutionContext() { + // This flag is resetted, when the returned value is extracted. + MOZ_ASSERT(!mWantsReturnValue); + } + + // The returned value would be converted to a string if the + // |aCoerceToString| is flag set. + ExecutionContext& SetCoerceToString(bool aCoerceToString) { + mCoerceToString = aCoerceToString; + return *this; + } + + // Set the scope chain in which the code should be executed. + void SetScopeChain(const JS::AutoObjectVector& aScopeChain); + + // Copy the returned value in the mutable handle argument, in case of a + // evaluation failure either during the execution or the conversion of the + // result to a string, the nsresult would be set to the corresponding result + // code, and the mutable handle argument would remain unchanged. + // + // The value returned in the mutable handle argument is part of the + // compartment given as argument to the ExecutionContext constructor. If the + // caller is in a different compartment, then the out-param value should be + // wrapped by calling |JS_WrapValue|. + MOZ_MUST_USE nsresult + ExtractReturnValue(JS::MutableHandle aRetValue); + + // After getting a notification that an off-thread compilation terminated, + // this function will synchronize the result by moving it to the main thread + // before starting the execution of the script. + // + // The compiled script would be returned in the |aScript| out-param. + MOZ_MUST_USE nsresult SyncAndExec(void **aOffThreadToken, + JS::MutableHandle aScript); + + // Compile a script contained in a SourceBuffer, and execute it. + nsresult CompileAndExec(JS::CompileOptions& aCompileOptions, + JS::SourceBufferHolder& aSrcBuf); + + // Compile a script contained in a string, and execute it. + nsresult CompileAndExec(JS::CompileOptions& aCompileOptions, + const nsAString& aScript); + }; + struct MOZ_STACK_CLASS EvaluateOptions { bool coerceToString; JS::AutoObjectVector scopeChain; From 39741d711a679cdd4e3d98b2efc401cbb489fc2a Mon Sep 17 00:00:00 2001 From: "Nicolas B. Pierron" Date: Wed, 22 Mar 2017 13:42:27 +0000 Subject: [PATCH 72/96] Bug 1331662 part 2 - Replace nsJSUtils::EvaluateString calls by ExecutionContext scopes. r=bz --- dom/base/nsGlobalWindow.cpp | 9 +++- dom/base/nsJSUtils.cpp | 87 ------------------------------ dom/base/nsJSUtils.h | 56 ------------------- dom/base/nsScriptLoader.cpp | 17 +++--- dom/jsurl/nsJSProtocolHandler.cpp | 12 +++-- dom/plugins/base/nsNPAPIPlugin.cpp | 17 ++++-- dom/worklet/Worklet.cpp | 3 -- dom/xbl/nsXBLProtoImplField.cpp | 17 +++--- js/src/jsfriendapi.cpp | 6 +++ js/src/jsfriendapi.h | 3 ++ 10 files changed, 59 insertions(+), 168 deletions(-) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 4214a8abc3e5..f0d69a3f0cbf 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -13077,9 +13077,14 @@ nsGlobalWindow::RunTimeoutHandler(Timeout* aTimeout, AutoEntryScript aes(this, reason, true); JS::CompileOptions options(aes.cx()); options.setFileAndLine(filename, lineNo).setVersion(JSVERSION_DEFAULT); + options.setNoScriptRval(true); JS::Rooted global(aes.cx(), FastGetGlobalJSObject()); - nsresult rv = - nsJSUtils::EvaluateString(aes.cx(), script, global, options); + nsresult rv = NS_OK; + { + nsJSUtils::ExecutionContext exec(aes.cx(), global); + rv = exec.CompileAndExec(options, script); + } + if (rv == NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE) { abortIntervalHandler = true; } diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp index 5c8802487b85..6fcf17a1fd1e 100644 --- a/dom/base/nsJSUtils.cpp +++ b/dom/base/nsJSUtils.cpp @@ -281,93 +281,6 @@ nsJSUtils::ExecutionContext::ExtractReturnValue(JS::MutableHandle aRe return NS_OK; } -nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - const nsAString& aScript, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue) -{ - const nsPromiseFlatString& flatScript = PromiseFlatString(aScript); - JS::SourceBufferHolder srcBuf(flatScript.get(), aScript.Length(), - JS::SourceBufferHolder::NoOwnership); - return EvaluateString(aCx, srcBuf, aEvaluationGlobal, aCompileOptions, - aEvaluateOptions, aRetValue, nullptr); -} - -nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue, - void **aOffThreadToken) -{ - ExecutionContext exec(aCx, aEvaluationGlobal); - exec.SetReturnValue(aCompileOptions) - .SetCoerceToString(aEvaluateOptions.coerceToString); - exec.SetScopeChain(aEvaluateOptions.scopeChain); - - nsresult rv = NS_OK; - if (aOffThreadToken) { - JS::Rooted script(aCx); - rv = exec.SyncAndExec(aOffThreadToken, &script); - } else { - rv = exec.CompileAndExec(aCompileOptions, aSrcBuf); - } - - if (NS_FAILED(rv)) { - return rv; - } - - if (!aCompileOptions.noScriptRval) { - return exec.ExtractReturnValue(aRetValue); - } - - return rv; -} - -nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue) -{ - return EvaluateString(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions, - aEvaluateOptions, aRetValue, nullptr); -} - -nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - const nsAString& aScript, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions) -{ - EvaluateOptions options(aCx); - aCompileOptions.setNoScriptRval(true); - JS::RootedValue unused(aCx); - return EvaluateString(aCx, aScript, aEvaluationGlobal, aCompileOptions, - options, &unused); -} - -nsresult -nsJSUtils::EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - void **aOffThreadToken) -{ - EvaluateOptions options(aCx); - aCompileOptions.setNoScriptRval(true); - JS::RootedValue unused(aCx); - return EvaluateString(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions, - options, &unused, aOffThreadToken); -} - nsresult nsJSUtils::CompileModule(JSContext* aCx, JS::SourceBufferHolder& aSrcBuf, diff --git a/dom/base/nsJSUtils.h b/dom/base/nsJSUtils.h index 71c313a71416..e6285b9bf9da 100644 --- a/dom/base/nsJSUtils.h +++ b/dom/base/nsJSUtils.h @@ -154,52 +154,6 @@ public: const nsAString& aScript); }; - struct MOZ_STACK_CLASS EvaluateOptions { - bool coerceToString; - JS::AutoObjectVector scopeChain; - - explicit EvaluateOptions(JSContext* cx) - : coerceToString(false) - , scopeChain(cx) - {} - - EvaluateOptions& setCoerceToString(bool aCoerce) { - coerceToString = aCoerce; - return *this; - } - }; - - // aEvaluationGlobal is the global to evaluate in. The return value - // will then be wrapped back into the compartment aCx is in when - // this function is called. For all the EvaluateString overloads, - // the JSContext must come from an AutoJSAPI that has had - // TakeOwnershipOfErrorReporting() called on it. - static nsresult EvaluateString(JSContext* aCx, - const nsAString& aScript, - JS::Handle aEvaluationGlobal, - JS::CompileOptions &aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue); - - static nsresult EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions &aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue); - - - static nsresult EvaluateString(JSContext* aCx, - const nsAString& aScript, - JS::Handle aEvaluationGlobal, - JS::CompileOptions &aCompileOptions); - - static nsresult EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions &aCompileOptions, - void **aOffThreadToken); - static nsresult CompileModule(JSContext* aCx, JS::SourceBufferHolder& aSrcBuf, JS::Handle aEvaluationGlobal, @@ -219,16 +173,6 @@ public: JS::AutoObjectVector& aScopeChain); static void ResetTimeZone(); - -private: - // Implementation for our EvaluateString bits - static nsresult EvaluateString(JSContext* aCx, - JS::SourceBufferHolder& aSrcBuf, - JS::Handle aEvaluationGlobal, - JS::CompileOptions& aCompileOptions, - const EvaluateOptions& aEvaluateOptions, - JS::MutableHandle aRetValue, - void **aOffThreadToken); }; template diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 76eb388b171e..e3aab285aa20 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -2152,8 +2152,6 @@ nsScriptLoader::FillCompileOptionsForRequest(const AutoJSAPI&jsapi, aOptions->setFileAndLine(aRequest->mURL.get(), aRequest->mLineNo); aOptions->setVersion(JSVersion(aRequest->mJSVersion)); aOptions->setIsRunOnce(true); - // We only need the setNoScriptRval bit when compiling off-thread here, since - // otherwise nsJSUtils::EvaluateString will set it up for us. aOptions->setNoScriptRval(true); if (aRequest->mHasSourceMapURL) { aOptions->setSourceMapURL(aRequest->mSourceMapURL.get()); @@ -2258,10 +2256,17 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest) rv = FillCompileOptionsForRequest(aes, aRequest, global, &options); if (NS_SUCCEEDED(rv)) { - nsAutoString inlineData; - SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData); - rv = nsJSUtils::EvaluateString(aes.cx(), srcBuf, global, options, - aRequest->OffThreadTokenPtr()); + { + nsJSUtils::ExecutionContext exec(aes.cx(), global); + if (aRequest->mOffThreadToken) { + JS::Rooted script(aes.cx()); + rv = exec.SyncAndExec(&aRequest->mOffThreadToken, &script); + } else { + nsAutoString inlineData; + SourceBufferHolder srcBuf = GetScriptSource(aRequest, inlineData); + rv = exec.CompileAndExec(options, srcBuf); + } + } } } } diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp index bd8f70e2bc87..0c1b5d9599fc 100644 --- a/dom/jsurl/nsJSProtocolHandler.cpp +++ b/dom/jsurl/nsJSProtocolHandler.cpp @@ -269,10 +269,14 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel, JS::CompileOptions options(cx); options.setFileAndLine(mURL.get(), 1) .setVersion(JSVERSION_DEFAULT); - nsJSUtils::EvaluateOptions evalOptions(cx); - evalOptions.setCoerceToString(true); - rv = nsJSUtils::EvaluateString(cx, NS_ConvertUTF8toUTF16(script), - globalJSObject, options, evalOptions, &v); + { + nsJSUtils::ExecutionContext exec(cx, globalJSObject); + exec.SetCoerceToString(true); + exec.CompileAndExec(options, NS_ConvertUTF8toUTF16(script)); + rv = exec.ExtractReturnValue(&v); + } + + js::AssertSameCompartment(cx, v); if (NS_FAILED(rv) || !(v.isString() || v.isUndefined())) { return NS_ERROR_MALFORMED_URI; diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index af8a182b5e99..6fcc157ce7b9 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -1368,14 +1368,23 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result) options.setFileAndLine(spec, 0) .setVersion(JSVERSION_DEFAULT); JS::Rooted rval(cx); - nsJSUtils::EvaluateOptions evalOptions(cx); + JS::AutoObjectVector scopeChain(cx); if (obj != js::GetGlobalForObjectCrossCompartment(obj) && - !evalOptions.scopeChain.append(obj)) { + !scopeChain.append(obj)) { return false; } obj = js::GetGlobalForObjectCrossCompartment(obj); - nsresult rv = nsJSUtils::EvaluateString(cx, utf16script, obj, options, - evalOptions, &rval); + nsresult rv = NS_OK; + { + nsJSUtils::ExecutionContext exec(cx, obj); + exec.SetScopeChain(scopeChain); + exec.CompileAndExec(options, utf16script); + rv = exec.ExtractReturnValue(&rval); + } + + if (!JS_WrapValue(cx, &rval)) { + return false; + } return NS_SUCCEEDED(rv) && (!result || JSValToNPVariant(npp, cx, rval, result)); diff --git a/dom/worklet/Worklet.cpp b/dom/worklet/Worklet.cpp index 133ad8cf9224..77b8a9647ba6 100644 --- a/dom/worklet/Worklet.cpp +++ b/dom/worklet/Worklet.cpp @@ -205,9 +205,6 @@ public: compileOptions.setFileAndLine(NS_ConvertUTF16toUTF8(mURL).get(), 0); compileOptions.setVersion(JSVERSION_DEFAULT); compileOptions.setIsRunOnce(true); - - // We only need the setNoScriptRval bit when compiling off-thread here, - // since otherwise nsJSUtils::EvaluateString will set it up for us. compileOptions.setNoScriptRval(true); JSAutoCompartment comp(cx, globalObj); diff --git a/dom/xbl/nsXBLProtoImplField.cpp b/dom/xbl/nsXBLProtoImplField.cpp index cc4d0c7591d8..8860deec1019 100644 --- a/dom/xbl/nsXBLProtoImplField.cpp +++ b/dom/xbl/nsXBLProtoImplField.cpp @@ -427,14 +427,19 @@ nsXBLProtoImplField::InstallField(JS::Handle aBoundNode, JS::CompileOptions options(cx); options.setFileAndLine(uriSpec.get(), mLineNumber) .setVersion(JSVERSION_LATEST); - nsJSUtils::EvaluateOptions evalOptions(cx); - if (!nsJSUtils::GetScopeChainForElement(cx, boundElement, - evalOptions.scopeChain)) { + JS::AutoObjectVector scopeChain(cx); + if (!nsJSUtils::GetScopeChainForElement(cx, boundElement, scopeChain)) { return NS_ERROR_OUT_OF_MEMORY; } - rv = nsJSUtils::EvaluateString(cx, nsDependentString(mFieldText, - mFieldTextLength), - scopeObject, options, evalOptions, &result); + rv = NS_OK; + { + nsJSUtils::ExecutionContext exec(cx, scopeObject); + exec.SetScopeChain(scopeChain); + exec.CompileAndExec(options, nsDependentString(mFieldText, + mFieldTextLength)); + rv = exec.ExtractReturnValue(&result); + } + if (NS_FAILED(rv)) { return rv; } diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 0989b942fb39..356ff8597c66 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -378,6 +378,12 @@ js::AssertSameCompartment(JSContext* cx, JSObject* obj) assertSameCompartment(cx, obj); } +JS_FRIEND_API(void) +js::AssertSameCompartment(JSContext* cx, JS::HandleValue v) +{ + assertSameCompartment(cx, v); +} + #ifdef DEBUG JS_FRIEND_API(void) js::AssertSameCompartment(JSObject* objA, JSObject* objB) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 76745822486e..41f7c0cae7b7 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -653,6 +653,9 @@ GetPrototypeNoProxy(JSObject* obj); JS_FRIEND_API(void) AssertSameCompartment(JSContext* cx, JSObject* obj); +JS_FRIEND_API(void) +AssertSameCompartment(JSContext* cx, JS::HandleValue v); + #ifdef JS_DEBUG JS_FRIEND_API(void) AssertSameCompartment(JSObject* objA, JSObject* objB); From 9093d5f005892d57b5a27fbf4039376110b421ca Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sat, 18 Mar 2017 16:08:12 -0400 Subject: [PATCH 73/96] Bug 1316683 - Avoid going into SpiderMonkey for retrieving origin attributes; r=baku Our caller is C++ code, and the implementations are all also written in C++, so there is no reason to go through SpiderMonkey here. This patch also makes nsILoadContext builtinclass to ensure that the implementation is always native. --- caps/nsScriptSecurityManager.cpp | 3 +- docshell/base/LoadContext.cpp | 30 ++++--------------- docshell/base/LoadContext.h | 2 ++ docshell/base/SerializedLoadContext.cpp | 4 +-- docshell/base/nsDocShell.cpp | 6 ++++ docshell/base/nsDocShell.h | 2 ++ docshell/base/nsILoadContext.idl | 6 ++-- dom/base/nsDocument.h | 20 +++++++++---- dom/ipc/TabParent.cpp | 1 + dom/offline/nsDOMOfflineResourceList.cpp | 3 +- .../prefetch/OfflineCacheUpdateParent.cpp | 8 +++++ uriloader/prefetch/OfflineCacheUpdateParent.h | 2 ++ 12 files changed, 46 insertions(+), 41 deletions(-) diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 0d587f8115a3..7d70c97a8f1e 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -1168,8 +1168,7 @@ nsScriptSecurityManager:: { NS_ENSURE_STATE(aLoadContext); OriginAttributes docShellAttrs; - bool result = aLoadContext->GetOriginAttributes(docShellAttrs); - NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); + aLoadContext->GetOriginAttributes(docShellAttrs); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, docShellAttrs); diff --git a/docshell/base/LoadContext.cpp b/docshell/base/LoadContext.cpp index 6c3ba6b52311..03fa53273189 100644 --- a/docshell/base/LoadContext.cpp +++ b/docshell/base/LoadContext.cpp @@ -12,30 +12,6 @@ #include "nsContentUtils.h" #include "xpcpublic.h" -bool -nsILoadContext::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) -{ - mozilla::dom::AutoJSAPI jsapi; - bool ok = jsapi.Init(xpc::PrivilegedJunkScope()); - NS_ENSURE_TRUE(ok, false); - JS::Rooted v(jsapi.cx()); - nsresult rv = GetOriginAttributes(&v); - NS_ENSURE_SUCCESS(rv, false); - NS_ENSURE_TRUE(v.isObject(), false); - JS::Rooted obj(jsapi.cx(), &v.toObject()); - - // If we're JS-implemented, the object will be left in a different (System-Principaled) - // scope, so we may need to enter its compartment. - MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj))); - JSAutoCompartment ac(jsapi.cx(), obj); - - mozilla::OriginAttributes attrs; - ok = attrs.Init(jsapi.cx(), v); - NS_ENSURE_TRUE(ok, false); - aAttrs = attrs; - return true; -} - namespace mozilla { NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor) @@ -181,6 +157,12 @@ LoadContext::GetOriginAttributes(JS::MutableHandleValue aAttrs) return NS_OK; } +NS_IMETHODIMP_(void) +LoadContext::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) +{ + aAttrs = mOriginAttributes; +} + NS_IMETHODIMP LoadContext::GetUseTrackingProtection(bool* aUseTrackingProtection) { diff --git a/docshell/base/LoadContext.h b/docshell/base/LoadContext.h index 0b05899ab934..ac81dbd3e06e 100644 --- a/docshell/base/LoadContext.h +++ b/docshell/base/LoadContext.h @@ -111,6 +111,8 @@ public: private: ~LoadContext() {} + void GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; + nsWeakPtr mTopFrameElement; uint64_t mNestedFrameId; bool mIsContent; diff --git a/docshell/base/SerializedLoadContext.cpp b/docshell/base/SerializedLoadContext.cpp index 501a417a5125..3964a78f9fc3 100644 --- a/docshell/base/SerializedLoadContext.cpp +++ b/docshell/base/SerializedLoadContext.cpp @@ -62,9 +62,7 @@ SerializedLoadContext::Init(nsILoadContext* aLoadContext) aLoadContext->GetIsContent(&mIsContent); aLoadContext->GetUseRemoteTabs(&mUseRemoteTabs); aLoadContext->GetUseTrackingProtection(&mUseTrackingProtection); - if (!aLoadContext->GetOriginAttributes(mOriginAttributes)) { - NS_WARNING("GetOriginAttributes failed"); - } + aLoadContext->GetOriginAttributes(mOriginAttributes); } else { mIsNotNull = false; mIsPrivateBitValid = false; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 6ed2909fb70e..d07474e493c3 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -14944,3 +14944,9 @@ nsDocShell::GetAwaitingLargeAlloc(bool* aResult) *aResult = static_cast(tabChild.get())->IsAwaitingLargeAlloc(); return NS_OK; } + +NS_IMETHODIMP_(void) +nsDocShell::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) +{ + aAttrs = mOriginAttributes; +} diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 937897023340..6b5a06888deb 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -806,6 +806,8 @@ protected: void UpdateGlobalHistoryTitle(nsIURI* aURI); + void GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; + // Dimensions of the docshell nsIntRect mBounds; nsString mName; diff --git a/docshell/base/nsILoadContext.idl b/docshell/base/nsILoadContext.idl index 98e8a2119171..d3a39a676c79 100644 --- a/docshell/base/nsILoadContext.idl +++ b/docshell/base/nsILoadContext.idl @@ -20,7 +20,7 @@ interface nsIDOMElement; * can be queried for various information about where the load is * happening. */ -[scriptable, uuid(2813a7a3-d084-4d00-acd0-f76620315c02)] +[builtinclass, scriptable, uuid(2813a7a3-d084-4d00-acd0-f76620315c02)] interface nsILoadContext : nsISupports { /** @@ -139,10 +139,8 @@ interface nsILoadContext : nsISupports #ifdef MOZILLA_INTERNAL_API /** * The C++ getter for origin attributes. - * - * Defined in LoadContext.cpp */ - bool GetOriginAttributes(mozilla::OriginAttributes& aAttrs); + NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) = 0; #endif %} }; diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 2dc245147f38..7218e6def399 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -444,7 +444,7 @@ protected: // implement one interface. // XXXbz I wish we could just derive the _allcaps thing from _i -#define DECL_SHIM(_i, _allcaps) \ +#define DECL_SHIM(_i, _allcaps, _customfwd) \ class _i##Shim final : public nsIInterfaceRequestor, \ public _i \ { \ @@ -459,17 +459,25 @@ protected: NS_DECL_ISUPPORTS \ NS_FORWARD_NSIINTERFACEREQUESTOR(mIfReq->) \ NS_FORWARD_##_allcaps(mRealPtr->) \ + _customfwd \ private: \ nsCOMPtr mIfReq; \ nsCOMPtr<_i> mRealPtr; \ }; - DECL_SHIM(nsILoadContext, NSILOADCONTEXT) - DECL_SHIM(nsIProgressEventSink, NSIPROGRESSEVENTSINK) - DECL_SHIM(nsIChannelEventSink, NSICHANNELEVENTSINK) - DECL_SHIM(nsISecurityEventSink, NSISECURITYEVENTSINK) - DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER) +#define DECL_FORWARD_CPP_GETORIGINATTRIBUTES \ + NS_IMETHODIMP_(void) \ + GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override \ + { \ + mRealPtr->GetOriginAttributes(aAttrs); \ + } + DECL_SHIM(nsILoadContext, NSILOADCONTEXT, DECL_FORWARD_CPP_GETORIGINATTRIBUTES) + DECL_SHIM(nsIProgressEventSink, NSIPROGRESSEVENTSINK, ) + DECL_SHIM(nsIChannelEventSink, NSICHANNELEVENTSINK, ) + DECL_SHIM(nsISecurityEventSink, NSISECURITYEVENTSINK, ) + DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER, ) #undef DECL_SHIM +#undef DECL_FORWARD_CPP_GETORIGINATTRIBUTES }; /** diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 87163e1bcb91..e6e144df1a89 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -3020,6 +3020,7 @@ public: NS_IMETHOD SetPrivateBrowsing(bool) NO_IMPL NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool*) NO_IMPL NS_IMETHOD GetOriginAttributes(JS::MutableHandleValue) NO_IMPL + NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override {} NS_IMETHOD GetUseRemoteTabs(bool*) NO_IMPL NS_IMETHOD SetRemoteTabs(bool) NO_IMPL NS_IMETHOD GetUseTrackingProtection(bool*) NO_IMPL diff --git a/dom/offline/nsDOMOfflineResourceList.cpp b/dom/offline/nsDOMOfflineResourceList.cpp index a02b2956245e..b6b49670b8b7 100644 --- a/dom/offline/nsDOMOfflineResourceList.cpp +++ b/dom/offline/nsDOMOfflineResourceList.cpp @@ -815,8 +815,7 @@ nsDOMOfflineResourceList::CacheKeys() nsAutoCString originSuffix; if (loadContext) { mozilla::OriginAttributes oa; - bool ok = loadContext->GetOriginAttributes(oa); - NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED); + loadContext->GetOriginAttributes(oa); oa.CreateSuffix(originSuffix); } diff --git a/uriloader/prefetch/OfflineCacheUpdateParent.cpp b/uriloader/prefetch/OfflineCacheUpdateParent.cpp index c77f2b49a02e..f10821292b71 100644 --- a/uriloader/prefetch/OfflineCacheUpdateParent.cpp +++ b/uriloader/prefetch/OfflineCacheUpdateParent.cpp @@ -276,6 +276,14 @@ OfflineCacheUpdateParent::GetOriginAttributes(JS::MutableHandleValue aAttrs) return NS_OK; } +NS_IMETHODIMP_(void) +OfflineCacheUpdateParent::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) +{ + if (mLoadingPrincipal) { + aAttrs = mLoadingPrincipal->OriginAttributesRef(); + } +} + NS_IMETHODIMP OfflineCacheUpdateParent::GetUseTrackingProtection(bool* aUseTrackingProtection) { diff --git a/uriloader/prefetch/OfflineCacheUpdateParent.h b/uriloader/prefetch/OfflineCacheUpdateParent.h index f6dbc1cb2a6f..ee3c22ea74cd 100644 --- a/uriloader/prefetch/OfflineCacheUpdateParent.h +++ b/uriloader/prefetch/OfflineCacheUpdateParent.h @@ -54,6 +54,8 @@ public: private: ~OfflineCacheUpdateParent(); + void GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; + bool mIPCClosed; nsCOMPtr mLoadingPrincipal; From 20fb8455d6fef72e8373b9640a346ad3f24767c2 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Wed, 22 Mar 2017 15:15:27 +0100 Subject: [PATCH 74/96] Backed out changeset 7e47807067a6 (bug 1316683) for Windows bustage. r=backout --- caps/nsScriptSecurityManager.cpp | 3 +- docshell/base/LoadContext.cpp | 30 +++++++++++++++---- docshell/base/LoadContext.h | 2 -- docshell/base/SerializedLoadContext.cpp | 4 ++- docshell/base/nsDocShell.cpp | 6 ---- docshell/base/nsDocShell.h | 2 -- docshell/base/nsILoadContext.idl | 6 ++-- dom/base/nsDocument.h | 20 ++++--------- dom/ipc/TabParent.cpp | 1 - dom/offline/nsDOMOfflineResourceList.cpp | 3 +- .../prefetch/OfflineCacheUpdateParent.cpp | 8 ----- uriloader/prefetch/OfflineCacheUpdateParent.h | 2 -- 12 files changed, 41 insertions(+), 46 deletions(-) diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 7d70c97a8f1e..0d587f8115a3 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -1168,7 +1168,8 @@ nsScriptSecurityManager:: { NS_ENSURE_STATE(aLoadContext); OriginAttributes docShellAttrs; - aLoadContext->GetOriginAttributes(docShellAttrs); + bool result = aLoadContext->GetOriginAttributes(docShellAttrs); + NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, docShellAttrs); diff --git a/docshell/base/LoadContext.cpp b/docshell/base/LoadContext.cpp index 03fa53273189..6c3ba6b52311 100644 --- a/docshell/base/LoadContext.cpp +++ b/docshell/base/LoadContext.cpp @@ -12,6 +12,30 @@ #include "nsContentUtils.h" #include "xpcpublic.h" +bool +nsILoadContext::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) +{ + mozilla::dom::AutoJSAPI jsapi; + bool ok = jsapi.Init(xpc::PrivilegedJunkScope()); + NS_ENSURE_TRUE(ok, false); + JS::Rooted v(jsapi.cx()); + nsresult rv = GetOriginAttributes(&v); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(v.isObject(), false); + JS::Rooted obj(jsapi.cx(), &v.toObject()); + + // If we're JS-implemented, the object will be left in a different (System-Principaled) + // scope, so we may need to enter its compartment. + MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj))); + JSAutoCompartment ac(jsapi.cx(), obj); + + mozilla::OriginAttributes attrs; + ok = attrs.Init(jsapi.cx(), v); + NS_ENSURE_TRUE(ok, false); + aAttrs = attrs; + return true; +} + namespace mozilla { NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor) @@ -157,12 +181,6 @@ LoadContext::GetOriginAttributes(JS::MutableHandleValue aAttrs) return NS_OK; } -NS_IMETHODIMP_(void) -LoadContext::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) -{ - aAttrs = mOriginAttributes; -} - NS_IMETHODIMP LoadContext::GetUseTrackingProtection(bool* aUseTrackingProtection) { diff --git a/docshell/base/LoadContext.h b/docshell/base/LoadContext.h index ac81dbd3e06e..0b05899ab934 100644 --- a/docshell/base/LoadContext.h +++ b/docshell/base/LoadContext.h @@ -111,8 +111,6 @@ public: private: ~LoadContext() {} - void GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; - nsWeakPtr mTopFrameElement; uint64_t mNestedFrameId; bool mIsContent; diff --git a/docshell/base/SerializedLoadContext.cpp b/docshell/base/SerializedLoadContext.cpp index 3964a78f9fc3..501a417a5125 100644 --- a/docshell/base/SerializedLoadContext.cpp +++ b/docshell/base/SerializedLoadContext.cpp @@ -62,7 +62,9 @@ SerializedLoadContext::Init(nsILoadContext* aLoadContext) aLoadContext->GetIsContent(&mIsContent); aLoadContext->GetUseRemoteTabs(&mUseRemoteTabs); aLoadContext->GetUseTrackingProtection(&mUseTrackingProtection); - aLoadContext->GetOriginAttributes(mOriginAttributes); + if (!aLoadContext->GetOriginAttributes(mOriginAttributes)) { + NS_WARNING("GetOriginAttributes failed"); + } } else { mIsNotNull = false; mIsPrivateBitValid = false; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index d07474e493c3..6ed2909fb70e 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -14944,9 +14944,3 @@ nsDocShell::GetAwaitingLargeAlloc(bool* aResult) *aResult = static_cast(tabChild.get())->IsAwaitingLargeAlloc(); return NS_OK; } - -NS_IMETHODIMP_(void) -nsDocShell::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) -{ - aAttrs = mOriginAttributes; -} diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 6b5a06888deb..937897023340 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -806,8 +806,6 @@ protected: void UpdateGlobalHistoryTitle(nsIURI* aURI); - void GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; - // Dimensions of the docshell nsIntRect mBounds; nsString mName; diff --git a/docshell/base/nsILoadContext.idl b/docshell/base/nsILoadContext.idl index d3a39a676c79..98e8a2119171 100644 --- a/docshell/base/nsILoadContext.idl +++ b/docshell/base/nsILoadContext.idl @@ -20,7 +20,7 @@ interface nsIDOMElement; * can be queried for various information about where the load is * happening. */ -[builtinclass, scriptable, uuid(2813a7a3-d084-4d00-acd0-f76620315c02)] +[scriptable, uuid(2813a7a3-d084-4d00-acd0-f76620315c02)] interface nsILoadContext : nsISupports { /** @@ -139,8 +139,10 @@ interface nsILoadContext : nsISupports #ifdef MOZILLA_INTERNAL_API /** * The C++ getter for origin attributes. + * + * Defined in LoadContext.cpp */ - NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) = 0; + bool GetOriginAttributes(mozilla::OriginAttributes& aAttrs); #endif %} }; diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 7218e6def399..2dc245147f38 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -444,7 +444,7 @@ protected: // implement one interface. // XXXbz I wish we could just derive the _allcaps thing from _i -#define DECL_SHIM(_i, _allcaps, _customfwd) \ +#define DECL_SHIM(_i, _allcaps) \ class _i##Shim final : public nsIInterfaceRequestor, \ public _i \ { \ @@ -459,25 +459,17 @@ protected: NS_DECL_ISUPPORTS \ NS_FORWARD_NSIINTERFACEREQUESTOR(mIfReq->) \ NS_FORWARD_##_allcaps(mRealPtr->) \ - _customfwd \ private: \ nsCOMPtr mIfReq; \ nsCOMPtr<_i> mRealPtr; \ }; -#define DECL_FORWARD_CPP_GETORIGINATTRIBUTES \ - NS_IMETHODIMP_(void) \ - GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override \ - { \ - mRealPtr->GetOriginAttributes(aAttrs); \ - } - DECL_SHIM(nsILoadContext, NSILOADCONTEXT, DECL_FORWARD_CPP_GETORIGINATTRIBUTES) - DECL_SHIM(nsIProgressEventSink, NSIPROGRESSEVENTSINK, ) - DECL_SHIM(nsIChannelEventSink, NSICHANNELEVENTSINK, ) - DECL_SHIM(nsISecurityEventSink, NSISECURITYEVENTSINK, ) - DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER, ) + DECL_SHIM(nsILoadContext, NSILOADCONTEXT) + DECL_SHIM(nsIProgressEventSink, NSIPROGRESSEVENTSINK) + DECL_SHIM(nsIChannelEventSink, NSICHANNELEVENTSINK) + DECL_SHIM(nsISecurityEventSink, NSISECURITYEVENTSINK) + DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER) #undef DECL_SHIM -#undef DECL_FORWARD_CPP_GETORIGINATTRIBUTES }; /** diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index e6e144df1a89..87163e1bcb91 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -3020,7 +3020,6 @@ public: NS_IMETHOD SetPrivateBrowsing(bool) NO_IMPL NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool*) NO_IMPL NS_IMETHOD GetOriginAttributes(JS::MutableHandleValue) NO_IMPL - NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override {} NS_IMETHOD GetUseRemoteTabs(bool*) NO_IMPL NS_IMETHOD SetRemoteTabs(bool) NO_IMPL NS_IMETHOD GetUseTrackingProtection(bool*) NO_IMPL diff --git a/dom/offline/nsDOMOfflineResourceList.cpp b/dom/offline/nsDOMOfflineResourceList.cpp index b6b49670b8b7..a02b2956245e 100644 --- a/dom/offline/nsDOMOfflineResourceList.cpp +++ b/dom/offline/nsDOMOfflineResourceList.cpp @@ -815,7 +815,8 @@ nsDOMOfflineResourceList::CacheKeys() nsAutoCString originSuffix; if (loadContext) { mozilla::OriginAttributes oa; - loadContext->GetOriginAttributes(oa); + bool ok = loadContext->GetOriginAttributes(oa); + NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED); oa.CreateSuffix(originSuffix); } diff --git a/uriloader/prefetch/OfflineCacheUpdateParent.cpp b/uriloader/prefetch/OfflineCacheUpdateParent.cpp index f10821292b71..c77f2b49a02e 100644 --- a/uriloader/prefetch/OfflineCacheUpdateParent.cpp +++ b/uriloader/prefetch/OfflineCacheUpdateParent.cpp @@ -276,14 +276,6 @@ OfflineCacheUpdateParent::GetOriginAttributes(JS::MutableHandleValue aAttrs) return NS_OK; } -NS_IMETHODIMP_(void) -OfflineCacheUpdateParent::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) -{ - if (mLoadingPrincipal) { - aAttrs = mLoadingPrincipal->OriginAttributesRef(); - } -} - NS_IMETHODIMP OfflineCacheUpdateParent::GetUseTrackingProtection(bool* aUseTrackingProtection) { diff --git a/uriloader/prefetch/OfflineCacheUpdateParent.h b/uriloader/prefetch/OfflineCacheUpdateParent.h index ee3c22ea74cd..f6dbc1cb2a6f 100644 --- a/uriloader/prefetch/OfflineCacheUpdateParent.h +++ b/uriloader/prefetch/OfflineCacheUpdateParent.h @@ -54,8 +54,6 @@ public: private: ~OfflineCacheUpdateParent(); - void GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; - bool mIPCClosed; nsCOMPtr mLoadingPrincipal; From a60b290b5651716ac036475378e7616fd32806d6 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Wed, 22 Mar 2017 09:05:36 -0400 Subject: [PATCH 75/96] Bug 1343499 - Expose native image sizes to imagelib users. r=tnikkel --- image/DynamicImage.cpp | 6 ++ image/DynamicImage.h | 1 + image/FrameTimeout.h | 119 ++++++++++++++++++++++ image/ImageMetadata.h | 13 ++- image/ImageOps.cpp | 110 ++++++++++++++++++-- image/ImageOps.h | 61 ++++++++++- image/ImageWrapper.cpp | 6 ++ image/ImageWrapper.h | 1 + image/OrientedImage.cpp | 16 +++ image/OrientedImage.h | 1 + image/RasterImage.cpp | 19 ++++ image/RasterImage.h | 2 + image/VectorImage.cpp | 7 ++ image/VectorImage.h | 1 + image/decoders/nsICODecoder.cpp | 2 + image/imgFrame.h | 101 +----------------- image/imgIContainer.idl | 4 + image/moz.build | 2 + image/test/gtest/Common.cpp | 6 ++ image/test/gtest/Common.h | 2 + image/test/gtest/TestDecodeToSurface.cpp | 84 +++++++++++++-- image/test/gtest/TestDecoders.cpp | 84 +++++++++++++++ image/test/gtest/green-multiple-sizes.ico | Bin 0 -> 14144 bytes image/test/gtest/moz.build | 1 + 24 files changed, 530 insertions(+), 119 deletions(-) create mode 100644 image/FrameTimeout.h create mode 100644 image/test/gtest/green-multiple-sizes.ico diff --git a/image/DynamicImage.cpp b/image/DynamicImage.cpp index d6444066a9e9..47c920944c3e 100644 --- a/image/DynamicImage.cpp +++ b/image/DynamicImage.cpp @@ -127,6 +127,12 @@ DynamicImage::GetHeight(int32_t* aHeight) return NS_OK; } +nsresult +DynamicImage::GetNativeSizes(nsTArray& aNativeSizes) const +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + NS_IMETHODIMP DynamicImage::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/DynamicImage.h b/image/DynamicImage.h index a39a29b8e37e..09c6ed550a25 100644 --- a/image/DynamicImage.h +++ b/image/DynamicImage.h @@ -31,6 +31,7 @@ public: } // Inherited methods from Image. + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual already_AddRefed GetProgressTracker() override; virtual size_t SizeOfSourceWithComputedFallback( MallocSizeOf aMallocSizeOf) const override; diff --git a/image/FrameTimeout.h b/image/FrameTimeout.h new file mode 100644 index 000000000000..4070bba65b2b --- /dev/null +++ b/image/FrameTimeout.h @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_image_FrameTimeout_h +#define mozilla_image_FrameTimeout_h + +#include +#include "mozilla/Assertions.h" + +namespace mozilla { +namespace image { + +/** + * FrameTimeout wraps a frame timeout value (measured in milliseconds) after + * first normalizing it. This normalization is necessary because some tools + * generate incorrect frame timeout values which we nevertheless have to + * support. For this reason, code that deals with frame timeouts should always + * use a FrameTimeout value rather than the raw value from the image header. + */ +struct FrameTimeout +{ + /** + * @return a FrameTimeout of zero. This should be used only for math + * involving FrameTimeout values. You can't obtain a zero FrameTimeout from + * FromRawMilliseconds(). + */ + static FrameTimeout Zero() { return FrameTimeout(0); } + + /// @return an infinite FrameTimeout. + static FrameTimeout Forever() { return FrameTimeout(-1); } + + /// @return a FrameTimeout obtained by normalizing a raw timeout value. + static FrameTimeout FromRawMilliseconds(int32_t aRawMilliseconds) + { + // Normalize all infinite timeouts to the same value. + if (aRawMilliseconds < 0) { + return FrameTimeout::Forever(); + } + + // Very small timeout values are problematic for two reasons: we don't want + // to burn energy redrawing animated images extremely fast, and broken tools + // generate these values when they actually want a "default" value, so such + // images won't play back right without normalization. For some context, + // see bug 890743, bug 125137, bug 139677, and bug 207059. The historical + // behavior of IE and Opera was: + // IE 6/Win: + // 10 - 50ms is normalized to 100ms. + // >50ms is used unnormalized. + // Opera 7 final/Win: + // 10ms is normalized to 100ms. + // >10ms is used unnormalized. + if (aRawMilliseconds >= 0 && aRawMilliseconds <= 10 ) { + return FrameTimeout(100); + } + + // The provided timeout value is OK as-is. + return FrameTimeout(aRawMilliseconds); + } + + bool operator==(const FrameTimeout& aOther) const + { + return mTimeout == aOther.mTimeout; + } + + bool operator!=(const FrameTimeout& aOther) const { return !(*this == aOther); } + + FrameTimeout operator+(const FrameTimeout& aOther) + { + if (*this == Forever() || aOther == Forever()) { + return Forever(); + } + + return FrameTimeout(mTimeout + aOther.mTimeout); + } + + FrameTimeout& operator+=(const FrameTimeout& aOther) + { + *this = *this + aOther; + return *this; + } + + /** + * @return this FrameTimeout's value in milliseconds. Illegal to call on a + * an infinite FrameTimeout value. + */ + uint32_t AsMilliseconds() const + { + if (*this == Forever()) { + MOZ_ASSERT_UNREACHABLE("Calling AsMilliseconds() on an infinite FrameTimeout"); + return 100; // Fail to something sane. + } + + return uint32_t(mTimeout); + } + + /** + * @return this FrameTimeout value encoded so that non-negative values + * represent a timeout in milliseconds, and -1 represents an infinite + * timeout. + * + * XXX(seth): This is a backwards compatibility hack that should be removed. + */ + int32_t AsEncodedValueDeprecated() const { return mTimeout; } + +private: + explicit FrameTimeout(int32_t aTimeout) + : mTimeout(aTimeout) + { } + + int32_t mTimeout; +}; + +} // namespace image +} // namespace mozilla + +#endif // mozilla_image_FrameTimeout_h diff --git a/image/ImageMetadata.h b/image/ImageMetadata.h index 05f5729802c7..b1a2edfb03fd 100644 --- a/image/ImageMetadata.h +++ b/image/ImageMetadata.h @@ -11,12 +11,11 @@ #include "mozilla/Maybe.h" #include "nsSize.h" #include "Orientation.h" +#include "FrameTimeout.h" namespace mozilla { namespace image { -class RasterImage; - // The metadata about an image that decoders accumulate as they decode. class ImageMetadata { @@ -64,6 +63,13 @@ public: nsIntSize GetSize() const { return *mSize; } bool HasSize() const { return mSize.isSome(); } + void AddNativeSize(const nsIntSize& aSize) + { + mNativeSizes.AppendElement(aSize); + } + + const nsTArray& GetNativeSizes() const { return mNativeSizes; } + Orientation GetOrientation() const { return *mOrientation; } bool HasOrientation() const { return mOrientation.isSome(); } @@ -90,6 +96,9 @@ private: Maybe mSize; Maybe mOrientation; + // Sizes the image can natively decode to. + nsTArray mNativeSizes; + bool mHasAnimation : 1; }; diff --git a/image/ImageOps.cpp b/image/ImageOps.cpp index d1d5da283642..fb4fc8fb7075 100644 --- a/image/ImageOps.cpp +++ b/image/ImageOps.cpp @@ -14,6 +14,7 @@ #include "FrozenImage.h" #include "IDecodingTask.h" #include "Image.h" +#include "ImageMetadata.h" #include "imgIContainer.h" #include "mozilla/gfx/2D.h" #include "nsStreamUtils.h" @@ -79,10 +80,27 @@ ImageOps::CreateFromDrawable(gfxDrawable* aDrawable) return drawableImage.forget(); } -/* static */ already_AddRefed -ImageOps::DecodeToSurface(nsIInputStream* aInputStream, - const nsACString& aMimeType, - uint32_t aFlags) +class ImageOps::ImageBufferImpl final : public ImageOps::ImageBuffer { +public: + ImageBufferImpl(already_AddRefed aSourceBuffer) + : mSourceBuffer(aSourceBuffer) + { } + +protected: + ~ImageBufferImpl() override { } + + virtual already_AddRefed GetSourceBuffer() + { + RefPtr sourceBuffer = mSourceBuffer; + return sourceBuffer.forget(); + } + +private: + RefPtr mSourceBuffer; +}; + +/* static */ already_AddRefed +ImageOps::CreateImageBuffer(nsIInputStream* aInputStream) { MOZ_ASSERT(aInputStream); @@ -107,7 +125,7 @@ ImageOps::DecodeToSurface(nsIInputStream* aInputStream, } // Write the data into a SourceBuffer. - NotNull> sourceBuffer = WrapNotNull(new SourceBuffer()); + RefPtr sourceBuffer = new SourceBuffer(); sourceBuffer->ExpectLength(length); rv = sourceBuffer->AppendFromInputStream(inputStream, length); if (NS_FAILED(rv)) { @@ -122,12 +140,90 @@ ImageOps::DecodeToSurface(nsIInputStream* aInputStream, } sourceBuffer->Complete(NS_OK); + RefPtr imageBuffer = new ImageBufferImpl(sourceBuffer.forget()); + return imageBuffer.forget(); +} + +/* static */ nsresult +ImageOps::DecodeMetadata(nsIInputStream* aInputStream, + const nsACString& aMimeType, + ImageMetadata& aMetadata) +{ + RefPtr buffer = CreateImageBuffer(aInputStream); + return DecodeMetadata(buffer, aMimeType, aMetadata); +} + +/* static */ nsresult +ImageOps::DecodeMetadata(ImageBuffer* aBuffer, + const nsACString& aMimeType, + ImageMetadata& aMetadata) +{ + if (!aBuffer) { + return NS_ERROR_FAILURE; + } + + RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); + if (NS_WARN_IF(!sourceBuffer)) { + return NS_ERROR_FAILURE; + } + // Create a decoder. DecoderType decoderType = DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); RefPtr decoder = - DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, - Nothing(), ToSurfaceFlags(aFlags)); + DecoderFactory::CreateAnonymousMetadataDecoder(decoderType, + WrapNotNull(sourceBuffer)); + if (!decoder) { + return NS_ERROR_FAILURE; + } + + // Run the decoder synchronously. + RefPtr task = new AnonymousDecodingTask(WrapNotNull(decoder)); + task->Run(); + if (!decoder->GetDecodeDone() || decoder->HasError()) { + return NS_ERROR_FAILURE; + } + + aMetadata = decoder->GetImageMetadata(); + if (aMetadata.GetNativeSizes().IsEmpty() && aMetadata.HasSize()) { + aMetadata.AddNativeSize(aMetadata.GetSize()); + } + + return NS_OK; +} + +/* static */ already_AddRefed +ImageOps::DecodeToSurface(nsIInputStream* aInputStream, + const nsACString& aMimeType, + uint32_t aFlags, + Maybe aSize /* = Nothing() */) +{ + RefPtr buffer = CreateImageBuffer(aInputStream); + return DecodeToSurface(buffer, aMimeType, aFlags, aSize); +} + +/* static */ already_AddRefed +ImageOps::DecodeToSurface(ImageBuffer* aBuffer, + const nsACString& aMimeType, + uint32_t aFlags, + Maybe aSize /* = Nothing() */) +{ + if (!aBuffer) { + return nullptr; + } + + RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); + if (NS_WARN_IF(!sourceBuffer)) { + return nullptr; + } + + // Create a decoder. + DecoderType decoderType = + DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); + RefPtr decoder = + DecoderFactory::CreateAnonymousDecoder(decoderType, + WrapNotNull(sourceBuffer), + aSize, ToSurfaceFlags(aFlags)); if (!decoder) { return nullptr; } diff --git a/image/ImageOps.h b/image/ImageOps.h index 7a8e19be3441..5a089fd16b03 100644 --- a/image/ImageOps.h +++ b/image/ImageOps.h @@ -9,6 +9,7 @@ #include "nsCOMPtr.h" #include "nsRect.h" +#include "ImageMetadata.h" class gfxDrawable; class imgIContainer; @@ -24,10 +25,23 @@ namespace image { class Image; struct Orientation; +class SourceBuffer; class ImageOps { public: + class ImageBuffer { + public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageOps::ImageBuffer); + protected: + friend class ImageOps; + + ImageBuffer() { } + virtual ~ImageBuffer() { } + + virtual already_AddRefed GetSourceBuffer() = 0; + }; + /** * Creates a version of an existing image which does not animate and is frozen * at the first frame. @@ -74,6 +88,39 @@ public: static already_AddRefed CreateFromDrawable(gfxDrawable* aDrawable); + /** + * Create a buffer to be used with DecodeMetadata and DecodeToSurface. Reusing + * an ImageBuffer representing the given input stream is more efficient if one + * has multiple Decode* calls to make on that stream. + * + * @param aInputStream An input stream containing an encoded image. + * @return An image buffer derived from the input stream. + */ + static already_AddRefed + CreateImageBuffer(nsIInputStream* aInputStream); + + /** + * Decodes an image's metadata from an nsIInputStream into the given + * structure. This function may be called off-main-thread. + * + * @param aInputStream An input stream containing an encoded image. + * @param aMimeType The MIME type of the image. + * @param aMetadata Where the image metadata is stored upon success. + * @return The status of the operation. + */ + static nsresult + DecodeMetadata(nsIInputStream* aInputStream, + const nsACString& aMimeType, + ImageMetadata& aMetadata); + + /** + * Same as above but takes an ImageBuffer instead of nsIInputStream. + */ + static nsresult + DecodeMetadata(ImageBuffer* aBuffer, + const nsACString& aMimeType, + ImageMetadata& aMetadata); + /** * Decodes an image from an nsIInputStream directly into a SourceSurface, * without ever creating an Image or imgIContainer (which are mostly @@ -89,9 +136,21 @@ public: static already_AddRefed DecodeToSurface(nsIInputStream* aInputStream, const nsACString& aMimeType, - uint32_t aFlags); + uint32_t aFlags, + Maybe aSize = Nothing()); + + /** + * Same as above but takes an ImageBuffer instead of nsIInputStream. + */ + static already_AddRefed + DecodeToSurface(ImageBuffer* aBuffer, + const nsACString& aMimeType, + uint32_t aFlags, + Maybe aSize = Nothing()); private: + class ImageBufferImpl; + // This is a static utility class, so disallow instantiation. virtual ~ImageOps() = 0; }; diff --git a/image/ImageWrapper.cpp b/image/ImageWrapper.cpp index dfc76641fd6f..852479904567 100644 --- a/image/ImageWrapper.cpp +++ b/image/ImageWrapper.cpp @@ -139,6 +139,12 @@ ImageWrapper::GetHeight(int32_t* aHeight) return mInnerImage->GetHeight(aHeight); } +nsresult +ImageWrapper::GetNativeSizes(nsTArray& aNativeSizes) const +{ + return mInnerImage->GetNativeSizes(aNativeSizes); +} + NS_IMETHODIMP ImageWrapper::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/ImageWrapper.h b/image/ImageWrapper.h index 94cf0948b537..19e9cb858232 100644 --- a/image/ImageWrapper.h +++ b/image/ImageWrapper.h @@ -22,6 +22,7 @@ public: NS_DECL_IMGICONTAINER // Inherited methods from Image. + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual already_AddRefed GetProgressTracker() override; virtual size_t diff --git a/image/OrientedImage.cpp b/image/OrientedImage.cpp index 951b0acbc94d..79767e2a796a 100644 --- a/image/OrientedImage.cpp +++ b/image/OrientedImage.cpp @@ -46,6 +46,22 @@ OrientedImage::GetHeight(int32_t* aHeight) } } +nsresult +OrientedImage::GetNativeSizes(nsTArray& aNativeSizes) const +{ + nsresult rv = InnerImage()->GetNativeSizes(aNativeSizes); + + if (mOrientation.SwapsWidthAndHeight()) { + auto i = aNativeSizes.Length(); + while (i > 0) { + --i; + swap(aNativeSizes[i].width, aNativeSizes[i].height); + } + } + + return rv; +} + NS_IMETHODIMP OrientedImage::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/OrientedImage.h b/image/OrientedImage.h index 2edf05de9f50..d1291ea74b20 100644 --- a/image/OrientedImage.h +++ b/image/OrientedImage.h @@ -30,6 +30,7 @@ public: NS_IMETHOD GetWidth(int32_t* aWidth) override; NS_IMETHOD GetHeight(int32_t* aHeight) override; + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override; NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override; NS_IMETHOD_(already_AddRefed) diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index b98744850295..b3da4ff3697e 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -220,6 +220,24 @@ RasterImage::GetHeight(int32_t* aHeight) return NS_OK; } +//****************************************************************************** +nsresult +RasterImage::GetNativeSizes(nsTArray& aNativeSizes) const +{ + if (mError) { + return NS_ERROR_FAILURE; + } + + if (mNativeSizes.IsEmpty()) { + aNativeSizes.Clear(); + aNativeSizes.AppendElement(mSize); + } else { + aNativeSizes = mNativeSizes; + } + + return NS_OK; +} + //****************************************************************************** NS_IMETHODIMP RasterImage::GetIntrinsicSize(nsSize* aSize) @@ -703,6 +721,7 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata, // Set the size and flag that we have it. mSize = size; mOrientation = orientation; + mNativeSizes = aMetadata.GetNativeSizes(); mHasSize = true; } diff --git a/image/RasterImage.h b/image/RasterImage.h index 09fa18b4df65..023985669a7a 100644 --- a/image/RasterImage.h +++ b/image/RasterImage.h @@ -160,6 +160,7 @@ public: NS_DECL_IMGICONTAINERDEBUG #endif + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual nsresult StartAnimation() override; virtual nsresult StopAnimation() override; @@ -380,6 +381,7 @@ private: private: // data nsIntSize mSize; + nsTArray mNativeSizes; Orientation mOrientation; /// If this has a value, we're waiting for SetSize() to send the load event. diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index fa3ecb8bc049..7c650fc7545c 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -520,6 +520,13 @@ VectorImage::GetWidth(int32_t* aWidth) return NS_OK; } +//****************************************************************************** +nsresult +VectorImage::GetNativeSizes(nsTArray& aNativeSizes) const +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + //****************************************************************************** NS_IMETHODIMP_(void) VectorImage::RequestRefresh(const TimeStamp& aTime) diff --git a/image/VectorImage.h b/image/VectorImage.h index cb55e057753c..a05c92f3cf38 100644 --- a/image/VectorImage.h +++ b/image/VectorImage.h @@ -34,6 +34,7 @@ public: // (no public constructor - use ImageFactory) // Methods inherited from Image + nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; virtual void CollectSizeOfSurfaces(nsTArray& aCounters, diff --git a/image/decoders/nsICODecoder.cpp b/image/decoders/nsICODecoder.cpp index 85b3c139b0d7..d8171431ea83 100644 --- a/image/decoders/nsICODecoder.cpp +++ b/image/decoders/nsICODecoder.cpp @@ -242,6 +242,8 @@ nsICODecoder::ReadDirEntry(const char* aData) } } + mImageMetadata.AddNativeSize(entrySize); + if (desiredSize) { // Calculate the delta between this resource's size and the desired size, so // we can see if it is better than our current-best option. In the case of diff --git a/image/imgFrame.h b/image/imgFrame.h index 77ff3507b177..bd858e088dcf 100644 --- a/image/imgFrame.h +++ b/image/imgFrame.h @@ -11,6 +11,7 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/Monitor.h" #include "mozilla/Move.h" +#include "FrameTimeout.h" #include "gfxDrawable.h" #include "imgIContainer.h" #include "MainThreadUtils.h" @@ -46,106 +47,6 @@ enum class Opacity : uint8_t { SOME_TRANSPARENCY }; -/** - * FrameTimeout wraps a frame timeout value (measured in milliseconds) after - * first normalizing it. This normalization is necessary because some tools - * generate incorrect frame timeout values which we nevertheless have to - * support. For this reason, code that deals with frame timeouts should always - * use a FrameTimeout value rather than the raw value from the image header. - */ -struct FrameTimeout -{ - /** - * @return a FrameTimeout of zero. This should be used only for math - * involving FrameTimeout values. You can't obtain a zero FrameTimeout from - * FromRawMilliseconds(). - */ - static FrameTimeout Zero() { return FrameTimeout(0); } - - /// @return an infinite FrameTimeout. - static FrameTimeout Forever() { return FrameTimeout(-1); } - - /// @return a FrameTimeout obtained by normalizing a raw timeout value. - static FrameTimeout FromRawMilliseconds(int32_t aRawMilliseconds) - { - // Normalize all infinite timeouts to the same value. - if (aRawMilliseconds < 0) { - return FrameTimeout::Forever(); - } - - // Very small timeout values are problematic for two reasons: we don't want - // to burn energy redrawing animated images extremely fast, and broken tools - // generate these values when they actually want a "default" value, so such - // images won't play back right without normalization. For some context, - // see bug 890743, bug 125137, bug 139677, and bug 207059. The historical - // behavior of IE and Opera was: - // IE 6/Win: - // 10 - 50ms is normalized to 100ms. - // >50ms is used unnormalized. - // Opera 7 final/Win: - // 10ms is normalized to 100ms. - // >10ms is used unnormalized. - if (aRawMilliseconds >= 0 && aRawMilliseconds <= 10 ) { - return FrameTimeout(100); - } - - // The provided timeout value is OK as-is. - return FrameTimeout(aRawMilliseconds); - } - - bool operator==(const FrameTimeout& aOther) const - { - return mTimeout == aOther.mTimeout; - } - - bool operator!=(const FrameTimeout& aOther) const { return !(*this == aOther); } - - FrameTimeout operator+(const FrameTimeout& aOther) - { - if (*this == Forever() || aOther == Forever()) { - return Forever(); - } - - return FrameTimeout(mTimeout + aOther.mTimeout); - } - - FrameTimeout& operator+=(const FrameTimeout& aOther) - { - *this = *this + aOther; - return *this; - } - - /** - * @return this FrameTimeout's value in milliseconds. Illegal to call on a - * an infinite FrameTimeout value. - */ - uint32_t AsMilliseconds() const - { - if (*this == Forever()) { - MOZ_ASSERT_UNREACHABLE("Calling AsMilliseconds() on an infinite FrameTimeout"); - return 100; // Fail to something sane. - } - - return uint32_t(mTimeout); - } - - /** - * @return this FrameTimeout value encoded so that non-negative values - * represent a timeout in milliseconds, and -1 represents an infinite - * timeout. - * - * XXX(seth): This is a backwards compatibility hack that should be removed. - */ - int32_t AsEncodedValueDeprecated() const { return mTimeout; } - -private: - explicit FrameTimeout(int32_t aTimeout) - : mTimeout(aTimeout) - { } - - int32_t mTimeout; -}; - /** * AnimationData contains all of the information necessary for using an imgFrame * as part of an animation. diff --git a/image/imgIContainer.idl b/image/imgIContainer.idl index 640eae352558..eed28e2668d9 100644 --- a/image/imgIContainer.idl +++ b/image/imgIContainer.idl @@ -90,6 +90,10 @@ interface imgIContainer : nsISupports */ readonly attribute int32_t height; + %{C++ + virtual nsresult GetNativeSizes(nsTArray& aNativeSizes) const = 0; + %} + /** * The intrinsic size of this image in appunits. If the image has no intrinsic * size in a dimension, -1 will be returned for that dimension. In the case of diff --git a/image/moz.build b/image/moz.build index c3a3a610fd8e..8ccb30247e91 100644 --- a/image/moz.build +++ b/image/moz.build @@ -37,8 +37,10 @@ XPIDL_MODULE = 'imglib2' EXPORTS += [ 'DrawResult.h', + 'FrameTimeout.h', 'ImageCacheKey.h', 'ImageLogging.h', + 'ImageMetadata.h', 'ImageOps.h', 'ImageRegion.h', 'imgLoader.h', diff --git a/image/test/gtest/Common.cpp b/image/test/gtest/Common.cpp index 4be34461c71c..4bc7fce1c32e 100644 --- a/image/test/gtest/Common.cpp +++ b/image/test/gtest/Common.cpp @@ -679,5 +679,11 @@ ImageTestCase TruncatedSmallGIFTestCase() return ImageTestCase("green-1x1-truncated.gif", "image/gif", IntSize(1, 1)); } +ImageTestCase GreenMultipleSizesICOTestCase() +{ + return ImageTestCase("green-multiple-sizes.ico", "image/x-icon", + IntSize(256, 256)); +} + } // namespace image } // namespace mozilla diff --git a/image/test/gtest/Common.h b/image/test/gtest/Common.h index 33fc26e750f8..63b8b9b70026 100644 --- a/image/test/gtest/Common.h +++ b/image/test/gtest/Common.h @@ -414,6 +414,8 @@ ImageTestCase DownscaledTransparentICOWithANDMaskTestCase(); ImageTestCase TruncatedSmallGIFTestCase(); +ImageTestCase GreenMultipleSizesICOTestCase(); + } // namespace image } // namespace mozilla diff --git a/image/test/gtest/TestDecodeToSurface.cpp b/image/test/gtest/TestDecodeToSurface.cpp index dd22d4308d9b..f5762d84c172 100644 --- a/image/test/gtest/TestDecodeToSurface.cpp +++ b/image/test/gtest/TestDecodeToSurface.cpp @@ -27,9 +27,11 @@ class DecodeToSurfaceRunnable : public Runnable public: DecodeToSurfaceRunnable(RefPtr& aSurface, nsIInputStream* aInputStream, + ImageOps::ImageBuffer* aImageBuffer, const ImageTestCase& aTestCase) : mSurface(aSurface) , mInputStream(aInputStream) + , mImageBuffer(aImageBuffer) , mTestCase(aTestCase) { } @@ -41,16 +43,35 @@ public: void Go() { - mSurface = - ImageOps::DecodeToSurface(mInputStream, - nsDependentCString(mTestCase.mMimeType), - imgIContainer::DECODE_FLAGS_DEFAULT); + Maybe outputSize; + if (mTestCase.mOutputSize != mTestCase.mSize) { + outputSize.emplace(mTestCase.mOutputSize); + } + + if (mImageBuffer) { + mSurface = + ImageOps::DecodeToSurface(mImageBuffer, + nsDependentCString(mTestCase.mMimeType), + imgIContainer::DECODE_FLAGS_DEFAULT, + outputSize); + } else { + mSurface = + ImageOps::DecodeToSurface(mInputStream, + nsDependentCString(mTestCase.mMimeType), + imgIContainer::DECODE_FLAGS_DEFAULT, + outputSize); + } ASSERT_TRUE(mSurface != nullptr); EXPECT_TRUE(mSurface->IsDataSourceSurface()); EXPECT_TRUE(mSurface->GetFormat() == SurfaceFormat::B8G8R8X8 || mSurface->GetFormat() == SurfaceFormat::B8G8R8A8); - EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); + + if (outputSize) { + EXPECT_EQ(*outputSize, mSurface->GetSize()); + } else { + EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); + } EXPECT_TRUE(IsSolidColor(mSurface, BGRAColor::Green(), mTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0)); @@ -59,14 +80,19 @@ public: private: RefPtr& mSurface; nsCOMPtr mInputStream; + RefPtr mImageBuffer; ImageTestCase mTestCase; }; static void -RunDecodeToSurface(const ImageTestCase& aTestCase) +RunDecodeToSurface(const ImageTestCase& aTestCase, + ImageOps::ImageBuffer* aImageBuffer = nullptr) { - nsCOMPtr inputStream = LoadFile(aTestCase.mPath); - ASSERT_TRUE(inputStream != nullptr); + nsCOMPtr inputStream; + if (!aImageBuffer) { + inputStream = LoadFile(aTestCase.mPath); + ASSERT_TRUE(inputStream != nullptr); + } nsCOMPtr thread; nsresult rv = @@ -77,7 +103,7 @@ RunDecodeToSurface(const ImageTestCase& aTestCase) // DecodeToSurface doesn't require any main-thread-only code. RefPtr surface; nsCOMPtr runnable = - new DecodeToSurfaceRunnable(surface, inputStream, aTestCase); + new DecodeToSurfaceRunnable(surface, inputStream, aImageBuffer, aTestCase); thread->Dispatch(runnable, nsIThread::DISPATCH_SYNC); thread->Shutdown(); @@ -122,3 +148,43 @@ TEST_F(ImageDecodeToSurface, Corrupt) imgIContainer::DECODE_FLAGS_DEFAULT); EXPECT_TRUE(surface == nullptr); } + +TEST_F(ImageDecodeToSurface, ICOMultipleSizes) +{ + ImageTestCase testCase = GreenMultipleSizesICOTestCase(); + + nsCOMPtr inputStream = LoadFile(testCase.mPath); + ASSERT_TRUE(inputStream != nullptr); + + RefPtr buffer = + ImageOps::CreateImageBuffer(inputStream); + ASSERT_TRUE(buffer != nullptr); + + ImageMetadata metadata; + nsresult rv = ImageOps::DecodeMetadata(buffer, + nsDependentCString(testCase.mMimeType), + metadata); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_TRUE(metadata.HasSize()); + EXPECT_EQ(testCase.mSize, metadata.GetSize()); + + const nsTArray& nativeSizes = metadata.GetNativeSizes(); + ASSERT_EQ(6u, nativeSizes.Length()); + + IntSize expectedSizes[] = { + IntSize(16, 16), + IntSize(32, 32), + IntSize(64, 64), + IntSize(128, 128), + IntSize(256, 256), + IntSize(256, 128), + }; + + for (int i = 0; i < 6; ++i) { + EXPECT_EQ(expectedSizes[i], nativeSizes[i]); + + // Request decoding at native size + testCase.mOutputSize = nativeSizes[i]; + RunDecodeToSurface(testCase, buffer); + } +} diff --git a/image/test/gtest/TestDecoders.cpp b/image/test/gtest/TestDecoders.cpp index d39b8e404a60..16b17ac63b3f 100644 --- a/image/test/gtest/TestDecoders.cpp +++ b/image/test/gtest/TestDecoders.cpp @@ -672,3 +672,87 @@ TEST_F(ImageDecoders, TruncatedSmallGIFSingleChunk) { CheckDecoderSingleChunk(TruncatedSmallGIFTestCase()); } + +TEST_F(ImageDecoders, MultipleSizesICOSingleChunk) +{ + ImageTestCase testCase = GreenMultipleSizesICOTestCase(); + + // Create an image. + RefPtr image = + ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType)); + ASSERT_TRUE(!image->HasError()); + + nsCOMPtr inputStream = LoadFile(testCase.mPath); + ASSERT_TRUE(inputStream); + + // Figure out how much data we have. + uint64_t length; + nsresult rv = inputStream->Available(&length); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + // Write the data into the image. + rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0, + static_cast(length)); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + // Let the image know we've sent all the data. + rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true); + ASSERT_TRUE(NS_SUCCEEDED(rv)); + + RefPtr tracker = image->GetProgressTracker(); + tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE); + + // Use GetFrame() to force a sync decode of the image. + RefPtr surface = + image->GetFrame(imgIContainer::FRAME_CURRENT, + imgIContainer::FLAG_SYNC_DECODE); + + // Ensure that the image's metadata meets our expectations. + IntSize imageSize(0, 0); + rv = image->GetWidth(&imageSize.width); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + rv = image->GetHeight(&imageSize.height); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + + EXPECT_EQ(testCase.mSize.width, imageSize.width); + EXPECT_EQ(testCase.mSize.height, imageSize.height); + + nsTArray nativeSizes; + rv = image->GetNativeSizes(nativeSizes); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_EQ(6u, nativeSizes.Length()); + + IntSize expectedSizes[] = { + IntSize(16, 16), + IntSize(32, 32), + IntSize(64, 64), + IntSize(128, 128), + IntSize(256, 256), + IntSize(256, 128) + }; + + for (int i = 0; i < 6; ++i) { + EXPECT_EQ(expectedSizes[i], nativeSizes[i]); + } + + RefPtr image90 = + ImageOps::Orient(image, Orientation(Angle::D90, Flip::Unflipped)); + rv = image90->GetNativeSizes(nativeSizes); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_EQ(6u, nativeSizes.Length()); + + for (int i = 0; i < 5; ++i) { + EXPECT_EQ(expectedSizes[i], nativeSizes[i]); + } + EXPECT_EQ(IntSize(128, 256), nativeSizes[5]); + + RefPtr image180 = + ImageOps::Orient(image, Orientation(Angle::D180, Flip::Unflipped)); + rv = image180->GetNativeSizes(nativeSizes); + EXPECT_TRUE(NS_SUCCEEDED(rv)); + ASSERT_EQ(6u, nativeSizes.Length()); + + for (int i = 0; i < 6; ++i) { + EXPECT_EQ(expectedSizes[i], nativeSizes[i]); + } +} diff --git a/image/test/gtest/green-multiple-sizes.ico b/image/test/gtest/green-multiple-sizes.ico new file mode 100644 index 0000000000000000000000000000000000000000..b9463d0c897117204b2edacfa6cbfc4f5f61d771 GIT binary patch literal 14144 zcmeI$u}Z^09LMorsuU?iGF5aj4uYeb;1s1*3sS3eaC9mnh?}dy&3ACb06tZ(!iOf<#;`kn$9d6k7uQwnw00` zaUxyT{R2m&RA=t*nr^D^Qz==H);#5cg;n_hP}ZY(wYf8)+x>!>Ikgv!B;X9iE3tM2N({eIg8WY>=`o{tYb zv)pNI^-teFUZdEfx8di(`TWMvmqon9E8ga6@%BCpJMC`kVf*AdR5C+V;zwm7l&;4? wWulUxM*sl?5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0;O_{00SHw$wg3PC literal 0 HcmV?d00001 diff --git a/image/test/gtest/moz.build b/image/test/gtest/moz.build index ad69e098518c..3e37573dba04 100644 --- a/image/test/gtest/moz.build +++ b/image/test/gtest/moz.build @@ -47,6 +47,7 @@ TEST_HARNESS_FILES.gtest += [ 'first-frame-green.png', 'first-frame-padding.gif', 'green-1x1-truncated.gif', + 'green-multiple-sizes.ico', 'green.bmp', 'green.gif', 'green.ico', From 10e3a2668df60d066518d928a07c76913b850655 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 22 Mar 2017 15:46:17 +0100 Subject: [PATCH 76/96] Bug 1331058 - Add testcase. r=me --HG-- extra : rebase_source : 913525b712bdacfcf497a8421b3b6af153ba6522 --- js/src/jit-test/tests/ion/bug1331058.js | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 js/src/jit-test/tests/ion/bug1331058.js diff --git a/js/src/jit-test/tests/ion/bug1331058.js b/js/src/jit-test/tests/ion/bug1331058.js new file mode 100644 index 000000000000..ffb8f29196d5 --- /dev/null +++ b/js/src/jit-test/tests/ion/bug1331058.js @@ -0,0 +1,29 @@ +function foo(o, trigger) { + bar = function() { return o.getY(); }; + if (trigger) + assertEq(bar(), undefined); + return 1; +} +function O(o, trigger) { + this.a1 = 1; + this.a2 = 2; + this.a3 = 3; + this.a4 = 4; + this.x = foo(this, trigger); +} +O.prototype.getY = function() { + return this.x; +} +function test() { + with(this) {}; // No Ion. + var arr = []; + for (var i=0; i<100; i++) + arr.push(new O({y: i}, false)); + + for (var i=0; i<100; i++) + bar(); + + for (var i=0; i<300; i++) + arr.push(new O({y: i}, true)); +} +test(); From 8440f55d6ea8e8abc0581962e830bea586fb3375 Mon Sep 17 00:00:00 2001 From: Jan de Mooij Date: Wed, 22 Mar 2017 15:47:21 +0100 Subject: [PATCH 77/96] Bug 1346140 - Flatten external strings when creating dependent strings. r=jwalden,h4writer --HG-- extra : rebase_source : b62ac91f6734d6c2da2e2f0cefa8792c57d800f7 --- js/src/jit/CodeGenerator.cpp | 7 ++----- js/src/jit/MacroAssembler-inl.h | 13 +++++++++++++ js/src/jit/MacroAssembler.h | 1 + js/src/vm/String-inl.h | 3 +++ js/src/vm/String.cpp | 6 ++++++ 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 461e0d46e653..240ed55f0ab1 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -1206,7 +1206,7 @@ PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Re } // Check for a linear input string. - masm.branchIfRope(input, failure); + masm.branchIfRopeOrExternal(input, temp1, failure); // Get the RegExpShared for the RegExp. masm.loadPtr(Address(regexp, NativeObject::getFixedSlotOffset(RegExpObject::PRIVATE_SLOT)), temp1); @@ -7608,10 +7608,7 @@ CodeGenerator::visitSubstr(LSubstr* lir) // Use slow path for ropes. masm.bind(&nonZero); - static_assert(JSString::ROPE_FLAGS == 0, - "rope flags must be zero for (flags & TYPE_FLAGS_MASK) == 0 " - "to be a valid is-rope check"); - masm.branchTest32(Assembler::Zero, stringFlags, Imm32(JSString::TYPE_FLAGS_MASK), slowPath); + masm.branchIfRopeOrExternal(string, temp, slowPath); // Handle inlined strings by creating a FatInlineString. masm.branchTest32(Assembler::Zero, stringFlags, Imm32(JSString::INLINE_CHARS_BIT), ¬Inline); diff --git a/js/src/jit/MacroAssembler-inl.h b/js/src/jit/MacroAssembler-inl.h index d089c32f2295..edca338fab0e 100644 --- a/js/src/jit/MacroAssembler-inl.h +++ b/js/src/jit/MacroAssembler-inl.h @@ -395,6 +395,19 @@ MacroAssembler::branchIfRope(Register str, Label* label) branchTest32(Assembler::Zero, flags, Imm32(JSString::TYPE_FLAGS_MASK), label); } +void +MacroAssembler::branchIfRopeOrExternal(Register str, Register temp, Label* label) +{ + Address flags(str, JSString::offsetOfFlags()); + move32(Imm32(JSString::TYPE_FLAGS_MASK), temp); + and32(flags, temp); + + static_assert(JSString::ROPE_FLAGS == 0, "Rope type flags must be 0"); + branchTest32(Assembler::Zero, temp, temp, label); + + branch32(Assembler::Equal, temp, Imm32(JSString::EXTERNAL_FLAGS), label); +} + void MacroAssembler::branchLatin1String(Register string, Label* label) { diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index e6189bde6e01..2a0d8faefdf8 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -1113,6 +1113,7 @@ class MacroAssembler : public MacroAssemblerSpecific inline void branchIfTrueBool(Register reg, Label* label); inline void branchIfRope(Register str, Label* label); + inline void branchIfRopeOrExternal(Register str, Register temp, Label* label); inline void branchLatin1String(Register string, Label* label); inline void branchTwoByteString(Register string, Label* label); diff --git a/js/src/vm/String-inl.h b/js/src/vm/String-inl.h index 7dc628d02117..ff98dcc1d319 100644 --- a/js/src/vm/String-inl.h +++ b/js/src/vm/String-inl.h @@ -181,6 +181,9 @@ JSDependentString::new_(JSContext* cx, JSLinearString* baseArg, size_t start, : js::NewInlineString(cx, base, start, length); } + if (baseArg->isExternal() && !baseArg->ensureFlat(cx)) + return nullptr; + JSDependentString* str = static_cast(js::Allocate(cx)); if (str) { str->init(cx, baseArg, start, length); diff --git a/js/src/vm/String.cpp b/js/src/vm/String.cpp index 4a1ec1d3f9dc..67ddee95ca01 100644 --- a/js/src/vm/String.cpp +++ b/js/src/vm/String.cpp @@ -928,6 +928,9 @@ AutoStableStringChars::init(JSContext* cx, JSString* s) MOZ_ASSERT(state_ == Uninitialized); + if (linearString->isExternal() && !linearString->ensureFlat(cx)) + return false; + // If the chars are inline then we need to copy them since they may be moved // by a compacting GC. if (baseIsInline(linearString)) { @@ -959,6 +962,9 @@ AutoStableStringChars::initTwoByte(JSContext* cx, JSString* s) if (linearString->hasLatin1Chars()) return copyAndInflateLatin1Chars(cx, linearString); + if (linearString->isExternal() && !linearString->ensureFlat(cx)) + return false; + // If the chars are inline then we need to copy them since they may be moved // by a compacting GC. if (baseIsInline(linearString)) From c21c5cb4c8bfac525ba17a0cb5fb74761a504680 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Wed, 22 Mar 2017 11:04:30 -0400 Subject: [PATCH 78/96] Backed out changeset 619b5b27ce87 (bug 1343499) for CLOSED TREE build bustage r=backout --- image/DynamicImage.cpp | 6 -- image/DynamicImage.h | 1 - image/FrameTimeout.h | 119 ---------------------- image/ImageMetadata.h | 13 +-- image/ImageOps.cpp | 110 ++------------------ image/ImageOps.h | 61 +---------- image/ImageWrapper.cpp | 6 -- image/ImageWrapper.h | 1 - image/OrientedImage.cpp | 16 --- image/OrientedImage.h | 1 - image/RasterImage.cpp | 19 ---- image/RasterImage.h | 2 - image/VectorImage.cpp | 7 -- image/VectorImage.h | 1 - image/decoders/nsICODecoder.cpp | 2 - image/imgFrame.h | 101 +++++++++++++++++- image/imgIContainer.idl | 4 - image/moz.build | 2 - image/test/gtest/Common.cpp | 6 -- image/test/gtest/Common.h | 2 - image/test/gtest/TestDecodeToSurface.cpp | 84 ++------------- image/test/gtest/TestDecoders.cpp | 84 --------------- image/test/gtest/green-multiple-sizes.ico | Bin 14144 -> 0 bytes image/test/gtest/moz.build | 1 - 24 files changed, 119 insertions(+), 530 deletions(-) delete mode 100644 image/FrameTimeout.h delete mode 100644 image/test/gtest/green-multiple-sizes.ico diff --git a/image/DynamicImage.cpp b/image/DynamicImage.cpp index 47c920944c3e..d6444066a9e9 100644 --- a/image/DynamicImage.cpp +++ b/image/DynamicImage.cpp @@ -127,12 +127,6 @@ DynamicImage::GetHeight(int32_t* aHeight) return NS_OK; } -nsresult -DynamicImage::GetNativeSizes(nsTArray& aNativeSizes) const -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - NS_IMETHODIMP DynamicImage::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/DynamicImage.h b/image/DynamicImage.h index 09c6ed550a25..a39a29b8e37e 100644 --- a/image/DynamicImage.h +++ b/image/DynamicImage.h @@ -31,7 +31,6 @@ public: } // Inherited methods from Image. - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual already_AddRefed GetProgressTracker() override; virtual size_t SizeOfSourceWithComputedFallback( MallocSizeOf aMallocSizeOf) const override; diff --git a/image/FrameTimeout.h b/image/FrameTimeout.h deleted file mode 100644 index 4070bba65b2b..000000000000 --- a/image/FrameTimeout.h +++ /dev/null @@ -1,119 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_image_FrameTimeout_h -#define mozilla_image_FrameTimeout_h - -#include -#include "mozilla/Assertions.h" - -namespace mozilla { -namespace image { - -/** - * FrameTimeout wraps a frame timeout value (measured in milliseconds) after - * first normalizing it. This normalization is necessary because some tools - * generate incorrect frame timeout values which we nevertheless have to - * support. For this reason, code that deals with frame timeouts should always - * use a FrameTimeout value rather than the raw value from the image header. - */ -struct FrameTimeout -{ - /** - * @return a FrameTimeout of zero. This should be used only for math - * involving FrameTimeout values. You can't obtain a zero FrameTimeout from - * FromRawMilliseconds(). - */ - static FrameTimeout Zero() { return FrameTimeout(0); } - - /// @return an infinite FrameTimeout. - static FrameTimeout Forever() { return FrameTimeout(-1); } - - /// @return a FrameTimeout obtained by normalizing a raw timeout value. - static FrameTimeout FromRawMilliseconds(int32_t aRawMilliseconds) - { - // Normalize all infinite timeouts to the same value. - if (aRawMilliseconds < 0) { - return FrameTimeout::Forever(); - } - - // Very small timeout values are problematic for two reasons: we don't want - // to burn energy redrawing animated images extremely fast, and broken tools - // generate these values when they actually want a "default" value, so such - // images won't play back right without normalization. For some context, - // see bug 890743, bug 125137, bug 139677, and bug 207059. The historical - // behavior of IE and Opera was: - // IE 6/Win: - // 10 - 50ms is normalized to 100ms. - // >50ms is used unnormalized. - // Opera 7 final/Win: - // 10ms is normalized to 100ms. - // >10ms is used unnormalized. - if (aRawMilliseconds >= 0 && aRawMilliseconds <= 10 ) { - return FrameTimeout(100); - } - - // The provided timeout value is OK as-is. - return FrameTimeout(aRawMilliseconds); - } - - bool operator==(const FrameTimeout& aOther) const - { - return mTimeout == aOther.mTimeout; - } - - bool operator!=(const FrameTimeout& aOther) const { return !(*this == aOther); } - - FrameTimeout operator+(const FrameTimeout& aOther) - { - if (*this == Forever() || aOther == Forever()) { - return Forever(); - } - - return FrameTimeout(mTimeout + aOther.mTimeout); - } - - FrameTimeout& operator+=(const FrameTimeout& aOther) - { - *this = *this + aOther; - return *this; - } - - /** - * @return this FrameTimeout's value in milliseconds. Illegal to call on a - * an infinite FrameTimeout value. - */ - uint32_t AsMilliseconds() const - { - if (*this == Forever()) { - MOZ_ASSERT_UNREACHABLE("Calling AsMilliseconds() on an infinite FrameTimeout"); - return 100; // Fail to something sane. - } - - return uint32_t(mTimeout); - } - - /** - * @return this FrameTimeout value encoded so that non-negative values - * represent a timeout in milliseconds, and -1 represents an infinite - * timeout. - * - * XXX(seth): This is a backwards compatibility hack that should be removed. - */ - int32_t AsEncodedValueDeprecated() const { return mTimeout; } - -private: - explicit FrameTimeout(int32_t aTimeout) - : mTimeout(aTimeout) - { } - - int32_t mTimeout; -}; - -} // namespace image -} // namespace mozilla - -#endif // mozilla_image_FrameTimeout_h diff --git a/image/ImageMetadata.h b/image/ImageMetadata.h index b1a2edfb03fd..05f5729802c7 100644 --- a/image/ImageMetadata.h +++ b/image/ImageMetadata.h @@ -11,11 +11,12 @@ #include "mozilla/Maybe.h" #include "nsSize.h" #include "Orientation.h" -#include "FrameTimeout.h" namespace mozilla { namespace image { +class RasterImage; + // The metadata about an image that decoders accumulate as they decode. class ImageMetadata { @@ -63,13 +64,6 @@ public: nsIntSize GetSize() const { return *mSize; } bool HasSize() const { return mSize.isSome(); } - void AddNativeSize(const nsIntSize& aSize) - { - mNativeSizes.AppendElement(aSize); - } - - const nsTArray& GetNativeSizes() const { return mNativeSizes; } - Orientation GetOrientation() const { return *mOrientation; } bool HasOrientation() const { return mOrientation.isSome(); } @@ -96,9 +90,6 @@ private: Maybe mSize; Maybe mOrientation; - // Sizes the image can natively decode to. - nsTArray mNativeSizes; - bool mHasAnimation : 1; }; diff --git a/image/ImageOps.cpp b/image/ImageOps.cpp index fb4fc8fb7075..d1d5da283642 100644 --- a/image/ImageOps.cpp +++ b/image/ImageOps.cpp @@ -14,7 +14,6 @@ #include "FrozenImage.h" #include "IDecodingTask.h" #include "Image.h" -#include "ImageMetadata.h" #include "imgIContainer.h" #include "mozilla/gfx/2D.h" #include "nsStreamUtils.h" @@ -80,27 +79,10 @@ ImageOps::CreateFromDrawable(gfxDrawable* aDrawable) return drawableImage.forget(); } -class ImageOps::ImageBufferImpl final : public ImageOps::ImageBuffer { -public: - ImageBufferImpl(already_AddRefed aSourceBuffer) - : mSourceBuffer(aSourceBuffer) - { } - -protected: - ~ImageBufferImpl() override { } - - virtual already_AddRefed GetSourceBuffer() - { - RefPtr sourceBuffer = mSourceBuffer; - return sourceBuffer.forget(); - } - -private: - RefPtr mSourceBuffer; -}; - -/* static */ already_AddRefed -ImageOps::CreateImageBuffer(nsIInputStream* aInputStream) +/* static */ already_AddRefed +ImageOps::DecodeToSurface(nsIInputStream* aInputStream, + const nsACString& aMimeType, + uint32_t aFlags) { MOZ_ASSERT(aInputStream); @@ -125,7 +107,7 @@ ImageOps::CreateImageBuffer(nsIInputStream* aInputStream) } // Write the data into a SourceBuffer. - RefPtr sourceBuffer = new SourceBuffer(); + NotNull> sourceBuffer = WrapNotNull(new SourceBuffer()); sourceBuffer->ExpectLength(length); rv = sourceBuffer->AppendFromInputStream(inputStream, length); if (NS_FAILED(rv)) { @@ -140,90 +122,12 @@ ImageOps::CreateImageBuffer(nsIInputStream* aInputStream) } sourceBuffer->Complete(NS_OK); - RefPtr imageBuffer = new ImageBufferImpl(sourceBuffer.forget()); - return imageBuffer.forget(); -} - -/* static */ nsresult -ImageOps::DecodeMetadata(nsIInputStream* aInputStream, - const nsACString& aMimeType, - ImageMetadata& aMetadata) -{ - RefPtr buffer = CreateImageBuffer(aInputStream); - return DecodeMetadata(buffer, aMimeType, aMetadata); -} - -/* static */ nsresult -ImageOps::DecodeMetadata(ImageBuffer* aBuffer, - const nsACString& aMimeType, - ImageMetadata& aMetadata) -{ - if (!aBuffer) { - return NS_ERROR_FAILURE; - } - - RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); - if (NS_WARN_IF(!sourceBuffer)) { - return NS_ERROR_FAILURE; - } - // Create a decoder. DecoderType decoderType = DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); RefPtr decoder = - DecoderFactory::CreateAnonymousMetadataDecoder(decoderType, - WrapNotNull(sourceBuffer)); - if (!decoder) { - return NS_ERROR_FAILURE; - } - - // Run the decoder synchronously. - RefPtr task = new AnonymousDecodingTask(WrapNotNull(decoder)); - task->Run(); - if (!decoder->GetDecodeDone() || decoder->HasError()) { - return NS_ERROR_FAILURE; - } - - aMetadata = decoder->GetImageMetadata(); - if (aMetadata.GetNativeSizes().IsEmpty() && aMetadata.HasSize()) { - aMetadata.AddNativeSize(aMetadata.GetSize()); - } - - return NS_OK; -} - -/* static */ already_AddRefed -ImageOps::DecodeToSurface(nsIInputStream* aInputStream, - const nsACString& aMimeType, - uint32_t aFlags, - Maybe aSize /* = Nothing() */) -{ - RefPtr buffer = CreateImageBuffer(aInputStream); - return DecodeToSurface(buffer, aMimeType, aFlags, aSize); -} - -/* static */ already_AddRefed -ImageOps::DecodeToSurface(ImageBuffer* aBuffer, - const nsACString& aMimeType, - uint32_t aFlags, - Maybe aSize /* = Nothing() */) -{ - if (!aBuffer) { - return nullptr; - } - - RefPtr sourceBuffer = aBuffer->GetSourceBuffer(); - if (NS_WARN_IF(!sourceBuffer)) { - return nullptr; - } - - // Create a decoder. - DecoderType decoderType = - DecoderFactory::GetDecoderType(PromiseFlatCString(aMimeType).get()); - RefPtr decoder = - DecoderFactory::CreateAnonymousDecoder(decoderType, - WrapNotNull(sourceBuffer), - aSize, ToSurfaceFlags(aFlags)); + DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, + Nothing(), ToSurfaceFlags(aFlags)); if (!decoder) { return nullptr; } diff --git a/image/ImageOps.h b/image/ImageOps.h index 5a089fd16b03..7a8e19be3441 100644 --- a/image/ImageOps.h +++ b/image/ImageOps.h @@ -9,7 +9,6 @@ #include "nsCOMPtr.h" #include "nsRect.h" -#include "ImageMetadata.h" class gfxDrawable; class imgIContainer; @@ -25,23 +24,10 @@ namespace image { class Image; struct Orientation; -class SourceBuffer; class ImageOps { public: - class ImageBuffer { - public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ImageOps::ImageBuffer); - protected: - friend class ImageOps; - - ImageBuffer() { } - virtual ~ImageBuffer() { } - - virtual already_AddRefed GetSourceBuffer() = 0; - }; - /** * Creates a version of an existing image which does not animate and is frozen * at the first frame. @@ -88,39 +74,6 @@ public: static already_AddRefed CreateFromDrawable(gfxDrawable* aDrawable); - /** - * Create a buffer to be used with DecodeMetadata and DecodeToSurface. Reusing - * an ImageBuffer representing the given input stream is more efficient if one - * has multiple Decode* calls to make on that stream. - * - * @param aInputStream An input stream containing an encoded image. - * @return An image buffer derived from the input stream. - */ - static already_AddRefed - CreateImageBuffer(nsIInputStream* aInputStream); - - /** - * Decodes an image's metadata from an nsIInputStream into the given - * structure. This function may be called off-main-thread. - * - * @param aInputStream An input stream containing an encoded image. - * @param aMimeType The MIME type of the image. - * @param aMetadata Where the image metadata is stored upon success. - * @return The status of the operation. - */ - static nsresult - DecodeMetadata(nsIInputStream* aInputStream, - const nsACString& aMimeType, - ImageMetadata& aMetadata); - - /** - * Same as above but takes an ImageBuffer instead of nsIInputStream. - */ - static nsresult - DecodeMetadata(ImageBuffer* aBuffer, - const nsACString& aMimeType, - ImageMetadata& aMetadata); - /** * Decodes an image from an nsIInputStream directly into a SourceSurface, * without ever creating an Image or imgIContainer (which are mostly @@ -136,21 +89,9 @@ public: static already_AddRefed DecodeToSurface(nsIInputStream* aInputStream, const nsACString& aMimeType, - uint32_t aFlags, - Maybe aSize = Nothing()); - - /** - * Same as above but takes an ImageBuffer instead of nsIInputStream. - */ - static already_AddRefed - DecodeToSurface(ImageBuffer* aBuffer, - const nsACString& aMimeType, - uint32_t aFlags, - Maybe aSize = Nothing()); + uint32_t aFlags); private: - class ImageBufferImpl; - // This is a static utility class, so disallow instantiation. virtual ~ImageOps() = 0; }; diff --git a/image/ImageWrapper.cpp b/image/ImageWrapper.cpp index 852479904567..dfc76641fd6f 100644 --- a/image/ImageWrapper.cpp +++ b/image/ImageWrapper.cpp @@ -139,12 +139,6 @@ ImageWrapper::GetHeight(int32_t* aHeight) return mInnerImage->GetHeight(aHeight); } -nsresult -ImageWrapper::GetNativeSizes(nsTArray& aNativeSizes) const -{ - return mInnerImage->GetNativeSizes(aNativeSizes); -} - NS_IMETHODIMP ImageWrapper::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/ImageWrapper.h b/image/ImageWrapper.h index 19e9cb858232..94cf0948b537 100644 --- a/image/ImageWrapper.h +++ b/image/ImageWrapper.h @@ -22,7 +22,6 @@ public: NS_DECL_IMGICONTAINER // Inherited methods from Image. - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual already_AddRefed GetProgressTracker() override; virtual size_t diff --git a/image/OrientedImage.cpp b/image/OrientedImage.cpp index 79767e2a796a..951b0acbc94d 100644 --- a/image/OrientedImage.cpp +++ b/image/OrientedImage.cpp @@ -46,22 +46,6 @@ OrientedImage::GetHeight(int32_t* aHeight) } } -nsresult -OrientedImage::GetNativeSizes(nsTArray& aNativeSizes) const -{ - nsresult rv = InnerImage()->GetNativeSizes(aNativeSizes); - - if (mOrientation.SwapsWidthAndHeight()) { - auto i = aNativeSizes.Length(); - while (i > 0) { - --i; - swap(aNativeSizes[i].width, aNativeSizes[i].height); - } - } - - return rv; -} - NS_IMETHODIMP OrientedImage::GetIntrinsicSize(nsSize* aSize) { diff --git a/image/OrientedImage.h b/image/OrientedImage.h index d1291ea74b20..2edf05de9f50 100644 --- a/image/OrientedImage.h +++ b/image/OrientedImage.h @@ -30,7 +30,6 @@ public: NS_IMETHOD GetWidth(int32_t* aWidth) override; NS_IMETHOD GetHeight(int32_t* aHeight) override; - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override; NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override; NS_IMETHOD_(already_AddRefed) diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index b3da4ff3697e..b98744850295 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -220,24 +220,6 @@ RasterImage::GetHeight(int32_t* aHeight) return NS_OK; } -//****************************************************************************** -nsresult -RasterImage::GetNativeSizes(nsTArray& aNativeSizes) const -{ - if (mError) { - return NS_ERROR_FAILURE; - } - - if (mNativeSizes.IsEmpty()) { - aNativeSizes.Clear(); - aNativeSizes.AppendElement(mSize); - } else { - aNativeSizes = mNativeSizes; - } - - return NS_OK; -} - //****************************************************************************** NS_IMETHODIMP RasterImage::GetIntrinsicSize(nsSize* aSize) @@ -721,7 +703,6 @@ RasterImage::SetMetadata(const ImageMetadata& aMetadata, // Set the size and flag that we have it. mSize = size; mOrientation = orientation; - mNativeSizes = aMetadata.GetNativeSizes(); mHasSize = true; } diff --git a/image/RasterImage.h b/image/RasterImage.h index 023985669a7a..09fa18b4df65 100644 --- a/image/RasterImage.h +++ b/image/RasterImage.h @@ -160,7 +160,6 @@ public: NS_DECL_IMGICONTAINERDEBUG #endif - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual nsresult StartAnimation() override; virtual nsresult StopAnimation() override; @@ -381,7 +380,6 @@ private: private: // data nsIntSize mSize; - nsTArray mNativeSizes; Orientation mOrientation; /// If this has a value, we're waiting for SetSize() to send the load event. diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index 7c650fc7545c..fa3ecb8bc049 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -520,13 +520,6 @@ VectorImage::GetWidth(int32_t* aWidth) return NS_OK; } -//****************************************************************************** -nsresult -VectorImage::GetNativeSizes(nsTArray& aNativeSizes) const -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - //****************************************************************************** NS_IMETHODIMP_(void) VectorImage::RequestRefresh(const TimeStamp& aTime) diff --git a/image/VectorImage.h b/image/VectorImage.h index a05c92f3cf38..cb55e057753c 100644 --- a/image/VectorImage.h +++ b/image/VectorImage.h @@ -34,7 +34,6 @@ public: // (no public constructor - use ImageFactory) // Methods inherited from Image - nsresult GetNativeSizes(nsTArray& aNativeSizes) const override; virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const override; virtual void CollectSizeOfSurfaces(nsTArray& aCounters, diff --git a/image/decoders/nsICODecoder.cpp b/image/decoders/nsICODecoder.cpp index d8171431ea83..85b3c139b0d7 100644 --- a/image/decoders/nsICODecoder.cpp +++ b/image/decoders/nsICODecoder.cpp @@ -242,8 +242,6 @@ nsICODecoder::ReadDirEntry(const char* aData) } } - mImageMetadata.AddNativeSize(entrySize); - if (desiredSize) { // Calculate the delta between this resource's size and the desired size, so // we can see if it is better than our current-best option. In the case of diff --git a/image/imgFrame.h b/image/imgFrame.h index bd858e088dcf..77ff3507b177 100644 --- a/image/imgFrame.h +++ b/image/imgFrame.h @@ -11,7 +11,6 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/Monitor.h" #include "mozilla/Move.h" -#include "FrameTimeout.h" #include "gfxDrawable.h" #include "imgIContainer.h" #include "MainThreadUtils.h" @@ -47,6 +46,106 @@ enum class Opacity : uint8_t { SOME_TRANSPARENCY }; +/** + * FrameTimeout wraps a frame timeout value (measured in milliseconds) after + * first normalizing it. This normalization is necessary because some tools + * generate incorrect frame timeout values which we nevertheless have to + * support. For this reason, code that deals with frame timeouts should always + * use a FrameTimeout value rather than the raw value from the image header. + */ +struct FrameTimeout +{ + /** + * @return a FrameTimeout of zero. This should be used only for math + * involving FrameTimeout values. You can't obtain a zero FrameTimeout from + * FromRawMilliseconds(). + */ + static FrameTimeout Zero() { return FrameTimeout(0); } + + /// @return an infinite FrameTimeout. + static FrameTimeout Forever() { return FrameTimeout(-1); } + + /// @return a FrameTimeout obtained by normalizing a raw timeout value. + static FrameTimeout FromRawMilliseconds(int32_t aRawMilliseconds) + { + // Normalize all infinite timeouts to the same value. + if (aRawMilliseconds < 0) { + return FrameTimeout::Forever(); + } + + // Very small timeout values are problematic for two reasons: we don't want + // to burn energy redrawing animated images extremely fast, and broken tools + // generate these values when they actually want a "default" value, so such + // images won't play back right without normalization. For some context, + // see bug 890743, bug 125137, bug 139677, and bug 207059. The historical + // behavior of IE and Opera was: + // IE 6/Win: + // 10 - 50ms is normalized to 100ms. + // >50ms is used unnormalized. + // Opera 7 final/Win: + // 10ms is normalized to 100ms. + // >10ms is used unnormalized. + if (aRawMilliseconds >= 0 && aRawMilliseconds <= 10 ) { + return FrameTimeout(100); + } + + // The provided timeout value is OK as-is. + return FrameTimeout(aRawMilliseconds); + } + + bool operator==(const FrameTimeout& aOther) const + { + return mTimeout == aOther.mTimeout; + } + + bool operator!=(const FrameTimeout& aOther) const { return !(*this == aOther); } + + FrameTimeout operator+(const FrameTimeout& aOther) + { + if (*this == Forever() || aOther == Forever()) { + return Forever(); + } + + return FrameTimeout(mTimeout + aOther.mTimeout); + } + + FrameTimeout& operator+=(const FrameTimeout& aOther) + { + *this = *this + aOther; + return *this; + } + + /** + * @return this FrameTimeout's value in milliseconds. Illegal to call on a + * an infinite FrameTimeout value. + */ + uint32_t AsMilliseconds() const + { + if (*this == Forever()) { + MOZ_ASSERT_UNREACHABLE("Calling AsMilliseconds() on an infinite FrameTimeout"); + return 100; // Fail to something sane. + } + + return uint32_t(mTimeout); + } + + /** + * @return this FrameTimeout value encoded so that non-negative values + * represent a timeout in milliseconds, and -1 represents an infinite + * timeout. + * + * XXX(seth): This is a backwards compatibility hack that should be removed. + */ + int32_t AsEncodedValueDeprecated() const { return mTimeout; } + +private: + explicit FrameTimeout(int32_t aTimeout) + : mTimeout(aTimeout) + { } + + int32_t mTimeout; +}; + /** * AnimationData contains all of the information necessary for using an imgFrame * as part of an animation. diff --git a/image/imgIContainer.idl b/image/imgIContainer.idl index eed28e2668d9..640eae352558 100644 --- a/image/imgIContainer.idl +++ b/image/imgIContainer.idl @@ -90,10 +90,6 @@ interface imgIContainer : nsISupports */ readonly attribute int32_t height; - %{C++ - virtual nsresult GetNativeSizes(nsTArray& aNativeSizes) const = 0; - %} - /** * The intrinsic size of this image in appunits. If the image has no intrinsic * size in a dimension, -1 will be returned for that dimension. In the case of diff --git a/image/moz.build b/image/moz.build index 8ccb30247e91..c3a3a610fd8e 100644 --- a/image/moz.build +++ b/image/moz.build @@ -37,10 +37,8 @@ XPIDL_MODULE = 'imglib2' EXPORTS += [ 'DrawResult.h', - 'FrameTimeout.h', 'ImageCacheKey.h', 'ImageLogging.h', - 'ImageMetadata.h', 'ImageOps.h', 'ImageRegion.h', 'imgLoader.h', diff --git a/image/test/gtest/Common.cpp b/image/test/gtest/Common.cpp index 4bc7fce1c32e..4be34461c71c 100644 --- a/image/test/gtest/Common.cpp +++ b/image/test/gtest/Common.cpp @@ -679,11 +679,5 @@ ImageTestCase TruncatedSmallGIFTestCase() return ImageTestCase("green-1x1-truncated.gif", "image/gif", IntSize(1, 1)); } -ImageTestCase GreenMultipleSizesICOTestCase() -{ - return ImageTestCase("green-multiple-sizes.ico", "image/x-icon", - IntSize(256, 256)); -} - } // namespace image } // namespace mozilla diff --git a/image/test/gtest/Common.h b/image/test/gtest/Common.h index 63b8b9b70026..33fc26e750f8 100644 --- a/image/test/gtest/Common.h +++ b/image/test/gtest/Common.h @@ -414,8 +414,6 @@ ImageTestCase DownscaledTransparentICOWithANDMaskTestCase(); ImageTestCase TruncatedSmallGIFTestCase(); -ImageTestCase GreenMultipleSizesICOTestCase(); - } // namespace image } // namespace mozilla diff --git a/image/test/gtest/TestDecodeToSurface.cpp b/image/test/gtest/TestDecodeToSurface.cpp index f5762d84c172..dd22d4308d9b 100644 --- a/image/test/gtest/TestDecodeToSurface.cpp +++ b/image/test/gtest/TestDecodeToSurface.cpp @@ -27,11 +27,9 @@ class DecodeToSurfaceRunnable : public Runnable public: DecodeToSurfaceRunnable(RefPtr& aSurface, nsIInputStream* aInputStream, - ImageOps::ImageBuffer* aImageBuffer, const ImageTestCase& aTestCase) : mSurface(aSurface) , mInputStream(aInputStream) - , mImageBuffer(aImageBuffer) , mTestCase(aTestCase) { } @@ -43,35 +41,16 @@ public: void Go() { - Maybe outputSize; - if (mTestCase.mOutputSize != mTestCase.mSize) { - outputSize.emplace(mTestCase.mOutputSize); - } - - if (mImageBuffer) { - mSurface = - ImageOps::DecodeToSurface(mImageBuffer, - nsDependentCString(mTestCase.mMimeType), - imgIContainer::DECODE_FLAGS_DEFAULT, - outputSize); - } else { - mSurface = - ImageOps::DecodeToSurface(mInputStream, - nsDependentCString(mTestCase.mMimeType), - imgIContainer::DECODE_FLAGS_DEFAULT, - outputSize); - } + mSurface = + ImageOps::DecodeToSurface(mInputStream, + nsDependentCString(mTestCase.mMimeType), + imgIContainer::DECODE_FLAGS_DEFAULT); ASSERT_TRUE(mSurface != nullptr); EXPECT_TRUE(mSurface->IsDataSourceSurface()); EXPECT_TRUE(mSurface->GetFormat() == SurfaceFormat::B8G8R8X8 || mSurface->GetFormat() == SurfaceFormat::B8G8R8A8); - - if (outputSize) { - EXPECT_EQ(*outputSize, mSurface->GetSize()); - } else { - EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); - } + EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); EXPECT_TRUE(IsSolidColor(mSurface, BGRAColor::Green(), mTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0)); @@ -80,19 +59,14 @@ public: private: RefPtr& mSurface; nsCOMPtr mInputStream; - RefPtr mImageBuffer; ImageTestCase mTestCase; }; static void -RunDecodeToSurface(const ImageTestCase& aTestCase, - ImageOps::ImageBuffer* aImageBuffer = nullptr) +RunDecodeToSurface(const ImageTestCase& aTestCase) { - nsCOMPtr inputStream; - if (!aImageBuffer) { - inputStream = LoadFile(aTestCase.mPath); - ASSERT_TRUE(inputStream != nullptr); - } + nsCOMPtr inputStream = LoadFile(aTestCase.mPath); + ASSERT_TRUE(inputStream != nullptr); nsCOMPtr thread; nsresult rv = @@ -103,7 +77,7 @@ RunDecodeToSurface(const ImageTestCase& aTestCase, // DecodeToSurface doesn't require any main-thread-only code. RefPtr surface; nsCOMPtr runnable = - new DecodeToSurfaceRunnable(surface, inputStream, aImageBuffer, aTestCase); + new DecodeToSurfaceRunnable(surface, inputStream, aTestCase); thread->Dispatch(runnable, nsIThread::DISPATCH_SYNC); thread->Shutdown(); @@ -148,43 +122,3 @@ TEST_F(ImageDecodeToSurface, Corrupt) imgIContainer::DECODE_FLAGS_DEFAULT); EXPECT_TRUE(surface == nullptr); } - -TEST_F(ImageDecodeToSurface, ICOMultipleSizes) -{ - ImageTestCase testCase = GreenMultipleSizesICOTestCase(); - - nsCOMPtr inputStream = LoadFile(testCase.mPath); - ASSERT_TRUE(inputStream != nullptr); - - RefPtr buffer = - ImageOps::CreateImageBuffer(inputStream); - ASSERT_TRUE(buffer != nullptr); - - ImageMetadata metadata; - nsresult rv = ImageOps::DecodeMetadata(buffer, - nsDependentCString(testCase.mMimeType), - metadata); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - ASSERT_TRUE(metadata.HasSize()); - EXPECT_EQ(testCase.mSize, metadata.GetSize()); - - const nsTArray& nativeSizes = metadata.GetNativeSizes(); - ASSERT_EQ(6u, nativeSizes.Length()); - - IntSize expectedSizes[] = { - IntSize(16, 16), - IntSize(32, 32), - IntSize(64, 64), - IntSize(128, 128), - IntSize(256, 256), - IntSize(256, 128), - }; - - for (int i = 0; i < 6; ++i) { - EXPECT_EQ(expectedSizes[i], nativeSizes[i]); - - // Request decoding at native size - testCase.mOutputSize = nativeSizes[i]; - RunDecodeToSurface(testCase, buffer); - } -} diff --git a/image/test/gtest/TestDecoders.cpp b/image/test/gtest/TestDecoders.cpp index 16b17ac63b3f..d39b8e404a60 100644 --- a/image/test/gtest/TestDecoders.cpp +++ b/image/test/gtest/TestDecoders.cpp @@ -672,87 +672,3 @@ TEST_F(ImageDecoders, TruncatedSmallGIFSingleChunk) { CheckDecoderSingleChunk(TruncatedSmallGIFTestCase()); } - -TEST_F(ImageDecoders, MultipleSizesICOSingleChunk) -{ - ImageTestCase testCase = GreenMultipleSizesICOTestCase(); - - // Create an image. - RefPtr image = - ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType)); - ASSERT_TRUE(!image->HasError()); - - nsCOMPtr inputStream = LoadFile(testCase.mPath); - ASSERT_TRUE(inputStream); - - // Figure out how much data we have. - uint64_t length; - nsresult rv = inputStream->Available(&length); - ASSERT_TRUE(NS_SUCCEEDED(rv)); - - // Write the data into the image. - rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0, - static_cast(length)); - ASSERT_TRUE(NS_SUCCEEDED(rv)); - - // Let the image know we've sent all the data. - rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true); - ASSERT_TRUE(NS_SUCCEEDED(rv)); - - RefPtr tracker = image->GetProgressTracker(); - tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE); - - // Use GetFrame() to force a sync decode of the image. - RefPtr surface = - image->GetFrame(imgIContainer::FRAME_CURRENT, - imgIContainer::FLAG_SYNC_DECODE); - - // Ensure that the image's metadata meets our expectations. - IntSize imageSize(0, 0); - rv = image->GetWidth(&imageSize.width); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - rv = image->GetHeight(&imageSize.height); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - - EXPECT_EQ(testCase.mSize.width, imageSize.width); - EXPECT_EQ(testCase.mSize.height, imageSize.height); - - nsTArray nativeSizes; - rv = image->GetNativeSizes(nativeSizes); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - ASSERT_EQ(6u, nativeSizes.Length()); - - IntSize expectedSizes[] = { - IntSize(16, 16), - IntSize(32, 32), - IntSize(64, 64), - IntSize(128, 128), - IntSize(256, 256), - IntSize(256, 128) - }; - - for (int i = 0; i < 6; ++i) { - EXPECT_EQ(expectedSizes[i], nativeSizes[i]); - } - - RefPtr image90 = - ImageOps::Orient(image, Orientation(Angle::D90, Flip::Unflipped)); - rv = image90->GetNativeSizes(nativeSizes); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - ASSERT_EQ(6u, nativeSizes.Length()); - - for (int i = 0; i < 5; ++i) { - EXPECT_EQ(expectedSizes[i], nativeSizes[i]); - } - EXPECT_EQ(IntSize(128, 256), nativeSizes[5]); - - RefPtr image180 = - ImageOps::Orient(image, Orientation(Angle::D180, Flip::Unflipped)); - rv = image180->GetNativeSizes(nativeSizes); - EXPECT_TRUE(NS_SUCCEEDED(rv)); - ASSERT_EQ(6u, nativeSizes.Length()); - - for (int i = 0; i < 6; ++i) { - EXPECT_EQ(expectedSizes[i], nativeSizes[i]); - } -} diff --git a/image/test/gtest/green-multiple-sizes.ico b/image/test/gtest/green-multiple-sizes.ico deleted file mode 100644 index b9463d0c897117204b2edacfa6cbfc4f5f61d771..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14144 zcmeI$u}Z^09LMorsuU?iGF5aj4uYeb;1s1*3sS3eaC9mnh?}dy&3ACb06tZ(!iOf<#;`kn$9d6k7uQwnw00` zaUxyT{R2m&RA=t*nr^D^Qz==H);#5cg;n_hP}ZY(wYf8)+x>!>Ikgv!B;X9iE3tM2N({eIg8WY>=`o{tYb zv)pNI^-teFUZdEfx8di(`TWMvmqon9E8ga6@%BCpJMC`kVf*AdR5C+V;zwm7l&;4? wWulUxM*sl?5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0;O_{00SHw$wg3PC diff --git a/image/test/gtest/moz.build b/image/test/gtest/moz.build index 3e37573dba04..ad69e098518c 100644 --- a/image/test/gtest/moz.build +++ b/image/test/gtest/moz.build @@ -47,7 +47,6 @@ TEST_HARNESS_FILES.gtest += [ 'first-frame-green.png', 'first-frame-padding.gif', 'green-1x1-truncated.gif', - 'green-multiple-sizes.ico', 'green.bmp', 'green.gif', 'green.ico', From b2b30c26f89e179339d989341d5f8ba56d282b86 Mon Sep 17 00:00:00 2001 From: Dylan Roeh Date: Tue, 21 Mar 2017 08:49:15 -0500 Subject: [PATCH 79/96] Bug 1349200 - Ensure mozglue is loaded before checking NEON compatibility in GeckoApp.onCreate(). r=jchen --- mobile/android/base/java/org/mozilla/gecko/GeckoApp.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java index 7bf6aac376c9..42db038390f4 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java @@ -1157,6 +1157,10 @@ public abstract class GeckoApp enableStrictMode(); } + // Mozglue should already be loaded by BrowserApp.onCreate() in Fennec, but in + // custom tabs it may not be. + GeckoLoader.loadMozGlue(getApplicationContext()); + if (!HardwareUtils.isSupportedSystem() || !GeckoLoader.neonCompatible()) { // This build does not support the Android version of the device: Show an error and finish the app. mIsAbortingAppLaunch = true; From 60207be9c034b168f68c64f7025b5c5a41dffe14 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Tue, 21 Mar 2017 19:21:34 +0100 Subject: [PATCH 80/96] Bug 1329676 - Wasm: eliminate redundant bounds checks on constant heap addresses. r=luke --HG-- extra : rebase_source : a9fdae31bd922f727e92c9d969ea7f7144601bec extra : source : fa1c05b07723a685daa127dfbc4a9ef007c1d352 --- js/src/jit/Ion.cpp | 18 +++++++++++------- js/src/jit/Lowering.cpp | 5 +---- js/src/jit/MIR.h | 11 +++++------ js/src/jit/WasmBCE.cpp | 36 ++++++++++++++++++++++++++++-------- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp index d7a51b51083b..df992177e6a3 100644 --- a/js/src/jit/Ion.cpp +++ b/js/src/jit/Ion.cpp @@ -1861,6 +1861,17 @@ OptimizeMIR(MIRGenerator* mir) return false; } + // BCE marks bounds checks as dead, so do BCE before DCE. + if (mir->compilingWasm() && !JitOptions.wasmAlwaysCheckBounds) { + if (!EliminateBoundsChecks(mir, graph)) + return false; + gs.spewPass("Redundant Bounds Check Elimination"); + AssertGraphCoherency(graph); + + if (mir->shouldCancel("BCE")) + return false; + } + { AutoTraceLog log(logger, TraceLogger_EliminateDeadCode); if (!EliminateDeadCode(mir, graph)) @@ -1933,13 +1944,6 @@ OptimizeMIR(MIRGenerator* mir) AssertGraphCoherency(graph); } - if (mir->compilingWasm()) { - if (!EliminateBoundsChecks(mir, graph)) - return false; - gs.spewPass("Redundant Bounds Check Elimination"); - AssertGraphCoherency(graph); - } - AssertGraphCoherency(graph, /* force = */ true); DumpMIRExpressions(graph); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 573c2ee3c52a..7c090b6f9cd5 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4278,10 +4278,7 @@ LIRGenerator::visitWasmBoundsCheck(MWasmBoundsCheck* ins) #ifdef WASM_HUGE_MEMORY MOZ_CRASH("No bounds checking on huge memory"); #else - if (ins->isRedundant()) { - if (MOZ_LIKELY(!JitOptions.wasmAlwaysCheckBounds)) - return; - } + MOZ_ASSERT(!ins->isRedundant()); MDefinition* index = ins->index(); MOZ_ASSERT(index->type() == MIRType::Int32); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 63ad3938b6c1..1b67d16d56df 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -13718,15 +13718,14 @@ class MWasmBoundsCheck : public MBinaryInstruction, public NoTypePolicy::Data { - bool redundant_; wasm::TrapOffset trapOffset_; explicit MWasmBoundsCheck(MDefinition* index, MDefinition* boundsCheckLimit, wasm::TrapOffset trapOffset) : MBinaryInstruction(index, boundsCheckLimit), - redundant_(false), trapOffset_(trapOffset) { - setGuard(); // Effectful: throws for OOB. + // Bounds check is effectful: it throws for OOB. + setGuard(); } public: @@ -13739,11 +13738,11 @@ class MWasmBoundsCheck } bool isRedundant() const { - return redundant_; + return !isGuard(); } - void setRedundant(bool val) { - redundant_ = val; + void setRedundant() { + setNotGuard(); } wasm::TrapOffset trapOffset() const { diff --git a/js/src/jit/WasmBCE.cpp b/js/src/jit/WasmBCE.cpp index aac362738572..20739a5de059 100644 --- a/js/src/jit/WasmBCE.cpp +++ b/js/src/jit/WasmBCE.cpp @@ -6,6 +6,7 @@ #include "jit/WasmBCE.h" #include "jit/MIRGenerator.h" #include "jit/MIRGraph.h" +#include "wasm/WasmTypes.h" using namespace js; using namespace js::jit; @@ -42,15 +43,34 @@ jit::EliminateBoundsChecks(MIRGenerator* mir, MIRGraph& graph) switch (def->op()) { case MDefinition::Op_WasmBoundsCheck: { MWasmBoundsCheck* bc = def->toWasmBoundsCheck(); - MDefinition* addr = def->getOperand(0); + MDefinition* addr = bc->index(); - LastSeenMap::AddPtr ptr = lastSeen.lookupForAdd(addr->id()); - if (ptr) { - if (ptr->value()->block()->dominates(block)) - bc->setRedundant(true); - } else { - if (!lastSeen.add(ptr, addr->id(), def)) - return false; + // Eliminate constant-address bounds checks to addresses below + // the heap minimum. + // + // The payload of the MConstant will be Double if the constant + // result is above 2^31-1, but we don't care about that for BCE. + +#ifndef WASM_HUGE_MEMORY + MOZ_ASSERT(wasm::MaxMemoryAccessSize < wasm::GuardSize, + "Guard page handles partial out-of-bounds"); +#endif + + if (addr->isConstant() && addr->toConstant()->type() == MIRType::Int32 && + uint32_t(addr->toConstant()->toInt32()) < mir->minWasmHeapLength()) + { + bc->setRedundant(); + } + else + { + LastSeenMap::AddPtr ptr = lastSeen.lookupForAdd(addr->id()); + if (ptr) { + if (ptr->value()->block()->dominates(block)) + bc->setRedundant(); + } else { + if (!lastSeen.add(ptr, addr->id(), def)) + return false; + } } break; } From e4d62401f0bbc647b1d39d555d44a096b4318a72 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Wed, 22 Mar 2017 17:30:50 +0000 Subject: [PATCH 81/96] Bug 1341044 - Rename the GC's 'zone group' concept to 'sweep group' r=sfink --- js/ipc/JavaScriptChild.cpp | 4 +- js/src/gc/GCRuntime.h | 28 +-- js/src/gc/Marking.cpp | 2 +- js/src/gc/Statistics.cpp | 2 +- js/src/gc/Statistics.h | 2 +- js/src/gc/Zone.cpp | 10 +- js/src/gc/Zone.h | 16 +- js/src/jsapi-tests/testGCFinalizeCallback.cpp | 2 +- js/src/jsapi-tests/testWeakMap.cpp | 4 +- js/src/jsapi.cpp | 8 +- js/src/jsapi.h | 8 +- js/src/jsgc.cpp | 172 +++++++++--------- js/src/jsgcinlines.h | 10 +- js/src/jsweakmap.cpp | 2 +- js/src/vm/Runtime.h | 2 +- js/xpconnect/src/XPCJSContext.cpp | 6 +- js/xpconnect/src/xpcprivate.h | 2 +- 17 files changed, 140 insertions(+), 140 deletions(-) diff --git a/js/ipc/JavaScriptChild.cpp b/js/ipc/JavaScriptChild.cpp index 69bc8ded243f..fecdcd060a1b 100644 --- a/js/ipc/JavaScriptChild.cpp +++ b/js/ipc/JavaScriptChild.cpp @@ -35,7 +35,7 @@ TraceChild(JSTracer* trc, void* data) JavaScriptChild::~JavaScriptChild() { JSContext* cx = dom::danger::GetJSContext(); - JS_RemoveWeakPointerZoneGroupCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup); + JS_RemoveWeakPointerZonesCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup); JS_RemoveExtraGCRootsTracer(cx, TraceChild, this); } @@ -48,7 +48,7 @@ JavaScriptChild::init() return false; JSContext* cx = dom::danger::GetJSContext(); - JS_AddWeakPointerZoneGroupCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup, this); + JS_AddWeakPointerZonesCallback(cx, UpdateChildWeakPointersBeforeSweepingZoneGroup, this); JS_AddExtraGCRootsTracer(cx, TraceChild, this); return true; } diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h index f8a8777ad380..5e90f60e48f0 100644 --- a/js/src/gc/GCRuntime.h +++ b/js/src/gc/GCRuntime.h @@ -788,9 +788,9 @@ class GCRuntime void callObjectsTenuredCallback(); MOZ_MUST_USE bool addFinalizeCallback(JSFinalizeCallback callback, void* data); void removeFinalizeCallback(JSFinalizeCallback func); - MOZ_MUST_USE bool addWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback, + MOZ_MUST_USE bool addWeakPointerZonesCallback(JSWeakPointerZonesCallback callback, void* data); - void removeWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback); + void removeWeakPointerZonesCallback(JSWeakPointerZonesCallback callback); MOZ_MUST_USE bool addWeakPointerCompartmentCallback(JSWeakPointerCompartmentCallback callback, void* data); void removeWeakPointerCompartmentCallback(JSWeakPointerCompartmentCallback callback); @@ -802,7 +802,7 @@ class GCRuntime void setFullCompartmentChecks(bool enable); - JS::Zone* getCurrentZoneGroup() { return currentZoneGroup; } + JS::Zone* getCurrentSweepGroup() { return currentSweepGroup; } void setFoundBlackGrayEdges(TenuredCell& target) { AutoEnterOOMUnsafeRegion oomUnsafe; if (!foundBlackGrayEdges.ref().append(&target)) @@ -978,13 +978,13 @@ class GCRuntime void markAllGrayReferences(gcstats::Phase phase); void beginSweepPhase(bool lastGC, AutoLockForExclusiveAccess& lock); - void findZoneGroups(AutoLockForExclusiveAccess& lock); + void groupZonesForSweeping(AutoLockForExclusiveAccess& lock); MOZ_MUST_USE bool findInterZoneEdges(); - void getNextZoneGroup(); - void endMarkingZoneGroup(); - void beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock); + void getNextSweepGroup(); + void endMarkingSweepGroup(); + void beginSweepingSweepGroup(AutoLockForExclusiveAccess& lock); bool shouldReleaseObservedTypes(); - void endSweepingZoneGroup(); + void endSweepingSweepGroup(); IncrementalProgress sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock); void endSweepPhase(bool lastGC, AutoLockForExclusiveAccess& lock); bool allCCVisibleZonesWereCollected() const; @@ -1024,7 +1024,7 @@ class GCRuntime #endif void callFinalizeCallbacks(FreeOp* fop, JSFinalizeStatus status) const; - void callWeakPointerZoneGroupCallbacks() const; + void callWeakPointerZonesCallbacks() const; void callWeakPointerCompartmentCallbacks(JSCompartment* comp) const; public: @@ -1196,14 +1196,14 @@ class GCRuntime ActiveThreadOrGCTaskData blocksToFreeAfterSweeping; private: - /* Index of current zone group (for stats). */ - ActiveThreadData zoneGroupIndex; + /* Index of current sweep group (for stats). */ + ActiveThreadData sweepGroupIndex; /* * Incremental sweep state. */ - ActiveThreadData zoneGroups; - ActiveThreadOrGCTaskData currentZoneGroup; + ActiveThreadData sweepGroups; + ActiveThreadOrGCTaskData currentSweepGroup; ActiveThreadData sweepingTypes; ActiveThreadData finalizePhase; ActiveThreadData sweepZone; @@ -1295,7 +1295,7 @@ class GCRuntime Callback gcDoCycleCollectionCallback; Callback tenuredCallback; CallbackVector finalizeCallbacks; - CallbackVector updateWeakPointerZoneGroupCallbacks; + CallbackVector updateWeakPointerZonesCallbacks; CallbackVector updateWeakPointerCompartmentCallbacks; MemoryCounter mallocCounter; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 70b6419f2aee..22839c291ce4 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -2451,7 +2451,7 @@ GCMarker::enterWeakMarkingMode() if (weakMapAction() == ExpandWeakMaps) { tag_ = TracerKindTag::WeakMarking; - for (GCZoneGroupIter zone(runtime()); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(runtime()); !zone.done(); zone.next()) { for (WeakMapBase* m : zone->gcWeakMapList()) { if (m->marked) (void) m->markIteratively(this); diff --git a/js/src/gc/Statistics.cpp b/js/src/gc/Statistics.cpp index 519c393aa6d1..8065fdc8b7a4 100644 --- a/js/src/gc/Statistics.cpp +++ b/js/src/gc/Statistics.cpp @@ -164,7 +164,7 @@ static const PhaseInfo phases[] = { { PHASE_SWEEP_MARK_GRAY, "Mark Gray", PHASE_SWEEP_MARK, 15 }, { PHASE_SWEEP_MARK_GRAY_WEAK, "Mark Gray and Weak", PHASE_SWEEP_MARK, 16 }, { PHASE_FINALIZE_START, "Finalize Start Callbacks", PHASE_SWEEP, 17 }, - { PHASE_WEAK_ZONEGROUP_CALLBACK, "Per-Slice Weak Callback", PHASE_FINALIZE_START, 57 }, + { PHASE_WEAK_ZONES_CALLBACK, "Per-Slice Weak Callback", PHASE_FINALIZE_START, 57 }, { PHASE_WEAK_COMPARTMENT_CALLBACK, "Per-Compartment Weak Callback", PHASE_FINALIZE_START, 58 }, { PHASE_SWEEP_ATOMS, "Sweep Atoms", PHASE_SWEEP, 18 }, { PHASE_SWEEP_COMPARTMENTS, "Sweep Compartments", PHASE_SWEEP, 20 }, diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h index 9af2245ba901..4957b9c26561 100644 --- a/js/src/gc/Statistics.h +++ b/js/src/gc/Statistics.h @@ -49,7 +49,7 @@ enum Phase : uint8_t { PHASE_SWEEP_MARK_GRAY, PHASE_SWEEP_MARK_GRAY_WEAK, PHASE_FINALIZE_START, - PHASE_WEAK_ZONEGROUP_CALLBACK, + PHASE_WEAK_ZONES_CALLBACK, PHASE_WEAK_COMPARTMENT_CALLBACK, PHASE_SWEEP_ATOMS, PHASE_SWEEP_COMPARTMENTS, diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 67030ea4d7ca..b8dade6039e8 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -37,7 +37,7 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group) gcWeakRefs_(group), weakCaches_(group), gcWeakKeys_(group, SystemAllocPolicy(), rt->randomHashCodeScrambler()), - gcZoneGroupEdges_(group), + gcSweepGroupEdges_(group), hasDeadProxies_(group), typeDescrObjects_(group, this, SystemAllocPolicy()), markedAtoms_(group), @@ -50,7 +50,7 @@ JS::Zone::Zone(JSRuntime* rt, ZoneGroup* group) data(group, nullptr), isSystem(group, false), #ifdef DEBUG - gcLastZoneGroupIndex(group, 0), + gcLastSweepGroupIndex(group, 0), #endif jitZone_(group, nullptr), gcState_(NoGC), @@ -90,7 +90,7 @@ bool Zone::init(bool isSystemArg) { isSystem = isSystemArg; return uniqueIds().init() && - gcZoneGroupEdges().init() && + gcSweepGroupEdges().init() && gcWeakKeys().init() && typeDescrObjects().init() && markedAtoms().init(); @@ -159,8 +159,8 @@ Zone::sweepBreakpoints(FreeOp* fop) GCPtrNativeObject& dbgobj = bp->debugger->toJSObjectRef(); // If we are sweeping, then we expect the script and the - // debugger object to be swept in the same zone group, except if - // the breakpoint was added after we computed the zone + // debugger object to be swept in the same sweep group, except + // if the breakpoint was added after we computed the sweep // groups. In this case both script and debugger object must be // live. MOZ_ASSERT_IF(isGCSweeping() && dbgobj->zone()->isCollecting(), diff --git a/js/src/gc/Zone.h b/js/src/gc/Zone.h index c9874caa86d5..7b6b87e7954a 100644 --- a/js/src/gc/Zone.h +++ b/js/src/gc/Zone.h @@ -270,9 +270,9 @@ struct Zone : public JS::shadow::Zone, void prepareForCompacting(); #ifdef DEBUG - // For testing purposes, return the index of the zone group which this zone + // For testing purposes, return the index of the sweep group which this zone // was swept in in the last GC. - unsigned lastZoneGroupIndex() { return gcLastZoneGroupIndex; } + unsigned lastSweepGroupIndex() { return gcLastSweepGroupIndex; } #endif using DebuggerVector = js::Vector; @@ -348,7 +348,7 @@ struct Zone : public JS::shadow::Zone, WeakEdges& gcWeakRefs() { return gcWeakRefs_.ref(); } private: - // List of non-ephemeron weak containers to sweep during beginSweepingZoneGroup. + // List of non-ephemeron weak containers to sweep during beginSweepingSweepGroup. js::ZoneGroupData>> weakCaches_; public: mozilla::LinkedList>& weakCaches() { return weakCaches_.ref(); } @@ -368,16 +368,16 @@ struct Zone : public JS::shadow::Zone, private: // A set of edges from this zone to other zones. // - // This is used during GC while calculating zone groups to record edges that - // can't be determined by examining this zone by itself. - js::ZoneGroupData gcZoneGroupEdges_; + // This is used during GC while calculating sweep groups to record edges + // that can't be determined by examining this zone by itself. + js::ZoneGroupData gcSweepGroupEdges_; // Zones with dead proxies require an extra scan through the wrapper map, // so track whether any dead proxies are known to exist. js::ZoneGroupData hasDeadProxies_; public: - ZoneSet& gcZoneGroupEdges() { return gcZoneGroupEdges_.ref(); } + ZoneSet& gcSweepGroupEdges() { return gcSweepGroupEdges_.ref(); } bool hasDeadProxies() { return hasDeadProxies_; } void setHasDeadProxies(bool b) { hasDeadProxies_ = b; } @@ -485,7 +485,7 @@ struct Zone : public JS::shadow::Zone, } #ifdef DEBUG - js::ZoneGroupData gcLastZoneGroupIndex; + js::ZoneGroupData gcLastSweepGroupIndex; #endif static js::HashNumber UniqueIdToHash(uint64_t uid) { diff --git a/js/src/jsapi-tests/testGCFinalizeCallback.cpp b/js/src/jsapi-tests/testGCFinalizeCallback.cpp index 95fac3d59959..1826487bef32 100644 --- a/js/src/jsapi-tests/testGCFinalizeCallback.cpp +++ b/js/src/jsapi-tests/testGCFinalizeCallback.cpp @@ -175,7 +175,7 @@ bool checkMultipleGroups() bool checkFinalizeStatus() { /* - * The finalize callback should be called twice for each zone group + * The finalize callback should be called twice for each sweep group * finalized, with status JSFINALIZE_GROUP_START and JSFINALIZE_GROUP_END, * and then once more with JSFINALIZE_COLLECTION_END. */ diff --git a/js/src/jsapi-tests/testWeakMap.cpp b/js/src/jsapi-tests/testWeakMap.cpp index 37a272817df4..a4540c11535d 100644 --- a/js/src/jsapi-tests/testWeakMap.cpp +++ b/js/src/jsapi-tests/testWeakMap.cpp @@ -102,7 +102,7 @@ BEGIN_TEST(testWeakMap_keyDelegates) while (JS::IsIncrementalGCInProgress(cx)) cx->runtime()->gc.debugGCSlice(budget); #ifdef DEBUG - CHECK(map->zone()->lastZoneGroupIndex() < delegateRoot->zone()->lastZoneGroupIndex()); + CHECK(map->zone()->lastSweepGroupIndex() < delegateRoot->zone()->lastSweepGroupIndex()); #endif /* Add our entry to the weakmap. */ @@ -124,7 +124,7 @@ BEGIN_TEST(testWeakMap_keyDelegates) * necessary because of the presence of the delegate and the CCW. */ #ifdef DEBUG - CHECK(map->zone()->lastZoneGroupIndex() == delegateRoot->zone()->lastZoneGroupIndex()); + CHECK(map->zone()->lastSweepGroupIndex() == delegateRoot->zone()->lastSweepGroupIndex()); #endif /* Check that when the delegate becomes unreachable the entry is removed. */ diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 7b8278820e79..80484310e513 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1382,16 +1382,16 @@ JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb) } JS_PUBLIC_API(bool) -JS_AddWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb, void* data) +JS_AddWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb, void* data) { AssertHeapIsIdle(); - return cx->runtime()->gc.addWeakPointerZoneGroupCallback(cb, data); + return cx->runtime()->gc.addWeakPointerZonesCallback(cb, data); } JS_PUBLIC_API(void) -JS_RemoveWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb) +JS_RemoveWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb) { - cx->runtime()->gc.removeWeakPointerZoneGroupCallback(cb); + cx->runtime()->gc.removeWeakPointerZonesCallback(cb); } JS_PUBLIC_API(bool) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 411aaf3bb9f5..bfbd82d0961f 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -585,7 +585,7 @@ typedef void (* JSFinalizeCallback)(JSFreeOp* fop, JSFinalizeStatus status, bool isZoneGC, void* data); typedef void -(* JSWeakPointerZoneGroupCallback)(JSContext* cx, void* data); +(* JSWeakPointerZonesCallback)(JSContext* cx, void* data); typedef void (* JSWeakPointerCompartmentCallback)(JSContext* cx, JSCompartment* comp, void* data); @@ -1720,7 +1720,7 @@ JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb); * about. * * Since sweeping is incremental, we have several callbacks to avoid repeatedly - * having to visit all embedder structures. The WeakPointerZoneGroupCallback is + * having to visit all embedder structures. The WeakPointerZonesCallback is * called once for each strongly connected group of zones, whereas the * WeakPointerCompartmentCallback is called once for each compartment that is * visited while sweeping. Structures that cannot contain references in more @@ -1739,10 +1739,10 @@ JS_RemoveFinalizeCallback(JSContext* cx, JSFinalizeCallback cb); */ extern JS_PUBLIC_API(bool) -JS_AddWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb, void* data); +JS_AddWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb, void* data); extern JS_PUBLIC_API(void) -JS_RemoveWeakPointerZoneGroupCallback(JSContext* cx, JSWeakPointerZoneGroupCallback cb); +JS_RemoveWeakPointerZonesCallback(JSContext* cx, JSWeakPointerZonesCallback cb); extern JS_PUBLIC_API(bool) JS_AddWeakPointerCompartmentCallback(JSContext* cx, JSWeakPointerCompartmentCallback cb, diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 9d8bde656774..7257455193ce 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -80,12 +80,12 @@ * * Slice n+1: Sweep: Mark objects in unswept zones that were newly * identified as alive (see below). Then sweep more zone - * groups. + * sweep groups. * * ... JS code runs ... * * Slice n+2: Sweep: Mark objects in unswept zones that were newly - * identified as alive. Then sweep more zone groups. + * identified as alive. Then sweep more zones. * * ... JS code runs ... * @@ -161,7 +161,7 @@ * conditions to change such that incremental collection is no longer safe. In * this case, the collection is 'reset' by ResetIncrementalGC(). If we are in * the mark state, this just stops marking, but if we have started sweeping - * already, we continue until we have swept the current zone group. Following a + * already, we continue until we have swept the current sweep group. Following a * reset, a new non-incremental collection is started. * * Compacting GC @@ -838,9 +838,9 @@ GCRuntime::GCRuntime(JSRuntime* rt) : lastMarkSlice(false), sweepOnBackgroundThread(false), blocksToFreeAfterSweeping((size_t) JSContext::TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE), - zoneGroupIndex(0), - zoneGroups(nullptr), - currentZoneGroup(nullptr), + sweepGroupIndex(0), + sweepGroups(nullptr), + currentSweepGroup(nullptr), sweepZone(nullptr), sweepKind(AllocKind::FIRST), abortSweepAfterCurrentGroup(false), @@ -1420,27 +1420,27 @@ GCRuntime::callFinalizeCallbacks(FreeOp* fop, JSFinalizeStatus status) const } bool -GCRuntime::addWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback, void* data) +GCRuntime::addWeakPointerZonesCallback(JSWeakPointerZonesCallback callback, void* data) { - return updateWeakPointerZoneGroupCallbacks.ref().append( - Callback(callback, data)); + return updateWeakPointerZonesCallbacks.ref().append( + Callback(callback, data)); } void -GCRuntime::removeWeakPointerZoneGroupCallback(JSWeakPointerZoneGroupCallback callback) +GCRuntime::removeWeakPointerZonesCallback(JSWeakPointerZonesCallback callback) { - for (auto& p : updateWeakPointerZoneGroupCallbacks.ref()) { + for (auto& p : updateWeakPointerZonesCallbacks.ref()) { if (p.op == callback) { - updateWeakPointerZoneGroupCallbacks.ref().erase(&p); + updateWeakPointerZonesCallbacks.ref().erase(&p); break; } } } void -GCRuntime::callWeakPointerZoneGroupCallbacks() const +GCRuntime::callWeakPointerZonesCallbacks() const { - for (auto const& p : updateWeakPointerZoneGroupCallbacks.ref()) + for (auto const& p : updateWeakPointerZonesCallbacks.ref()) p.op(TlsContext.get(), p.data); } @@ -2561,7 +2561,7 @@ GCRuntime::updateRuntimePointersToRelocatedCells(AutoLockForExclusiveAccess& loc blocksToFreeAfterSweeping.ref().freeAll(); // Call callbacks to get the rest of the system to fixup other untraced pointers. - callWeakPointerZoneGroupCallbacks(); + callWeakPointerZonesCallbacks(); } void @@ -4057,7 +4057,7 @@ GCRuntime::markWeakReferences(gcstats::Phase phase) void GCRuntime::markWeakReferencesInCurrentGroup(gcstats::Phase phase) { - markWeakReferences(phase); + markWeakReferences(phase); } template @@ -4080,7 +4080,7 @@ GCRuntime::markGrayReferences(gcstats::Phase phase) void GCRuntime::markGrayReferencesInCurrentGroup(gcstats::Phase phase) { - markGrayReferences(phase); + markGrayReferences(phase); } void @@ -4466,7 +4466,7 @@ JSCompartment::findDeadProxyZoneEdges(bool* foundAny) if (IsDeadProxyObject(&value.toObject())) { *foundAny = true; CrossCompartmentKey& key = e.front().mutableKey(); - if (!key.as()->zone()->gcZoneGroupEdges().put(zone())) + if (!key.as()->zone()->gcSweepGroupEdges().put(zone())) return false; } } @@ -4490,7 +4490,7 @@ Zone::findOutgoingEdges(ZoneComponentFinder& finder) for (CompartmentsInZoneIter comp(this); !comp.done(); comp.next()) comp->findOutgoingEdges(finder); - for (ZoneSet::Range r = gcZoneGroupEdges().all(); !r.empty(); r.popFront()) { + for (ZoneSet::Range r = gcSweepGroupEdges().all(); !r.empty(); r.popFront()) { if (r.front()->isGCMarking()) finder.addEdgeTo(r.front()); } @@ -4534,11 +4534,11 @@ GCRuntime::findInterZoneEdges() } void -GCRuntime::findZoneGroups(AutoLockForExclusiveAccess& lock) +GCRuntime::groupZonesForSweeping(AutoLockForExclusiveAccess& lock) { #ifdef DEBUG for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) - MOZ_ASSERT(zone->gcZoneGroupEdges().empty()); + MOZ_ASSERT(zone->gcSweepGroupEdges().empty()); #endif JSContext* cx = TlsContext.get(); @@ -4550,22 +4550,22 @@ GCRuntime::findZoneGroups(AutoLockForExclusiveAccess& lock) MOZ_ASSERT(zone->isGCMarking()); finder.addNode(zone); } - zoneGroups = finder.getResultsList(); - currentZoneGroup = zoneGroups; - zoneGroupIndex = 0; + sweepGroups = finder.getResultsList(); + currentSweepGroup = sweepGroups; + sweepGroupIndex = 0; for (GCZonesIter zone(rt); !zone.done(); zone.next()) - zone->gcZoneGroupEdges().clear(); + zone->gcSweepGroupEdges().clear(); #ifdef DEBUG - for (Zone* head = currentZoneGroup; head; head = head->nextGroup()) { + for (Zone* head = currentSweepGroup; head; head = head->nextGroup()) { for (Zone* zone = head; zone; zone = zone->nextNodeInGroup()) MOZ_ASSERT(zone->isGCMarking()); } - MOZ_ASSERT_IF(!isIncremental, !currentZoneGroup->nextGroup()); + MOZ_ASSERT_IF(!isIncremental, !currentSweepGroup->nextGroup()); for (ZonesIter zone(rt, WithAtoms); !zone.done(); zone.next()) - MOZ_ASSERT(zone->gcZoneGroupEdges().empty()); + MOZ_ASSERT(zone->gcSweepGroupEdges().empty()); #endif } @@ -4573,26 +4573,26 @@ static void ResetGrayList(JSCompartment* comp); void -GCRuntime::getNextZoneGroup() +GCRuntime::getNextSweepGroup() { - currentZoneGroup = currentZoneGroup->nextGroup(); - ++zoneGroupIndex; - if (!currentZoneGroup) { + currentSweepGroup = currentSweepGroup->nextGroup(); + ++sweepGroupIndex; + if (!currentSweepGroup) { abortSweepAfterCurrentGroup = false; return; } - for (Zone* zone = currentZoneGroup; zone; zone = zone->nextNodeInGroup()) { + for (Zone* zone = currentSweepGroup; zone; zone = zone->nextNodeInGroup()) { MOZ_ASSERT(zone->isGCMarking()); MOZ_ASSERT(!zone->isQueuedForBackgroundSweep()); } if (!isIncremental) - ZoneComponentFinder::mergeGroups(currentZoneGroup); + ZoneComponentFinder::mergeGroups(currentSweepGroup); if (abortSweepAfterCurrentGroup) { MOZ_ASSERT(!isIncremental); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(!zone->gcNextGraphComponent); MOZ_ASSERT(zone->isGCMarking()); zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit); @@ -4604,7 +4604,7 @@ GCRuntime::getNextZoneGroup() ResetGrayList(comp); abortSweepAfterCurrentGroup = false; - currentZoneGroup = nullptr; + currentSweepGroup = nullptr; } } @@ -4853,7 +4853,7 @@ js::NotifyGCPostSwap(JSObject* a, JSObject* b, unsigned removedFlags) } void -GCRuntime::endMarkingZoneGroup() +GCRuntime::endMarkingSweepGroup() { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_MARK); @@ -4871,7 +4871,7 @@ GCRuntime::endMarkingZoneGroup() * these will be marked through, as they are not marked with * MarkCrossCompartmentXXX. */ - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(zone->isGCMarkingBlack()); zone->setGCState(Zone::MarkGray); } @@ -4885,7 +4885,7 @@ GCRuntime::endMarkingZoneGroup() markWeakReferencesInCurrentGroup(gcstats::PHASE_SWEEP_MARK_GRAY_WEAK); /* Restore marking state. */ - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(zone->isGCMarkingGray()); zone->setGCState(Zone::Mark); } @@ -5010,7 +5010,7 @@ using WeakCacheTaskVector = mozilla::Vector* cache : zone->weakCaches()) { SweepWeakCacheTask task(rt, *cache); task.runFromActiveCooperatingThread(rt); @@ -5022,7 +5022,7 @@ static WeakCacheTaskVector PrepareWeakCacheTasks(JSRuntime* rt) { WeakCacheTaskVector out; - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { for (JS::WeakCache* cache : zone->weakCaches()) { if (!out.append(SweepWeakCacheTask(rt, *cache))) { SweepWeakCachesFromActiveCooperatingThread(rt); @@ -5034,15 +5034,15 @@ PrepareWeakCacheTasks(JSRuntime* rt) } void -GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) +GCRuntime::beginSweepingSweepGroup(AutoLockForExclusiveAccess& lock) { /* - * Begin sweeping the group of zones in gcCurrentZoneGroup, - * performing actions that must be done before yielding to caller. + * Begin sweeping the group of zones in currentSweepGroup, performing + * actions that must be done before yielding to caller. */ bool sweepingAtoms = false; - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { /* Set the GC state to sweeping. */ MOZ_ASSERT(zone->isGCMarking()); zone->setGCState(Zone::Sweep); @@ -5057,7 +5057,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) rt->sweepZoneCallback(zone); #ifdef DEBUG - zone->gcLastZoneGroupIndex = zoneGroupIndex; + zone->gcLastSweepGroupIndex = sweepGroupIndex; #endif } @@ -5071,7 +5071,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) SweepMiscTask sweepMiscTask(rt); WeakCacheTaskVector sweepCacheTasks = PrepareWeakCacheTasks(rt); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { /* Clear all weakrefs that point to unmarked things. */ for (auto edge : zone->gcWeakRefs()) { /* Edges may be present multiple times, so may already be nulled. */ @@ -5080,22 +5080,22 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) } zone->gcWeakRefs().clear(); - /* No need to look up any more weakmap keys from this zone group. */ + /* No need to look up any more weakmap keys from this sweep group. */ AutoEnterOOMUnsafeRegion oomUnsafe; if (!zone->gcWeakKeys().clear()) - oomUnsafe.crash("clearing weak keys in beginSweepingZoneGroup()"); + oomUnsafe.crash("clearing weak keys in beginSweepingSweepGroup()"); } { gcstats::AutoPhase ap(stats(), gcstats::PHASE_FINALIZE_START); callFinalizeCallbacks(&fop, JSFINALIZE_GROUP_START); { - gcstats::AutoPhase ap2(stats(), gcstats::PHASE_WEAK_ZONEGROUP_CALLBACK); - callWeakPointerZoneGroupCallbacks(); + gcstats::AutoPhase ap2(stats(), gcstats::PHASE_WEAK_ZONES_CALLBACK); + callWeakPointerZonesCallbacks(); } { gcstats::AutoPhase ap2(stats(), gcstats::PHASE_WEAK_COMPARTMENT_CALLBACK); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) callWeakPointerCompartmentCallbacks(comp); } @@ -5109,7 +5109,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_COMPARTMENTS); - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + gcstats::AutoSCC scc(stats(), sweepGroupIndex); { AutoLockHelperThreadState helperLock; @@ -5136,7 +5136,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) c->sweepTemplateObjects(); } - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->sweepWeakMaps(); // Bug 1071218: the following two methods have not yet been @@ -5159,26 +5159,26 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) { gcstats::AutoPhase apdc(stats(), gcstats::PHASE_SWEEP_DISCARD_CODE); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->discardJitCode(&fop); } { gcstats::AutoPhase ap1(stats(), gcstats::PHASE_SWEEP_TYPES); gcstats::AutoPhase ap2(stats(), gcstats::PHASE_SWEEP_TYPES_BEGIN); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->beginSweepTypes(&fop, releaseObservedTypes && !zone->isPreservingCode()); } { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_BREAKPOINT); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->sweepBreakpoints(&fop); } { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_BREAKPOINT); - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zone->sweepUniqueIds(&fop); } } @@ -5191,7 +5191,7 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) { gcstats::AutoPhase ap(stats(), gcstats::PHASE_SWEEP_COMPARTMENTS); - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + gcstats::AutoSCC scc(stats(), sweepGroupIndex); AutoLockHelperThreadState helperLock; joinTask(sweepCCWrappersTask, gcstats::PHASE_SWEEP_CC_WRAPPER, helperLock); @@ -5211,29 +5211,29 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) * Objects are finalized immediately but this may change in the future. */ - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { + gcstats::AutoSCC scc(stats(), sweepGroupIndex); zone->arenas.queueForegroundObjectsForSweep(&fop); } - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { + gcstats::AutoSCC scc(stats(), sweepGroupIndex); for (unsigned i = 0; i < ArrayLength(IncrementalFinalizePhases); ++i) zone->arenas.queueForForegroundSweep(&fop, IncrementalFinalizePhases[i]); } - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { + gcstats::AutoSCC scc(stats(), sweepGroupIndex); for (unsigned i = 0; i < ArrayLength(BackgroundFinalizePhases); ++i) zone->arenas.queueForBackgroundSweep(&fop, BackgroundFinalizePhases[i]); } - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { - gcstats::AutoSCC scc(stats(), zoneGroupIndex); + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { + gcstats::AutoSCC scc(stats(), sweepGroupIndex); zone->arenas.queueForegroundThingsForSweep(&fop); } sweepingTypes = true; finalizePhase = 0; - sweepZone = currentZoneGroup; + sweepZone = currentSweepGroup; sweepKind = AllocKind::FIRST; { @@ -5243,10 +5243,10 @@ GCRuntime::beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock) } void -GCRuntime::endSweepingZoneGroup() +GCRuntime::endSweepingSweepGroup() { /* Update the GC state for zones we have swept. */ - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) { + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) { MOZ_ASSERT(zone->isGCSweeping()); AutoLockGC lock(rt); zone->setGCState(Zone::Finished); @@ -5256,7 +5256,7 @@ GCRuntime::endSweepingZoneGroup() /* Start background thread to sweep zones if required. */ ZoneList zones; - for (GCZoneGroupIter zone(rt); !zone.done(); zone.next()) + for (GCSweepGroupIter zone(rt); !zone.done(); zone.next()) zones.append(zone); if (sweepOnBackgroundThread) queueZonesForBackgroundSweep(zones); @@ -5299,9 +5299,9 @@ GCRuntime::beginSweepPhase(bool destroyingRuntime, AutoLockForExclusiveAccess& l AssertNoWrappersInGrayList(rt); DropStringWrappers(rt); - findZoneGroups(lock); - endMarkingZoneGroup(); - beginSweepingZoneGroup(lock); + groupZonesForSweeping(lock); + endMarkingSweepGroup(); + beginSweepingSweepGroup(lock); } bool @@ -5391,10 +5391,10 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock // Sweep dead type information stored in scripts and object groups, but // don't finalize them yet. We have to sweep dead information from both // live and dead scripts and object groups, so that no dead references - // remain in them. Type inference can end up crawling these zones - // again, such as for TypeCompartment::markSetsUnknown, and if this - // happens after sweeping for the zone group finishes we won't be able - // to determine which things in the zone are live. + // remain in them. Type inference can end up crawling these zones again, + // such as for TypeCompartment::markSetsUnknown, and if this happens + // after sweeping for the sweep group finishes we won't be able to + // determine which things in the zone are live. if (sweepingTypes) { gcstats::AutoPhase ap1(stats(), gcstats::PHASE_SWEEP_COMPARTMENTS); gcstats::AutoPhase ap2(stats(), gcstats::PHASE_SWEEP_TYPES); @@ -5425,7 +5425,7 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock al.mergeForegroundSweptObjectArenas(); } - sweepZone = currentZoneGroup; + sweepZone = currentSweepGroup; sweepingTypes = false; } @@ -5456,7 +5456,7 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock } sweepKind = AllocKind::FIRST; } - sweepZone = currentZoneGroup; + sweepZone = currentSweepGroup; } /* Remove dead shapes from the shape tree, but don't finalize them yet. */ @@ -5474,13 +5474,13 @@ GCRuntime::sweepPhase(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock } } - endSweepingZoneGroup(); - getNextZoneGroup(); - if (!currentZoneGroup) + endSweepingSweepGroup(); + getNextSweepGroup(); + if (!currentSweepGroup) return Finished; - endMarkingZoneGroup(); - beginSweepingZoneGroup(lock); + endMarkingSweepGroup(); + beginSweepingSweepGroup(lock); } } @@ -5807,7 +5807,7 @@ GCRuntime::resetIncrementalGC(gc::AbortReason reason, AutoLockForExclusiveAccess for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) c->scheduledForDestruction = false; - /* Finish sweeping the current zone group, then abort. */ + /* Finish sweeping the current sweep group, then abort. */ abortSweepAfterCurrentGroup = true; /* Don't perform any compaction after sweeping. */ diff --git a/js/src/jsgcinlines.h b/js/src/jsgcinlines.h index 612c854b734d..9024985af073 100644 --- a/js/src/jsgcinlines.h +++ b/js/src/jsgcinlines.h @@ -445,15 +445,15 @@ class GCZonesIter typedef CompartmentsIterT GCCompartmentsIter; -/* Iterates over all zones in the current zone group. */ -class GCZoneGroupIter { +/* Iterates over all zones in the current sweep group. */ +class GCSweepGroupIter { private: JS::Zone* current; public: - explicit GCZoneGroupIter(JSRuntime* rt) { + explicit GCSweepGroupIter(JSRuntime* rt) { MOZ_ASSERT(CurrentThreadIsPerformingGC()); - current = rt->gc.getCurrentZoneGroup(); + current = rt->gc.getCurrentSweepGroup(); } bool done() const { return !current; } @@ -472,7 +472,7 @@ class GCZoneGroupIter { JS::Zone* operator->() const { return get(); } }; -typedef CompartmentsIterT GCCompartmentGroupIter; +typedef CompartmentsIterT GCCompartmentGroupIter; inline void RelocationOverlay::forwardTo(Cell* cell) diff --git a/js/src/jsweakmap.cpp b/js/src/jsweakmap.cpp index 349c0fbb3c42..9764af9c1a3c 100644 --- a/js/src/jsweakmap.cpp +++ b/js/src/jsweakmap.cpp @@ -147,7 +147,7 @@ ObjectValueMap::findZoneEdges() Zone* delegateZone = delegate->zone(); if (delegateZone == zone() || !delegateZone->isGCMarking()) continue; - if (!delegateZone->gcZoneGroupEdges().put(key->zone())) + if (!delegateZone->gcSweepGroupEdges().put(key->zone())) return false; } return true; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 250819b3e26d..3dc4109817bd 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -561,7 +561,7 @@ struct JSRuntime : public js::MallocProvider } private: - // List of non-ephemeron weak containers to sweep during beginSweepingZoneGroup. + // List of non-ephemeron weak containers to sweep during beginSweepingSweepGroup. js::ActiveThreadData>> weakCaches_; public: mozilla::LinkedList>& weakCaches() { return weakCaches_.ref(); } diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index 6f72c9db8510..81536d9b57b6 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -888,7 +888,7 @@ XPCJSContext::FinalizeCallback(JSFreeOp* fop, } /* static */ void -XPCJSContext::WeakPointerZoneGroupCallback(JSContext* cx, void* data) +XPCJSContext::WeakPointerZonesCallback(JSContext* cx, void* data) { // Called before each sweeping slice -- after processing any final marking // triggered by barriers -- to clear out any references to things that are @@ -1582,7 +1582,7 @@ XPCJSContext::~XPCJSContext() // callbacks if we aren't careful. Null out the relevant callbacks. js::SetActivityCallback(Context(), nullptr, nullptr); JS_RemoveFinalizeCallback(Context(), FinalizeCallback); - JS_RemoveWeakPointerZoneGroupCallback(Context(), WeakPointerZoneGroupCallback); + JS_RemoveWeakPointerZonesCallback(Context(), WeakPointerZonesCallback); JS_RemoveWeakPointerCompartmentCallback(Context(), WeakPointerCompartmentCallback); // Clear any pending exception. It might be an XPCWrappedJS, and if we try @@ -3502,7 +3502,7 @@ XPCJSContext::Initialize() mPrevDoCycleCollectionCallback = JS::SetDoCycleCollectionCallback(cx, DoCycleCollectionCallback); JS_AddFinalizeCallback(cx, FinalizeCallback, nullptr); - JS_AddWeakPointerZoneGroupCallback(cx, WeakPointerZoneGroupCallback, this); + JS_AddWeakPointerZonesCallback(cx, WeakPointerZonesCallback, this); JS_AddWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback, this); JS_SetWrapObjectCallbacks(cx, &WrapObjectCallbacks); js::SetPreserveWrapperCallback(cx, PreserveWrapper); diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index b9145d73495d..9f2dbe04c208 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -538,7 +538,7 @@ public: JSFinalizeStatus status, bool isZoneGC, void* data); - static void WeakPointerZoneGroupCallback(JSContext* cx, void* data); + static void WeakPointerZonesCallback(JSContext* cx, void* data); static void WeakPointerCompartmentCallback(JSContext* cx, JSCompartment* comp, void* data); inline void AddVariantRoot(XPCTraceableVariant* variant); From 4aa4377a32a3af2fc862425be2a3dda56aad5452 Mon Sep 17 00:00:00 2001 From: Ganesh Chaitanya Kale Date: Wed, 22 Mar 2017 20:46:24 +0530 Subject: [PATCH 82/96] Bug 1349502 - Make tabbrowser.xml use AppConstants from the global scope. r=dao --- browser/base/content/tabbrowser.xml | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 48ecdbcccefc..08a3bdfd0ab4 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -68,9 +68,6 @@ Components.classes["@mozilla.org/autocomplete/search;1?name=unifiedcomplete"] .getService(Components.interfaces.mozIPlacesAutoComplete); - - (Components.utils.import("resource://gre/modules/AppConstants.jsm", {})).AppConstants; - document.getAnonymousElementByAttribute(this, "anonid", "tabbox"); @@ -108,7 +105,7 @@ new Map(); - this.AppConstants.platform == "macosx"; + AppConstants == "macosx"; @@ -3388,7 +3385,7 @@ Date: Wed, 22 Mar 2017 18:44:10 +0100 Subject: [PATCH 83/96] Bug 1349434 - Fixing the saving in the JSONviewer, r=qdot --- devtools/client/jsonview/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devtools/client/jsonview/main.js b/devtools/client/jsonview/main.js index eb552649717b..b12fe414225b 100644 --- a/devtools/client/jsonview/main.js +++ b/devtools/client/jsonview/main.js @@ -50,7 +50,7 @@ var JsonView = { * in the parent process. */ onSave: function (message) { - JsonViewUtils.getTargetFile(file => { + JsonViewUtils.getTargetFile().then(file => { if (file) { JsonViewUtils.saveToFile(file, message.data); } From 8d7c2746eaa1986df1127f874f505fa7751a385d Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Wed, 22 Mar 2017 18:45:40 +0100 Subject: [PATCH 84/96] Bug 1349512 - Move OriginAttributes class in separate files, r=qdot --HG-- rename : caps/BasePrincipal.cpp => caps/OriginAttributes.cpp rename : caps/BasePrincipal.h => caps/OriginAttributes.h --- caps/BasePrincipal.cpp | 270 ------------------------------------ caps/BasePrincipal.h | 172 +---------------------- caps/OriginAttributes.cpp | 283 ++++++++++++++++++++++++++++++++++++++ caps/OriginAttributes.h | 184 +++++++++++++++++++++++++ caps/moz.build | 4 +- 5 files changed, 471 insertions(+), 442 deletions(-) create mode 100644 caps/OriginAttributes.cpp create mode 100644 caps/OriginAttributes.h diff --git a/caps/BasePrincipal.cpp b/caps/BasePrincipal.cpp index f2a008208f09..b4873eeb4498 100644 --- a/caps/BasePrincipal.cpp +++ b/caps/BasePrincipal.cpp @@ -12,7 +12,6 @@ #endif #include "nsIAddonPolicyService.h" #include "nsIContentSecurityPolicy.h" -#include "nsIEffectiveTLDService.h" #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" @@ -25,279 +24,10 @@ #include "mozilla/dom/ChromeUtils.h" #include "mozilla/dom/CSPDictionariesBinding.h" -#include "mozilla/dom/quota/QuotaManager.h" #include "mozilla/dom/ToJSValue.h" -#include "mozilla/dom/URLSearchParams.h" namespace mozilla { -using dom::URLParams; - -bool OriginAttributes::sFirstPartyIsolation = false; -bool OriginAttributes::sRestrictedOpenerAccess = false; - -void -OriginAttributes::InitPrefs() -{ - MOZ_ASSERT(NS_IsMainThread()); - static bool sInited = false; - if (!sInited) { - sInited = true; - Preferences::AddBoolVarCache(&sFirstPartyIsolation, - "privacy.firstparty.isolate"); - Preferences::AddBoolVarCache(&sRestrictedOpenerAccess, - "privacy.firstparty.isolate.restrict_opener_access"); - } -} - -void -OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument, - nsIURI* aURI) -{ - bool isFirstPartyEnabled = IsFirstPartyEnabled(); - - // If the pref is off or this is not a top level load, bail out. - if (!isFirstPartyEnabled || !aIsTopLevelDocument) { - return; - } - - nsCOMPtr tldService = - do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); - MOZ_ASSERT(tldService); - if (!tldService) { - return; - } - - nsAutoCString baseDomain; - nsresult rv = tldService->GetBaseDomain(aURI, 0, baseDomain); - if (NS_FAILED(rv)) { - nsAutoCString scheme; - rv = aURI->GetScheme(scheme); - NS_ENSURE_SUCCESS_VOID(rv); - if (scheme.EqualsLiteral("about")) { - baseDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN); - } - } - - mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain); -} - -void -OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument, - const nsACString& aDomain) -{ - bool isFirstPartyEnabled = IsFirstPartyEnabled(); - - // If the pref is off or this is not a top level load, bail out. - if (!isFirstPartyEnabled || !aIsTopLevelDocument) { - return; - } - - mFirstPartyDomain = NS_ConvertUTF8toUTF16(aDomain); -} - -void -OriginAttributes::CreateSuffix(nsACString& aStr) const -{ - URLParams params; - nsAutoString value; - - // - // Important: While serializing any string-valued attributes, perform a - // release-mode assertion to make sure that they don't contain characters that - // will break the quota manager when it uses the serialization for file - // naming. - // - - if (mAppId != nsIScriptSecurityManager::NO_APP_ID) { - value.AppendInt(mAppId); - params.Set(NS_LITERAL_STRING("appId"), value); - } - - if (mInIsolatedMozBrowser) { - params.Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1")); - } - - if (mUserContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) { - value.Truncate(); - value.AppendInt(mUserContextId); - params.Set(NS_LITERAL_STRING("userContextId"), value); - } - - - if (mPrivateBrowsingId) { - value.Truncate(); - value.AppendInt(mPrivateBrowsingId); - params.Set(NS_LITERAL_STRING("privateBrowsingId"), value); - } - - if (!mFirstPartyDomain.IsEmpty()) { - MOZ_RELEASE_ASSERT(mFirstPartyDomain.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound); - params.Set(NS_LITERAL_STRING("firstPartyDomain"), mFirstPartyDomain); - } - - aStr.Truncate(); - - params.Serialize(value); - if (!value.IsEmpty()) { - aStr.AppendLiteral("^"); - aStr.Append(NS_ConvertUTF16toUTF8(value)); - } - -// In debug builds, check the whole string for illegal characters too (just in case). -#ifdef DEBUG - nsAutoCString str; - str.Assign(aStr); - MOZ_ASSERT(str.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound); -#endif -} - -void -OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const -{ - OriginAttributes attrs = *this; - - if (!attrs.mFirstPartyDomain.IsEmpty()) { - attrs.mFirstPartyDomain.AssignLiteral("_anonymizedFirstPartyDomain_"); - } - - attrs.CreateSuffix(aStr); -} - -namespace { - -class MOZ_STACK_CLASS PopulateFromSuffixIterator final - : public URLParams::ForEachIterator -{ -public: - explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes) - : mOriginAttributes(aOriginAttributes) - { - MOZ_ASSERT(aOriginAttributes); - // If mPrivateBrowsingId is passed in as >0 and is not present in the suffix, - // then it will remain >0 when it should be 0 according to the suffix. Set to 0 before - // iterating to fix this. - mOriginAttributes->mPrivateBrowsingId = 0; - } - - bool URLParamsIterator(const nsString& aName, - const nsString& aValue) override - { - if (aName.EqualsLiteral("appId")) { - nsresult rv; - int64_t val = aValue.ToInteger64(&rv); - NS_ENSURE_SUCCESS(rv, false); - NS_ENSURE_TRUE(val <= UINT32_MAX, false); - mOriginAttributes->mAppId = static_cast(val); - - return true; - } - - if (aName.EqualsLiteral("inBrowser")) { - if (!aValue.EqualsLiteral("1")) { - return false; - } - - mOriginAttributes->mInIsolatedMozBrowser = true; - return true; - } - - if (aName.EqualsLiteral("addonId")) { - // No longer supported. Silently ignore so that legacy origin strings - // don't cause failures. - return true; - } - - if (aName.EqualsLiteral("userContextId")) { - nsresult rv; - int64_t val = aValue.ToInteger64(&rv); - NS_ENSURE_SUCCESS(rv, false); - NS_ENSURE_TRUE(val <= UINT32_MAX, false); - mOriginAttributes->mUserContextId = static_cast(val); - - return true; - } - - if (aName.EqualsLiteral("privateBrowsingId")) { - nsresult rv; - int64_t val = aValue.ToInteger64(&rv); - NS_ENSURE_SUCCESS(rv, false); - NS_ENSURE_TRUE(val >= 0 && val <= UINT32_MAX, false); - mOriginAttributes->mPrivateBrowsingId = static_cast(val); - - return true; - } - - if (aName.EqualsLiteral("firstPartyDomain")) { - MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty()); - mOriginAttributes->mFirstPartyDomain.Assign(aValue); - return true; - } - - // No other attributes are supported. - return false; - } - -private: - OriginAttributes* mOriginAttributes; -}; - -} // namespace - -bool -OriginAttributes::PopulateFromSuffix(const nsACString& aStr) -{ - if (aStr.IsEmpty()) { - return true; - } - - if (aStr[0] != '^') { - return false; - } - - URLParams params; - params.ParseInput(Substring(aStr, 1, aStr.Length() - 1)); - - PopulateFromSuffixIterator iterator(this); - return params.ForEach(iterator); -} - -bool -OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin, - nsACString& aOriginNoSuffix) -{ - // RFindChar is only available on nsCString. - nsCString origin(aOrigin); - int32_t pos = origin.RFindChar('^'); - - if (pos == kNotFound) { - aOriginNoSuffix = origin; - return true; - } - - aOriginNoSuffix = Substring(origin, 0, pos); - return PopulateFromSuffix(Substring(origin, pos)); -} - -void -OriginAttributes::SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing) -{ - mPrivateBrowsingId = aInPrivateBrowsing ? 1 : 0; -} - -/* static */ -bool -OriginAttributes::IsPrivateBrowsing(const nsACString& aOrigin) -{ - nsAutoCString dummy; - OriginAttributes attrs; - if (NS_WARN_IF(!attrs.PopulateFromOrigin(aOrigin, dummy))) { - return false; - } - - return !!attrs.mPrivateBrowsingId; -} - BasePrincipal::BasePrincipal(PrincipalKind aKind) : mKind(aKind) , mDomainSet(false) diff --git a/caps/BasePrincipal.h b/caps/BasePrincipal.h index 877060779f7a..054f3764fcbc 100644 --- a/caps/BasePrincipal.h +++ b/caps/BasePrincipal.h @@ -10,9 +10,7 @@ #include "nsJSPrincipals.h" #include "mozilla/Attributes.h" -#include "mozilla/dom/ChromeUtils.h" -#include "mozilla/dom/ChromeUtilsBinding.h" -#include "nsIScriptSecurityManager.h" +#include "mozilla/OriginAttributes.h" class nsIContentSecurityPolicy; class nsIObjectOutputStream; @@ -23,174 +21,6 @@ class ExpandedPrincipal; namespace mozilla { -// Base OriginAttributes class. This has several subclass flavors, and is not -// directly constructable itself. -class OriginAttributes : public dom::OriginAttributesDictionary -{ -public: - OriginAttributes() {} - - OriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser) - { - mAppId = aAppId; - mInIsolatedMozBrowser = aInIsolatedMozBrowser; - } - - explicit OriginAttributes(const OriginAttributesDictionary& aOther) - : OriginAttributesDictionary(aOther) - {} - - void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI); - void SetFirstPartyDomain(const bool aIsTopLevelDocument, const nsACString& aDomain); - - enum { - STRIP_FIRST_PARTY_DOMAIN = 0x01, - STRIP_USER_CONTEXT_ID = 0x02, - }; - - inline void StripAttributes(uint32_t aFlags) - { - if (aFlags & STRIP_FIRST_PARTY_DOMAIN) { - mFirstPartyDomain.Truncate(); - } - - if (aFlags & STRIP_USER_CONTEXT_ID) { - mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID; - } - } - - bool operator==(const OriginAttributes& aOther) const - { - return mAppId == aOther.mAppId && - mInIsolatedMozBrowser == aOther.mInIsolatedMozBrowser && - mUserContextId == aOther.mUserContextId && - mPrivateBrowsingId == aOther.mPrivateBrowsingId && - mFirstPartyDomain == aOther.mFirstPartyDomain; - } - - bool operator!=(const OriginAttributes& aOther) const - { - return !(*this == aOther); - } - - // Serializes/Deserializes non-default values into the suffix format, i.e. - // |!key1=value1&key2=value2|. If there are no non-default attributes, this - // returns an empty string. - void CreateSuffix(nsACString& aStr) const; - - // Don't use this method for anything else than debugging! - void CreateAnonymizedSuffix(nsACString& aStr) const; - - MOZ_MUST_USE bool PopulateFromSuffix(const nsACString& aStr); - - // Populates the attributes from a string like - // |uri!key1=value1&key2=value2| and returns the uri without the suffix. - MOZ_MUST_USE bool PopulateFromOrigin(const nsACString& aOrigin, - nsACString& aOriginNoSuffix); - - // Helper function to match mIsPrivateBrowsing to existing private browsing - // flags. Once all other flags are removed, this can be removed too. - void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing); - - // check if "privacy.firstparty.isolate" is enabled. - static inline bool IsFirstPartyEnabled() - { - return sFirstPartyIsolation; - } - - // check if the access of window.opener across different FPDs is restricted. - // We only restrict the access of window.opener when first party isolation - // is enabled and "privacy.firstparty.isolate.restrict_opener_access" is on. - static inline bool IsRestrictOpenerAccessForFPI() - { - // We always want to restrict window.opener if first party isolation is - // disabled. - return !sFirstPartyIsolation || sRestrictedOpenerAccess; - } - - // returns true if the originAttributes suffix has mPrivateBrowsingId value - // different than 0. - static bool IsPrivateBrowsing(const nsACString& aOrigin); - - static void InitPrefs(); - -private: - static bool sFirstPartyIsolation; - static bool sRestrictedOpenerAccess; -}; - -class OriginAttributesPattern : public dom::OriginAttributesPatternDictionary -{ -public: - // To convert a JSON string to an OriginAttributesPattern, do the following: - // - // OriginAttributesPattern pattern; - // if (!pattern.Init(aJSONString)) { - // ... // handle failure. - // } - OriginAttributesPattern() {} - - explicit OriginAttributesPattern(const OriginAttributesPatternDictionary& aOther) - : OriginAttributesPatternDictionary(aOther) {} - - // Performs a match of |aAttrs| against this pattern. - bool Matches(const OriginAttributes& aAttrs) const - { - if (mAppId.WasPassed() && mAppId.Value() != aAttrs.mAppId) { - return false; - } - - if (mInIsolatedMozBrowser.WasPassed() && mInIsolatedMozBrowser.Value() != aAttrs.mInIsolatedMozBrowser) { - return false; - } - - if (mUserContextId.WasPassed() && mUserContextId.Value() != aAttrs.mUserContextId) { - return false; - } - - if (mPrivateBrowsingId.WasPassed() && mPrivateBrowsingId.Value() != aAttrs.mPrivateBrowsingId) { - return false; - } - - if (mFirstPartyDomain.WasPassed() && mFirstPartyDomain.Value() != aAttrs.mFirstPartyDomain) { - return false; - } - - return true; - } - - bool Overlaps(const OriginAttributesPattern& aOther) const - { - if (mAppId.WasPassed() && aOther.mAppId.WasPassed() && - mAppId.Value() != aOther.mAppId.Value()) { - return false; - } - - if (mInIsolatedMozBrowser.WasPassed() && - aOther.mInIsolatedMozBrowser.WasPassed() && - mInIsolatedMozBrowser.Value() != aOther.mInIsolatedMozBrowser.Value()) { - return false; - } - - if (mUserContextId.WasPassed() && aOther.mUserContextId.WasPassed() && - mUserContextId.Value() != aOther.mUserContextId.Value()) { - return false; - } - - if (mPrivateBrowsingId.WasPassed() && aOther.mPrivateBrowsingId.WasPassed() && - mPrivateBrowsingId.Value() != aOther.mPrivateBrowsingId.Value()) { - return false; - } - - if (mFirstPartyDomain.WasPassed() && aOther.mFirstPartyDomain.WasPassed() && - mFirstPartyDomain.Value() != aOther.mFirstPartyDomain.Value()) { - return false; - } - - return true; - } -}; - /* * Base class from which all nsIPrincipal implementations inherit. Use this for * default implementations and other commonalities between principal diff --git a/caps/OriginAttributes.cpp b/caps/OriginAttributes.cpp new file mode 100644 index 000000000000..9ee38822e33a --- /dev/null +++ b/caps/OriginAttributes.cpp @@ -0,0 +1,283 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/OriginAttributes.h" +#include "mozilla/Preferences.h" +#include "mozilla/dom/URLSearchParams.h" +#include "mozilla/dom/quota/QuotaManager.h" +#include "nsIEffectiveTLDService.h" +#include "nsIURI.h" + +namespace mozilla { + +using dom::URLParams; + +bool OriginAttributes::sFirstPartyIsolation = false; +bool OriginAttributes::sRestrictedOpenerAccess = false; + +void +OriginAttributes::InitPrefs() +{ + MOZ_ASSERT(NS_IsMainThread()); + static bool sInited = false; + if (!sInited) { + sInited = true; + Preferences::AddBoolVarCache(&sFirstPartyIsolation, + "privacy.firstparty.isolate"); + Preferences::AddBoolVarCache(&sRestrictedOpenerAccess, + "privacy.firstparty.isolate.restrict_opener_access"); + } +} + +void +OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument, + nsIURI* aURI) +{ + bool isFirstPartyEnabled = IsFirstPartyEnabled(); + + // If the pref is off or this is not a top level load, bail out. + if (!isFirstPartyEnabled || !aIsTopLevelDocument) { + return; + } + + nsCOMPtr tldService = + do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID); + MOZ_ASSERT(tldService); + if (!tldService) { + return; + } + + nsAutoCString baseDomain; + nsresult rv = tldService->GetBaseDomain(aURI, 0, baseDomain); + if (NS_FAILED(rv)) { + nsAutoCString scheme; + rv = aURI->GetScheme(scheme); + NS_ENSURE_SUCCESS_VOID(rv); + if (scheme.EqualsLiteral("about")) { + baseDomain.AssignLiteral(ABOUT_URI_FIRST_PARTY_DOMAIN); + } + } + + mFirstPartyDomain = NS_ConvertUTF8toUTF16(baseDomain); +} + +void +OriginAttributes::SetFirstPartyDomain(const bool aIsTopLevelDocument, + const nsACString& aDomain) +{ + bool isFirstPartyEnabled = IsFirstPartyEnabled(); + + // If the pref is off or this is not a top level load, bail out. + if (!isFirstPartyEnabled || !aIsTopLevelDocument) { + return; + } + + mFirstPartyDomain = NS_ConvertUTF8toUTF16(aDomain); +} + +void +OriginAttributes::CreateSuffix(nsACString& aStr) const +{ + URLParams params; + nsAutoString value; + + // + // Important: While serializing any string-valued attributes, perform a + // release-mode assertion to make sure that they don't contain characters that + // will break the quota manager when it uses the serialization for file + // naming. + // + + if (mAppId != nsIScriptSecurityManager::NO_APP_ID) { + value.AppendInt(mAppId); + params.Set(NS_LITERAL_STRING("appId"), value); + } + + if (mInIsolatedMozBrowser) { + params.Set(NS_LITERAL_STRING("inBrowser"), NS_LITERAL_STRING("1")); + } + + if (mUserContextId != nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID) { + value.Truncate(); + value.AppendInt(mUserContextId); + params.Set(NS_LITERAL_STRING("userContextId"), value); + } + + + if (mPrivateBrowsingId) { + value.Truncate(); + value.AppendInt(mPrivateBrowsingId); + params.Set(NS_LITERAL_STRING("privateBrowsingId"), value); + } + + if (!mFirstPartyDomain.IsEmpty()) { + MOZ_RELEASE_ASSERT(mFirstPartyDomain.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound); + params.Set(NS_LITERAL_STRING("firstPartyDomain"), mFirstPartyDomain); + } + + aStr.Truncate(); + + params.Serialize(value); + if (!value.IsEmpty()) { + aStr.AppendLiteral("^"); + aStr.Append(NS_ConvertUTF16toUTF8(value)); + } + +// In debug builds, check the whole string for illegal characters too (just in case). +#ifdef DEBUG + nsAutoCString str; + str.Assign(aStr); + MOZ_ASSERT(str.FindCharInSet(dom::quota::QuotaManager::kReplaceChars) == kNotFound); +#endif +} + +void +OriginAttributes::CreateAnonymizedSuffix(nsACString& aStr) const +{ + OriginAttributes attrs = *this; + + if (!attrs.mFirstPartyDomain.IsEmpty()) { + attrs.mFirstPartyDomain.AssignLiteral("_anonymizedFirstPartyDomain_"); + } + + attrs.CreateSuffix(aStr); +} + +namespace { + +class MOZ_STACK_CLASS PopulateFromSuffixIterator final + : public URLParams::ForEachIterator +{ +public: + explicit PopulateFromSuffixIterator(OriginAttributes* aOriginAttributes) + : mOriginAttributes(aOriginAttributes) + { + MOZ_ASSERT(aOriginAttributes); + // If mPrivateBrowsingId is passed in as >0 and is not present in the suffix, + // then it will remain >0 when it should be 0 according to the suffix. Set to 0 before + // iterating to fix this. + mOriginAttributes->mPrivateBrowsingId = 0; + } + + bool URLParamsIterator(const nsString& aName, + const nsString& aValue) override + { + if (aName.EqualsLiteral("appId")) { + nsresult rv; + int64_t val = aValue.ToInteger64(&rv); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(val <= UINT32_MAX, false); + mOriginAttributes->mAppId = static_cast(val); + + return true; + } + + if (aName.EqualsLiteral("inBrowser")) { + if (!aValue.EqualsLiteral("1")) { + return false; + } + + mOriginAttributes->mInIsolatedMozBrowser = true; + return true; + } + + if (aName.EqualsLiteral("addonId")) { + // No longer supported. Silently ignore so that legacy origin strings + // don't cause failures. + return true; + } + + if (aName.EqualsLiteral("userContextId")) { + nsresult rv; + int64_t val = aValue.ToInteger64(&rv); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(val <= UINT32_MAX, false); + mOriginAttributes->mUserContextId = static_cast(val); + + return true; + } + + if (aName.EqualsLiteral("privateBrowsingId")) { + nsresult rv; + int64_t val = aValue.ToInteger64(&rv); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(val >= 0 && val <= UINT32_MAX, false); + mOriginAttributes->mPrivateBrowsingId = static_cast(val); + + return true; + } + + if (aName.EqualsLiteral("firstPartyDomain")) { + MOZ_RELEASE_ASSERT(mOriginAttributes->mFirstPartyDomain.IsEmpty()); + mOriginAttributes->mFirstPartyDomain.Assign(aValue); + return true; + } + + // No other attributes are supported. + return false; + } + +private: + OriginAttributes* mOriginAttributes; +}; + +} // namespace + +bool +OriginAttributes::PopulateFromSuffix(const nsACString& aStr) +{ + if (aStr.IsEmpty()) { + return true; + } + + if (aStr[0] != '^') { + return false; + } + + URLParams params; + params.ParseInput(Substring(aStr, 1, aStr.Length() - 1)); + + PopulateFromSuffixIterator iterator(this); + return params.ForEach(iterator); +} + +bool +OriginAttributes::PopulateFromOrigin(const nsACString& aOrigin, + nsACString& aOriginNoSuffix) +{ + // RFindChar is only available on nsCString. + nsCString origin(aOrigin); + int32_t pos = origin.RFindChar('^'); + + if (pos == kNotFound) { + aOriginNoSuffix = origin; + return true; + } + + aOriginNoSuffix = Substring(origin, 0, pos); + return PopulateFromSuffix(Substring(origin, pos)); +} + +void +OriginAttributes::SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing) +{ + mPrivateBrowsingId = aInPrivateBrowsing ? 1 : 0; +} + +/* static */ +bool +OriginAttributes::IsPrivateBrowsing(const nsACString& aOrigin) +{ + nsAutoCString dummy; + OriginAttributes attrs; + if (NS_WARN_IF(!attrs.PopulateFromOrigin(aOrigin, dummy))) { + return false; + } + + return !!attrs.mPrivateBrowsingId; +} + +} // namespace mozilla diff --git a/caps/OriginAttributes.h b/caps/OriginAttributes.h new file mode 100644 index 000000000000..b0ca8bf2fa19 --- /dev/null +++ b/caps/OriginAttributes.h @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_OriginAttributes_h +#define mozilla_OriginAttributes_h + +#include "mozilla/dom/ChromeUtils.h" +#include "mozilla/dom/ChromeUtilsBinding.h" +#include "nsIScriptSecurityManager.h" + +namespace mozilla { + +class OriginAttributes : public dom::OriginAttributesDictionary +{ +public: + OriginAttributes() {} + + OriginAttributes(uint32_t aAppId, bool aInIsolatedMozBrowser) + { + mAppId = aAppId; + mInIsolatedMozBrowser = aInIsolatedMozBrowser; + } + + explicit OriginAttributes(const OriginAttributesDictionary& aOther) + : OriginAttributesDictionary(aOther) + {} + + void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI); + void SetFirstPartyDomain(const bool aIsTopLevelDocument, const nsACString& aDomain); + + enum { + STRIP_FIRST_PARTY_DOMAIN = 0x01, + STRIP_USER_CONTEXT_ID = 0x02, + }; + + inline void StripAttributes(uint32_t aFlags) + { + if (aFlags & STRIP_FIRST_PARTY_DOMAIN) { + mFirstPartyDomain.Truncate(); + } + + if (aFlags & STRIP_USER_CONTEXT_ID) { + mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID; + } + } + + bool operator==(const OriginAttributes& aOther) const + { + return mAppId == aOther.mAppId && + mInIsolatedMozBrowser == aOther.mInIsolatedMozBrowser && + mUserContextId == aOther.mUserContextId && + mPrivateBrowsingId == aOther.mPrivateBrowsingId && + mFirstPartyDomain == aOther.mFirstPartyDomain; + } + + bool operator!=(const OriginAttributes& aOther) const + { + return !(*this == aOther); + } + + // Serializes/Deserializes non-default values into the suffix format, i.e. + // |!key1=value1&key2=value2|. If there are no non-default attributes, this + // returns an empty string. + void CreateSuffix(nsACString& aStr) const; + + // Don't use this method for anything else than debugging! + void CreateAnonymizedSuffix(nsACString& aStr) const; + + MOZ_MUST_USE bool PopulateFromSuffix(const nsACString& aStr); + + // Populates the attributes from a string like + // |uri!key1=value1&key2=value2| and returns the uri without the suffix. + MOZ_MUST_USE bool PopulateFromOrigin(const nsACString& aOrigin, + nsACString& aOriginNoSuffix); + + // Helper function to match mIsPrivateBrowsing to existing private browsing + // flags. Once all other flags are removed, this can be removed too. + void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing); + + // check if "privacy.firstparty.isolate" is enabled. + static inline bool IsFirstPartyEnabled() + { + return sFirstPartyIsolation; + } + + // check if the access of window.opener across different FPDs is restricted. + // We only restrict the access of window.opener when first party isolation + // is enabled and "privacy.firstparty.isolate.restrict_opener_access" is on. + static inline bool IsRestrictOpenerAccessForFPI() + { + // We always want to restrict window.opener if first party isolation is + // disabled. + return !sFirstPartyIsolation || sRestrictedOpenerAccess; + } + + // returns true if the originAttributes suffix has mPrivateBrowsingId value + // different than 0. + static bool IsPrivateBrowsing(const nsACString& aOrigin); + + static void InitPrefs(); + +private: + static bool sFirstPartyIsolation; + static bool sRestrictedOpenerAccess; +}; + +class OriginAttributesPattern : public dom::OriginAttributesPatternDictionary +{ +public: + // To convert a JSON string to an OriginAttributesPattern, do the following: + // + // OriginAttributesPattern pattern; + // if (!pattern.Init(aJSONString)) { + // ... // handle failure. + // } + OriginAttributesPattern() {} + + explicit OriginAttributesPattern(const OriginAttributesPatternDictionary& aOther) + : OriginAttributesPatternDictionary(aOther) {} + + // Performs a match of |aAttrs| against this pattern. + bool Matches(const OriginAttributes& aAttrs) const + { + if (mAppId.WasPassed() && mAppId.Value() != aAttrs.mAppId) { + return false; + } + + if (mInIsolatedMozBrowser.WasPassed() && mInIsolatedMozBrowser.Value() != aAttrs.mInIsolatedMozBrowser) { + return false; + } + + if (mUserContextId.WasPassed() && mUserContextId.Value() != aAttrs.mUserContextId) { + return false; + } + + if (mPrivateBrowsingId.WasPassed() && mPrivateBrowsingId.Value() != aAttrs.mPrivateBrowsingId) { + return false; + } + + if (mFirstPartyDomain.WasPassed() && mFirstPartyDomain.Value() != aAttrs.mFirstPartyDomain) { + return false; + } + + return true; + } + + bool Overlaps(const OriginAttributesPattern& aOther) const + { + if (mAppId.WasPassed() && aOther.mAppId.WasPassed() && + mAppId.Value() != aOther.mAppId.Value()) { + return false; + } + + if (mInIsolatedMozBrowser.WasPassed() && + aOther.mInIsolatedMozBrowser.WasPassed() && + mInIsolatedMozBrowser.Value() != aOther.mInIsolatedMozBrowser.Value()) { + return false; + } + + if (mUserContextId.WasPassed() && aOther.mUserContextId.WasPassed() && + mUserContextId.Value() != aOther.mUserContextId.Value()) { + return false; + } + + if (mPrivateBrowsingId.WasPassed() && aOther.mPrivateBrowsingId.WasPassed() && + mPrivateBrowsingId.Value() != aOther.mPrivateBrowsingId.Value()) { + return false; + } + + if (mFirstPartyDomain.WasPassed() && aOther.mFirstPartyDomain.WasPassed() && + mFirstPartyDomain.Value() != aOther.mFirstPartyDomain.Value()) { + return false; + } + + return true; + } +}; + +} // namespace mozilla + +#endif /* mozilla_OriginAttributes_h */ diff --git a/caps/moz.build b/caps/moz.build index 2f3d6614cdf5..46331e93f097 100644 --- a/caps/moz.build +++ b/caps/moz.build @@ -30,7 +30,8 @@ EXPORTS += [ ] EXPORTS.mozilla = [ - 'BasePrincipal.h' + 'BasePrincipal.h', + 'OriginAttributes.h', ] SOURCES += [ @@ -47,6 +48,7 @@ UNIFIED_SOURCES += [ 'nsScriptSecurityManager.cpp', 'NullPrincipal.cpp', 'NullPrincipalURI.cpp', + 'OriginAttributes.cpp', 'SystemPrincipal.cpp', ] From 101a58b3c65f343460177e604c174c360e0c236b Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sat, 18 Mar 2017 16:08:12 -0400 Subject: [PATCH 85/96] Bug 1316683 - Avoid going into SpiderMonkey for retrieving origin attributes; r=baku Our caller is C++ code, and the implementations are all also written in C++, so there is no reason to go through SpiderMonkey here. This patch also makes nsILoadContext builtinclass to ensure that the implementation is always native. --- caps/nsScriptSecurityManager.cpp | 3 +- docshell/base/LoadContext.cpp | 30 ++++--------------- docshell/base/LoadContext.h | 2 ++ docshell/base/SerializedLoadContext.cpp | 4 +-- docshell/base/nsDocShell.cpp | 6 ++++ docshell/base/nsDocShell.h | 2 ++ docshell/base/nsILoadContext.idl | 6 ++-- dom/base/nsDocument.h | 20 +++++++++---- dom/ipc/TabParent.cpp | 1 + dom/offline/nsDOMOfflineResourceList.cpp | 3 +- .../prefetch/OfflineCacheUpdateParent.cpp | 8 +++++ uriloader/prefetch/OfflineCacheUpdateParent.h | 2 ++ 12 files changed, 46 insertions(+), 41 deletions(-) diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 0d587f8115a3..7d70c97a8f1e 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -1168,8 +1168,7 @@ nsScriptSecurityManager:: { NS_ENSURE_STATE(aLoadContext); OriginAttributes docShellAttrs; - bool result = aLoadContext->GetOriginAttributes(docShellAttrs); - NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); + aLoadContext->GetOriginAttributes(docShellAttrs); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, docShellAttrs); diff --git a/docshell/base/LoadContext.cpp b/docshell/base/LoadContext.cpp index 6c3ba6b52311..03fa53273189 100644 --- a/docshell/base/LoadContext.cpp +++ b/docshell/base/LoadContext.cpp @@ -12,30 +12,6 @@ #include "nsContentUtils.h" #include "xpcpublic.h" -bool -nsILoadContext::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) -{ - mozilla::dom::AutoJSAPI jsapi; - bool ok = jsapi.Init(xpc::PrivilegedJunkScope()); - NS_ENSURE_TRUE(ok, false); - JS::Rooted v(jsapi.cx()); - nsresult rv = GetOriginAttributes(&v); - NS_ENSURE_SUCCESS(rv, false); - NS_ENSURE_TRUE(v.isObject(), false); - JS::Rooted obj(jsapi.cx(), &v.toObject()); - - // If we're JS-implemented, the object will be left in a different (System-Principaled) - // scope, so we may need to enter its compartment. - MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj))); - JSAutoCompartment ac(jsapi.cx(), obj); - - mozilla::OriginAttributes attrs; - ok = attrs.Init(jsapi.cx(), v); - NS_ENSURE_TRUE(ok, false); - aAttrs = attrs; - return true; -} - namespace mozilla { NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor) @@ -181,6 +157,12 @@ LoadContext::GetOriginAttributes(JS::MutableHandleValue aAttrs) return NS_OK; } +NS_IMETHODIMP_(void) +LoadContext::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) +{ + aAttrs = mOriginAttributes; +} + NS_IMETHODIMP LoadContext::GetUseTrackingProtection(bool* aUseTrackingProtection) { diff --git a/docshell/base/LoadContext.h b/docshell/base/LoadContext.h index 0b05899ab934..dc0012c76d3c 100644 --- a/docshell/base/LoadContext.h +++ b/docshell/base/LoadContext.h @@ -111,6 +111,8 @@ public: private: ~LoadContext() {} + NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; + nsWeakPtr mTopFrameElement; uint64_t mNestedFrameId; bool mIsContent; diff --git a/docshell/base/SerializedLoadContext.cpp b/docshell/base/SerializedLoadContext.cpp index 501a417a5125..3964a78f9fc3 100644 --- a/docshell/base/SerializedLoadContext.cpp +++ b/docshell/base/SerializedLoadContext.cpp @@ -62,9 +62,7 @@ SerializedLoadContext::Init(nsILoadContext* aLoadContext) aLoadContext->GetIsContent(&mIsContent); aLoadContext->GetUseRemoteTabs(&mUseRemoteTabs); aLoadContext->GetUseTrackingProtection(&mUseTrackingProtection); - if (!aLoadContext->GetOriginAttributes(mOriginAttributes)) { - NS_WARNING("GetOriginAttributes failed"); - } + aLoadContext->GetOriginAttributes(mOriginAttributes); } else { mIsNotNull = false; mIsPrivateBitValid = false; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 6ed2909fb70e..d07474e493c3 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -14944,3 +14944,9 @@ nsDocShell::GetAwaitingLargeAlloc(bool* aResult) *aResult = static_cast(tabChild.get())->IsAwaitingLargeAlloc(); return NS_OK; } + +NS_IMETHODIMP_(void) +nsDocShell::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) +{ + aAttrs = mOriginAttributes; +} diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 937897023340..af5416c105c9 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -806,6 +806,8 @@ protected: void UpdateGlobalHistoryTitle(nsIURI* aURI); + NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; + // Dimensions of the docshell nsIntRect mBounds; nsString mName; diff --git a/docshell/base/nsILoadContext.idl b/docshell/base/nsILoadContext.idl index 98e8a2119171..d3a39a676c79 100644 --- a/docshell/base/nsILoadContext.idl +++ b/docshell/base/nsILoadContext.idl @@ -20,7 +20,7 @@ interface nsIDOMElement; * can be queried for various information about where the load is * happening. */ -[scriptable, uuid(2813a7a3-d084-4d00-acd0-f76620315c02)] +[builtinclass, scriptable, uuid(2813a7a3-d084-4d00-acd0-f76620315c02)] interface nsILoadContext : nsISupports { /** @@ -139,10 +139,8 @@ interface nsILoadContext : nsISupports #ifdef MOZILLA_INTERNAL_API /** * The C++ getter for origin attributes. - * - * Defined in LoadContext.cpp */ - bool GetOriginAttributes(mozilla::OriginAttributes& aAttrs); + NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) = 0; #endif %} }; diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 9ef1d404de77..05d0cb772e88 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -444,7 +444,7 @@ protected: // implement one interface. // XXXbz I wish we could just derive the _allcaps thing from _i -#define DECL_SHIM(_i, _allcaps) \ +#define DECL_SHIM(_i, _allcaps, _customfwd) \ class _i##Shim final : public nsIInterfaceRequestor, \ public _i \ { \ @@ -459,17 +459,25 @@ protected: NS_DECL_ISUPPORTS \ NS_FORWARD_NSIINTERFACEREQUESTOR(mIfReq->) \ NS_FORWARD_##_allcaps(mRealPtr->) \ + _customfwd \ private: \ nsCOMPtr mIfReq; \ nsCOMPtr<_i> mRealPtr; \ }; - DECL_SHIM(nsILoadContext, NSILOADCONTEXT) - DECL_SHIM(nsIProgressEventSink, NSIPROGRESSEVENTSINK) - DECL_SHIM(nsIChannelEventSink, NSICHANNELEVENTSINK) - DECL_SHIM(nsISecurityEventSink, NSISECURITYEVENTSINK) - DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER) +#define DECL_FORWARD_CPP_GETORIGINATTRIBUTES \ + NS_IMETHODIMP_(void) \ + GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override \ + { \ + mRealPtr->GetOriginAttributes(aAttrs); \ + } + DECL_SHIM(nsILoadContext, NSILOADCONTEXT, DECL_FORWARD_CPP_GETORIGINATTRIBUTES) + DECL_SHIM(nsIProgressEventSink, NSIPROGRESSEVENTSINK, ) + DECL_SHIM(nsIChannelEventSink, NSICHANNELEVENTSINK, ) + DECL_SHIM(nsISecurityEventSink, NSISECURITYEVENTSINK, ) + DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER, ) #undef DECL_SHIM +#undef DECL_FORWARD_CPP_GETORIGINATTRIBUTES }; /** diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index 87163e1bcb91..e6e144df1a89 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -3020,6 +3020,7 @@ public: NS_IMETHOD SetPrivateBrowsing(bool) NO_IMPL NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool*) NO_IMPL NS_IMETHOD GetOriginAttributes(JS::MutableHandleValue) NO_IMPL + NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override {} NS_IMETHOD GetUseRemoteTabs(bool*) NO_IMPL NS_IMETHOD SetRemoteTabs(bool) NO_IMPL NS_IMETHOD GetUseTrackingProtection(bool*) NO_IMPL diff --git a/dom/offline/nsDOMOfflineResourceList.cpp b/dom/offline/nsDOMOfflineResourceList.cpp index a02b2956245e..b6b49670b8b7 100644 --- a/dom/offline/nsDOMOfflineResourceList.cpp +++ b/dom/offline/nsDOMOfflineResourceList.cpp @@ -815,8 +815,7 @@ nsDOMOfflineResourceList::CacheKeys() nsAutoCString originSuffix; if (loadContext) { mozilla::OriginAttributes oa; - bool ok = loadContext->GetOriginAttributes(oa); - NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED); + loadContext->GetOriginAttributes(oa); oa.CreateSuffix(originSuffix); } diff --git a/uriloader/prefetch/OfflineCacheUpdateParent.cpp b/uriloader/prefetch/OfflineCacheUpdateParent.cpp index c77f2b49a02e..f10821292b71 100644 --- a/uriloader/prefetch/OfflineCacheUpdateParent.cpp +++ b/uriloader/prefetch/OfflineCacheUpdateParent.cpp @@ -276,6 +276,14 @@ OfflineCacheUpdateParent::GetOriginAttributes(JS::MutableHandleValue aAttrs) return NS_OK; } +NS_IMETHODIMP_(void) +OfflineCacheUpdateParent::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) +{ + if (mLoadingPrincipal) { + aAttrs = mLoadingPrincipal->OriginAttributesRef(); + } +} + NS_IMETHODIMP OfflineCacheUpdateParent::GetUseTrackingProtection(bool* aUseTrackingProtection) { diff --git a/uriloader/prefetch/OfflineCacheUpdateParent.h b/uriloader/prefetch/OfflineCacheUpdateParent.h index f6dbc1cb2a6f..2637c6bdca42 100644 --- a/uriloader/prefetch/OfflineCacheUpdateParent.h +++ b/uriloader/prefetch/OfflineCacheUpdateParent.h @@ -54,6 +54,8 @@ public: private: ~OfflineCacheUpdateParent(); + NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; + bool mIPCClosed; nsCOMPtr mLoadingPrincipal; From 6c54db1fdfe7fde0a2fc56486818323726439958 Mon Sep 17 00:00:00 2001 From: Robert Strong Date: Wed, 22 Mar 2017 11:45:11 -0700 Subject: [PATCH 86/96] Bug 1348609 - Use the installation dir path CityHash hash for the updates directory even when the hash hasn't been written to the registry by the installer. r=mhowell, r=dtownsend --- toolkit/xre/moz.build | 1 + toolkit/xre/nsXREDirProvider.cpp | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/toolkit/xre/moz.build b/toolkit/xre/moz.build index b119d38ab76f..f79080b35aaa 100644 --- a/toolkit/xre/moz.build +++ b/toolkit/xre/moz.build @@ -37,6 +37,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': ] DEFINES['PROXY_PRINTING'] = 1 LOCAL_INCLUDES += [ + '../../other-licenses/nsis/Contrib/CityHash/cityhash', '../components/printingui/win', ] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp index 2c9a41b0feb6..4878923c6f1d 100644 --- a/toolkit/xre/nsXREDirProvider.cpp +++ b/toolkit/xre/nsXREDirProvider.cpp @@ -46,6 +46,7 @@ #include #ifdef XP_WIN +#include "city.h" #include #include #endif @@ -1439,12 +1440,26 @@ nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult) } } - // Get the local app data directory and if a vendor name exists append it. - // If only a product name exists, append it. If neither exist fallback to - // old handling. We don't use the product name on purpose because we want a - // shared update directory for different apps run from the same path. + if (!pathHashResult) { + // This should only happen when the installer isn't used (e.g. zip builds). + uint64_t hash = CityHash64(static_cast(appDirPath.get()), + appDirPath.Length() * sizeof(nsAutoString::char_type)); + pathHash.AppendInt((int)(hash >> 32), 16); + pathHash.AppendInt((int)hash, 16); + // The installer implementation writes the registry values that were checked + // in the previous block for this value in uppercase and since it is an + // option to have a case sensitive file system on Windows this value must + // also be in uppercase. + ToUpperCase(pathHash); + } + + // As a last ditch effort, get the local app data directory and if a vendor + // name exists append it. If only a product name exists, append it. If neither + // exist fallback to old handling. We don't use the product name on purpose + // because we want a shared update directory for different apps run from the + // same path. nsCOMPtr localDir; - if (pathHashResult && (hasVendor || gAppData->name) && + if ((hasVendor || gAppData->name) && NS_SUCCEEDED(GetUserDataDirectoryHome(getter_AddRefs(localDir), true)) && NS_SUCCEEDED(localDir->AppendNative(nsDependentCString(hasVendor ? gAppData->vendor : gAppData->name))) && From baebc834321800b5693a929fb63d5b3dcc4fb279 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 22 Mar 2017 14:57:25 -0400 Subject: [PATCH 87/96] Bug 1347632 - make RecordedSourceSurfaceCreation fallible. r=tobytailor MozReview-Commit-ID: G4x3zTluGb4 --- gfx/2d/RecordedEvent.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/gfx/2d/RecordedEvent.cpp b/gfx/2d/RecordedEvent.cpp index 6d3688ac05f3..370ac98d1ffe 100644 --- a/gfx/2d/RecordedEvent.cpp +++ b/gfx/2d/RecordedEvent.cpp @@ -1299,6 +1299,10 @@ RecordedSourceSurfaceCreation::~RecordedSourceSurfaceCreation() bool RecordedSourceSurfaceCreation::PlayEvent(Translator *aTranslator) const { + if (!mData) { + return false; + } + RefPtr src = aTranslator->GetReferenceDrawTarget()-> CreateSourceSurfaceFromData(mData, mSize, mSize.width * BytesPerPixel(mFormat), mFormat); aTranslator->AddSourceSurface(mRefPtr, src); @@ -1311,6 +1315,7 @@ RecordedSourceSurfaceCreation::RecordToStream(ostream &aStream) const WriteElement(aStream, mRefPtr); WriteElement(aStream, mSize); WriteElement(aStream, mFormat); + MOZ_ASSERT(mData); for (int y = 0; y < mSize.height; y++) { aStream.write((const char*)mData + y * mStride, BytesPerPixel(mFormat) * mSize.width); } @@ -1322,8 +1327,12 @@ RecordedSourceSurfaceCreation::RecordedSourceSurfaceCreation(istream &aStream) ReadElement(aStream, mRefPtr); ReadElement(aStream, mSize); ReadElement(aStream, mFormat); - mData = (uint8_t*)new char[mSize.width * mSize.height * BytesPerPixel(mFormat)]; - aStream.read((char*)mData, mSize.width * mSize.height * BytesPerPixel(mFormat)); + mData = (uint8_t*)new (fallible) char[mSize.width * mSize.height * BytesPerPixel(mFormat)]; + if (!mData) { + gfxWarning() << "RecordedSourceSurfaceCreation failed to allocate data"; + } else { + aStream.read((char*)mData, mSize.width * mSize.height * BytesPerPixel(mFormat)); + } } void From 49eb5ba0b6d242f42591214ca7e7b9b587137dc7 Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Tue, 21 Mar 2017 22:34:03 -0400 Subject: [PATCH 88/96] Bug 1285533. Remove non-fontconfig platform fontlist codepath. r=lsalzman This has been disabled for two years. It's time for it to die. --- accessible/base/TextAttrs.cpp | 34 +++---------- gfx/thebes/gfxPlatform.cpp | 18 ++----- gfx/thebes/gfxPlatformGtk.cpp | 94 ++++++++--------------------------- gfx/thebes/gfxPlatformGtk.h | 6 --- gfx/thebes/gfxTextRun.cpp | 14 ------ layout/base/nsPresContext.cpp | 14 +----- modules/libpref/init/all.js | 6 --- 7 files changed, 33 insertions(+), 153 deletions(-) diff --git a/accessible/base/TextAttrs.cpp b/accessible/base/TextAttrs.cpp index cb66d1380b9c..f6e6d8519972 100644 --- a/accessible/base/TextAttrs.cpp +++ b/accessible/base/TextAttrs.cpp @@ -18,10 +18,6 @@ #include "mozilla/AppUnits.h" #include "mozilla/gfx/2D.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - using namespace mozilla; using namespace mozilla::a11y; @@ -652,28 +648,14 @@ TextAttrsMgr::FontWeightTextAttr:: if (font->IsSyntheticBold()) return 700; - bool useFontEntryWeight = true; - - // Under Linux, when gfxPangoFontGroup code is used, - // font->GetStyle()->weight will give the absolute weight requested of the - // font face. The gfxPangoFontGroup code uses the gfxFontEntry constructor - // which doesn't initialize the weight field. -#if defined(MOZ_WIDGET_GTK) - useFontEntryWeight = gfxPlatformGtk::UseFcFontList(); -#endif - - if (useFontEntryWeight) { - // On Windows, font->GetStyle()->weight will give the same weight as - // fontEntry->Weight(), the weight of the first font in the font group, - // which may not be the weight of the font face used to render the - // characters. On Mac, font->GetStyle()->weight will just give the same - // number as getComputedStyle(). fontEntry->Weight() will give the weight - // of the font face used. - gfxFontEntry *fontEntry = font->GetFontEntry(); - return fontEntry->Weight(); - } else { - return font->GetStyle()->weight; - } + // On Windows, font->GetStyle()->weight will give the same weight as + // fontEntry->Weight(), the weight of the first font in the font group, + // which may not be the weight of the font face used to render the + // characters. On Mac, font->GetStyle()->weight will just give the same + // number as getComputedStyle(). fontEntry->Weight() will give the weight + // of the font face used. + gfxFontEntry *fontEntry = font->GetFontEntry(); + return fontEntry->Weight(); } //////////////////////////////////////////////////////////////////////////////// diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 95536eea123d..9a4bd2ae07cd 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -88,10 +88,6 @@ #include "GLContextProvider.h" #include "mozilla/gfx/Logging.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - #ifdef MOZ_WIDGET_ANDROID #include "TexturePoolOGL.h" #include "mozilla/layers/UiCompositorControllerChild.h" @@ -711,17 +707,9 @@ gfxPlatform::Init() gPlatform->ComputeTileSize(); nsresult rv; - - bool usePlatformFontList = true; -#if defined(MOZ_WIDGET_GTK) - usePlatformFontList = gfxPlatformGtk::UseFcFontList(); -#endif - - if (usePlatformFontList) { - rv = gfxPlatformFontList::Init(); - if (NS_FAILED(rv)) { - MOZ_CRASH("Could not initialize gfxPlatformFontList"); - } + rv = gfxPlatformFontList::Init(); + if (NS_FAILED(rv)) { + MOZ_CRASH("Could not initialize gfxPlatformFontList"); } gPlatform->mScreenReferenceSurface = diff --git a/gfx/thebes/gfxPlatformGtk.cpp b/gfx/thebes/gfxPlatformGtk.cpp index 501389934abd..a7629ed5916b 100644 --- a/gfx/thebes/gfxPlatformGtk.cpp +++ b/gfx/thebes/gfxPlatformGtk.cpp @@ -67,23 +67,14 @@ using namespace mozilla; using namespace mozilla::gfx; using namespace mozilla::unicode; -gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nullptr; - #if (MOZ_WIDGET_GTK == 2) static cairo_user_data_key_t cairo_gdk_drawable_key; #endif -bool gfxPlatformGtk::sUseFcFontList = false; - gfxPlatformGtk::gfxPlatformGtk() { gtk_init(nullptr, nullptr); - sUseFcFontList = mozilla::Preferences::GetBool("gfx.font_rendering.fontconfig.fontlist.enabled"); - if (!sUseFcFontList && !sFontconfigUtils) { - sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils(); - } - mMaxGenericSubstitutions = UNINITIALIZED_VALUE; #ifdef MOZ_X11 @@ -117,12 +108,6 @@ gfxPlatformGtk::gfxPlatformGtk() gfxPlatformGtk::~gfxPlatformGtk() { - if (!sUseFcFontList) { - gfxFontconfigUtils::Shutdown(); - sFontconfigUtils = nullptr; - gfxPangoFontGroup::Shutdown(); - } - #ifdef MOZ_X11 if (mCompositorDisplay) { XCloseDisplay(mCompositorDisplay); @@ -200,27 +185,17 @@ gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup, const nsACString& aGenericFamily, nsTArray& aListOfFonts) { - if (sUseFcFontList) { - gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, - aGenericFamily, - aListOfFonts); - return NS_OK; - } - - return sFontconfigUtils->GetFontList(aLangGroup, - aGenericFamily, - aListOfFonts); + gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup, + aGenericFamily, + aListOfFonts); + return NS_OK; } nsresult gfxPlatformGtk::UpdateFontList() { - if (sUseFcFontList) { - gfxPlatformFontList::PlatformFontList()->UpdateFontList(); - return NS_OK; - } - - return sFontconfigUtils->UpdateFontList(); + gfxPlatformFontList::PlatformFontList()->UpdateFontList(); + return NS_OK; } // xxx - this is ubuntu centric, need to go through other distros and flesh @@ -287,13 +262,9 @@ gfxPlatformGtk::CreatePlatformFontList() nsresult gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) { - if (sUseFcFontList) { - gfxPlatformFontList::PlatformFontList()-> - GetStandardFamilyName(aFontName, aFamilyName); - return NS_OK; - } - - return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName); + gfxPlatformFontList::PlatformFontList()-> + GetStandardFamilyName(aFontName, aFamilyName); + return NS_OK; } gfxFontGroup * @@ -303,13 +274,8 @@ gfxPlatformGtk::CreateFontGroup(const FontFamilyList& aFontFamilyList, gfxUserFontSet* aUserFontSet, gfxFloat aDevToCssSize) { - if (sUseFcFontList) { - return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, - aUserFontSet, aDevToCssSize); - } - - return new gfxPangoFontGroup(aFontFamilyList, aStyle, - aUserFontSet, aDevToCssSize); + return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf, + aUserFontSet, aDevToCssSize); } gfxFontEntry* @@ -318,14 +284,9 @@ gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName, int16_t aStretch, uint8_t aStyle) { - if (sUseFcFontList) { - gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); - return pfl->LookupLocalFont(aFontName, aWeight, aStretch, - aStyle); - } - - return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight, - aStretch, aStyle); + gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); + return pfl->LookupLocalFont(aFontName, aWeight, aStretch, + aStyle); } gfxFontEntry* @@ -336,26 +297,15 @@ gfxPlatformGtk::MakePlatformFont(const nsAString& aFontName, const uint8_t* aFontData, uint32_t aLength) { - if (sUseFcFontList) { - gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); - return pfl->MakePlatformFont(aFontName, aWeight, aStretch, - aStyle, aFontData, aLength); - } - - // passing ownership of the font data to the new font entry - return gfxPangoFontGroup::NewFontEntry(aFontName, aWeight, - aStretch, aStyle, - aFontData, aLength); + gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList(); + return pfl->MakePlatformFont(aFontName, aWeight, aStretch, + aStyle, aFontData, aLength); } FT_Library gfxPlatformGtk::GetFTLibrary() { - if (sUseFcFontList) { - return gfxFcPlatformFontList::GetFTLibrary(); - } - - return gfxPangoFontGroup::GetFTLibrary(); + return gfxFcPlatformFontList::GetFTLibrary(); } bool @@ -447,11 +397,9 @@ void gfxPlatformGtk::FontsPrefsChanged(const char *aPref) } mMaxGenericSubstitutions = UNINITIALIZED_VALUE; - if (sUseFcFontList) { - gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList(); - pfl->ClearGenericMappings(); - FlushFontAndWordCaches(); - } + gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList(); + pfl->ClearGenericMappings(); + FlushFontAndWordCaches(); } uint32_t gfxPlatformGtk::MaxGenericSubstitions() diff --git a/gfx/thebes/gfxPlatformGtk.h b/gfx/thebes/gfxPlatformGtk.h index 25706de85bf8..baa4353cab37 100644 --- a/gfx/thebes/gfxPlatformGtk.h +++ b/gfx/thebes/gfxPlatformGtk.h @@ -113,8 +113,6 @@ public: } #endif - static bool UseFcFontList() { return sUseFcFontList; } - bool UseImageOffscreenSurfaces(); virtual gfxImageFormat GetOffscreenFormat() override; @@ -158,10 +156,6 @@ private: #ifdef MOZ_X11 Display* mCompositorDisplay; #endif - - // xxx - this will be removed once the new fontconfig platform font list - // replaces gfxPangoFontGroup - static bool sUseFcFontList; }; #endif /* GFX_PLATFORM_GTK_H */ diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index e32d50c89146..8f6c359a78bd 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -28,10 +28,6 @@ #include "mozilla/gfx/Logging.h" // for gfxCriticalError #include "mozilla/UniquePtr.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - #ifdef XP_WIN #include "gfxWindowsPlatform.h" #endif @@ -1730,16 +1726,6 @@ gfxFontGroup::~gfxFontGroup() void gfxFontGroup::BuildFontList() { - bool enumerateFonts = true; - -#if defined(MOZ_WIDGET_GTK) - // xxx - eliminate this once gfxPangoFontGroup is no longer needed - enumerateFonts = gfxPlatformGtk::UseFcFontList(); -#endif - if (!enumerateFonts) { - return; - } - // initialize fonts in the font family list AutoTArray fonts; gfxPlatformFontList *pfl = gfxPlatformFontList::PlatformFontList(); diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index ca1234ac16fa..970427db77f7 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -82,11 +82,6 @@ #include "mozilla/dom/PerformanceTiming.h" #include "mozilla/layers/APZThreadUtils.h" -#if defined(MOZ_WIDGET_GTK) -#include "gfxPlatformGtk.h" // xxx - for UseFcFontList -#endif - - // Needed for Start/Stop of Image Animation #include "imgIContainer.h" #include "nsIImageLoadingContent.h" @@ -2214,19 +2209,12 @@ nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) if (!mShell) return; - bool usePlatformFontList = true; -#if defined(MOZ_WIDGET_GTK) - usePlatformFontList = gfxPlatformGtk::UseFcFontList(); -#endif - - // xxx - until the Linux platform font list is always used, use full - // restyle to force updates with gfxPangoFontGroup usage // Note: this method is called without a font when rules in the userfont set // are updated, which may occur during reflow as a result of the lazy // initialization of the userfont set. It would be better to avoid a full // restyle but until this method is only called outside of reflow, schedule a // full restyle in these cases. - if (!usePlatformFontList || !aUpdatedFont) { + if (!aUpdatedFont) { PostRebuildAllStyleDataEvent(NS_STYLE_HINT_REFLOW, eRestyle_ForceDescendants); return; } diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index edeea402fe3f..8887ee65770e 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -4204,13 +4204,7 @@ pref("intl.ime.use_simple_context_on_password_field", true); pref("intl.ime.use_simple_context_on_password_field", false); #endif -# enable new platform fontlist for linux on GTK platforms -# temporary pref to allow flipping back to the existing -# gfxPangoFontGroup/gfxFontconfigUtils code for handling system fonts - #ifdef MOZ_WIDGET_GTK -pref("gfx.font_rendering.fontconfig.fontlist.enabled", true); - // maximum number of fonts to substitute for a generic pref("gfx.font_rendering.fontconfig.max_generic_substitutions", 3); #endif From da3210576b57436bf717239748f720cfc3553fff Mon Sep 17 00:00:00 2001 From: Jeff Muizelaar Date: Wed, 22 Mar 2017 12:00:02 -0400 Subject: [PATCH 89/96] Bug 1119128. Eliminate gfxPangoFontGroup and gfxFontconfigUtils. r=lsalzman --- build/valgrind/i386-redhat-linux-gnu.sup | 10 - build/valgrind/x86_64-redhat-linux-gnu.sup | 10 - gfx/thebes/gfxFontconfigFonts.cpp | 2262 -------------------- gfx/thebes/gfxFontconfigFonts.h | 99 - gfx/thebes/gfxFontconfigUtils.cpp | 1100 ---------- gfx/thebes/gfxFontconfigUtils.h | 281 +-- gfx/thebes/gfxTextRun.cpp | 5 +- gfx/thebes/gfxTextRun.h | 3 - gfx/thebes/gfxUserFontSet.cpp | 26 - gfx/thebes/gfxUserFontSet.h | 8 - gfx/thebes/moz.build | 2 - 11 files changed, 4 insertions(+), 3802 deletions(-) delete mode 100644 gfx/thebes/gfxFontconfigFonts.cpp delete mode 100644 gfx/thebes/gfxFontconfigUtils.cpp diff --git a/build/valgrind/i386-redhat-linux-gnu.sup b/build/valgrind/i386-redhat-linux-gnu.sup index c1d39cd24482..cfdc37bb0009 100644 --- a/build/valgrind/i386-redhat-linux-gnu.sup +++ b/build/valgrind/i386-redhat-linux-gnu.sup @@ -18,16 +18,6 @@ obj:/lib/libdbus-1.so.3.4.0 ... } -{ - Bug 793600 - Memcheck:Leak - fun:realloc - obj:/usr/lib/libfontconfig.so.1.4.4 - ... - fun:FcDefaultSubstitute - fun:_ZN17gfxPangoFontGroup11MakeFontSetEP14_PangoLanguagedP9nsAutoRefI10_FcPatternE - ... -} { Bug 794366 Memcheck:Leak diff --git a/build/valgrind/x86_64-redhat-linux-gnu.sup b/build/valgrind/x86_64-redhat-linux-gnu.sup index 06435e466526..aa8fb80a742d 100644 --- a/build/valgrind/x86_64-redhat-linux-gnu.sup +++ b/build/valgrind/x86_64-redhat-linux-gnu.sup @@ -18,16 +18,6 @@ obj:/lib64/libdbus-1.so.3.4.0 ... } -{ - Bug 793600 - Memcheck:Leak - fun:realloc - obj:/usr/lib64/libfontconfig.so.1.4.4 - ... - fun:FcDefaultSubstitute - fun:_ZN17gfxPangoFontGroup11MakeFontSetEP14_PangoLanguagedP9nsAutoRefI10_FcPatternE - ... -} # Fontconfig is going fancy with its cache structure and that confuses valgrind. # https://bugs.freedesktop.org/show_bug.cgi?id=8215 # https://bugs.freedesktop.org/show_bug.cgi?id=8428 diff --git a/gfx/thebes/gfxFontconfigFonts.cpp b/gfx/thebes/gfxFontconfigFonts.cpp deleted file mode 100644 index bbcbbabf9159..000000000000 --- a/gfx/thebes/gfxFontconfigFonts.cpp +++ /dev/null @@ -1,2262 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "prlink.h" -#include "gfxTypes.h" - -#include "nsTArray.h" - -#include "gfxContext.h" -#ifdef MOZ_WIDGET_GTK -#include "gfxPlatformGtk.h" -#endif -#include "gfxFontconfigFonts.h" -#include "gfxFT2FontBase.h" -#include "gfxFT2Utils.h" -#include "harfbuzz/hb.h" -#include "harfbuzz/hb-glib.h" -#include "harfbuzz/hb-ot.h" -#include "nsUnicodeProperties.h" -#include "nsUnicodeScriptCodes.h" -#include "gfxFontconfigUtils.h" -#include "gfxUserFontSet.h" -#include "gfxFontConstants.h" -#include "nsGkAtoms.h" -#include "nsILanguageAtomService.h" -#include "nsServiceManagerUtils.h" - -#include -#include -#include "mozilla/gfx/HelpersCairo.h" - -#include -#include - -#include FT_TRUETYPE_TABLES_H - -#ifdef MOZ_WIDGET_GTK -#include -#endif - -#include - -using namespace mozilla; -using namespace mozilla::unicode; - -#define PRINTING_FC_PROPERTY "gfx.printing" - -static PangoLanguage *GuessPangoLanguage(nsIAtom *aLanguage); - -static cairo_scaled_font_t * -CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace); - -static FT_Library gFTLibrary; - -// FC_FAMILYLANG and FC_FULLNAME were introduced in fontconfig-2.2.97 -// and so fontconfig-2.3.0 (2005). -#ifndef FC_FAMILYLANG -#define FC_FAMILYLANG "familylang" -#endif -#ifndef FC_FULLNAME -#define FC_FULLNAME "fullname" -#endif - -static PRFuncPtr -FindFunctionSymbol(const char *name) -{ - PRLibrary *lib = nullptr; - PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(name, &lib); - if (lib) { - PR_UnloadLibrary(lib); - } - - return result; -} - -static bool HasChar(FcPattern *aFont, FcChar32 wc) -{ - FcCharSet *charset = nullptr; - FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset); - - return charset && FcCharSetHasChar(charset, wc); -} - -/** - * gfxFcFontEntry: - * - * An abstract base class of for gfxFontEntry implementations used by - * gfxFcFont and gfxUserFontSet. - */ - -class gfxFcFontEntry : public gfxFontEntry { -public: - // For all FontEntrys attached to gfxFcFonts, there will be only one - // pattern in this array. This is always a font pattern, not a fully - // resolved pattern. gfxFcFont only uses this to construct a PangoFont. - // - // FontEntrys for src:local() fonts in gfxUserFontSet may return more than - // one pattern. (See comment in gfxUserFcFontEntry.) - const nsTArray< nsCountedRef >& GetPatterns() - { - return mPatterns; - } - - static gfxFcFontEntry *LookupFontEntry(cairo_font_face_t *aFace) - { - return static_cast - (cairo_font_face_get_user_data(aFace, &sFontEntryKey)); - } - - // override the gfxFontEntry impl to read the name from fontconfig - // instead of trying to get the 'name' table, as we don't implement - // GetFontTable() here - virtual nsString RealFaceName(); - - // This is needed to make gfxFontEntry::HasCharacter(aCh) work. - virtual bool TestCharacterMap(uint32_t aCh) - { - for (uint32_t i = 0; i < mPatterns.Length(); ++i) { - if (HasChar(mPatterns[i], aCh)) { - return true; - } - } - return false; - } - -protected: - explicit gfxFcFontEntry(const nsAString& aName) - : gfxFontEntry(aName) - { - } - - // One pattern is the common case and some subclasses rely on successful - // addition of the first element to the array. - AutoTArray,1> mPatterns; - - static cairo_user_data_key_t sFontEntryKey; -}; - -cairo_user_data_key_t gfxFcFontEntry::sFontEntryKey; - -nsString -gfxFcFontEntry::RealFaceName() -{ - FcChar8 *name; - if (!mPatterns.IsEmpty()) { - if (FcPatternGetString(mPatterns[0], - FC_FULLNAME, 0, &name) == FcResultMatch) { - return NS_ConvertUTF8toUTF16((const char*)name); - } - if (FcPatternGetString(mPatterns[0], - FC_FAMILY, 0, &name) == FcResultMatch) { - NS_ConvertUTF8toUTF16 result((const char*)name); - if (FcPatternGetString(mPatterns[0], - FC_STYLE, 0, &name) == FcResultMatch) { - result.Append(' '); - AppendUTF8toUTF16((const char*)name, result); - } - return result; - } - } - // fall back to gfxFontEntry implementation (only works for sfnt fonts) - return gfxFontEntry::RealFaceName(); -} - -/** - * gfxSystemFcFontEntry: - * - * An implementation of gfxFcFontEntry used by gfxFcFonts for system fonts, - * including those from regular family-name based font selection as well as - * those from src:local(). - * - * All gfxFcFonts using the same cairo_font_face_t share the same FontEntry. - */ - -class gfxSystemFcFontEntry : public gfxFcFontEntry { -public: - // For memory efficiency, aFontPattern should be a font pattern, - // not a fully resolved pattern. - gfxSystemFcFontEntry(cairo_font_face_t *aFontFace, - FcPattern *aFontPattern, - const nsAString& aName) - : gfxFcFontEntry(aName), mFontFace(aFontFace), - mFTFace(nullptr), mFTFaceInitialized(false) - { - cairo_font_face_reference(mFontFace); - cairo_font_face_set_user_data(mFontFace, &sFontEntryKey, this, nullptr); - - // mPatterns is an AutoTArray with 1 space always available, so the - // AppendElement always succeeds. - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible)); - mPatterns[0] = aFontPattern; - - FcChar8 *name; - if (FcPatternGetString(aFontPattern, - FC_FAMILY, 0, &name) == FcResultMatch) { - mFamilyName = NS_ConvertUTF8toUTF16((const char*)name); - } - } - - ~gfxSystemFcFontEntry() - { - cairo_font_face_set_user_data(mFontFace, - &sFontEntryKey, - nullptr, - nullptr); - cairo_font_face_destroy(mFontFace); - } - - virtual void ForgetHBFace() override; - virtual void ReleaseGrFace(gr_face* aFace) override; - -protected: - virtual nsresult - CopyFontTable(uint32_t aTableTag, nsTArray& aBuffer) override; - - void MaybeReleaseFTFace(); - -private: - cairo_font_face_t *mFontFace; - FT_Face mFTFace; - bool mFTFaceInitialized; -}; - -nsresult -gfxSystemFcFontEntry::CopyFontTable(uint32_t aTableTag, - nsTArray& aBuffer) -{ - if (!mFTFaceInitialized) { - mFTFaceInitialized = true; - FcChar8 *filename; - if (FcPatternGetString(mPatterns[0], FC_FILE, 0, &filename) != FcResultMatch) { - return NS_ERROR_FAILURE; - } - int index; - if (FcPatternGetInteger(mPatterns[0], FC_INDEX, 0, &index) != FcResultMatch) { - index = 0; // default to 0 if not found in pattern - } - if (FT_New_Face(gfxPangoFontGroup::GetFTLibrary(), - (const char*)filename, index, &mFTFace) != 0) { - return NS_ERROR_FAILURE; - } - } - - if (!mFTFace) { - return NS_ERROR_NOT_AVAILABLE; - } - - FT_ULong length = 0; - if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, nullptr, &length) != 0) { - return NS_ERROR_NOT_AVAILABLE; - } - if (!aBuffer.SetLength(length, fallible)) { - return NS_ERROR_OUT_OF_MEMORY; - } - if (FT_Load_Sfnt_Table(mFTFace, aTableTag, 0, aBuffer.Elements(), &length) != 0) { - aBuffer.Clear(); - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - -void -gfxSystemFcFontEntry::MaybeReleaseFTFace() -{ - // don't release if either HB or Gr face still exists - if (mHBFace || mGrFace) { - return; - } - if (mFTFace) { - FT_Done_Face(mFTFace); - mFTFace = nullptr; - } - mFTFaceInitialized = false; -} - -void -gfxSystemFcFontEntry::ForgetHBFace() -{ - gfxFontEntry::ForgetHBFace(); - MaybeReleaseFTFace(); -} - -void -gfxSystemFcFontEntry::ReleaseGrFace(gr_face* aFace) -{ - gfxFontEntry::ReleaseGrFace(aFace); - MaybeReleaseFTFace(); -} - -// A namespace for @font-face family names in FcPatterns so that fontconfig -// aliases do not pick up families from @font-face rules and so that -// fontconfig rules can distinguish between web fonts and platform fonts. -// http://lists.freedesktop.org/archives/fontconfig/2008-November/003037.html -#define FONT_FACE_FAMILY_PREFIX "@font-face:" - -/** - * gfxUserFcFontEntry: - * - * An abstract class for objects in a gfxUserFontSet that can provide - * FcPattern* handles to fonts. - * - * Separate implementations of this class support local fonts from src:local() - * and web fonts from src:url(). - */ - -// There is a one-to-one correspondence between gfxUserFcFontEntry objects and -// @font-face rules, but sometimes a one-to-many correspondence between font -// entries and font patterns. -// -// http://www.w3.org/TR/2002/WD-css3-webfonts-20020802#font-descriptions -// provided a font-size descriptor to specify the sizes supported by the face, -// but the "Editor's Draft 27 June 2008" -// http://dev.w3.org/csswg/css3-fonts/#font-resources does not provide such a -// descriptor, and Mozilla does not recognize such a descriptor. -// -// Font face names used in src:local() also do not usually specify a size. -// -// PCF format fonts have each size in a different file, and each of these -// files is referenced by its own pattern, but really these are each -// different sizes of one face with one name. -// -// Multiple patterns in an entry also effectively deals with a set of -// PostScript Type 1 font files that all have the same face name but are in -// several files because of the limit on the number of glyphs in a Type 1 font -// file. (e.g. Computer Modern.) - -class gfxUserFcFontEntry : public gfxFcFontEntry { -protected: - explicit gfxUserFcFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle) - : gfxFcFontEntry(aFontName) - { - mStyle = aStyle; - mWeight = aWeight; - mStretch = aStretch; - } - - // Helper function to change a pattern so that it matches the CSS style - // descriptors and so gets properly sorted in font selection. This also - // avoids synthetic style effects being added by the renderer when the - // style of the font itself does not match the descriptor provided by the - // author. - void AdjustPatternToCSS(FcPattern *aPattern); -}; - -void -gfxUserFcFontEntry::AdjustPatternToCSS(FcPattern *aPattern) -{ - int fontWeight = -1; - FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &fontWeight); - int cssWeight = gfxFontconfigUtils::FcWeightForBaseWeight(mWeight / 100); - if (cssWeight != fontWeight) { - FcPatternDel(aPattern, FC_WEIGHT); - FcPatternAddInteger(aPattern, FC_WEIGHT, cssWeight); - } - - int fontSlant; - FcResult res = FcPatternGetInteger(aPattern, FC_SLANT, 0, &fontSlant); - // gfxFontEntry doesn't understand the difference between oblique - // and italic. - if (res != FcResultMatch || - IsItalic() != (fontSlant != FC_SLANT_ROMAN)) { - FcPatternDel(aPattern, FC_SLANT); - FcPatternAddInteger(aPattern, FC_SLANT, - IsItalic() ? FC_SLANT_OBLIQUE : FC_SLANT_ROMAN); - } - - int fontWidth = -1; - FcPatternGetInteger(aPattern, FC_WIDTH, 0, &fontWidth); - int cssWidth = gfxFontconfigUtils::FcWidthForThebesStretch(mStretch); - if (cssWidth != fontWidth) { - FcPatternDel(aPattern, FC_WIDTH); - FcPatternAddInteger(aPattern, FC_WIDTH, cssWidth); - } - - // Ensure that there is a fullname property (if there is a family - // property) so that fontconfig rules can identify the real name of the - // font, because the family property will be replaced. - FcChar8 *unused; - if (FcPatternGetString(aPattern, - FC_FULLNAME, 0, &unused) == FcResultNoMatch) { - nsAutoCString fullname; - if (gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(aPattern, - &fullname)) { - FcPatternAddString(aPattern, FC_FULLNAME, - gfxFontconfigUtils::ToFcChar8(fullname)); - } - } - - nsAutoCString family; - family.Append(FONT_FACE_FAMILY_PREFIX); - AppendUTF16toUTF8(Name(), family); - - FcPatternDel(aPattern, FC_FAMILY); - FcPatternDel(aPattern, FC_FAMILYLANG); - FcPatternAddString(aPattern, FC_FAMILY, - gfxFontconfigUtils::ToFcChar8(family)); -} - -/** - * gfxLocalFcFontEntry: - * - * An implementation of gfxUserFcFontEntry for local fonts from src:local(). - * - * This class is used only in gfxUserFontSet and for providing FcPattern* - * handles to system fonts for font selection. gfxFcFonts created from these - * patterns will use gfxSystemFcFontEntrys, which may be shared with - * gfxFcFonts from regular family-name based font selection. - */ - -class gfxLocalFcFontEntry : public gfxUserFcFontEntry { -public: - gfxLocalFcFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const nsTArray< nsCountedRef >& aPatterns) - : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle) - { - if (!mPatterns.SetCapacity(aPatterns.Length(), fallible)) - return; // OOM - - for (uint32_t i = 0; i < aPatterns.Length(); ++i) { - FcPattern *pattern = FcPatternDuplicate(aPatterns.ElementAt(i)); - if (!pattern) - return; // OOM - - AdjustPatternToCSS(pattern); - - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible)); - mPatterns[i].own(pattern); - } - mIsLocalUserFont = true; - } -}; - -/** - * gfxDownloadedFcFontEntry: - * - * An implementation of gfxFcFontEntry for web fonts from src:url(). - * - * When a cairo_font_face_t is created for these fonts, the cairo_font_face_t - * keeps a reference to the FontEntry to keep the font data alive. - */ - -class gfxDownloadedFcFontEntry : public gfxUserFcFontEntry { -public: - // This takes ownership of the face and its underlying data - gfxDownloadedFcFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const uint8_t *aData, FT_Face aFace) - : gfxUserFcFontEntry(aFontName, aWeight, aStretch, aStyle), - mFontData(aData), mFace(aFace) - { - NS_PRECONDITION(aFace != nullptr, "aFace is NULL!"); - mIsDataUserFont = true; - InitPattern(); - } - - virtual ~gfxDownloadedFcFontEntry(); - - // Returns true on success - bool SetCairoFace(cairo_font_face_t *aFace); - - virtual hb_blob_t* GetFontTable(uint32_t aTableTag) override; - -protected: - void InitPattern(); - - // mFontData holds the data used to instantiate the FT_Face; - // this has to persist until we are finished with the face, - // then be released with free(). - const uint8_t* mFontData; - - FT_Face mFace; -}; - -// A property for recording gfxDownloadedFcFontEntrys on FcPatterns. -static const char *kFontEntryFcProp = "-moz-font-entry"; - -static FcBool AddDownloadedFontEntry(FcPattern *aPattern, - gfxDownloadedFcFontEntry *aFontEntry) -{ - FcValue value; - value.type = FcTypeFTFace; // void* field of union - value.u.f = aFontEntry; - - return FcPatternAdd(aPattern, kFontEntryFcProp, value, FcFalse); -} - -static FcBool DelDownloadedFontEntry(FcPattern *aPattern) -{ - return FcPatternDel(aPattern, kFontEntryFcProp); -} - -static gfxDownloadedFcFontEntry *GetDownloadedFontEntry(FcPattern *aPattern) -{ - FcValue value; - if (FcPatternGet(aPattern, kFontEntryFcProp, 0, &value) != FcResultMatch) - return nullptr; - - if (value.type != FcTypeFTFace) { - NS_NOTREACHED("Wrong type for -moz-font-entry font property"); - return nullptr; - } - - return static_cast(value.u.f); -} - -gfxDownloadedFcFontEntry::~gfxDownloadedFcFontEntry() -{ - if (mPatterns.Length() != 0) { - // Remove back reference to this font entry and the face in case - // anyone holds a reference to the pattern. - NS_ASSERTION(mPatterns.Length() == 1, - "More than one pattern in gfxDownloadedFcFontEntry!"); - DelDownloadedFontEntry(mPatterns[0]); - FcPatternDel(mPatterns[0], FC_FT_FACE); - } - FT_Done_Face(mFace); - free((void*)mFontData); -} - -typedef FcPattern* (*QueryFaceFunction)(const FT_Face face, - const FcChar8 *file, int id, - FcBlanks *blanks); - -void -gfxDownloadedFcFontEntry::InitPattern() -{ - static QueryFaceFunction sQueryFacePtr = - reinterpret_cast - (FindFunctionSymbol("FcFreeTypeQueryFace")); - FcPattern *pattern; - - // FcFreeTypeQueryFace is the same function used to construct patterns for - // system fonts and so is the preferred function to use for this purpose. - // This will set up the langset property, which helps with sorting, and - // the foundry, fullname, and fontversion properties, which properly - // identify the font to fontconfig rules. However, FcFreeTypeQueryFace is - // available only from fontconfig-2.4.2 (December 2006). (CentOS 5.0 has - // fontconfig-2.4.1.) - if (sQueryFacePtr) { - // The "file" argument cannot be nullptr (in fontconfig-2.6.0 at - // least). The dummy file passed here is removed below. - // - // When fontconfig scans the system fonts, FcConfigGetBlanks(nullptr) - // is passed as the "blanks" argument, which provides that unexpectedly - // blank glyphs are elided. Here, however, we pass nullptr for - // "blanks", effectively assuming that, if the font has a blank glyph, - // then the author intends any associated character to be rendered - // blank. - pattern = - (*sQueryFacePtr)(mFace, - gfxFontconfigUtils::ToFcChar8(""), - 0, - nullptr); - if (!pattern) - // Either OOM, or fontconfig chose to skip this font because it - // has "no encoded characters", which I think means "BDF and PCF - // fonts which are not in Unicode (or the effectively equivalent - // ISO Latin-1) encoding". - return; - - // These properties don't make sense for this face without a file. - FcPatternDel(pattern, FC_FILE); - FcPatternDel(pattern, FC_INDEX); - - } else { - // Do the minimum necessary to construct a pattern for sorting. - - // FC_CHARSET is vital to determine which characters are supported. - nsAutoRef charset(FcFreeTypeCharSet(mFace, nullptr)); - // If there are no characters then assume we don't know how to read - // this font. - if (!charset || FcCharSetCount(charset) == 0) - return; - - pattern = FcPatternCreate(); - FcPatternAddCharSet(pattern, FC_CHARSET, charset); - - // FC_PIXEL_SIZE can be important for font selection of fixed-size - // fonts. - if (!(mFace->face_flags & FT_FACE_FLAG_SCALABLE)) { - for (FT_Int i = 0; i < mFace->num_fixed_sizes; ++i) { -#if HAVE_FT_BITMAP_SIZE_Y_PPEM - double size = FLOAT_FROM_26_6(mFace->available_sizes[i].y_ppem); -#else - double size = mFace->available_sizes[i].height; -#endif - FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size); - } - - // Not sure whether this is important; - // imitating FcFreeTypeQueryFace: - FcPatternAddBool (pattern, FC_ANTIALIAS, FcFalse); - } - - // Setting up the FC_LANGSET property is very difficult with the APIs - // available prior to FcFreeTypeQueryFace. Having no FC_LANGSET - // property seems better than having a property with an empty LangSet. - // With no FC_LANGSET property, fontconfig sort functions will - // consider this face to have the same priority as (otherwise equal) - // faces that have support for the primary requested language, but - // will not consider any language to have been satisfied (and so will - // continue to look for a face with language support in fallback - // fonts). - } - - AdjustPatternToCSS(pattern); - - FcPatternAddFTFace(pattern, FC_FT_FACE, mFace); - AddDownloadedFontEntry(pattern, this); - - // There is never more than one pattern - // FIXME: Make this infallible after bug 968520 is done. - MOZ_ALWAYS_TRUE(mPatterns.AppendElement(fallible)); - mPatterns[0].own(pattern); -} - -static void ReleaseDownloadedFontEntry(void *data) -{ - gfxDownloadedFcFontEntry *downloadedFontEntry = - static_cast(data); - NS_RELEASE(downloadedFontEntry); -} - -bool gfxDownloadedFcFontEntry::SetCairoFace(cairo_font_face_t *aFace) -{ - if (CAIRO_STATUS_SUCCESS != - cairo_font_face_set_user_data(aFace, &sFontEntryKey, this, - ReleaseDownloadedFontEntry)) - return false; - - // Hold a reference to this font entry to keep the font face data. - NS_ADDREF(this); - return true; -} - -hb_blob_t * -gfxDownloadedFcFontEntry::GetFontTable(uint32_t aTableTag) -{ - // The entry already owns the (sanitized) sfnt data in mFontData, - // so we can just return a blob that "wraps" the appropriate chunk of it. - // The blob should not attempt to free its data, as the entire sfnt data - // will be freed when the font entry is deleted. - return gfxFontUtils::GetTableFromFontData(mFontData, aTableTag); -} - -/* - * gfxFcFont - * - * This is a gfxFont implementation using a CAIRO_FONT_TYPE_FT - * cairo_scaled_font created from an FcPattern. - */ - -class gfxFcFont : public gfxFontconfigFontBase { -public: - virtual ~gfxFcFont(); - static already_AddRefed - GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern, - const gfxFontStyle *aFontStyle); - - // return a cloned font resized and offset to simulate sub/superscript glyphs - virtual already_AddRefed - GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) override; - -protected: - virtual already_AddRefed MakeScaledFont(gfxFontStyle *aFontStyle, - gfxFloat aFontScale); - virtual already_AddRefed GetSmallCapsFont() override; - -private: - gfxFcFont(cairo_scaled_font_t *aCairoFont, - FcPattern *aPattern, - gfxFcFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle); - - // key for locating a gfxFcFont corresponding to a cairo_scaled_font - static cairo_user_data_key_t sGfxFontKey; -}; - -/** - * gfxFcFontSet: - * - * Translation from a desired FcPattern to a sorted set of font references - * (fontconfig cache data) and (when needed) fonts. - */ - -class gfxFcFontSet final { -public: - NS_INLINE_DECL_REFCOUNTING(gfxFcFontSet) - - explicit gfxFcFontSet(FcPattern *aPattern, - gfxUserFontSet *aUserFontSet) - : mSortPattern(aPattern), mUserFontSet(aUserFontSet), - mFcFontsTrimmed(0), - mHaveFallbackFonts(false) - { - bool waitForUserFont; - mFcFontSet = SortPreferredFonts(waitForUserFont); - mWaitingForUserFont = waitForUserFont; - } - - // A reference is held by the FontSet. - // The caller may add a ref to keep the font alive longer than the FontSet. - gfxFcFont *GetFontAt(uint32_t i, const gfxFontStyle *aFontStyle) - { - if (i >= mFonts.Length() || !mFonts[i].mFont) { - // GetFontPatternAt sets up mFonts - FcPattern *fontPattern = GetFontPatternAt(i); - if (!fontPattern) - return nullptr; - - mFonts[i].mFont = - gfxFcFont::GetOrMakeFont(mSortPattern, fontPattern, - aFontStyle); - } - return mFonts[i].mFont; - } - - FcPattern *GetFontPatternAt(uint32_t i); - - bool WaitingForUserFont() const { - return mWaitingForUserFont; - } - -private: - // Private destructor, to discourage deletion outside of Release(): - ~gfxFcFontSet() - { - } - - nsReturnRef SortPreferredFonts(bool& aWaitForUserFont); - nsReturnRef SortFallbackFonts(); - - struct FontEntry { - explicit FontEntry(FcPattern *aPattern) : mPattern(aPattern) {} - nsCountedRef mPattern; - RefPtr mFont; - }; - - struct LangSupportEntry { - LangSupportEntry(FcChar8 *aLang, FcLangResult aSupport) : - mLang(aLang), mBestSupport(aSupport) {} - FcChar8 *mLang; - FcLangResult mBestSupport; - }; - -public: - // public for nsTArray - class LangComparator { - public: - bool Equals(const LangSupportEntry& a, const FcChar8 *b) const - { - return FcStrCmpIgnoreCase(a.mLang, b) == 0; - } - }; - -private: - // The requested pattern - nsCountedRef mSortPattern; - // Fonts from @font-face rules - RefPtr mUserFontSet; - // A (trimmed) list of font patterns and fonts that is built up as - // required. - nsTArray mFonts; - // Holds a list of font patterns that will be trimmed. This is first set - // to a list of preferred fonts. Then, if/when all the preferred fonts - // have been trimmed and added to mFonts, this is set to a list of - // fallback fonts. - nsAutoRef mFcFontSet; - // The set of characters supported by the fonts in mFonts. - nsAutoRef mCharSet; - // The index of the next font in mFcFontSet that has not yet been - // considered for mFonts. - int mFcFontsTrimmed; - // True iff fallback fonts are either stored in mFcFontSet or have been - // trimmed and added to mFonts (so that mFcFontSet is nullptr). - bool mHaveFallbackFonts; - // True iff there was a user font set with pending downloads, - // so the set may be updated when downloads complete - bool mWaitingForUserFont; -}; - -// Find the FcPattern for an @font-face font suitable for CSS family |aFamily| -// and style |aStyle| properties. -static const nsTArray< nsCountedRef >* -FindFontPatterns(gfxUserFontSet *mUserFontSet, - const nsACString &aFamily, uint8_t aStyle, - uint16_t aWeight, int16_t aStretch, - bool& aWaitForUserFont) -{ - // Convert to UTF16 - NS_ConvertUTF8toUTF16 utf16Family(aFamily); - - // needsBold is not used here. Instead synthetic bold is enabled through - // FcFontRenderPrepare when the weight in the requested pattern is - // compared against the weight in the font pattern. - bool needsBold; - - gfxFontStyle style; - style.style = aStyle; - style.weight = aWeight; - style.stretch = aStretch; - - gfxUserFcFontEntry *fontEntry = nullptr; - gfxFontFamily *family = mUserFontSet->LookupFamily(utf16Family); - if (family) { - gfxUserFontEntry* userFontEntry = - mUserFontSet->FindUserFontEntryAndLoad(family, style, needsBold, - aWaitForUserFont); - if (userFontEntry) { - fontEntry = static_cast - (userFontEntry->GetPlatformFontEntry()); - } - - // Accept synthetic oblique for italic and oblique. - // xxx - this isn't really ideal behavior, for docs that only use a - // single italic face it will also pull down the normal face - // and probably never use it - if (!fontEntry && aStyle != NS_FONT_STYLE_NORMAL) { - style.style = NS_FONT_STYLE_NORMAL; - userFontEntry = - mUserFontSet->FindUserFontEntryAndLoad(family, style, - needsBold, - aWaitForUserFont); - if (userFontEntry) { - fontEntry = static_cast - (userFontEntry->GetPlatformFontEntry()); - } - } - } - - if (!fontEntry) { - return nullptr; - } - - return &fontEntry->GetPatterns(); -} - -typedef FcBool (*FcPatternRemoveFunction)(FcPattern *p, const char *object, - int id); - -// FcPatternRemove is available in fontconfig-2.3.0 (2005) -static FcBool -moz_FcPatternRemove(FcPattern *p, const char *object, int id) -{ - static FcPatternRemoveFunction sFcPatternRemovePtr = - reinterpret_cast - (FindFunctionSymbol("FcPatternRemove")); - - if (!sFcPatternRemovePtr) - return FcFalse; - - return (*sFcPatternRemovePtr)(p, object, id); -} - -// fontconfig prefers a matching family or lang to pixelsize of bitmap -// fonts. CSS suggests a tolerance of 20% on pixelsize. -static bool -SizeIsAcceptable(FcPattern *aFont, double aRequestedSize) -{ - double size; - int v = 0; - while (FcPatternGetDouble(aFont, - FC_PIXEL_SIZE, v, &size) == FcResultMatch) { - ++v; - if (5.0 * fabs(size - aRequestedSize) < aRequestedSize) - return true; - } - - // No size means scalable - return v == 0; -} - -// Sorting only the preferred fonts first usually saves having to sort through -// every font on the system. -nsReturnRef -gfxFcFontSet::SortPreferredFonts(bool &aWaitForUserFont) -{ - aWaitForUserFont = false; - - gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); - if (!utils) - return nsReturnRef(); - - // The list of families in mSortPattern has values with both weak and - // strong bindings. Values with strong bindings should be preferred. - // Values with weak bindings are default fonts that should be considered - // only when the font provides the best support for a requested language - // or after other fonts have satisfied all the requested languages. - // - // There are no direct fontconfig APIs to get the binding type. The - // binding only takes effect in the sort and match functions. - - // |requiredLangs| is a list of requested languages that have not yet been - // satisfied. gfxFontconfigUtils only sets one FC_LANG property value, - // but FcConfigSubstitute may add more values (e.g. prepending "en" to - // "ja" will use western fonts to render Latin/Arabic numerals in Japanese - // text.) - AutoTArray requiredLangs; - for (int v = 0; ; ++v) { - FcChar8 *lang; - FcResult result = FcPatternGetString(mSortPattern, FC_LANG, v, &lang); - if (result != FcResultMatch) { - // No need to check FcPatternGetLangSet() because - // gfxFontconfigUtils sets only a string value for FC_LANG and - // FcConfigSubstitute cannot add LangSets. - NS_ASSERTION(result != FcResultTypeMismatch, - "Expected a string for FC_LANG"); - break; - } - - if (!requiredLangs.Contains(lang, LangComparator())) { - FcLangResult bestLangSupport = utils->GetBestLangSupport(lang); - if (bestLangSupport != FcLangDifferentLang) { - requiredLangs. - AppendElement(LangSupportEntry(lang, bestLangSupport)); - } - } - } - - nsAutoRef fontSet(FcFontSetCreate()); - if (!fontSet) - return fontSet.out(); - - // FcDefaultSubstitute() ensures a slant on mSortPattern, but, if that ever - // doesn't happen, Roman will be used. - int requestedSlant = FC_SLANT_ROMAN; - FcPatternGetInteger(mSortPattern, FC_SLANT, 0, &requestedSlant); - double requestedSize = -1.0; - FcPatternGetDouble(mSortPattern, FC_PIXEL_SIZE, 0, &requestedSize); - - nsTHashtable existingFamilies(32); - FcChar8 *family; - for (int v = 0; - FcPatternGetString(mSortPattern, - FC_FAMILY, v, &family) == FcResultMatch; ++v) { - const nsTArray< nsCountedRef > *familyFonts = nullptr; - - // Is this an @font-face family? - bool isUserFont = false; - if (mUserFontSet) { - // Have some @font-face definitions - - nsDependentCString cFamily(gfxFontconfigUtils::ToCString(family)); - NS_NAMED_LITERAL_CSTRING(userPrefix, FONT_FACE_FAMILY_PREFIX); - - if (StringBeginsWith(cFamily, userPrefix)) { - isUserFont = true; - - // Trim off the prefix - nsDependentCSubstring cssFamily(cFamily, userPrefix.Length()); - - uint8_t thebesStyle = - gfxFontconfigUtils::FcSlantToThebesStyle(requestedSlant); - uint16_t thebesWeight = - gfxFontconfigUtils::GetThebesWeight(mSortPattern); - int16_t thebesStretch = - gfxFontconfigUtils::GetThebesStretch(mSortPattern); - - bool waitForUserFont; - familyFonts = FindFontPatterns(mUserFontSet, cssFamily, - thebesStyle, - thebesWeight, thebesStretch, - waitForUserFont); - if (waitForUserFont) { - aWaitForUserFont = true; - } - } - } - - if (!isUserFont) { - familyFonts = &utils->GetFontsForFamily(family); - } - - if (!familyFonts || familyFonts->Length() == 0) { - // There are no fonts matching this family, so there is no point - // in searching for this family in the FontSort. - // - // Perhaps the original pattern should be retained for - // FcFontRenderPrepare. However, the only a useful config - // substitution test against missing families that i can imagine - // would only be interested in the preferred family - // (qual="first"), so always keep the first family and use the - // same pattern for Sort and RenderPrepare. - if (v != 0 && moz_FcPatternRemove(mSortPattern, FC_FAMILY, v)) { - --v; - } - continue; - } - - // Aliases seem to often end up occurring more than once, but - // duplicate families can't be removed from the sort pattern without - // knowing whether duplicates have the same binding. - gfxFontconfigUtils::DepFcStrEntry *familyEntry = - existingFamilies.PutEntry(family); - if (familyEntry) { - if (familyEntry->mKey) // old entry - continue; - - familyEntry->mKey = family; // initialize new entry - } - - for (uint32_t f = 0; f < familyFonts->Length(); ++f) { - FcPattern *font = familyFonts->ElementAt(f); - - // Fix up the family name of user-font patterns, as the same - // font entry may be used (via the UserFontCache) for multiple - // CSS family names - if (isUserFont) { - font = FcPatternDuplicate(font); - FcPatternDel(font, FC_FAMILY); - FcPatternAddString(font, FC_FAMILY, family); - } - - // User fonts are already filtered by slant (but not size) in - // mUserFontSet->FindUserFontEntry(). - if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize)) - continue; - - for (uint32_t r = 0; r < requiredLangs.Length(); ++r) { - const LangSupportEntry& langEntry = requiredLangs[r]; - FcLangResult support = - gfxFontconfigUtils::GetLangSupport(font, langEntry.mLang); - if (support <= langEntry.mBestSupport) { // lower is better - requiredLangs.RemoveElementAt(r); - --r; - } - } - - // FcFontSetDestroy will remove a reference but FcFontSetAdd - // does _not_ take a reference! - if (FcFontSetAdd(fontSet, font)) { - // We don't add a reference here for user fonts, because we're - // using a local clone of the pattern (see above) in order to - // override the family name - if (!isUserFont) { - FcPatternReference(font); - } - } - } - } - - FcPattern *truncateMarker = nullptr; - for (uint32_t r = 0; r < requiredLangs.Length(); ++r) { - const nsTArray< nsCountedRef >& langFonts = - utils->GetFontsForLang(requiredLangs[r].mLang); - - bool haveLangFont = false; - for (uint32_t f = 0; f < langFonts.Length(); ++f) { - FcPattern *font = langFonts[f]; - if (requestedSize != -1.0 && !SizeIsAcceptable(font, requestedSize)) - continue; - - haveLangFont = true; - if (FcFontSetAdd(fontSet, font)) { - FcPatternReference(font); - } - } - - if (!haveLangFont && langFonts.Length() > 0) { - // There is a font that supports this language but it didn't pass - // the slant and size criteria. Weak default font families should - // not be considered until the language has been satisfied. - // - // Insert a font that supports the language so that it will mark - // the position of fonts from weak families in the sorted set and - // they can be removed. The language and weak families will be - // considered in the fallback fonts, which use fontconfig's - // algorithm. - // - // Of the fonts that don't meet slant and size criteria, strong - // default font families should be considered before (other) fonts - // for this language, so this marker font will be removed (as well - // as the fonts from weak families), and strong families will be - // reconsidered in the fallback fonts. - FcPattern *font = langFonts[0]; - if (FcFontSetAdd(fontSet, font)) { - FcPatternReference(font); - truncateMarker = font; - } - break; - } - } - - FcFontSet *sets[1] = { fontSet }; - FcResult result; -#ifdef SOLARIS - // Get around a crash of FcFontSetSort when FcConfig is nullptr - // Solaris's FcFontSetSort needs an FcConfig (bug 474758) - fontSet.own(FcFontSetSort(FcConfigGetCurrent(), sets, 1, mSortPattern, - FcFalse, nullptr, &result)); -#else - fontSet.own(FcFontSetSort(nullptr, sets, 1, mSortPattern, - FcFalse, nullptr, &result)); -#endif - - if (truncateMarker != nullptr && fontSet) { - nsAutoRef truncatedSet(FcFontSetCreate()); - - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - if (font == truncateMarker) - break; - - if (FcFontSetAdd(truncatedSet, font)) { - FcPatternReference(font); - } - } - - fontSet.steal(truncatedSet); - } - - return fontSet.out(); -} - -nsReturnRef -gfxFcFontSet::SortFallbackFonts() -{ - // Setting trim to FcTrue would provide a much smaller (~ 1/10) FcFontSet, - // but would take much longer due to comparing all the character sets. - // - // The references to fonts in this FcFontSet are almost free - // as they are pointers into mmaped cache files. - // - // GetFontPatternAt() will trim lazily if and as needed, which will also - // remove duplicates of preferred fonts. - FcResult result; - return nsReturnRef(FcFontSort(nullptr, mSortPattern, - FcFalse, nullptr, &result)); -} - -// GetFontAt relies on this setting up all patterns up to |i|. -FcPattern * -gfxFcFontSet::GetFontPatternAt(uint32_t i) -{ - while (i >= mFonts.Length()) { - while (!mFcFontSet) { - if (mHaveFallbackFonts) - return nullptr; - - mFcFontSet = SortFallbackFonts(); - mHaveFallbackFonts = true; - mFcFontsTrimmed = 0; - // Loop to test that mFcFontSet is non-nullptr. - } - - while (mFcFontsTrimmed < mFcFontSet->nfont) { - FcPattern *font = mFcFontSet->fonts[mFcFontsTrimmed]; - ++mFcFontsTrimmed; - - if (mFonts.Length() != 0) { - // See if the next font provides support for any extra - // characters. Most often the next font is not going to - // support more characters so check for a SubSet first before - // allocating a new CharSet with Union. - FcCharSet *supportedChars = mCharSet; - if (!supportedChars) { - FcPatternGetCharSet(mFonts[mFonts.Length() - 1].mPattern, - FC_CHARSET, 0, &supportedChars); - } - - if (supportedChars) { - FcCharSet *newChars = nullptr; - FcPatternGetCharSet(font, FC_CHARSET, 0, &newChars); - if (newChars) { - if (FcCharSetIsSubset(newChars, supportedChars)) - continue; - - mCharSet.own(FcCharSetUnion(supportedChars, newChars)); - } else if (!mCharSet) { - mCharSet.own(FcCharSetCopy(supportedChars)); - } - } - } - - mFonts.AppendElement(font); - if (mFonts.Length() >= i) - break; - } - - if (mFcFontsTrimmed == mFcFontSet->nfont) { - // finished with this font set - mFcFontSet.reset(); - } - } - - return mFonts[i].mPattern; -} - -#ifdef MOZ_WIDGET_GTK -static void ApplyGdkScreenFontOptions(FcPattern *aPattern); -#endif - -// Apply user settings and defaults to pattern in preparation for matching. -static void -PrepareSortPattern(FcPattern *aPattern, double aFallbackSize, - double aSizeAdjustFactor, bool aIsPrinterFont) -{ - FcConfigSubstitute(nullptr, aPattern, FcMatchPattern); - - // This gets cairo_font_options_t for the Screen. We should have - // different font options for printing (no hinting) but we are not told - // what we are measuring for. - // - // If cairo adds support for lcd_filter, gdk will not provide the default - // setting for that option. We could get the default setting by creating - // an xlib surface once, recording its font_options, and then merging the - // gdk options. - // - // Using an xlib surface would also be an option to get Screen font - // options for non-GTK X11 toolkits, but less efficient than using GDK to - // pick up dynamic changes. - if(aIsPrinterFont) { - cairo_font_options_t *options = cairo_font_options_create(); - cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); - cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); - cairo_ft_font_options_substitute(options, aPattern); - cairo_font_options_destroy(options); - FcPatternAddBool(aPattern, PRINTING_FC_PROPERTY, FcTrue); - } else { -#ifdef MOZ_WIDGET_GTK - ApplyGdkScreenFontOptions(aPattern); -#endif - } - - // Protect against any fontconfig settings that may have incorrectly - // modified the pixelsize, and consider aSizeAdjustFactor. - double size = aFallbackSize; - if (FcPatternGetDouble(aPattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch - || aSizeAdjustFactor != 1.0) { - FcPatternDel(aPattern, FC_PIXEL_SIZE); - FcPatternAddDouble(aPattern, FC_PIXEL_SIZE, size * aSizeAdjustFactor); - } - - FcDefaultSubstitute(aPattern); -} - -/** - ** gfxPangoFontGroup - **/ - -gfxPangoFontGroup::gfxPangoFontGroup(const FontFamilyList& aFontFamilyList, - const gfxFontStyle *aStyle, - gfxUserFontSet *aUserFontSet, - gfxFloat aDevToCssSize) - : gfxFontGroup(aFontFamilyList, aStyle, nullptr, aUserFontSet, aDevToCssSize), - mPangoLanguage(GuessPangoLanguage(aStyle->language)) -{ - // This language is passed to the font for shaping. - // Shaping doesn't know about lang groups so make it a real language. - if (mPangoLanguage) { - mStyle.language = NS_Atomize(pango_language_to_string(mPangoLanguage)); - } - - // dummy entry, will be replaced when actually needed - mFonts.AppendElement(FamilyFace()); - mSkipUpdateUserFonts = true; -} - -gfxPangoFontGroup::~gfxPangoFontGroup() -{ -} - -gfxFontGroup * -gfxPangoFontGroup::Copy(const gfxFontStyle *aStyle) -{ - return new gfxPangoFontGroup(mFamilyList, aStyle, mUserFontSet, mDevToCssSize); -} - -void -gfxPangoFontGroup::FindGenericFontsPFG(FontFamilyType aGenericType, - nsIAtom *aLanguage, - void *aClosure) -{ - AutoTArray resolvedGenerics; - ResolveGenericFontNamesPFG(aGenericType, aLanguage, resolvedGenerics); - uint32_t g = 0, numGenerics = resolvedGenerics.Length(); - for (g = 0; g < numGenerics; g++) { - FindPlatformFontPFG(resolvedGenerics[g], false, aClosure); - } -} - -/* static */ void -gfxPangoFontGroup::ResolveGenericFontNamesPFG(FontFamilyType aGenericType, - nsIAtom *aLanguage, - nsTArray& aGenericFamilies) -{ - static const char kGeneric_serif[] = "serif"; - static const char kGeneric_sans_serif[] = "sans-serif"; - static const char kGeneric_monospace[] = "monospace"; - static const char kGeneric_cursive[] = "cursive"; - static const char kGeneric_fantasy[] = "fantasy"; - - // treat -moz-fixed as monospace - if (aGenericType == eFamily_moz_fixed) { - aGenericType = eFamily_monospace; - } - - // type should be standard generic type at this point - NS_ASSERTION(aGenericType >= eFamily_serif && - aGenericType <= eFamily_fantasy, - "standard generic font family type required"); - - // create the lang string - nsIAtom *langGroupAtom = nullptr; - nsAutoCString langGroupString; - if (aLanguage) { - if (!gLangService) { - CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService); - } - if (gLangService) { - nsresult rv; - langGroupAtom = gLangService->GetLanguageGroup(aLanguage, &rv); - } - } - if (!langGroupAtom) { - langGroupAtom = nsGkAtoms::Unicode; - } - langGroupAtom->ToUTF8String(langGroupString); - - // map generic type to string - const char *generic = nullptr; - switch (aGenericType) { - case eFamily_serif: - generic = kGeneric_serif; - break; - case eFamily_sans_serif: - generic = kGeneric_sans_serif; - break; - case eFamily_monospace: - generic = kGeneric_monospace; - break; - case eFamily_cursive: - generic = kGeneric_cursive; - break; - case eFamily_fantasy: - generic = kGeneric_fantasy; - break; - default: - break; - } - - if (!generic) { - return; - } - - aGenericFamilies.Clear(); - - // load family for "font.name.generic.lang" - nsAutoCString prefFontName("font.name."); - prefFontName.Append(generic); - prefFontName.Append('.'); - prefFontName.Append(langGroupString); - gfxFontUtils::AppendPrefsFontList(prefFontName.get(), - aGenericFamilies); - - // if lang has pref fonts, also load fonts for "font.name-list.generic.lang" - if (!aGenericFamilies.IsEmpty()) { - nsAutoCString prefFontListName("font.name-list."); - prefFontListName.Append(generic); - prefFontListName.Append('.'); - prefFontListName.Append(langGroupString); - gfxFontUtils::AppendPrefsFontList(prefFontListName.get(), - aGenericFamilies); - } - -#if 0 // dump out generic mappings - printf("%s ===> ", prefFontName.get()); - for (uint32_t k = 0; k < aGenericFamilies.Length(); k++) { - if (k > 0) printf(", "); - printf("%s", NS_ConvertUTF16toUTF8(aGenericFamilies[k]).get()); - } - printf("\n"); -#endif -} - -void gfxPangoFontGroup::EnumerateFontListPFG(nsIAtom *aLanguage, void *aClosure) -{ - // initialize fonts in the font family list - const nsTArray& fontlist = mFamilyList.GetFontlist(); - - // lookup fonts in the fontlist - uint32_t i, numFonts = fontlist.Length(); - for (i = 0; i < numFonts; i++) { - const FontFamilyName& name = fontlist[i]; - if (name.IsNamed()) { - FindPlatformFontPFG(name.mName, true, aClosure); - } else { - FindGenericFontsPFG(name.mType, aLanguage, aClosure); - } - } - - // if necessary, append default generic onto the end - if (mFamilyList.GetDefaultFontType() != eFamily_none && - !mFamilyList.HasDefaultGeneric()) { - FindGenericFontsPFG(mFamilyList.GetDefaultFontType(), - aLanguage, aClosure); - } -} - -void -gfxPangoFontGroup::FindPlatformFontPFG(const nsAString& fontName, - bool aUseFontSet, - void *aClosure) -{ - nsTArray *list = static_cast*>(aClosure); - - if (!list->Contains(fontName)) { - // names present in the user fontset are not matched against system fonts - if (aUseFontSet && mUserFontSet && mUserFontSet->HasFamily(fontName)) { - nsAutoString userFontName = - NS_LITERAL_STRING(FONT_FACE_FAMILY_PREFIX) + fontName; - list->AppendElement(userFontName); - } else { - list->AppendElement(fontName); - } - } -} - -gfxFcFont * -gfxPangoFontGroup::GetBaseFont() -{ - if (mFonts[0].Font() == nullptr) { - gfxFont* font = GetBaseFontSet()->GetFontAt(0, GetStyle()); - mFonts[0] = FamilyFace(nullptr, font); - } - - return static_cast(mFonts[0].Font()); -} - -gfxFont* -gfxPangoFontGroup::GetFirstValidFont(uint32_t aCh) -{ - return GetFontAt(0); -} - -gfxFont * -gfxPangoFontGroup::GetFontAt(int32_t i, uint32_t aCh) -{ - // If it turns out to be hard for all clients that cache font - // groups to call UpdateUserFonts at appropriate times, we could - // instead consider just calling UpdateUserFonts from someplace - // more central (such as here). - NS_ASSERTION(!mUserFontSet || mCurrGeneration == GetGeneration(), - "Whoever was caching this font group should have " - "called UpdateUserFonts on it"); - - NS_PRECONDITION(i == 0, "Only have one font"); - - return GetBaseFont(); -} - -void -gfxPangoFontGroup::UpdateUserFonts() -{ - uint64_t newGeneration = GetGeneration(); - if (newGeneration == mCurrGeneration) - return; - - mFonts[0] = FamilyFace(); - mFontSets.Clear(); - ClearCachedData(); - mCurrGeneration = newGeneration; -} - -already_AddRefed -gfxPangoFontGroup::MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor, - nsAutoRef *aMatchPattern) -{ - const char *lang = pango_language_to_string(aLang); - - RefPtr langGroup; - if (aLang != mPangoLanguage) { - // Set up langGroup for Mozilla's font prefs. - langGroup = NS_Atomize(lang); - } - - AutoTArray fcFamilyList; - EnumerateFontListPFG(langGroup ? langGroup.get() : mStyle.language.get(), - &fcFamilyList); - - // To consider: A fontset cache here could be helpful. - - // Get a pattern suitable for matching. - nsAutoRef pattern - (gfxFontconfigUtils::NewPattern(fcFamilyList, mStyle, lang)); - - PrepareSortPattern(pattern, mStyle.size, aSizeAdjustFactor, mStyle.printerFont); - - RefPtr fontset = - new gfxFcFontSet(pattern, mUserFontSet); - - mSkipDrawing = fontset->WaitingForUserFont(); - - if (aMatchPattern) - aMatchPattern->steal(pattern); - - return fontset.forget(); -} - -gfxPangoFontGroup:: -FontSetByLangEntry::FontSetByLangEntry(PangoLanguage *aLang, - gfxFcFontSet *aFontSet) - : mLang(aLang), mFontSet(aFontSet) -{ -} - -gfxFcFontSet * -gfxPangoFontGroup::GetFontSet(PangoLanguage *aLang) -{ - GetBaseFontSet(); // sets mSizeAdjustFactor and mFontSets[0] - - if (!aLang) - return mFontSets[0].mFontSet; - - for (uint32_t i = 0; i < mFontSets.Length(); ++i) { - if (mFontSets[i].mLang == aLang) - return mFontSets[i].mFontSet; - } - - RefPtr fontSet = - MakeFontSet(aLang, mSizeAdjustFactor); - mFontSets.AppendElement(FontSetByLangEntry(aLang, fontSet)); - - return fontSet; -} - -already_AddRefed -gfxPangoFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, - uint32_t aNextCh, Script aRunScript, - gfxFont *aPrevMatchedFont, - uint8_t *aMatchType) -{ - if (aPrevMatchedFont) { - // Don't switch fonts for control characters, regardless of - // whether they are present in the current font, as they won't - // actually be rendered (see bug 716229) - uint8_t category = GetGeneralCategory(aCh); - if (category == HB_UNICODE_GENERAL_CATEGORY_CONTROL) { - return RefPtr(aPrevMatchedFont).forget(); - } - - // if this character is a join-control or the previous is a join-causer, - // use the same font as the previous range if we can - if (gfxFontUtils::IsJoinControl(aCh) || - gfxFontUtils::IsJoinCauser(aPrevCh)) { - if (aPrevMatchedFont->HasCharacter(aCh)) { - return RefPtr(aPrevMatchedFont).forget(); - } - } - } - - // if this character is a variation selector, - // use the previous font regardless of whether it supports VS or not. - // otherwise the text run will be divided. - if (gfxFontUtils::IsVarSelector(aCh)) { - if (aPrevMatchedFont) { - return RefPtr(aPrevMatchedFont).forget(); - } - // VS alone. it's meaningless to search different fonts - return nullptr; - } - - // The real fonts that fontconfig provides for generic/fallback families - // depend on the language used, so a different FontSet is used for each - // language (except for the variation below). - // - // With most fontconfig configurations any real family names prior to a - // fontconfig generic with corresponding fonts installed will still lead - // to the same leading fonts in each FontSet. - // - // There is an inefficiency here therefore because the same base FontSet - // could often be used if these real families support the character. - // However, with fontconfig aliases, it is difficult to distinguish - // where exactly alias fonts end and generic/fallback fonts begin. - // - // The variation from pure language-based matching used here is that the - // same primary/base font is always used irrespective of the language. - // This provides that SCRIPT_COMMON characters are consistently rendered - // with the same font (bug 339513 and bug 416725). This is particularly - // important with the word cache as script can't be reliably determined - // from surrounding words. It also often avoids the unnecessary extra - // FontSet efficiency mentioned above. - // - // However, in two situations, the base font is not checked before the - // language-specific FontSet. - // - // 1. When we don't have a language to make a good choice for - // the base font. - // - // 2. For system fonts, use the default Pango behavior to give - // consistency with other apps. This is relevant when un-localized - // builds are run in non-Latin locales. This special-case probably - // wouldn't be necessary but for bug 91190. - - gfxFcFontSet *fontSet = GetBaseFontSet(); - uint32_t nextFont = 0; - FcPattern *basePattern = nullptr; - if (!mStyle.systemFont && mPangoLanguage) { - basePattern = fontSet->GetFontPatternAt(0); - if (HasChar(basePattern, aCh)) { - *aMatchType = gfxTextRange::kFontGroup; - return RefPtr(GetBaseFont()).forget(); - } - - nextFont = 1; - } - - // Our MOZ_SCRIPT_* codes may not match the PangoScript enumeration values - // (if we're using ICU's codes), so convert by mapping through ISO 15924 tag. - // Note that PangoScript is defined to be compatible with GUnicodeScript: - // https://developer.gnome.org/pango/stable/pango-Scripts-and-Languages.html#PangoScript - const hb_tag_t scriptTag = GetScriptTagForCode(aRunScript); - const PangoScript script = - (const PangoScript)hb_glib_script_from_script(hb_script_from_iso15924_tag(scriptTag)); - - // Might be nice to call pango_language_includes_script only once for the - // run rather than for each character. - PangoLanguage *scriptLang; - if ((!basePattern || - !pango_language_includes_script(mPangoLanguage, script)) && - (scriptLang = pango_script_get_sample_language(script))) { - fontSet = GetFontSet(scriptLang); - nextFont = 0; - } - - for (uint32_t i = nextFont; - FcPattern *pattern = fontSet->GetFontPatternAt(i); - ++i) { - if (pattern == basePattern) { - continue; // already checked basePattern - } - - if (HasChar(pattern, aCh)) { - *aMatchType = gfxTextRange::kFontGroup; - return RefPtr(fontSet->GetFontAt(i, GetStyle())).forget(); - } - } - - return nullptr; -} - -/** - ** gfxFcFont - **/ - -cairo_user_data_key_t gfxFcFont::sGfxFontKey; - -gfxFcFont::gfxFcFont(cairo_scaled_font_t *aCairoFont, - FcPattern *aPattern, - gfxFcFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle) - : gfxFontconfigFontBase(aCairoFont, aPattern, aFontEntry, aFontStyle) -{ - cairo_scaled_font_set_user_data(mScaledFont, &sGfxFontKey, this, nullptr); -} - -gfxFcFont::~gfxFcFont() -{ - cairo_scaled_font_set_user_data(mScaledFont, - &sGfxFontKey, - nullptr, - nullptr); -} - -already_AddRefed -gfxFcFont::GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) -{ - gfxFontStyle style(*GetStyle()); - style.AdjustForSubSuperscript(aAppUnitsPerDevPixel); - return MakeScaledFont(&style, style.size / GetStyle()->size); -} - -already_AddRefed -gfxFcFont::MakeScaledFont(gfxFontStyle *aFontStyle, gfxFloat aScaleFactor) -{ - gfxFcFontEntry* fe = static_cast(GetFontEntry()); - RefPtr font = - gfxFontCache::GetCache()->Lookup(fe, aFontStyle, nullptr); - if (font) { - return font.forget(); - } - - cairo_matrix_t fontMatrix; - cairo_scaled_font_get_font_matrix(mScaledFont, &fontMatrix); - cairo_matrix_scale(&fontMatrix, aScaleFactor, aScaleFactor); - - cairo_matrix_t ctm; - cairo_scaled_font_get_ctm(mScaledFont, &ctm); - - cairo_font_options_t *options = cairo_font_options_create(); - cairo_scaled_font_get_font_options(mScaledFont, options); - - cairo_scaled_font_t *newFont = - cairo_scaled_font_create(cairo_scaled_font_get_font_face(mScaledFont), - &fontMatrix, &ctm, options); - cairo_font_options_destroy(options); - - font = new gfxFcFont(newFont, GetPattern(), fe, aFontStyle); - gfxFontCache::GetCache()->AddNew(font); - cairo_scaled_font_destroy(newFont); - - return font.forget(); -} - -already_AddRefed -gfxFcFont::GetSmallCapsFont() -{ - gfxFontStyle style(*GetStyle()); - style.size *= SMALL_CAPS_SCALE_FACTOR; - style.variantCaps = NS_FONT_VARIANT_CAPS_NORMAL; - return MakeScaledFont(&style, SMALL_CAPS_SCALE_FACTOR); -} - -/* static */ void -gfxPangoFontGroup::Shutdown() -{ - // Resetting gFTLibrary in case this is wanted again after a - // cairo_debug_reset_static_data. - gFTLibrary = nullptr; -} - -/* static */ gfxFontEntry * -gfxPangoFontGroup::NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle) -{ - gfxFontconfigUtils *utils = gfxFontconfigUtils::GetFontconfigUtils(); - if (!utils) - return nullptr; - - // The font face name from @font-face { src: local() } is not well - // defined. - // - // On MS Windows, this name gets compared with - // ENUMLOGFONTEXW::elfFullName, which for OpenType fonts seems to be the - // full font name from the name table. For CFF OpenType fonts this is the - // same as the PostScript name, but for TrueType fonts it is usually - // different. - // - // On Mac, the font face name is compared with the PostScript name, even - // for TrueType fonts. - // - // Fontconfig only records the full font names, so the behavior here - // follows that on MS Windows. However, to provide the possibility - // of aliases to compensate for variations, the font face name is passed - // through FcConfigSubstitute. - - nsAutoRef pattern(FcPatternCreate()); - if (!pattern) - return nullptr; - - NS_ConvertUTF16toUTF8 fullname(aFontName); - FcPatternAddString(pattern, FC_FULLNAME, - gfxFontconfigUtils::ToFcChar8(fullname)); - FcConfigSubstitute(nullptr, pattern, FcMatchPattern); - - FcChar8 *name; - for (int v = 0; - FcPatternGetString(pattern, FC_FULLNAME, v, &name) == FcResultMatch; - ++v) { - const nsTArray< nsCountedRef >& fonts = - utils->GetFontsForFullname(name); - - if (fonts.Length() != 0) - return new gfxLocalFcFontEntry(aFontName, - aWeight, - aStretch, - aStyle, - fonts); - } - - return nullptr; -} - -/* static */ FT_Library -gfxPangoFontGroup::GetFTLibrary() -{ - if (!gFTLibrary) { - // Use cairo's FT_Library so that cairo takes care of shutdown of the - // FT_Library after it has destroyed its font_faces, and FT_Done_Face - // has been called on each FT_Face, at least until this bug is fixed: - // https://bugs.freedesktop.org/show_bug.cgi?id=18857 - // - // Cairo's FT_Library can be obtained from any cairo_scaled_font. The - // font properties requested here are chosen to get an FT_Face that is - // likely to be also used elsewhere. - gfxFontStyle style; - RefPtr fontGroup = - new gfxPangoFontGroup(FontFamilyList(eFamily_sans_serif), - &style, nullptr, 1.0); - - gfxFcFont *font = fontGroup->GetBaseFont(); - if (!font) - return nullptr; - - gfxFT2LockedFace face(font); - if (!face.get()) - return nullptr; - - gFTLibrary = face.get()->glyph->library; - } - - return gFTLibrary; -} - -/* static */ gfxFontEntry * -gfxPangoFontGroup::NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const uint8_t* aFontData, - uint32_t aLength) -{ - // Ownership of aFontData is passed in here, and transferred to the - // new fontEntry, which will release it when no longer needed. - - // Using face_index = 0 for the first face in the font, as we have no - // other information. FT_New_Memory_Face checks for a nullptr FT_Library. - FT_Face face; - FT_Error error = - FT_New_Memory_Face(GetFTLibrary(), aFontData, aLength, 0, &face); - if (error != 0) { - free((void*)aFontData); - return nullptr; - } - - return new gfxDownloadedFcFontEntry(aFontName, aWeight, - aStretch, aStyle, - aFontData, face); -} - - -static double -GetPixelSize(FcPattern *aPattern) -{ - double size; - if (FcPatternGetDouble(aPattern, - FC_PIXEL_SIZE, 0, &size) == FcResultMatch) - return size; - - NS_NOTREACHED("No size on pattern"); - return 0.0; -} - -/** - * The following gfxFcFonts are accessed from the cairo_scaled_font or created - * from the FcPattern, not from the gfxFontCache hash table. The gfxFontCache - * hash table is keyed by desired family and style, whereas here we only know - * actual family and style. There may be more than one of these fonts with - * the same family and style, but different PangoFont and actual font face. - * - * The point of this is to record the exact font face for gfxTextRun glyph - * indices. The style of this font does not necessarily represent the exact - * gfxFontStyle used to build the text run. Notably, the language is not - * recorded. - */ - -/* static */ -already_AddRefed -gfxFcFont::GetOrMakeFont(FcPattern *aRequestedPattern, FcPattern *aFontPattern, - const gfxFontStyle *aFontStyle) -{ - nsAutoRef renderPattern - (FcFontRenderPrepare(nullptr, aRequestedPattern, aFontPattern)); - - // If synthetic bold/italic is not allowed by the style, adjust the - // resulting pattern to match the actual properties of the font. - if (!aFontStyle->allowSyntheticWeight) { - int weight; - if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, - &weight) == FcResultMatch) { - FcPatternDel(renderPattern, FC_WEIGHT); - FcPatternAddInteger(renderPattern, FC_WEIGHT, weight); - } - } - if (!aFontStyle->allowSyntheticStyle) { - int slant; - if (FcPatternGetInteger(aFontPattern, FC_SLANT, 0, - &slant) == FcResultMatch) { - FcPatternDel(renderPattern, FC_SLANT); - FcPatternAddInteger(renderPattern, FC_SLANT, slant); - } - } - - cairo_font_face_t *face = - cairo_ft_font_face_create_for_pattern(renderPattern); - - // Reuse an existing font entry if available. - RefPtr fe = gfxFcFontEntry::LookupFontEntry(face); - if (!fe) { - gfxDownloadedFcFontEntry *downloadedFontEntry = - GetDownloadedFontEntry(aFontPattern); - if (downloadedFontEntry) { - // Web font - fe = downloadedFontEntry; - if (cairo_font_face_status(face) == CAIRO_STATUS_SUCCESS) { - // cairo_font_face_t is using the web font data. - // Hold a reference to the font entry to keep the font face - // data. - if (!downloadedFontEntry->SetCairoFace(face)) { - // OOM. Let cairo pick a fallback font - cairo_font_face_destroy(face); - face = cairo_ft_font_face_create_for_pattern(aRequestedPattern); - fe = gfxFcFontEntry::LookupFontEntry(face); - } - } - } - if (!fe) { - // Get a unique name for the font face from the file and id. - nsAutoString name; - FcChar8 *fc_file; - if (FcPatternGetString(renderPattern, - FC_FILE, 0, &fc_file) == FcResultMatch) { - int index; - if (FcPatternGetInteger(renderPattern, - FC_INDEX, 0, &index) != FcResultMatch) { - // cairo defaults to 0. - index = 0; - } - - AppendUTF8toUTF16(gfxFontconfigUtils::ToCString(fc_file), name); - if (index != 0) { - name.Append('/'); - name.AppendInt(index); - } - } - - fe = new gfxSystemFcFontEntry(face, aFontPattern, name); - } - } - - gfxFontStyle style(*aFontStyle); - style.size = GetPixelSize(renderPattern); - style.style = gfxFontconfigUtils::GetThebesStyle(renderPattern); - style.weight = gfxFontconfigUtils::GetThebesWeight(renderPattern); - - RefPtr font = - gfxFontCache::GetCache()->Lookup(fe, &style, nullptr); - if (!font) { - // Note that a file/index pair (or FT_Face) and the gfxFontStyle are - // not necessarily enough to provide a key that will describe a unique - // font. cairoFont contains information from renderPattern, which is a - // fully resolved pattern from FcFontRenderPrepare. - // FcFontRenderPrepare takes the requested pattern and the face - // pattern as input and can modify elements of the resulting pattern - // that affect rendering but are not included in the gfxFontStyle. - cairo_scaled_font_t *cairoFont = CreateScaledFont(renderPattern, face); - font = new gfxFcFont(cairoFont, renderPattern, fe, &style); - gfxFontCache::GetCache()->AddNew(font); - cairo_scaled_font_destroy(cairoFont); - } - - cairo_font_face_destroy(face); - - RefPtr retval(static_cast(font.get())); - return retval.forget(); -} - -gfxFcFontSet * -gfxPangoFontGroup::GetBaseFontSet() -{ - if (mFontSets.Length() > 0) - return mFontSets[0].mFontSet; - - mSizeAdjustFactor = 1.0; // will be adjusted below if necessary - nsAutoRef pattern; - RefPtr fontSet = - MakeFontSet(mPangoLanguage, mSizeAdjustFactor, &pattern); - - double size = GetPixelSize(pattern); - if (size != 0.0 && mStyle.sizeAdjust > 0.0) { - gfxFcFont *font = fontSet->GetFontAt(0, GetStyle()); - if (font) { - const gfxFont::Metrics& metrics = - font->GetMetrics(gfxFont::eHorizontal); // XXX vertical? - - // The factor of 0.1 ensures that xHeight is sane so fonts don't - // become huge. Strictly ">" ensures that xHeight and emHeight are - // not both zero. - if (metrics.xHeight > 0.1 * metrics.emHeight) { - mSizeAdjustFactor = - mStyle.sizeAdjust * metrics.emHeight / metrics.xHeight; - - size *= mSizeAdjustFactor; - FcPatternDel(pattern, FC_PIXEL_SIZE); - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, size); - - fontSet = new gfxFcFontSet(pattern, mUserFontSet); - } - } - } - - PangoLanguage *pangoLang = mPangoLanguage; - FcChar8 *fcLang; - if (!pangoLang && - FcPatternGetString(pattern, FC_LANG, 0, &fcLang) == FcResultMatch) { - pangoLang = - pango_language_from_string(gfxFontconfigUtils::ToCString(fcLang)); - } - - mFontSets.AppendElement(FontSetByLangEntry(pangoLang, fontSet)); - - return fontSet; -} - -/** - ** gfxTextRun - * - * A serious problem: - * - * -- We draw with a font that's hinted for the CTM, but we measure with a font - * hinted to the identity matrix, so our "bounding metrics" may not be accurate. - * - **/ - -// This will fetch an existing scaled_font if one exists. -static cairo_scaled_font_t * -CreateScaledFont(FcPattern *aPattern, cairo_font_face_t *aFace) -{ - double size = GetPixelSize(aPattern); - - cairo_matrix_t fontMatrix; - FcMatrix *fcMatrix; - if (FcPatternGetMatrix(aPattern, FC_MATRIX, 0, &fcMatrix) == FcResultMatch) - cairo_matrix_init(&fontMatrix, fcMatrix->xx, -fcMatrix->yx, -fcMatrix->xy, fcMatrix->yy, 0, 0); - else - cairo_matrix_init_identity(&fontMatrix); - cairo_matrix_scale(&fontMatrix, size, size); - - FcBool printing; - if (FcPatternGetBool(aPattern, PRINTING_FC_PROPERTY, 0, &printing) != FcResultMatch) { - printing = FcFalse; - } - - // The cairo_scaled_font is created with a unit ctm so that metrics and - // positions are in user space, but this means that hinting effects will - // not be estimated accurately for non-unit transformations. - cairo_matrix_t identityMatrix; - cairo_matrix_init_identity(&identityMatrix); - - // Font options are set explicitly here to improve cairo's caching - // behavior and to record the relevant parts of the pattern for - // SetupCairoFont (so that the pattern can be released). - // - // Most font_options have already been set as defaults on the FcPattern - // with cairo_ft_font_options_substitute(), then user and system - // fontconfig configurations were applied. The resulting font_options - // have been recorded on the face during - // cairo_ft_font_face_create_for_pattern(). - // - // None of the settings here cause this scaled_font to behave any - // differently from how it would behave if it were created from the same - // face with default font_options. - // - // We set options explicitly so that the same scaled_font will be found in - // the cairo_scaled_font_map when cairo loads glyphs from a context with - // the same font_face, font_matrix, ctm, and surface font_options. - // - // Unfortunately, _cairo_scaled_font_keys_equal doesn't know about the - // font_options on the cairo_ft_font_face, and doesn't consider default - // option values to not match any explicit values. - // - // Even after cairo_set_scaled_font is used to set font_options for the - // cairo context, when cairo looks for a scaled_font for the context, it - // will look for a font with some option values from the target surface if - // any values are left default on the context font_options. If this - // scaled_font is created with default font_options, cairo will not find - // it. - cairo_font_options_t *fontOptions = cairo_font_options_create(); - - // The one option not recorded in the pattern is hint_metrics, which will - // affect glyph metrics. The default behaves as CAIRO_HINT_METRICS_ON. - // We should be considering the font_options of the surface on which this - // font will be used, but currently we don't have different gfxFonts for - // different surface font_options, so we'll create a font suitable for the - // Screen. Image and xlib surfaces default to CAIRO_HINT_METRICS_ON. - if (printing) { - cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_OFF); - } else { - cairo_font_options_set_hint_metrics(fontOptions, CAIRO_HINT_METRICS_ON); - } - - // The remaining options have been recorded on the pattern and the face. - // _cairo_ft_options_merge has some logic to decide which options from the - // scaled_font or from the cairo_ft_font_face take priority in the way the - // font behaves. - // - // In the majority of cases, _cairo_ft_options_merge uses the options from - // the cairo_ft_font_face, so sometimes it is not so important which - // values are set here so long as they are not defaults, but we'll set - // them to the exact values that we expect from the font, to be consistent - // and to protect against changes in cairo. - // - // In some cases, _cairo_ft_options_merge uses some options from the - // scaled_font's font_options rather than options on the - // cairo_ft_font_face (from fontconfig). - // https://bugs.freedesktop.org/show_bug.cgi?id=11838 - // - // Surface font options were set on the pattern in - // cairo_ft_font_options_substitute. If fontconfig has changed the - // hint_style then that is what the user (or distribution) wants, so we - // use the setting from the FcPattern. - // - // Fallback values here mirror treatment of defaults in cairo-ft-font.c. - FcBool hinting = FcFalse; - if (FcPatternGetBool(aPattern, FC_HINTING, 0, &hinting) != FcResultMatch) { - hinting = FcTrue; - } - - cairo_hint_style_t hint_style; - if (printing || !hinting) { - hint_style = CAIRO_HINT_STYLE_NONE; - } else { -#ifdef FC_HINT_STYLE // FC_HINT_STYLE is available from fontconfig 2.2.91. - int fc_hintstyle; - if (FcPatternGetInteger(aPattern, FC_HINT_STYLE, - 0, &fc_hintstyle ) != FcResultMatch) { - fc_hintstyle = FC_HINT_FULL; - } - switch (fc_hintstyle) { - case FC_HINT_NONE: - hint_style = CAIRO_HINT_STYLE_NONE; - break; - case FC_HINT_SLIGHT: - hint_style = CAIRO_HINT_STYLE_SLIGHT; - break; - case FC_HINT_MEDIUM: - default: // This fallback mirrors _get_pattern_ft_options in cairo. - hint_style = CAIRO_HINT_STYLE_MEDIUM; - break; - case FC_HINT_FULL: - hint_style = CAIRO_HINT_STYLE_FULL; - break; - } -#else // no FC_HINT_STYLE - hint_style = CAIRO_HINT_STYLE_FULL; -#endif - } - cairo_font_options_set_hint_style(fontOptions, hint_style); - - int rgba; - if (FcPatternGetInteger(aPattern, - FC_RGBA, 0, &rgba) != FcResultMatch) { - rgba = FC_RGBA_UNKNOWN; - } - cairo_subpixel_order_t subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; - switch (rgba) { - case FC_RGBA_UNKNOWN: - case FC_RGBA_NONE: - default: - // There is no CAIRO_SUBPIXEL_ORDER_NONE. Subpixel antialiasing - // is disabled through cairo_antialias_t. - rgba = FC_RGBA_NONE; - // subpixel_order won't be used by the font as we won't use - // CAIRO_ANTIALIAS_SUBPIXEL, but don't leave it at default for - // caching reasons described above. Fall through: - MOZ_FALLTHROUGH; - case FC_RGBA_RGB: - subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; - break; - case FC_RGBA_BGR: - subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; - break; - case FC_RGBA_VRGB: - subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; - break; - case FC_RGBA_VBGR: - subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; - break; - } - cairo_font_options_set_subpixel_order(fontOptions, subpixel_order); - - FcBool fc_antialias; - if (FcPatternGetBool(aPattern, - FC_ANTIALIAS, 0, &fc_antialias) != FcResultMatch) { - fc_antialias = FcTrue; - } - cairo_antialias_t antialias; - if (!fc_antialias) { - antialias = CAIRO_ANTIALIAS_NONE; - } else if (rgba == FC_RGBA_NONE) { - antialias = CAIRO_ANTIALIAS_GRAY; - } else { - antialias = CAIRO_ANTIALIAS_SUBPIXEL; - } - cairo_font_options_set_antialias(fontOptions, antialias); - - cairo_scaled_font_t *scaledFont = - cairo_scaled_font_create(aFace, &fontMatrix, &identityMatrix, - fontOptions); - - cairo_font_options_destroy(fontOptions); - - NS_ASSERTION(cairo_scaled_font_status(scaledFont) == CAIRO_STATUS_SUCCESS, - "Failed to create scaled font"); - return scaledFont; -} - -/* static */ -PangoLanguage * -GuessPangoLanguage(nsIAtom *aLanguage) -{ - if (!aLanguage) - return nullptr; - - // Pango and fontconfig won't understand mozilla's internal langGroups, so - // find a real language. - nsAutoCString lang; - gfxFontconfigUtils::GetSampleLangForGroup(aLanguage, &lang); - if (lang.IsEmpty()) - return nullptr; - - return pango_language_from_string(lang.get()); -} - -#ifdef MOZ_WIDGET_GTK -/*************************************************************************** - * - * This function must be last in the file because it uses the system cairo - * library. Above this point the cairo library used is the tree cairo if - * MOZ_TREE_CAIRO. - */ - -#if MOZ_TREE_CAIRO -// Tree cairo symbols have different names. Disable their activation through -// preprocessor macros. -#undef cairo_ft_font_options_substitute - -// The system cairo functions are not declared because the include paths cause -// the gdk headers to pick up the tree cairo.h. -extern "C" { -NS_VISIBILITY_DEFAULT void -cairo_ft_font_options_substitute (const cairo_font_options_t *options, - FcPattern *pattern); -} -#endif - -static void -ApplyGdkScreenFontOptions(FcPattern *aPattern) -{ - const cairo_font_options_t *options = - gdk_screen_get_font_options(gdk_screen_get_default()); - - cairo_ft_font_options_substitute(options, aPattern); -} - -#endif // MOZ_WIDGET_GTK - diff --git a/gfx/thebes/gfxFontconfigFonts.h b/gfx/thebes/gfxFontconfigFonts.h index cd59cfc68c62..09bf51c6e98b 100644 --- a/gfx/thebes/gfxFontconfigFonts.h +++ b/gfx/thebes/gfxFontconfigFonts.h @@ -21,103 +21,4 @@ typedef struct _FcPattern FcPattern; typedef struct FT_FaceRec_* FT_Face; typedef struct FT_LibraryRec_ *FT_Library; -class gfxPangoFontGroup : public gfxFontGroup { -public: - gfxPangoFontGroup(const mozilla::FontFamilyList& aFontFamilyList, - const gfxFontStyle *aStyle, - gfxUserFontSet *aUserFontSet, - gfxFloat aDevToCssSize); - virtual ~gfxPangoFontGroup(); - - virtual gfxFontGroup *Copy(const gfxFontStyle *aStyle); - - virtual gfxFont* GetFirstValidFont(uint32_t aCh = 0x20); - - virtual void UpdateUserFonts(); - - virtual already_AddRefed - FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh, - Script aRunScript, gfxFont *aPrevMatchedFont, - uint8_t *aMatchType); - - static void Shutdown(); - - // Used for @font-face { src: local(); } - static gfxFontEntry *NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle); - // Used for @font-face { src: url(); } - static gfxFontEntry *NewFontEntry(const nsAString& aFontName, - uint16_t aWeight, - int16_t aStretch, - uint8_t aStyle, - const uint8_t* aFontData, - uint32_t aLength); - - static FT_Library GetFTLibrary(); - -private: - - virtual gfxFont *GetFontAt(int32_t i, uint32_t aCh = 0x20); - - // @param aLang [in] language to use for pref fonts and system default font - // selection, or nullptr for the language guessed from the - // gfxFontStyle. - // The FontGroup holds a reference to this set. - gfxFcFontSet *GetFontSet(PangoLanguage *aLang = nullptr); - - class FontSetByLangEntry { - public: - FontSetByLangEntry(PangoLanguage *aLang, gfxFcFontSet *aFontSet); - PangoLanguage *mLang; - RefPtr mFontSet; - }; - // There is only one of entry in this array unless characters from scripts - // of other languages are measured. - AutoTArray mFontSets; - - gfxFloat mSizeAdjustFactor; - PangoLanguage *mPangoLanguage; - - // @param aLang [in] language to use for pref fonts and system font - // resolution, or nullptr to guess a language from the gfxFontStyle. - // @param aMatchPattern [out] if non-nullptr, will return the pattern used. - already_AddRefed - MakeFontSet(PangoLanguage *aLang, gfxFloat aSizeAdjustFactor, - nsAutoRef *aMatchPattern = nullptr); - - gfxFcFontSet *GetBaseFontSet(); - gfxFcFont *GetBaseFont(); - - gfxFloat GetSizeAdjustFactor() - { - if (mFontSets.Length() == 0) - GetBaseFontSet(); - return mSizeAdjustFactor; - } - - // old helper methods from gfxFontGroup, moved here so that those methods - // can be revamped without affecting the legacy code here - - // iterate over the fontlist, lookup names and expand generics - void EnumerateFontListPFG(nsIAtom *aLanguage, void *aClosure); - - // expand a generic to a list of specific names based on prefs - void FindGenericFontsPFG(mozilla::FontFamilyType aGenericType, - nsIAtom *aLanguage, - void *aClosure); - - // lookup and add a font with a given name (i.e. *not* a generic!) - void FindPlatformFontPFG(const nsAString& aName, - bool aUseFontSet, - void *aClosure); - - static void - ResolveGenericFontNamesPFG(mozilla::FontFamilyType aGenericType, - nsIAtom *aLanguage, - nsTArray& aGenericFamilies); - -}; - #endif /* GFX_FONTCONFIG_FONTS_H */ diff --git a/gfx/thebes/gfxFontconfigUtils.cpp b/gfx/thebes/gfxFontconfigUtils.cpp deleted file mode 100644 index 5bf606c13e25..000000000000 --- a/gfx/thebes/gfxFontconfigUtils.cpp +++ /dev/null @@ -1,1100 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/ArrayUtils.h" - -#include "gfxFontconfigUtils.h" -#include "gfxFont.h" -#include "nsGkAtoms.h" - -#include -#include - -#include "nsServiceManagerUtils.h" -#include "nsILanguageAtomService.h" -#include "nsTArray.h" -#include "mozilla/Preferences.h" -#include "nsDirectoryServiceUtils.h" -#include "nsDirectoryServiceDefs.h" -#include "nsAppDirectoryServiceDefs.h" - -#include "nsIAtom.h" -#include "nsCRT.h" -#include "gfxFontConstants.h" -#include "mozilla/gfx/2D.h" - -using namespace mozilla; - -/* static */ gfxFontconfigUtils* gfxFontconfigUtils::sUtils = nullptr; -static nsILanguageAtomService* gLangService = nullptr; - -/* static */ void -gfxFontconfigUtils::Shutdown() { - if (sUtils) { - delete sUtils; - sUtils = nullptr; - } - NS_IF_RELEASE(gLangService); -} - -/* static */ uint8_t -gfxFontconfigUtils::FcSlantToThebesStyle(int aFcSlant) -{ - switch (aFcSlant) { - case FC_SLANT_ITALIC: - return NS_FONT_STYLE_ITALIC; - case FC_SLANT_OBLIQUE: - return NS_FONT_STYLE_OBLIQUE; - default: - return NS_FONT_STYLE_NORMAL; - } -} - -/* static */ uint8_t -gfxFontconfigUtils::GetThebesStyle(FcPattern *aPattern) -{ - int slant; - if (FcPatternGetInteger(aPattern, FC_SLANT, 0, &slant) != FcResultMatch) { - return NS_FONT_STYLE_NORMAL; - } - - return FcSlantToThebesStyle(slant); -} - -/* static */ int -gfxFontconfigUtils::GetFcSlant(const gfxFontStyle& aFontStyle) -{ - if (aFontStyle.style == NS_FONT_STYLE_ITALIC) - return FC_SLANT_ITALIC; - if (aFontStyle.style == NS_FONT_STYLE_OBLIQUE) - return FC_SLANT_OBLIQUE; - - return FC_SLANT_ROMAN; -} - -// OS/2 weight classes were introduced in fontconfig-2.1.93 (2003). -#ifndef FC_WEIGHT_THIN -#define FC_WEIGHT_THIN 0 // 2.1.93 -#define FC_WEIGHT_EXTRALIGHT 40 // 2.1.93 -#define FC_WEIGHT_REGULAR 80 // 2.1.93 -#define FC_WEIGHT_EXTRABOLD 205 // 2.1.93 -#endif -// book was introduced in fontconfig-2.2.90 (and so fontconfig-2.3.0 in 2005) -#ifndef FC_WEIGHT_BOOK -#define FC_WEIGHT_BOOK 75 -#endif -// extra black was introduced in fontconfig-2.4.91 (2007) -#ifndef FC_WEIGHT_EXTRABLACK -#define FC_WEIGHT_EXTRABLACK 215 -#endif - -/* static */ uint16_t -gfxFontconfigUtils::GetThebesWeight(FcPattern *aPattern) -{ - int weight; - if (FcPatternGetInteger(aPattern, FC_WEIGHT, 0, &weight) != FcResultMatch) - return NS_FONT_WEIGHT_NORMAL; - - if (weight <= (FC_WEIGHT_THIN + FC_WEIGHT_EXTRALIGHT) / 2) - return 100; - if (weight <= (FC_WEIGHT_EXTRALIGHT + FC_WEIGHT_LIGHT) / 2) - return 200; - if (weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_BOOK) / 2) - return 300; - if (weight <= (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2) - // This includes FC_WEIGHT_BOOK - return 400; - if (weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2) - return 500; - if (weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2) - return 600; - if (weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_EXTRABOLD) / 2) - return 700; - if (weight <= (FC_WEIGHT_EXTRABOLD + FC_WEIGHT_BLACK) / 2) - return 800; - if (weight <= FC_WEIGHT_BLACK) - return 900; - - // including FC_WEIGHT_EXTRABLACK - return 901; -} - -/* static */ int -gfxFontconfigUtils::FcWeightForBaseWeight(int8_t aBaseWeight) -{ - NS_PRECONDITION(aBaseWeight >= 0 && aBaseWeight <= 10, - "base weight out of range"); - - switch (aBaseWeight) { - case 2: - return FC_WEIGHT_EXTRALIGHT; - case 3: - return FC_WEIGHT_LIGHT; - case 4: - return FC_WEIGHT_REGULAR; - case 5: - return FC_WEIGHT_MEDIUM; - case 6: - return FC_WEIGHT_DEMIBOLD; - case 7: - return FC_WEIGHT_BOLD; - case 8: - return FC_WEIGHT_EXTRABOLD; - case 9: - return FC_WEIGHT_BLACK; - } - - // extremes - return aBaseWeight < 2 ? FC_WEIGHT_THIN : FC_WEIGHT_EXTRABLACK; -} - -/* static */ int16_t -gfxFontconfigUtils::GetThebesStretch(FcPattern *aPattern) -{ - int width; - if (FcPatternGetInteger(aPattern, FC_WIDTH, 0, &width) != FcResultMatch) { - return NS_FONT_STRETCH_NORMAL; - } - - if (width <= (FC_WIDTH_ULTRACONDENSED + FC_WIDTH_EXTRACONDENSED) / 2) { - return NS_FONT_STRETCH_ULTRA_CONDENSED; - } - if (width <= (FC_WIDTH_EXTRACONDENSED + FC_WIDTH_CONDENSED) / 2) { - return NS_FONT_STRETCH_EXTRA_CONDENSED; - } - if (width <= (FC_WIDTH_CONDENSED + FC_WIDTH_SEMICONDENSED) / 2) { - return NS_FONT_STRETCH_CONDENSED; - } - if (width <= (FC_WIDTH_SEMICONDENSED + FC_WIDTH_NORMAL) / 2) { - return NS_FONT_STRETCH_SEMI_CONDENSED; - } - if (width <= (FC_WIDTH_NORMAL + FC_WIDTH_SEMIEXPANDED) / 2) { - return NS_FONT_STRETCH_NORMAL; - } - if (width <= (FC_WIDTH_SEMIEXPANDED + FC_WIDTH_EXPANDED) / 2) { - return NS_FONT_STRETCH_SEMI_EXPANDED; - } - if (width <= (FC_WIDTH_EXPANDED + FC_WIDTH_EXTRAEXPANDED) / 2) { - return NS_FONT_STRETCH_EXPANDED; - } - if (width <= (FC_WIDTH_EXTRAEXPANDED + FC_WIDTH_ULTRAEXPANDED) / 2) { - return NS_FONT_STRETCH_EXTRA_EXPANDED; - } - return NS_FONT_STRETCH_ULTRA_EXPANDED; -} - -/* static */ int -gfxFontconfigUtils::FcWidthForThebesStretch(int16_t aStretch) -{ - switch (aStretch) { - default: // this will catch "normal" (0) as well as out-of-range values - return FC_WIDTH_NORMAL; - case NS_FONT_STRETCH_ULTRA_CONDENSED: - return FC_WIDTH_ULTRACONDENSED; - case NS_FONT_STRETCH_EXTRA_CONDENSED: - return FC_WIDTH_EXTRACONDENSED; - case NS_FONT_STRETCH_CONDENSED: - return FC_WIDTH_CONDENSED; - case NS_FONT_STRETCH_SEMI_CONDENSED: - return FC_WIDTH_SEMICONDENSED; - case NS_FONT_STRETCH_SEMI_EXPANDED: - return FC_WIDTH_SEMIEXPANDED; - case NS_FONT_STRETCH_EXPANDED: - return FC_WIDTH_EXPANDED; - case NS_FONT_STRETCH_EXTRA_EXPANDED: - return FC_WIDTH_EXTRAEXPANDED; - case NS_FONT_STRETCH_ULTRA_EXPANDED: - return FC_WIDTH_ULTRAEXPANDED; - } -} - -// This makes a guess at an FC_WEIGHT corresponding to a base weight and -// offset (without any knowledge of which weights are available). - -/* static */ int -GuessFcWeight(const gfxFontStyle& aFontStyle) -{ - /* - * weights come in two parts crammed into one - * integer -- the "base" weight is weight / 100, - * the rest of the value is the "offset" from that - * weight -- the number of steps to move to adjust - * the weight in the list of supported font weights, - * this value can be negative or positive. - */ - int8_t weight = aFontStyle.ComputeWeight(); - - // ComputeWeight trimmed the range of weights for us - NS_ASSERTION(weight >= 0 && weight <= 10, - "base weight out of range"); - - return gfxFontconfigUtils::FcWeightForBaseWeight(weight); -} - -static void -AddString(FcPattern *aPattern, const char *object, const char *aString) -{ - FcPatternAddString(aPattern, object, - gfxFontconfigUtils::ToFcChar8(aString)); -} - -static void -AddWeakString(FcPattern *aPattern, const char *object, const char *aString) -{ - FcValue value; - value.type = FcTypeString; - value.u.s = gfxFontconfigUtils::ToFcChar8(aString); - - FcPatternAddWeak(aPattern, object, value, FcTrue); -} - -static void -AddLangGroup(FcPattern *aPattern, nsIAtom *aLangGroup) -{ - // Translate from mozilla's internal mapping into fontconfig's - nsAutoCString lang; - gfxFontconfigUtils::GetSampleLangForGroup(aLangGroup, &lang); - - if (!lang.IsEmpty()) { - AddString(aPattern, FC_LANG, lang.get()); - } -} - -nsReturnRef -gfxFontconfigUtils::NewPattern(const nsTArray& aFamilies, - const gfxFontStyle& aFontStyle, - const char *aLang) -{ - static const char* sFontconfigGenerics[] = - { "sans-serif", "serif", "monospace", "fantasy", "cursive" }; - - nsAutoRef pattern(FcPatternCreate()); - if (!pattern) - return nsReturnRef(); - - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, aFontStyle.size); - FcPatternAddInteger(pattern, FC_SLANT, GetFcSlant(aFontStyle)); - FcPatternAddInteger(pattern, FC_WEIGHT, GuessFcWeight(aFontStyle)); - FcPatternAddInteger(pattern, FC_WIDTH, FcWidthForThebesStretch(aFontStyle.stretch)); - - if (aLang) { - AddString(pattern, FC_LANG, aLang); - } - - bool useWeakBinding = false; - for (uint32_t i = 0; i < aFamilies.Length(); ++i) { - NS_ConvertUTF16toUTF8 family(aFamilies[i]); - if (!useWeakBinding) { - AddString(pattern, FC_FAMILY, family.get()); - - // fontconfig generic families are typically implemented with weak - // aliases (so that the preferred font depends on language). - // However, this would give them lower priority than subsequent - // non-generic families in the list. To ensure that subsequent - // families do not have a higher priority, they are given weak - // bindings. - for (uint32_t g = 0; - g < ArrayLength(sFontconfigGenerics); - ++g) { - if (0 == FcStrCmpIgnoreCase(ToFcChar8(sFontconfigGenerics[g]), - ToFcChar8(family.get()))) { - useWeakBinding = true; - break; - } - } - } else { - AddWeakString(pattern, FC_FAMILY, family.get()); - } - } - - return pattern.out(); -} - -gfxFontconfigUtils::gfxFontconfigUtils() - : mFontsByFamily(32) - , mFontsByFullname(32) - , mLangSupportTable(32) - , mLastConfig(nullptr) -#ifdef MOZ_BUNDLED_FONTS - , mBundledFontsInitialized(false) -#endif -{ - UpdateFontListInternal(); -} - -nsresult -gfxFontconfigUtils::GetFontList(nsIAtom *aLangGroup, - const nsACString& aGenericFamily, - nsTArray& aListOfFonts) -{ - aListOfFonts.Clear(); - - nsTArray fonts; - nsresult rv = GetFontListInternal(fonts, aLangGroup); - if (NS_FAILED(rv)) - return rv; - - for (uint32_t i = 0; i < fonts.Length(); ++i) { - aListOfFonts.AppendElement(NS_ConvertUTF8toUTF16(fonts[i])); - } - - aListOfFonts.Sort(); - - int32_t serif = 0, sansSerif = 0, monospace = 0; - - // Fontconfig supports 3 generic fonts, "serif", "sans-serif", and - // "monospace", slightly different from CSS's 5. - if (aGenericFamily.IsEmpty()) - serif = sansSerif = monospace = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("serif")) - serif = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("sans-serif")) - sansSerif = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("monospace")) - monospace = 1; - else if (aGenericFamily.LowerCaseEqualsLiteral("cursive") || - aGenericFamily.LowerCaseEqualsLiteral("fantasy")) - serif = sansSerif = 1; - else - NS_NOTREACHED("unexpected CSS generic font family"); - - // The first in the list becomes the default in - // FontBuilder.readFontSelection() if the preference-selected font is not - // available, so put system configured defaults first. - if (monospace) - aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("monospace")); - if (sansSerif) - aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("sans-serif")); - if (serif) - aListOfFonts.InsertElementAt(0, NS_LITERAL_STRING("serif")); - - return NS_OK; -} - -struct MozLangGroupData { - nsIAtom* const& mozLangGroup; - const char *defaultLang; -}; - -const MozLangGroupData MozLangGroups[] = { - { nsGkAtoms::x_western, "en" }, - { nsGkAtoms::x_cyrillic, "ru" }, - { nsGkAtoms::x_devanagari, "hi" }, - { nsGkAtoms::x_tamil, "ta" }, - { nsGkAtoms::x_armn, "hy" }, - { nsGkAtoms::x_beng, "bn" }, - { nsGkAtoms::x_cans, "iu" }, - { nsGkAtoms::x_ethi, "am" }, - { nsGkAtoms::x_geor, "ka" }, - { nsGkAtoms::x_gujr, "gu" }, - { nsGkAtoms::x_guru, "pa" }, - { nsGkAtoms::x_khmr, "km" }, - { nsGkAtoms::x_knda, "kn" }, - { nsGkAtoms::x_mlym, "ml" }, - { nsGkAtoms::x_orya, "or" }, - { nsGkAtoms::x_sinh, "si" }, - { nsGkAtoms::x_telu, "te" }, - { nsGkAtoms::x_tibt, "bo" }, - { nsGkAtoms::Unicode, 0 }, -}; - -static bool -TryLangForGroup(const nsACString& aOSLang, nsIAtom *aLangGroup, - nsACString *aFcLang) -{ - // Truncate at '.' or '@' from aOSLang, and convert '_' to '-'. - // aOSLang is in the form "language[_territory][.codeset][@modifier]". - // fontconfig takes languages in the form "language-territory". - // nsILanguageAtomService takes languages in the form language-subtag, - // where subtag may be a territory. fontconfig and nsILanguageAtomService - // handle case-conversion for us. - const char *pos, *end; - aOSLang.BeginReading(pos); - aOSLang.EndReading(end); - aFcLang->Truncate(); - while (pos < end) { - switch (*pos) { - case '.': - case '@': - end = pos; - break; - case '_': - aFcLang->Append('-'); - break; - default: - aFcLang->Append(*pos); - } - ++pos; - } - - nsIAtom *atom = - gLangService->LookupLanguage(*aFcLang); - - return atom == aLangGroup; -} - -/* static */ void -gfxFontconfigUtils::GetSampleLangForGroup(nsIAtom *aLangGroup, - nsACString *aFcLang) -{ - NS_PRECONDITION(aFcLang != nullptr, "aFcLang must not be NULL"); - - const MozLangGroupData *langGroup = nullptr; - - for (unsigned int i = 0; i < ArrayLength(MozLangGroups); ++i) { - if (aLangGroup == MozLangGroups[i].mozLangGroup) { - langGroup = &MozLangGroups[i]; - break; - } - } - - if (!langGroup) { - // Not a special mozilla language group. - // Use aLangGroup as a language code. - aLangGroup->ToUTF8String(*aFcLang); - return; - } - - // Check the environment for the users preferred language that corresponds - // to this langGroup. - if (!gLangService) { - CallGetService(NS_LANGUAGEATOMSERVICE_CONTRACTID, &gLangService); - } - - if (gLangService) { - const char *languages = getenv("LANGUAGE"); - if (languages) { - const char separator = ':'; - - for (const char *pos = languages; true; ++pos) { - if (*pos == '\0' || *pos == separator) { - if (languages < pos && - TryLangForGroup(Substring(languages, pos), - aLangGroup, aFcLang)) - return; - - if (*pos == '\0') - break; - - languages = pos + 1; - } - } - } - const char *ctype = setlocale(LC_CTYPE, nullptr); - if (ctype && - TryLangForGroup(nsDependentCString(ctype), aLangGroup, aFcLang)) - return; - } - - if (langGroup->defaultLang) { - aFcLang->Assign(langGroup->defaultLang); - } else { - aFcLang->Truncate(); - } -} - -nsresult -gfxFontconfigUtils::GetFontListInternal(nsTArray& aListOfFonts, - nsIAtom *aLangGroup) -{ - FcPattern *pat = nullptr; - FcObjectSet *os = nullptr; - FcFontSet *fs = nullptr; - nsresult rv = NS_ERROR_FAILURE; - - aListOfFonts.Clear(); - - pat = FcPatternCreate(); - if (!pat) - goto end; - - os = FcObjectSetBuild(FC_FAMILY, nullptr); - if (!os) - goto end; - - // take the pattern and add the lang group to it - if (aLangGroup) { - AddLangGroup(pat, aLangGroup); - } - - fs = FcFontList(nullptr, pat, os); - if (!fs) - goto end; - - for (int i = 0; i < fs->nfont; i++) { - char *family; - - if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, - (FcChar8 **) &family) != FcResultMatch) - { - continue; - } - - // Remove duplicates... - nsAutoCString strFamily(family); - if (aListOfFonts.Contains(strFamily)) - continue; - - aListOfFonts.AppendElement(strFamily); - } - - rv = NS_OK; - - end: - if (NS_FAILED(rv)) - aListOfFonts.Clear(); - - if (pat) - FcPatternDestroy(pat); - if (os) - FcObjectSetDestroy(os); - if (fs) - FcFontSetDestroy(fs); - - return rv; -} - -nsresult -gfxFontconfigUtils::UpdateFontList() -{ - return UpdateFontListInternal(true); -} - -nsresult -gfxFontconfigUtils::UpdateFontListInternal(bool aForce) -{ - if (!aForce) { - // This checks periodically according to fontconfig's configured - // interval. - FcInitBringUptoDate(); - } else if (!FcConfigUptoDate(nullptr)) { // check now with aForce - mLastConfig = nullptr; - FcInitReinitialize(); - } - - // FcInitReinitialize() (used by FcInitBringUptoDate) creates a new config - // before destroying the old config, so the only way that we'd miss an - // update is if fontconfig did more than one update and the memory for the - // most recent config happened to be at the same location as the original - // config. - FcConfig *currentConfig = FcConfigGetCurrent(); - if (currentConfig == mLastConfig) - return NS_OK; - -#ifdef MOZ_BUNDLED_FONTS - ActivateBundledFonts(); -#endif - - // These FcFontSets are owned by fontconfig - FcFontSet *fontSets[] = { - FcConfigGetFonts(currentConfig, FcSetSystem) -#ifdef MOZ_BUNDLED_FONTS - , FcConfigGetFonts(currentConfig, FcSetApplication) -#endif - }; - - mFontsByFamily.Clear(); - mFontsByFullname.Clear(); - mLangSupportTable.Clear(); - - // Record the existing font families - for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) { - FcFontSet *fontSet = fontSets[fs]; - if (!fontSet) { // the application set might not exist - continue; - } - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - - FcChar8 *family; - for (int v = 0; - FcPatternGetString(font, FC_FAMILY, v, &family) == FcResultMatch; - ++v) { - FontsByFcStrEntry *entry = mFontsByFamily.PutEntry(family); - if (entry) { - bool added = entry->AddFont(font); - - if (!entry->mKey) { - // The reference to the font pattern keeps the pointer - // to string for the key valid. If adding the font - // failed then the entry must be removed. - if (added) { - entry->mKey = family; - } else { - mFontsByFamily.RemoveEntry(entry); - } - } - } - } - } - } - - mLastConfig = currentConfig; - return NS_OK; -} - -nsresult -gfxFontconfigUtils::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) -{ - aFamilyName.Truncate(); - - // The fontconfig has generic family names in the font list. - if (aFontName.EqualsLiteral("serif") || - aFontName.EqualsLiteral("sans-serif") || - aFontName.EqualsLiteral("monospace")) { - aFamilyName.Assign(aFontName); - return NS_OK; - } - - nsresult rv = UpdateFontListInternal(); - if (NS_FAILED(rv)) - return rv; - - NS_ConvertUTF16toUTF8 fontname(aFontName); - - // return empty string if no such family exists - if (!IsExistingFamily(fontname)) - return NS_OK; - - FcPattern *pat = nullptr; - FcObjectSet *os = nullptr; - FcFontSet *givenFS = nullptr; - nsTArray candidates; - FcFontSet *candidateFS = nullptr; - rv = NS_ERROR_FAILURE; - - pat = FcPatternCreate(); - if (!pat) - goto end; - - FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)fontname.get()); - - os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_INDEX, nullptr); - if (!os) - goto end; - - givenFS = FcFontList(nullptr, pat, os); - if (!givenFS) - goto end; - - // The first value associated with a FC_FAMILY property is the family - // returned by GetFontList(), so use this value if appropriate. - - // See if there is a font face with first family equal to the given family. - for (int i = 0; i < givenFS->nfont; ++i) { - char *firstFamily; - if (FcPatternGetString(givenFS->fonts[i], FC_FAMILY, 0, - (FcChar8 **) &firstFamily) != FcResultMatch) - continue; - - nsDependentCString first(firstFamily); - if (!candidates.Contains(first)) { - candidates.AppendElement(first); - - if (fontname.Equals(first)) { - aFamilyName.Assign(aFontName); - rv = NS_OK; - goto end; - } - } - } - - // See if any of the first family names represent the same set of font - // faces as the given family. - for (uint32_t j = 0; j < candidates.Length(); ++j) { - FcPatternDel(pat, FC_FAMILY); - FcPatternAddString(pat, FC_FAMILY, (FcChar8 *)candidates[j].get()); - - candidateFS = FcFontList(nullptr, pat, os); - if (!candidateFS) - goto end; - - if (candidateFS->nfont != givenFS->nfont) - continue; - - bool equal = true; - for (int i = 0; i < givenFS->nfont; ++i) { - if (!FcPatternEqual(candidateFS->fonts[i], givenFS->fonts[i])) { - equal = false; - break; - } - } - if (equal) { - AppendUTF8toUTF16(candidates[j], aFamilyName); - rv = NS_OK; - goto end; - } - } - - // No match found; return empty string. - rv = NS_OK; - - end: - if (pat) - FcPatternDestroy(pat); - if (os) - FcObjectSetDestroy(os); - if (givenFS) - FcFontSetDestroy(givenFS); - if (candidateFS) - FcFontSetDestroy(candidateFS); - - return rv; -} - -bool -gfxFontconfigUtils::IsExistingFamily(const nsCString& aFamilyName) -{ - return mFontsByFamily.GetEntry(ToFcChar8(aFamilyName)) != nullptr; -} - -const nsTArray< nsCountedRef >& -gfxFontconfigUtils::GetFontsForFamily(const FcChar8 *aFamilyName) -{ - FontsByFcStrEntry *entry = mFontsByFamily.GetEntry(aFamilyName); - - if (!entry) - return mEmptyPatternArray; - - return entry->GetFonts(); -} - -// Fontconfig only provides a fullname property for fonts in formats with SFNT -// wrappers. For other font formats (including PCF and PS Type 1), a fullname -// must be generated from the family and style properties. Only the first -// family and style is checked, but that should be OK, as I don't expect -// non-SFNT fonts to have multiple families or styles. -bool -gfxFontconfigUtils::GetFullnameFromFamilyAndStyle(FcPattern *aFont, - nsACString *aFullname) -{ - FcChar8 *family; - if (FcPatternGetString(aFont, FC_FAMILY, 0, &family) != FcResultMatch) - return false; - - aFullname->Truncate(); - aFullname->Append(ToCString(family)); - - FcChar8 *style; - if (FcPatternGetString(aFont, FC_STYLE, 0, &style) == FcResultMatch && - strcmp(ToCString(style), "Regular") != 0) { - aFullname->Append(' '); - aFullname->Append(ToCString(style)); - } - - return true; -} - -bool -gfxFontconfigUtils::FontsByFullnameEntry::KeyEquals(KeyTypePointer aKey) const -{ - const FcChar8 *key = mKey; - // If mKey is nullptr, key comes from the style and family of the first - // font. - nsAutoCString fullname; - if (!key) { - NS_ASSERTION(mFonts.Length(), "No font in FontsByFullnameEntry!"); - GetFullnameFromFamilyAndStyle(mFonts[0], &fullname); - - key = ToFcChar8(fullname); - } - - return FcStrCmpIgnoreCase(aKey, key) == 0; -} - -void -gfxFontconfigUtils::AddFullnameEntries() -{ - // These FcFontSets are owned by fontconfig - FcFontSet *fontSets[] = { - FcConfigGetFonts(nullptr, FcSetSystem) -#ifdef MOZ_BUNDLED_FONTS - , FcConfigGetFonts(nullptr, FcSetApplication) -#endif - }; - - for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) { - FcFontSet *fontSet = fontSets[fs]; - if (!fontSet) { - continue; - } - // Record the existing font families - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - - int v = 0; - FcChar8 *fullname; - while (FcPatternGetString(font, - FC_FULLNAME, v, &fullname) == FcResultMatch) { - FontsByFullnameEntry *entry = - mFontsByFullname.PutEntry(fullname); - if (entry) { - // entry always has space for one font, so the first - // AddFont will always succeed, and so the entry will - // always have a font from which to obtain the key. - bool added = entry->AddFont(font); - // The key may be nullptr either if this is the first - // font, or if the first font does not have a fullname - // property, and so the key is obtained from the font. - // Set the key in both cases. The check that AddFont - // succeeded is required for the second case. - if (!entry->mKey && added) { - entry->mKey = fullname; - } - } - - ++v; - } - - // Fontconfig does not provide a fullname property for all fonts. - if (v == 0) { - nsAutoCString name; - if (!GetFullnameFromFamilyAndStyle(font, &name)) - continue; - - FontsByFullnameEntry *entry = - mFontsByFullname.PutEntry(ToFcChar8(name)); - if (entry) { - entry->AddFont(font); - // Either entry->mKey has been set for a previous font or it - // remains nullptr to indicate that the key is obtained from - // the first font. - } - } - } - } -} - -const nsTArray< nsCountedRef >& -gfxFontconfigUtils::GetFontsForFullname(const FcChar8 *aFullname) -{ - if (mFontsByFullname.Count() == 0) { - AddFullnameEntries(); - } - - FontsByFullnameEntry *entry = mFontsByFullname.GetEntry(aFullname); - - if (!entry) - return mEmptyPatternArray; - - return entry->GetFonts(); -} - -static FcLangResult -CompareLangString(const FcChar8 *aLangA, const FcChar8 *aLangB) { - FcLangResult result = FcLangDifferentLang; - for (uint32_t i = 0; ; ++i) { - FcChar8 a = FcToLower(aLangA[i]); - FcChar8 b = FcToLower(aLangB[i]); - - if (a != b) { - if ((a == '\0' && b == '-') || (a == '-' && b == '\0')) - return FcLangDifferentCountry; - - return result; - } - if (a == '\0') - return FcLangEqual; - - if (a == '-') { - result = FcLangDifferentCountry; - } - } -} - -/* static */ -FcLangResult -gfxFontconfigUtils::GetLangSupport(FcPattern *aFont, const FcChar8 *aLang) -{ - // When fontconfig builds a pattern for a system font, it will set a - // single LangSet property value for the font. That value may be removed - // and additional string values may be added through FcConfigSubsitute - // with FcMatchScan. Values that are neither LangSet nor string are - // considered errors in fontconfig sort and match functions. - // - // If no string nor LangSet value is found, then either the font is a - // system font and the LangSet has been removed through FcConfigSubsitute, - // or the font is a web font and its language support is unknown. - // Returning FcLangDifferentLang for these fonts ensures that this font - // will not be assumed to satisfy the language, and so language will be - // prioritized in sorting fallback fonts. - FcValue value; - FcLangResult best = FcLangDifferentLang; - for (int v = 0; - FcPatternGet(aFont, FC_LANG, v, &value) == FcResultMatch; - ++v) { - - FcLangResult support; - switch (value.type) { - case FcTypeLangSet: - support = FcLangSetHasLang(value.u.l, aLang); - break; - case FcTypeString: - support = CompareLangString(value.u.s, aLang); - break; - default: - // error. continue to see if there is a useful value. - continue; - } - - if (support < best) { // lower is better - if (support == FcLangEqual) - return support; - best = support; - } - } - - return best; -} - -gfxFontconfigUtils::LangSupportEntry * -gfxFontconfigUtils::GetLangSupportEntry(const FcChar8 *aLang, bool aWithFonts) -{ - // Currently any unrecognized languages from documents will be converted - // to x-unicode by nsILanguageAtomService, so there is a limit on the - // langugages that will be added here. Reconsider when/if document - // languages are passed to this routine. - - LangSupportEntry *entry = mLangSupportTable.PutEntry(aLang); - if (!entry) - return nullptr; - - FcLangResult best = FcLangDifferentLang; - - if (!entry->IsKeyInitialized()) { - entry->InitKey(aLang); - } else { - // mSupport is already initialized. - if (!aWithFonts) - return entry; - - best = entry->mSupport; - // If there is support for this language, an empty font list indicates - // that the list hasn't been initialized yet. - if (best == FcLangDifferentLang || entry->mFonts.Length() > 0) - return entry; - } - - // These FcFontSets are owned by fontconfig - FcFontSet *fontSets[] = { - FcConfigGetFonts(nullptr, FcSetSystem) -#ifdef MOZ_BUNDLED_FONTS - , FcConfigGetFonts(nullptr, FcSetApplication) -#endif - }; - - AutoTArray fonts; - - for (unsigned fs = 0; fs < ArrayLength(fontSets); ++fs) { - FcFontSet *fontSet = fontSets[fs]; - if (!fontSet) { - continue; - } - for (int f = 0; f < fontSet->nfont; ++f) { - FcPattern *font = fontSet->fonts[f]; - - FcLangResult support = GetLangSupport(font, aLang); - - if (support < best) { // lower is better - best = support; - if (aWithFonts) { - fonts.Clear(); - } else if (best == FcLangEqual) { - break; - } - } - - // The font list in the LangSupportEntry is expected to be used - // only when no default fonts support the language. There would - // be a large number of fonts in entries for languages using Latin - // script but these do not need to be created because default - // fonts already support these languages. - if (aWithFonts && support != FcLangDifferentLang && - support == best) { - fonts.AppendElement(font); - } - } - } - - entry->mSupport = best; - if (aWithFonts) { - if (fonts.Length() != 0) { - entry->mFonts.AppendElements(fonts.Elements(), fonts.Length()); - } else if (best != FcLangDifferentLang) { - // Previously there was a font that supported this language at the - // level of entry->mSupport, but it has now disappeared. At least - // entry->mSupport needs to be recalculated, but this is an - // indication that the set of installed fonts has changed, so - // update all caches. - mLastConfig = nullptr; // invalidates caches - UpdateFontListInternal(true); - return GetLangSupportEntry(aLang, aWithFonts); - } - } - - return entry; -} - -FcLangResult -gfxFontconfigUtils::GetBestLangSupport(const FcChar8 *aLang) -{ - UpdateFontListInternal(); - - LangSupportEntry *entry = GetLangSupportEntry(aLang, false); - if (!entry) - return FcLangEqual; - - return entry->mSupport; -} - -const nsTArray< nsCountedRef >& -gfxFontconfigUtils::GetFontsForLang(const FcChar8 *aLang) -{ - LangSupportEntry *entry = GetLangSupportEntry(aLang, true); - if (!entry) - return mEmptyPatternArray; - - return entry->mFonts; -} - -#ifdef MOZ_BUNDLED_FONTS - -void -gfxFontconfigUtils::ActivateBundledFonts() -{ - if (!mBundledFontsInitialized) { - mBundledFontsInitialized = true; - nsCOMPtr localDir; - nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(localDir)); - if (NS_FAILED(rv)) { - return; - } - if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("fonts")))) { - return; - } - bool isDir; - if (NS_FAILED(localDir->IsDirectory(&isDir)) || !isDir) { - return; - } - if (NS_FAILED(localDir->GetNativePath(mBundledFontsPath))) { - return; - } - } - if (!mBundledFontsPath.IsEmpty()) { - FcConfigAppFontAddDir(nullptr, (const FcChar8*)mBundledFontsPath.get()); - } -} - -#endif - -gfxFontconfigFontBase::gfxFontconfigFontBase(cairo_scaled_font_t *aScaledFont, - FcPattern *aPattern, - gfxFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle) - : gfxFT2FontBase(aScaledFont, aFontEntry, aFontStyle) - , mPattern(aPattern) -{ -} - diff --git a/gfx/thebes/gfxFontconfigUtils.h b/gfx/thebes/gfxFontconfigUtils.h index eee69e481646..3f502c124345 100644 --- a/gfx/thebes/gfxFontconfigUtils.h +++ b/gfx/thebes/gfxFontconfigUtils.h @@ -8,11 +8,7 @@ #include "gfxPlatform.h" -#include "mozilla/MathAlgorithms.h" #include "nsAutoRef.h" -#include "nsTArray.h" -#include "nsTHashtable.h" -#include "nsISupportsImpl.h" #include "gfxFT2FontBase.h" #include @@ -40,285 +36,14 @@ public: static void Release(FcCharSet *ptr) { FcCharSetDestroy(ptr); } }; -class gfxIgnoreCaseCStringComparator -{ - public: - bool Equals(const nsACString& a, const nsACString& b) const - { - return nsCString(a).Equals(b, nsCaseInsensitiveCStringComparator()); - } - - bool LessThan(const nsACString& a, const nsACString& b) const - { - return a < b; - } -}; - -class gfxFontconfigUtils { -public: - gfxFontconfigUtils(); - - static gfxFontconfigUtils* GetFontconfigUtils() { - if (!sUtils) - sUtils = new gfxFontconfigUtils(); - return sUtils; - } - - static void Shutdown(); - - nsresult GetFontList(nsIAtom *aLangGroup, - const nsACString& aGenericFamily, - nsTArray& aListOfFonts); - - nsresult UpdateFontList(); - - nsresult GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName); - - const nsTArray< nsCountedRef >& - GetFontsForFamily(const FcChar8 *aFamilyName); - - const nsTArray< nsCountedRef >& - GetFontsForFullname(const FcChar8 *aFullname); - - // Returns the best support that any font offers for |aLang|. - FcLangResult GetBestLangSupport(const FcChar8 *aLang); - // Returns the fonts offering this best level of support. - const nsTArray< nsCountedRef >& - GetFontsForLang(const FcChar8 *aLang); - - // Retuns the language support for a fontconfig font pattern - static FcLangResult GetLangSupport(FcPattern *aFont, const FcChar8 *aLang); - - // Conversions between FcChar8*, which is unsigned char*, - // and (signed) char*, that check the type of the argument. - static const FcChar8 *ToFcChar8(const char *aCharPtr) - { - return reinterpret_cast(aCharPtr); - } - static const FcChar8 *ToFcChar8(const nsCString& aCString) - { - return ToFcChar8(aCString.get()); - } - static const char *ToCString(const FcChar8 *aChar8Ptr) - { - return reinterpret_cast(aChar8Ptr); - } - - static uint8_t FcSlantToThebesStyle(int aFcSlant); - static uint8_t GetThebesStyle(FcPattern *aPattern); // slant - static uint16_t GetThebesWeight(FcPattern *aPattern); - static int16_t GetThebesStretch(FcPattern *aPattern); - - static int GetFcSlant(const gfxFontStyle& aFontStyle); - // Returns a precise FC_WEIGHT from |aBaseWeight|, - // which is a CSS absolute weight / 100. - static int FcWeightForBaseWeight(int8_t aBaseWeight); - - static int FcWidthForThebesStretch(int16_t aStretch); - - static bool GetFullnameFromFamilyAndStyle(FcPattern *aFont, - nsACString *aFullname); - - // This doesn't consider which faces exist, and so initializes the pattern - // using a guessed weight, and doesn't consider sizeAdjust. - static nsReturnRef - NewPattern(const nsTArray& aFamilies, - const gfxFontStyle& aFontStyle, const char *aLang); - - /** - * @param aLangGroup [in] a Mozilla langGroup. - * @param aFcLang [out] returns a language suitable for fontconfig - * matching |aLangGroup| or an empty string if no match is found. - */ - static void GetSampleLangForGroup(nsIAtom *aLangGroup, - nsACString *aFcLang); - -protected: - // Base class for hash table entries with case-insensitive FcChar8 - // string keys. - class FcStrEntryBase : public PLDHashEntryHdr { - public: - typedef const FcChar8 *KeyType; - typedef const FcChar8 *KeyTypePointer; - - static KeyTypePointer KeyToPointer(KeyType aKey) { return aKey; } - // Case-insensitive hash. - // - // fontconfig always ignores case of ASCII characters in family - // names and languages, but treatment of whitespace in families is - // not consistent. FcFontSort and FcFontMatch ignore whitespace - // except for whitespace in the first character, while FcFontList - // and config subsitution tests require whitespace to match - // exactly. CSS 2.1 implies that whitespace is important in the - // font-family property. FcStrCmpIgnoreCase considers whitespace - // important. - static PLDHashNumber HashKey(const FcChar8 *aKey) { - uint32_t hash = 0; - for (const FcChar8 *c = aKey; *c != '\0'; ++c) { - hash = mozilla::RotateLeft(hash, 3) ^ FcToLower(*c); - } - return hash; - } - enum { ALLOW_MEMMOVE = true }; - }; - -public: - // Hash entry with a dependent const FcChar8* pointer to an external - // string for a key (and no data). The user must ensure that the string - // associated with the pointer is not destroyed. This entry type is - // useful for family name keys as the family name string is held in the - // font pattern. - class DepFcStrEntry : public FcStrEntryBase { - public: - // When constructing a new entry in the hashtable, the key is left - // nullptr. The caller of PutEntry() must fill in mKey when nullptr. - // This provides a mechanism for the caller of PutEntry() to determine - // whether the entry has been initialized. - explicit DepFcStrEntry(KeyTypePointer aName) - : mKey(nullptr) { } - - DepFcStrEntry(const DepFcStrEntry& toCopy) - : mKey(toCopy.mKey) { } - - bool KeyEquals(KeyTypePointer aKey) const { - return FcStrCmpIgnoreCase(aKey, mKey) == 0; - } - - const FcChar8 *mKey; - }; - - // Hash entry that uses a copy of an FcChar8 string to store the key. - // This entry type is useful for language keys, as languages are usually - // not stored as strings in font patterns. - class CopiedFcStrEntry : public FcStrEntryBase { - public: - // When constructing a new entry in the hashtable, the key is void. - // The caller of PutEntry() must call InitKey() when IsKeyInitialized() - // returns false. This provides a mechanism for the caller of - // PutEntry() to determine whether the entry has been initialized. - explicit CopiedFcStrEntry(KeyTypePointer aName) { - mKey.SetIsVoid(true); - } - - CopiedFcStrEntry(const CopiedFcStrEntry& toCopy) - : mKey(toCopy.mKey) { } - - bool KeyEquals(KeyTypePointer aKey) const { - return FcStrCmpIgnoreCase(aKey, ToFcChar8(mKey)) == 0; - } - - bool IsKeyInitialized() { return !mKey.IsVoid(); } - void InitKey(const FcChar8* aKey) { mKey.Assign(ToCString(aKey)); } - - private: - nsCString mKey; - }; - -protected: - class FontsByFcStrEntry : public DepFcStrEntry { - public: - explicit FontsByFcStrEntry(KeyTypePointer aName) - : DepFcStrEntry(aName) { } - - FontsByFcStrEntry(const FontsByFcStrEntry& toCopy) - : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } - - bool AddFont(FcPattern *aFont) { - return mFonts.AppendElement(aFont) != nullptr; - } - const nsTArray< nsCountedRef >& GetFonts() { - return mFonts; - } - private: - nsTArray< nsCountedRef > mFonts; - }; - - // FontsByFullnameEntry is similar to FontsByFcStrEntry (used for - // mFontsByFamily) except for two differences: - // - // * The font does not always contain a single string for the fullname, so - // the key is sometimes a combination of family and style. - // - // * There is usually only one font. - class FontsByFullnameEntry : public DepFcStrEntry { - public: - // When constructing a new entry in the hashtable, the key is left - // nullptr. The caller of PutEntry() is must fill in mKey when adding - // the first font if the key is not derived from the family and style. - // If the key is derived from family and style, a font must be added. - explicit FontsByFullnameEntry(KeyTypePointer aName) - : DepFcStrEntry(aName) { } - - FontsByFullnameEntry(const FontsByFullnameEntry& toCopy) - : DepFcStrEntry(toCopy), mFonts(toCopy.mFonts) { } - - bool KeyEquals(KeyTypePointer aKey) const; - - bool AddFont(FcPattern *aFont) { - return mFonts.AppendElement(aFont) != nullptr; - } - const nsTArray< nsCountedRef >& GetFonts() { - return mFonts; - } - - // Don't memmove the AutoTArray. - enum { ALLOW_MEMMOVE = false }; - private: - // There is usually only one font, but sometimes more. - AutoTArray,1> mFonts; - }; - - class LangSupportEntry : public CopiedFcStrEntry { - public: - explicit LangSupportEntry(KeyTypePointer aName) - : CopiedFcStrEntry(aName) { } - - LangSupportEntry(const LangSupportEntry& toCopy) - : CopiedFcStrEntry(toCopy), mSupport(toCopy.mSupport) { } - - FcLangResult mSupport; - nsTArray< nsCountedRef > mFonts; - }; - - static gfxFontconfigUtils* sUtils; - - bool IsExistingFamily(const nsCString& aFamilyName); - - nsresult GetFontListInternal(nsTArray& aListOfFonts, - nsIAtom *aLangGroup); - nsresult UpdateFontListInternal(bool aForce = false); - - void AddFullnameEntries(); - - LangSupportEntry *GetLangSupportEntry(const FcChar8 *aLang, - bool aWithFonts); - - // mFontsByFamily and mFontsByFullname contain entries only for families - // and fullnames for which there are fonts. - nsTHashtable mFontsByFamily; - nsTHashtable mFontsByFullname; - // mLangSupportTable contains an entry for each language that has been - // looked up through GetLangSupportEntry, even when the language is not - // supported. - nsTHashtable mLangSupportTable; - const nsTArray< nsCountedRef > mEmptyPatternArray; - - FcConfig *mLastConfig; - -#ifdef MOZ_BUNDLED_FONTS - void ActivateBundledFonts(); - - nsCString mBundledFontsPath; - bool mBundledFontsInitialized; -#endif -}; - class gfxFontconfigFontBase : public gfxFT2FontBase { public: gfxFontconfigFontBase(cairo_scaled_font_t *aScaledFont, FcPattern *aPattern, gfxFontEntry *aFontEntry, - const gfxFontStyle *aFontStyle); + const gfxFontStyle *aFontStyle) + : gfxFT2FontBase(aScaledFont, aFontEntry, aFontStyle) + , mPattern(aPattern) { } virtual FontType GetType() const override { return FONT_TYPE_FONTCONFIG; } virtual FcPattern *GetPattern() const { return mPattern; } diff --git a/gfx/thebes/gfxTextRun.cpp b/gfx/thebes/gfxTextRun.cpp index 8f6c359a78bd..6e968736feac 100644 --- a/gfx/thebes/gfxTextRun.cpp +++ b/gfx/thebes/gfxTextRun.cpp @@ -1711,7 +1711,6 @@ gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList, , mPageLang(gfxPlatformFontList::GetFontPrefLangFor(aStyle->language)) , mLastPrefFirstFont(false) , mSkipDrawing(false) - , mSkipUpdateUserFonts(false) { // We don't use SetUserFontSet() here, as we want to unconditionally call // BuildFontList() rather than only do UpdateUserFonts() if it changed. @@ -2440,7 +2439,7 @@ gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget, "don't call InitScriptRun with aborted shaping state"); // confirm the load state of userfonts in the list - if (!mSkipUpdateUserFonts && mUserFontSet && + if (mUserFontSet && mCurrGeneration != mUserFontSet->GetGeneration()) { UpdateUserFonts(); } @@ -3178,8 +3177,6 @@ gfxFontGroup::GetRebuildGeneration() return mUserFontSet->GetRebuildGeneration(); } -// note: gfxPangoFontGroup overrides UpdateUserFonts, such that -// BuildFontList is never used void gfxFontGroup::UpdateUserFonts() { diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h index e817518982da..2e1f4b495be8 100644 --- a/gfx/thebes/gfxTextRun.h +++ b/gfx/thebes/gfxTextRun.h @@ -1115,9 +1115,6 @@ protected: // download to complete (or fallback // timer to fire) - // xxx - gfxPangoFontGroup skips UpdateUserFonts - bool mSkipUpdateUserFonts; - /** * Textrun creation short-cuts for special cases where we don't need to * call a font shaper to generate glyphs. diff --git a/gfx/thebes/gfxUserFontSet.cpp b/gfx/thebes/gfxUserFontSet.cpp index d918b4877d68..8fc68c9c7fd1 100644 --- a/gfx/thebes/gfxUserFontSet.cpp +++ b/gfx/thebes/gfxUserFontSet.cpp @@ -978,32 +978,6 @@ gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName, } } -gfxUserFontEntry* -gfxUserFontSet::FindUserFontEntryAndLoad(gfxFontFamily* aFamily, - const gfxFontStyle& aFontStyle, - bool& aNeedsBold, - bool& aWaitForUserFont) -{ - aWaitForUserFont = false; - gfxFontEntry* fe = aFamily->FindFontForStyle(aFontStyle, aNeedsBold); - NS_ASSERTION(!fe || fe->mIsUserFontContainer, - "should only have userfont entries in userfont families"); - if (!fe) { - return nullptr; - } - - gfxUserFontEntry* userFontEntry = static_cast(fe); - - // start the load if it hasn't been loaded - userFontEntry->Load(); - if (userFontEntry->GetPlatformFontEntry()) { - return userFontEntry; - } - - aWaitForUserFont = userFontEntry->WaitForUserFont(); - return nullptr; -} - void gfxUserFontSet::IncrementGeneration(bool aIsRebuild) { diff --git a/gfx/thebes/gfxUserFontSet.h b/gfx/thebes/gfxUserFontSet.h index 0a5da53830f6..c869d8911933 100644 --- a/gfx/thebes/gfxUserFontSet.h +++ b/gfx/thebes/gfxUserFontSet.h @@ -248,14 +248,6 @@ public: // Look up names in a fontlist and return true if any are in the set bool ContainsUserFontSetFonts(const mozilla::FontFamilyList& aFontList) const; - // Lookup a font entry for a given style, returns null if not loaded. - // aFamily must be a family returned by our LookupFamily method. - // (only used by gfxPangoFontGroup for now) - gfxUserFontEntry* FindUserFontEntryAndLoad(gfxFontFamily* aFamily, - const gfxFontStyle& aFontStyle, - bool& aNeedsBold, - bool& aWaitForUserFont); - // check whether the given source is allowed to be loaded; // returns the Principal (for use in the key when caching the loaded font), // and whether the load should bypass the cache (force-reload). diff --git a/gfx/thebes/moz.build b/gfx/thebes/moz.build index a08aa27b1b7c..f51288fcbd11 100644 --- a/gfx/thebes/moz.build +++ b/gfx/thebes/moz.build @@ -110,8 +110,6 @@ elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']: ] SOURCES += [ 'gfxFcPlatformFontList.cpp', - 'gfxFontconfigFonts.cpp', - 'gfxFontconfigUtils.cpp', 'gfxFT2FontBase.cpp', 'gfxFT2Utils.cpp', 'gfxGdkNativeRenderer.cpp', From aa429c08b7e8b4ce825d649079e83eb95c253b4e Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Wed, 22 Mar 2017 15:03:03 -0400 Subject: [PATCH 90/96] Bug 1347262 - fix Skia's round_asymmetric_to_int to bias all sides. r=jrmuizel MozReview-Commit-ID: AMDi6YF0zn --- gfx/skia/skia/src/core/SkScan_Path.cpp | 51 +++++++++++++------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/gfx/skia/skia/src/core/SkScan_Path.cpp b/gfx/skia/skia/src/core/SkScan_Path.cpp index a3116bb92922..5b80492cfa28 100644 --- a/gfx/skia/skia/src/core/SkScan_Path.cpp +++ b/gfx/skia/skia/src/core/SkScan_Path.cpp @@ -592,29 +592,35 @@ static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) { } /** - * Variant of SkScalarRoundToInt, identical to SkDScalarRoundToInt except when the input fraction - * is 0.5. In this case only, round the value down. This is used to round the top and left - * of a rectangle, and corresponds to the way the scan converter treats the top and left edges. + * Variants of SkScalarRoundToInt, identical to SkDScalarRoundToInt except when the input fraction + * is 0.5. When SK_RASTERIZE_EVEN_ROUNDING is enabled, we must bias the result before rounding to + * account for potential FDot6 rounding edge-cases. + */ +#ifdef SK_RASTERIZE_EVEN_ROUNDING +static const double kRoundBias = 0.5 / SK_FDot6One; +#else +static const double kRoundBias = 0.0; +#endif + +/** + * Round the value down. This is used to round the top and left of a rectangle, + * and corresponds to the way the scan converter treats the top and left edges. */ static inline int round_down_to_int(SkScalar x) { double xx = x; - xx += 0.5; - double floorXX = floor(xx); - return (int)floorXX - (xx == floorXX); + xx -= 0.5 + kRoundBias; + return (int)ceil(xx); } -#ifdef SK_RASTERIZE_EVEN_ROUNDING /** - * Variant of SkDScalarRoundToInt that allows offseting the input by a small fraction - * while trying to preserve intermediate double-precision (rather than directly adding - * the bias to the input at lower single-precision). + * Round the value up. This is used to round the bottom and right of a rectangle, + * and corresponds to the way the scan converter treats the bottom and right edges. */ -static inline int round_biased_to_int(SkScalar x, SkScalar bias) { +static inline int round_up_to_int(SkScalar x) { double xx = x; - xx += 0.5 + bias; + xx += 0.5 + kRoundBias; return (int)floor(xx); } -#endif /** * Variant of SkRect::round() that explicitly performs the rounding step (i.e. floor(x + 0.5)) @@ -635,26 +641,21 @@ static inline int round_biased_to_int(SkScalar x, SkScalar bias) { * SkASSERT(0 == iright); // <--- succeeds * * - * If using SK_RASTERIZE_EVEN_ROUNDING, we need to ensure that bottom and right account for - * edges bounded by this rect being rounded to FDot6 format before being later rounded to an - * integer. For example, a value like 0.499 can be below 0.5, but round to 0.5 as FDot6, which - * would finally round to the integer 1, instead of just rounding to 0. + * If using SK_RASTERIZE_EVEN_ROUNDING, we need to ensure we account for edges bounded by this + * rect being rounded to FDot6 format before being later rounded to an integer. For example, a + * value like 0.499 can be below 0.5, but round to 0.5 as FDot6, which would finally round to + * the integer 1, instead of just rounding to 0. * * To handle this, a small bias of half an FDot6 increment is added before actually rounding to * an integer value. This simulates the rounding of SkScalarRoundToFDot6 without incurring the * range loss of converting to FDot6 format first, preserving the integer range for the SkIRect. - * Thus, bottom and right are rounded in this manner (biased up), ensuring the rect is large enough. - * Top and left can round as normal since they will round (biased down) to values less or equal - * to the desired rect origin. + * Thus, bottom and right are rounded in this manner (biased up), ensuring the rect is large + * enough. */ static void round_asymmetric_to_int(const SkRect& src, SkIRect* dst) { SkASSERT(dst); dst->set(round_down_to_int(src.fLeft), round_down_to_int(src.fTop), -#ifdef SK_RASTERIZE_EVEN_ROUNDING - round_biased_to_int(src.fRight, 0.5f / SK_FDot6One), round_biased_to_int(src.fBottom, 0.5f / SK_FDot6One)); -#else - SkDScalarRoundToInt(src.fRight), SkDScalarRoundToInt(src.fBottom)); -#endif + round_up_to_int(src.fRight), round_up_to_int(src.fBottom)); } void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, From f5e68bc3e1a4c38a241ad48255fcb083adef7ef8 Mon Sep 17 00:00:00 2001 From: Sebastian Hengst Date: Wed, 22 Mar 2017 20:28:39 +0100 Subject: [PATCH 91/96] Backed out changeset ef22dba0dac5 (bug 1316683) for various test failures, e.g. xpcshell netwerk/test/unit/test_bug826063.js and browser-chrome browser/components/downloads/test/browser/browser_iframe_gone_mid_download.js. r=backout on a CLOSED TREE --- caps/nsScriptSecurityManager.cpp | 3 +- docshell/base/LoadContext.cpp | 30 +++++++++++++++---- docshell/base/LoadContext.h | 2 -- docshell/base/SerializedLoadContext.cpp | 4 ++- docshell/base/nsDocShell.cpp | 6 ---- docshell/base/nsDocShell.h | 2 -- docshell/base/nsILoadContext.idl | 6 ++-- dom/base/nsDocument.h | 20 ++++--------- dom/ipc/TabParent.cpp | 1 - dom/offline/nsDOMOfflineResourceList.cpp | 3 +- .../prefetch/OfflineCacheUpdateParent.cpp | 8 ----- uriloader/prefetch/OfflineCacheUpdateParent.h | 2 -- 12 files changed, 41 insertions(+), 46 deletions(-) diff --git a/caps/nsScriptSecurityManager.cpp b/caps/nsScriptSecurityManager.cpp index 7d70c97a8f1e..0d587f8115a3 100644 --- a/caps/nsScriptSecurityManager.cpp +++ b/caps/nsScriptSecurityManager.cpp @@ -1168,7 +1168,8 @@ nsScriptSecurityManager:: { NS_ENSURE_STATE(aLoadContext); OriginAttributes docShellAttrs; - aLoadContext->GetOriginAttributes(docShellAttrs); + bool result = aLoadContext->GetOriginAttributes(docShellAttrs); + NS_ENSURE_TRUE(result, NS_ERROR_FAILURE); nsCOMPtr prin = BasePrincipal::CreateCodebasePrincipal(aURI, docShellAttrs); diff --git a/docshell/base/LoadContext.cpp b/docshell/base/LoadContext.cpp index 03fa53273189..6c3ba6b52311 100644 --- a/docshell/base/LoadContext.cpp +++ b/docshell/base/LoadContext.cpp @@ -12,6 +12,30 @@ #include "nsContentUtils.h" #include "xpcpublic.h" +bool +nsILoadContext::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) +{ + mozilla::dom::AutoJSAPI jsapi; + bool ok = jsapi.Init(xpc::PrivilegedJunkScope()); + NS_ENSURE_TRUE(ok, false); + JS::Rooted v(jsapi.cx()); + nsresult rv = GetOriginAttributes(&v); + NS_ENSURE_SUCCESS(rv, false); + NS_ENSURE_TRUE(v.isObject(), false); + JS::Rooted obj(jsapi.cx(), &v.toObject()); + + // If we're JS-implemented, the object will be left in a different (System-Principaled) + // scope, so we may need to enter its compartment. + MOZ_ASSERT(nsContentUtils::IsSystemPrincipal(nsContentUtils::ObjectPrincipal(obj))); + JSAutoCompartment ac(jsapi.cx(), obj); + + mozilla::OriginAttributes attrs; + ok = attrs.Init(jsapi.cx(), v); + NS_ENSURE_TRUE(ok, false); + aAttrs = attrs; + return true; +} + namespace mozilla { NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor) @@ -157,12 +181,6 @@ LoadContext::GetOriginAttributes(JS::MutableHandleValue aAttrs) return NS_OK; } -NS_IMETHODIMP_(void) -LoadContext::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) -{ - aAttrs = mOriginAttributes; -} - NS_IMETHODIMP LoadContext::GetUseTrackingProtection(bool* aUseTrackingProtection) { diff --git a/docshell/base/LoadContext.h b/docshell/base/LoadContext.h index dc0012c76d3c..0b05899ab934 100644 --- a/docshell/base/LoadContext.h +++ b/docshell/base/LoadContext.h @@ -111,8 +111,6 @@ public: private: ~LoadContext() {} - NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; - nsWeakPtr mTopFrameElement; uint64_t mNestedFrameId; bool mIsContent; diff --git a/docshell/base/SerializedLoadContext.cpp b/docshell/base/SerializedLoadContext.cpp index 3964a78f9fc3..501a417a5125 100644 --- a/docshell/base/SerializedLoadContext.cpp +++ b/docshell/base/SerializedLoadContext.cpp @@ -62,7 +62,9 @@ SerializedLoadContext::Init(nsILoadContext* aLoadContext) aLoadContext->GetIsContent(&mIsContent); aLoadContext->GetUseRemoteTabs(&mUseRemoteTabs); aLoadContext->GetUseTrackingProtection(&mUseTrackingProtection); - aLoadContext->GetOriginAttributes(mOriginAttributes); + if (!aLoadContext->GetOriginAttributes(mOriginAttributes)) { + NS_WARNING("GetOriginAttributes failed"); + } } else { mIsNotNull = false; mIsPrivateBitValid = false; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index d07474e493c3..6ed2909fb70e 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -14944,9 +14944,3 @@ nsDocShell::GetAwaitingLargeAlloc(bool* aResult) *aResult = static_cast(tabChild.get())->IsAwaitingLargeAlloc(); return NS_OK; } - -NS_IMETHODIMP_(void) -nsDocShell::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) -{ - aAttrs = mOriginAttributes; -} diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index af5416c105c9..937897023340 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -806,8 +806,6 @@ protected: void UpdateGlobalHistoryTitle(nsIURI* aURI); - NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; - // Dimensions of the docshell nsIntRect mBounds; nsString mName; diff --git a/docshell/base/nsILoadContext.idl b/docshell/base/nsILoadContext.idl index d3a39a676c79..98e8a2119171 100644 --- a/docshell/base/nsILoadContext.idl +++ b/docshell/base/nsILoadContext.idl @@ -20,7 +20,7 @@ interface nsIDOMElement; * can be queried for various information about where the load is * happening. */ -[builtinclass, scriptable, uuid(2813a7a3-d084-4d00-acd0-f76620315c02)] +[scriptable, uuid(2813a7a3-d084-4d00-acd0-f76620315c02)] interface nsILoadContext : nsISupports { /** @@ -139,8 +139,10 @@ interface nsILoadContext : nsISupports #ifdef MOZILLA_INTERNAL_API /** * The C++ getter for origin attributes. + * + * Defined in LoadContext.cpp */ - NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) = 0; + bool GetOriginAttributes(mozilla::OriginAttributes& aAttrs); #endif %} }; diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index 05d0cb772e88..9ef1d404de77 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -444,7 +444,7 @@ protected: // implement one interface. // XXXbz I wish we could just derive the _allcaps thing from _i -#define DECL_SHIM(_i, _allcaps, _customfwd) \ +#define DECL_SHIM(_i, _allcaps) \ class _i##Shim final : public nsIInterfaceRequestor, \ public _i \ { \ @@ -459,25 +459,17 @@ protected: NS_DECL_ISUPPORTS \ NS_FORWARD_NSIINTERFACEREQUESTOR(mIfReq->) \ NS_FORWARD_##_allcaps(mRealPtr->) \ - _customfwd \ private: \ nsCOMPtr mIfReq; \ nsCOMPtr<_i> mRealPtr; \ }; -#define DECL_FORWARD_CPP_GETORIGINATTRIBUTES \ - NS_IMETHODIMP_(void) \ - GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override \ - { \ - mRealPtr->GetOriginAttributes(aAttrs); \ - } - DECL_SHIM(nsILoadContext, NSILOADCONTEXT, DECL_FORWARD_CPP_GETORIGINATTRIBUTES) - DECL_SHIM(nsIProgressEventSink, NSIPROGRESSEVENTSINK, ) - DECL_SHIM(nsIChannelEventSink, NSICHANNELEVENTSINK, ) - DECL_SHIM(nsISecurityEventSink, NSISECURITYEVENTSINK, ) - DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER, ) + DECL_SHIM(nsILoadContext, NSILOADCONTEXT) + DECL_SHIM(nsIProgressEventSink, NSIPROGRESSEVENTSINK) + DECL_SHIM(nsIChannelEventSink, NSICHANNELEVENTSINK) + DECL_SHIM(nsISecurityEventSink, NSISECURITYEVENTSINK) + DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER) #undef DECL_SHIM -#undef DECL_FORWARD_CPP_GETORIGINATTRIBUTES }; /** diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index e6e144df1a89..87163e1bcb91 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -3020,7 +3020,6 @@ public: NS_IMETHOD SetPrivateBrowsing(bool) NO_IMPL NS_IMETHOD GetIsInIsolatedMozBrowserElement(bool*) NO_IMPL NS_IMETHOD GetOriginAttributes(JS::MutableHandleValue) NO_IMPL - NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override {} NS_IMETHOD GetUseRemoteTabs(bool*) NO_IMPL NS_IMETHOD SetRemoteTabs(bool) NO_IMPL NS_IMETHOD GetUseTrackingProtection(bool*) NO_IMPL diff --git a/dom/offline/nsDOMOfflineResourceList.cpp b/dom/offline/nsDOMOfflineResourceList.cpp index b6b49670b8b7..a02b2956245e 100644 --- a/dom/offline/nsDOMOfflineResourceList.cpp +++ b/dom/offline/nsDOMOfflineResourceList.cpp @@ -815,7 +815,8 @@ nsDOMOfflineResourceList::CacheKeys() nsAutoCString originSuffix; if (loadContext) { mozilla::OriginAttributes oa; - loadContext->GetOriginAttributes(oa); + bool ok = loadContext->GetOriginAttributes(oa); + NS_ENSURE_TRUE(ok, NS_ERROR_UNEXPECTED); oa.CreateSuffix(originSuffix); } diff --git a/uriloader/prefetch/OfflineCacheUpdateParent.cpp b/uriloader/prefetch/OfflineCacheUpdateParent.cpp index f10821292b71..c77f2b49a02e 100644 --- a/uriloader/prefetch/OfflineCacheUpdateParent.cpp +++ b/uriloader/prefetch/OfflineCacheUpdateParent.cpp @@ -276,14 +276,6 @@ OfflineCacheUpdateParent::GetOriginAttributes(JS::MutableHandleValue aAttrs) return NS_OK; } -NS_IMETHODIMP_(void) -OfflineCacheUpdateParent::GetOriginAttributes(mozilla::OriginAttributes& aAttrs) -{ - if (mLoadingPrincipal) { - aAttrs = mLoadingPrincipal->OriginAttributesRef(); - } -} - NS_IMETHODIMP OfflineCacheUpdateParent::GetUseTrackingProtection(bool* aUseTrackingProtection) { diff --git a/uriloader/prefetch/OfflineCacheUpdateParent.h b/uriloader/prefetch/OfflineCacheUpdateParent.h index 2637c6bdca42..f6dbc1cb2a6f 100644 --- a/uriloader/prefetch/OfflineCacheUpdateParent.h +++ b/uriloader/prefetch/OfflineCacheUpdateParent.h @@ -54,8 +54,6 @@ public: private: ~OfflineCacheUpdateParent(); - NS_IMETHOD_(void) GetOriginAttributes(mozilla::OriginAttributes& aAttrs) override; - bool mIPCClosed; nsCOMPtr mLoadingPrincipal; From 705c03f5965cc8e071ba50e28fb631b3c8ceb115 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Thu, 23 Mar 2017 08:45:41 +0100 Subject: [PATCH 92/96] Backed out changeset 3ccb231829a9 (bug 1349690) --- dom/base/ScriptSettings.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dom/base/ScriptSettings.cpp b/dom/base/ScriptSettings.cpp index c9fa9e1f2ba9..a89b3419127a 100644 --- a/dom/base/ScriptSettings.cpp +++ b/dom/base/ScriptSettings.cpp @@ -376,13 +376,6 @@ AutoJSAPI::InitInternal(nsIGlobalObject* aGlobalObject, JSObject* aGlobal, if (exn.isObject()) { JS::Rooted exnObj(aCx, &exn.toObject()); - // Make sure we can actually read things from it. This UncheckedUwrap is - // safe because we're only getting data for a debug printf. In - // particular, we do not expose this data to anyone, which is very - // important; otherwise it could be a cross-origin information leak. - exnObj = js::UncheckedUwrap(exnObj); - JSAutoCompartment ac(aCx, exnObj); - nsAutoJSString stack, filename, name, message; int32_t line; From aa7af8949ad1017ffe917cf95964b790fb3ec79b Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Thu, 23 Mar 2017 08:45:45 +0100 Subject: [PATCH 93/96] Backed out changeset 8ba41a1bd062 (bug 1348095) --- js/xpconnect/wrappers/XrayWrapper.cpp | 33 ++++++--------------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 45eb0ffa95c9..42a4a4ddc3d8 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -2410,35 +2410,16 @@ XrayWrapper::getPrototype(JSContext* cx, JS::HandleObject wrapper, // only if there's been a set. If there's not an expando, or the expando // slot is |undefined|, hand back the default proto, appropriately wrapped. + RootedValue v(cx); if (expando) { - RootedValue v(cx); - { // Scope for JSAutoCompartment - JSAutoCompartment ac(cx, expando); - v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE); - } - if (!v.isUndefined()) { - protop.set(v.toObjectOrNull()); - return JS_WrapObject(cx, protop); - } + JSAutoCompartment ac(cx, expando); + v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE); } + if (v.isUndefined()) + return getPrototypeHelper(cx, wrapper, target, protop); - // Check our holder, and cache there if we don't have it cached already. - RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper)); - if (!holder) - return false; - - Value cached = js::GetReservedSlot(holder, - Traits::HOLDER_SLOT_CACHED_PROTO); - if (cached.isUndefined()) { - if (!getPrototypeHelper(cx, wrapper, target, protop)) - return false; - - js::SetReservedSlot(holder, Traits::HOLDER_SLOT_CACHED_PROTO, - ObjectOrNullValue(protop)); - } else { - protop.set(cached.toObjectOrNull()); - } - return true; + protop.set(v.toObjectOrNull()); + return JS_WrapObject(cx, protop); } template From 601d56a7652a825923b82597d3ead95ca6618467 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Thu, 23 Mar 2017 08:45:48 +0100 Subject: [PATCH 94/96] Backed out changeset 3efe3c6f4e7f (bug 1348095) --- js/xpconnect/wrappers/XrayWrapper.cpp | 7 ++----- js/xpconnect/wrappers/XrayWrapper.h | 12 ++---------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 42a4a4ddc3d8..6d4d565e059f 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -201,12 +201,9 @@ XPCWrappedNativeXrayTraits::getWN(JSObject* wrapper) } const JSClass XPCWrappedNativeXrayTraits::HolderClass = { - "NativePropertyHolder", JSCLASS_HAS_RESERVED_SLOTS(HOLDER_SHARED_SLOT_COUNT) + "NativePropertyHolder" }; -const JSClass XrayTraits::HolderClass = { - "XrayHolder", JSCLASS_HAS_RESERVED_SLOTS(HOLDER_SHARED_SLOT_COUNT) -}; const JSClass JSXrayTraits::HolderClass = { "JSXrayHolder", JSCLASS_HAS_RESERVED_SLOTS(SLOT_COUNT) @@ -1857,7 +1854,7 @@ DOMXrayTraits::preserveWrapper(JSObject* target) JSObject* DOMXrayTraits::createHolder(JSContext* cx, JSObject* wrapper) { - return JS_NewObjectWithGivenProto(cx, &HolderClass, nullptr); + return JS_NewObjectWithGivenProto(cx, nullptr, nullptr); } const JSClass* diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 4527e3b0a1f0..5630982c28c4 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -99,12 +99,6 @@ public: JSObject* ensureExpandoObject(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject target); - // Slots for holder objects. - enum { - HOLDER_SLOT_CACHED_PROTO = 0, - HOLDER_SHARED_SLOT_COUNT - }; - JSObject* getHolder(JSObject* wrapper); JSObject* ensureHolder(JSContext* cx, JS::HandleObject wrapper); virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) = 0; @@ -114,8 +108,6 @@ public: bool cloneExpandoChain(JSContext* cx, JS::HandleObject dst, JS::HandleObject src); protected: - static const JSClass HolderClass; - // Get the JSClass we should use for our expando object. virtual const JSClass* getExpandoClass(JSContext* cx, JS::HandleObject target) const; @@ -309,7 +301,7 @@ public: } enum { - SLOT_PROTOKEY = HOLDER_SHARED_SLOT_COUNT, + SLOT_PROTOKEY = 0, SLOT_ISPROTOTYPE, SLOT_CONSTRUCTOR_FOR, SLOT_COUNT @@ -429,7 +421,7 @@ public: virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) override { - return JS_NewObjectWithGivenProto(cx, &HolderClass, nullptr); + return JS_NewObjectWithGivenProto(cx, nullptr, nullptr); } static OpaqueXrayTraits singleton; From 69710f6637708d063ee45e270a712c5cc9e6e3c4 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Thu, 23 Mar 2017 08:46:07 +0100 Subject: [PATCH 95/96] Backed out changeset 60471d1feaa4 (bug 1348095) for bustage --- js/xpconnect/wrappers/XrayWrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 6d4d565e059f..0daf207897f0 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -201,7 +201,7 @@ XPCWrappedNativeXrayTraits::getWN(JSObject* wrapper) } const JSClass XPCWrappedNativeXrayTraits::HolderClass = { - "NativePropertyHolder" + "NativePropertyHolder", JSCLASS_HAS_RESERVED_SLOTS(2) }; From 5f3ac554bcd8711cf0f13812556813694e48e569 Mon Sep 17 00:00:00 2001 From: "Carsten \"Tomcat\" Book" Date: Thu, 23 Mar 2017 08:50:13 +0100 Subject: [PATCH 96/96] Backed out changeset aa77848f51ee (bug 1349572) for test failures in test_fileReadSlice.xul and others --- dom/workers/FileReaderSync.cpp | 46 +++++++++------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/dom/workers/FileReaderSync.cpp b/dom/workers/FileReaderSync.cpp index 3d855aef9fd0..18efcb194c71 100644 --- a/dom/workers/FileReaderSync.cpp +++ b/dom/workers/FileReaderSync.cpp @@ -20,8 +20,7 @@ #include "nsError.h" #include "nsIConverterInputStream.h" #include "nsIInputStream.h" -#include "nsIMultiplexInputStream.h" -#include "nsStringStream.h" +#include "nsISeekableStream.h" #include "nsISupportsImpl.h" #include "nsNetUtil.h" #include "nsServiceManagerUtils.h" @@ -134,23 +133,17 @@ FileReaderSync::ReadAsText(Blob& aBlob, } nsAutoCString encoding; - - nsAutoCString sniffBuf; - if (!sniffBuf.SetLength(3, fallible)) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - - uint32_t numRead = 0; - aRv = stream->Read(sniffBuf.BeginWriting(), sniffBuf.Length(), &numRead); + unsigned char sniffBuf[3] = { 0, 0, 0 }; + uint32_t numRead; + aRv = stream->Read(reinterpret_cast(sniffBuf), + sizeof(sniffBuf), &numRead); if (NS_WARN_IF(aRv.Failed())) { return; } // The BOM sniffing is baked into the "decode" part of the Encoding // Standard, which the File API references. - if (!nsContentUtils::CheckForBOM((const unsigned char*)sniffBuf.BeginReading(), - numRead, encoding)) { + if (!nsContentUtils::CheckForBOM(sniffBuf, numRead, encoding)) { // BOM sniffing failed. Try the API argument. if (!aEncoding.WasPassed() || !EncodingUtils::FindEncodingForLabel(aEncoding.Value(), @@ -174,35 +167,20 @@ FileReaderSync::ReadAsText(Blob& aBlob, } } - // Let's recreate the full stream using a: - // multiplexStream(stringStream + original stream) - // In theory, we could try to see if the inputStream is a nsISeekableStream, - // but this doesn't work correctly for nsPipe3 - See bug 1349570. - - nsCOMPtr stringStream; - aRv = NS_NewCStringInputStream(getter_AddRefs(stringStream), sniffBuf); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - nsCOMPtr multiplexStream = - do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1"); - if (NS_WARN_IF(!multiplexStream)) { + nsCOMPtr seekable = do_QueryInterface(stream); + if (!seekable) { aRv.Throw(NS_ERROR_FAILURE); return; } - aRv = multiplexStream->AppendStream(stringStream); + // Seek to 0 because to undo the BOM sniffing advance. UTF-8 and UTF-16 + // decoders will swallow the BOM. + aRv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0); if (NS_WARN_IF(aRv.Failed())) { return; } - aRv = multiplexStream->AppendStream(stream); - if (NS_WARN_IF(aRv.Failed())) { - return; - } - - aRv = ConvertStream(multiplexStream, encoding.get(), aResult); + aRv = ConvertStream(stream, encoding.get(), aResult); if (NS_WARN_IF(aRv.Failed())) { return; }