Merge mozilla-central to autoland
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 14 Sep 2016 15:45:49 +0200
changeset 313897 4b1f411b1ea6e183a32c43bdd1ff672cca7fee6d
parent 313879 109281cadd425161c50bce8ab4064faa68c4113c (current diff)
parent 313896 8a494adbc5cced90a4edf0c98cffde906bf7f3ae (diff)
child 313898 33de74be048e90b1ba1ca5ca8703d5ce176827c2
push id32267
push usercbook@mozilla.com
push dateWed, 14 Sep 2016 13:46:59 +0000
treeherderautoland@4b1f411b1ea6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-central to autoland
--- a/accessible/base/TextAttrs.h
+++ b/accessible/base/TextAttrs.h
@@ -175,23 +175,23 @@ protected:
     virtual bool GetValueFor(Accessible* aAccessible, T* aValue) = 0;
 
     // Indicates if root value should be exposed.
     bool mGetRootValue;
 
     // Native value and flag indicating if the value is defined (initialized in
     // derived classes). Note, undefined native value means it is inherited
     // from root.
-    T mNativeValue;
-    bool mIsDefined;
+    MOZ_INIT_OUTSIDE_CTOR T mNativeValue;
+    MOZ_INIT_OUTSIDE_CTOR bool mIsDefined;
 
     // Native root value and flag indicating if the value is defined  (initialized
     // in derived classes).
-    T mRootNativeValue;
-    bool mIsRootDefined;
+    MOZ_INIT_OUTSIDE_CTOR T mRootNativeValue;
+    MOZ_INIT_OUTSIDE_CTOR bool mIsRootDefined;
   };
 
 
   /**
    * Class is used for the work with 'language' text attribute.
    */
   class LangTextAttr : public TTextAttr<nsString>
   {
--- a/dom/base/nsXMLContentSerializer.h
+++ b/dom/base/nsXMLContentSerializer.h
@@ -331,42 +331,42 @@ class nsXMLContentSerializer : public ns
     nsString mPrefix;
     nsString mURI;
     nsIContent* mOwner;
   };
 
   nsTArray<NameSpaceDecl> mNameSpaceStack;
 
   // nsIDocumentEncoder flags
-  uint32_t  mFlags;
+  MOZ_INIT_OUTSIDE_CTOR uint32_t  mFlags;
 
   // characters to use for line break
   nsString  mLineBreak;
 
   // The charset that was passed to Init()
   nsCString mCharset;
   
   // current column position on the current line
   uint32_t   mColPos;
 
   // true = pretty formating should be done (OutputFormated flag)
-  bool mDoFormat;
+  MOZ_INIT_OUTSIDE_CTOR bool mDoFormat;
 
   // true = no formatting,(OutputRaw flag)
   // no newline convertion and no rewrap long lines even if OutputWrap is set.
-  bool mDoRaw;
+  MOZ_INIT_OUTSIDE_CTOR bool mDoRaw;
 
   // true = wrapping should be done (OutputWrap flag)
-  bool mDoWrap;
+  MOZ_INIT_OUTSIDE_CTOR bool mDoWrap;
 
   // true = we can break lines (OutputDisallowLineBreaking flag)
-  bool mAllowLineBreaking;
+  MOZ_INIT_OUTSIDE_CTOR bool mAllowLineBreaking;
 
   // number of maximum column in a line, in the wrap mode
-  uint32_t   mMaxColumn;
+  MOZ_INIT_OUTSIDE_CTOR uint32_t   mMaxColumn;
 
   // current indent value
   nsString   mIndent;
 
   // this is the indentation level after the indentation reached
   // the maximum length of indentation
   int32_t    mIndentOverflow;
 
@@ -392,15 +392,15 @@ class nsXMLContentSerializer : public ns
   // such character has already been added into the output string
   bool          mMayIgnoreLineBreakSequence;
 
   bool          mBodyOnly;
   int32_t       mInBody;
 
 private:
   // number of nested elements which have preformated content
-  int32_t       mPreLevel;
+  MOZ_INIT_OUTSIDE_CTOR int32_t mPreLevel;
 };
 
 nsresult
 NS_NewXMLContentSerializer(nsIContentSerializer** aSerializer);
 
 #endif 
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -2462,17 +2462,19 @@ CanvasRenderingContext2D::CreatePattern(
     HTMLImageElement* img = &aSource.GetAsHTMLImageElement();
     if (img->IntrinsicState().HasState(NS_EVENT_STATE_BROKEN)) {
       aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
       return nullptr;
     }
 
     htmlElement = img;
   } else if (aSource.IsHTMLVideoElement()) {
-    htmlElement = &aSource.GetAsHTMLVideoElement();
+    auto& video = aSource.GetAsHTMLVideoElement();
+    video.MarkAsContentSource(mozilla::dom::HTMLVideoElement::CallerAPI::CREATE_PATTERN);
+    htmlElement = &video;
   } else {
     // Special case for ImageBitmap
     ImageBitmap& imgBitmap = aSource.GetAsImageBitmap();
     EnsureTarget();
     RefPtr<SourceSurface> srcSurf = imgBitmap.PrepareForDrawTarget(mTarget);
     if (!srcSurf) {
       JSContext* context = nsContentUtils::GetCurrentJSContext();
       if (context) {
@@ -4763,16 +4765,17 @@ CanvasRenderingContext2D::DrawImage(cons
     imgSize = gfx::IntSize(imageBitmap.Width(), imageBitmap.Height());
   }
   else {
     if (aImage.IsHTMLImageElement()) {
       HTMLImageElement* img = &aImage.GetAsHTMLImageElement();
       element = img;
     } else {
       HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement();
+      video->MarkAsContentSource(mozilla::dom::HTMLVideoElement::CallerAPI::DRAW_IMAGE);
       element = video;
     }
 
     srcSurf =
      CanvasImageCache::LookupCanvas(element, mCanvasElement, &imgSize, mIsSkiaGL);
   }
 
   nsLayoutUtils::DirectDrawInfo drawInfo;
--- a/dom/canvas/ImageBitmap.cpp
+++ b/dom/canvas/ImageBitmap.cpp
@@ -788,16 +788,18 @@ ImageBitmap::CreateInternal(nsIGlobalObj
 
   return ret.forget();
 }
 
 /* static */ already_AddRefed<ImageBitmap>
 ImageBitmap::CreateInternal(nsIGlobalObject* aGlobal, HTMLVideoElement& aVideoEl,
                             const Maybe<IntRect>& aCropRect, ErrorResult& aRv)
 {
+  aVideoEl.MarkAsContentSource(mozilla::dom::HTMLVideoElement::CallerAPI::CREATE_IMAGEBITMAP);
+
   // Check network state.
   if (aVideoEl.NetworkState() == HTMLMediaElement::NETWORK_EMPTY) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return nullptr;
   }
 
   // Check ready state.
   // Cannot be HTMLMediaElement::HAVE_NOTHING or HTMLMediaElement::HAVE_METADATA.
--- a/dom/filesystem/GetFilesHelper.cpp
+++ b/dom/filesystem/GetFilesHelper.cpp
@@ -2,16 +2,17 @@
 /* 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 "GetFilesHelper.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
+#include "nsProxyRelease.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 // This class is used in the DTOR of GetFilesHelper to release resources in the
 // correct thread.
@@ -604,16 +605,21 @@ private:
 GetFilesHelperParent::GetFilesHelperParent(const nsID& aUUID,
                                            ContentParent* aContentParent,
                                            bool aRecursiveFlag)
   : GetFilesHelper(nullptr, aRecursiveFlag)
   , mContentParent(aContentParent)
   , mUUID(aUUID)
 {}
 
+GetFilesHelperParent::~GetFilesHelperParent()
+{
+  NS_ReleaseOnMainThread(mContentParent.forget());
+}
+
 /* static */ already_AddRefed<GetFilesHelperParent>
 GetFilesHelperParent::Create(const nsID& aUUID, const nsAString& aDirectoryPath,
                              bool aRecursiveFlag, ContentParent* aContentParent,
                              ErrorResult& aRv)
 {
   MOZ_ASSERT(aContentParent);
 
   RefPtr<GetFilesHelperParent> helper =
--- a/dom/filesystem/GetFilesHelper.h
+++ b/dom/filesystem/GetFilesHelper.h
@@ -193,16 +193,18 @@ public:
   static already_AddRefed<GetFilesHelperParent>
   Create(const nsID& aUUID, const nsAString& aDirectoryPath,
          bool aRecursiveFlag, ContentParent* aContentParent, ErrorResult& aRv);
 
 private:
   GetFilesHelperParent(const nsID& aUUID, ContentParent* aContentParent,
                        bool aRecursiveFlag);
 
+  ~GetFilesHelperParent();
+
   RefPtr<ContentParent> mContentParent;
   nsID mUUID;
 };
 
 } // dom namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_GetFilesHelper_h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2541,16 +2541,18 @@ HTMLMediaElement::AddCaptureMediaTrackTo
 
 already_AddRefed<DOMMediaStream>
 HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
                                         bool aCaptureAudio,
                                         MediaStreamGraph* aGraph)
 {
   MOZ_RELEASE_ASSERT(aGraph);
 
+    MarkAsContentSource(CallerAPI::CAPTURE_STREAM);
+
   nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
   if (!window) {
     return nullptr;
   }
 #ifdef MOZ_EME
   if (ContainsRestrictedContent()) {
     return nullptr;
   }
@@ -2920,17 +2922,18 @@ HTMLMediaElement::HTMLMediaElement(alrea
     mAudioChannelVolume(1.0),
     mPlayingThroughTheAudioChannel(false),
     mDisableVideo(false),
     mElementInTreeState(ELEMENT_NOT_INTREE),
     mHasUserInteraction(false),
     mFirstFrameLoaded(false),
     mDefaultPlaybackStartPosition(0.0),
     mIsAudioTrackAudible(false),
-    mAudible(IsAudible())
+    mAudible(IsAudible()),
+    mVisibilityState(Visibility::APPROXIMATELY_NONVISIBLE)
 {
   ErrorResult rv;
 
   double defaultVolume = Preferences::GetFloat("media.default_volume", 1.0);
   SetVolume(defaultVolume, rv);
 
   mAudioChannel = AudioChannelService::GetDefaultAudioChannel();
 
@@ -6039,16 +6042,18 @@ static const char* VisibilityString(Visi
 }
 
 void
 HTMLMediaElement::OnVisibilityChange(Visibility aNewVisibility)
 {
   LOG(LogLevel::Debug, ("OnVisibilityChange(): %s\n",
       VisibilityString(aNewVisibility)));
 
+  mVisibilityState = aNewVisibility;
+
   if (!mDecoder) {
     return;
   }
 
   switch (aNewVisibility) {
     case Visibility::UNTRACKED: {
         MOZ_ASSERT_UNREACHABLE("Shouldn't notify for untracked visibility");
         break;
@@ -6589,10 +6594,71 @@ HTMLMediaElement::NotifyCueDisplayStates
 {
   if (!mTextTrackManager) {
     return;
   }
 
   mTextTrackManager->DispatchUpdateCueDisplay();
 }
 
+void
+HTMLMediaElement::MarkAsContentSource(CallerAPI aAPI)
+{
+  const bool isVisible = mVisibilityState != Visibility::APPROXIMATELY_NONVISIBLE;
+
+  if (isVisible) {
+    // 0 = ALL_VISIBLE
+    Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 0);
+  } else {
+    // 1 = ALL_INVISIBLE
+    Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 1);
+  }
+
+  switch (aAPI) {
+    case CallerAPI::DRAW_IMAGE: {
+      if (isVisible) {
+        // 2 = drawImage_VISIBLE
+        Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 2);
+      } else {
+        // 3 = drawImage_INVISIBLE
+        Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 3);
+      }
+      break;
+    }
+    case CallerAPI::CREATE_PATTERN: {
+      if (isVisible) {
+        // 4 = createPattern_VISIBLE
+        Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 4);
+      } else {
+        // 5 = createPattern_INVISIBLE
+        Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 5);
+      }
+      break;
+    }
+    case CallerAPI::CREATE_IMAGEBITMAP: {
+      if (isVisible) {
+        // 6 = createImageBitmap_VISIBLE
+        Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 6);
+      } else {
+        // 7 = createImageBitmap_INVISIBLE
+        Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 7);
+      }
+      break;
+    }
+    case CallerAPI::CAPTURE_STREAM: {
+      if (isVisible) {
+        // 8 = captureStream_VISIBLE
+        Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 8);
+      } else {
+        // 9 = captureStream_INVISIBLE
+        Telemetry::Accumulate(Telemetry::VIDEO_AS_CONTENT_SOURCE, 9);
+      }
+      break;
+    }
+  }
+
+  LOG(LogLevel::Debug,
+      ("%p Log VIDEO_AS_CONTENT_SOURCE: visibility = %u, API: '%d' and 'All'",
+       this, isVisible, aAPI));
+}
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -734,16 +734,27 @@ public:
 
   // These are used for testing only
   float ComputedVolume() const;
   bool ComputedMuted() const;
   nsSuspendedTypes ComputedSuspended() const;
 
   void SetMediaInfo(const MediaInfo& aInfo);
 
+  // Telemetry: to record the usage of a {visible / invisible} video element as
+  // the source of {drawImage(), createPattern(), createImageBitmap() and
+  // captureStream()} APIs.
+  enum class CallerAPI {
+    DRAW_IMAGE,
+    CREATE_PATTERN,
+    CREATE_IMAGEBITMAP,
+    CAPTURE_STREAM,
+  };
+  void MarkAsContentSource(CallerAPI aAPI);
+
 protected:
   virtual ~HTMLMediaElement();
 
   class ChannelLoader;
   class MediaLoadListener;
   class MediaStreamTracksAvailableCallback;
   class MediaStreamTrackListener;
   class StreamListener;
@@ -1710,14 +1721,16 @@ private:
   // be seeked even before the media is loaded.
   double mDefaultPlaybackStartPosition;
 
   // True if the audio track is not silent.
   bool mIsAudioTrackAudible;
 
   // True if media element is audible for users.
   bool mAudible;
+
+  Visibility mVisibilityState;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_HTMLMediaElement_h
--- a/dom/xul/templates/nsXULSortService.h
+++ b/dom/xul/templates/nsXULSortService.h
@@ -37,33 +37,34 @@ enum nsSortState_direction {
   nsSortState_ascending,
   nsSortState_natural
 };
   
 // the sort state holds info about the current sort
 struct nsSortState
 {
   bool initialized;
-  bool invertSort;
-  bool inbetweenSeparatorSort;
-  bool sortStaticsLast;
-  bool isContainerRDFSeq;
+  MOZ_INIT_OUTSIDE_CTOR bool invertSort;
+  MOZ_INIT_OUTSIDE_CTOR bool inbetweenSeparatorSort;
+  MOZ_INIT_OUTSIDE_CTOR bool sortStaticsLast;
+  MOZ_INIT_OUTSIDE_CTOR bool isContainerRDFSeq;
 
   uint32_t sortHints;
 
-  nsSortState_direction direction;
+  MOZ_INIT_OUTSIDE_CTOR nsSortState_direction direction;
   nsAutoString sort;
   nsCOMArray<nsIAtom> sortKeys;
 
   nsCOMPtr<nsIXULTemplateQueryProcessor> processor;
   nsCOMPtr<nsIContent> lastContainer;
-  bool lastWasFirst, lastWasLast;
+  MOZ_INIT_OUTSIDE_CTOR bool lastWasFirst, lastWasLast;
 
   nsSortState()
     : initialized(false),
+      isContainerRDFSeq(false),
       sortHints(0)
   {
   }
   void Traverse(nsCycleCollectionTraversalCallback &cb) const
   {
     cb.NoteXPCOMChild(processor);
     cb.NoteXPCOMChild(lastContainer);
   }
--- a/gfx/gl/GLScreenBuffer.cpp
+++ b/gfx/gl/GLScreenBuffer.cpp
@@ -946,21 +946,21 @@ ReadBuffer::Create(GLContext* gl,
 
     GLenum err = localError.GetError();
     MOZ_ASSERT_IF(err != LOCAL_GL_NO_ERROR, err == LOCAL_GL_OUT_OF_MEMORY);
     if (err)
         return nullptr;
 
     const bool needsAcquire = !surf->IsProducerAcquired();
     if (needsAcquire) {
-        surf->ProducerAcquire();
+        surf->ProducerReadAcquire();
     }
     const bool isComplete = gl->IsFramebufferComplete(fb);
     if (needsAcquire) {
-        surf->ProducerRelease();
+        surf->ProducerReadRelease();
     }
 
     if (!isComplete)
         return nullptr;
 
     return Move(ret);
 }
 
--- a/js/src/asmjs/WasmBinary.h
+++ b/js/src/asmjs/WasmBinary.h
@@ -19,16 +19,24 @@
 #ifndef wasm_binary_h
 #define wasm_binary_h
 
 #include "builtin/SIMD.h"
 
 namespace js {
 namespace wasm {
 
+// Telemetry sample values for the JS_AOT_USAGE key, indicating whether asm.js
+// or WebAssembly is used.
+
+enum class Telemetry {
+    ASMJS = 0,
+    WASM = 1
+};
+
 static const uint32_t MagicNumber        = 0x6d736100; // "\0asm"
 static const uint32_t EncodingVersion    = 0x0b;
 
 static const char TypeSectionId[]        = "type";
 static const char GlobalSectionId[]      = "global";
 static const char ImportSectionId[]      = "import";
 static const char FunctionSectionId[]    = "function";
 static const char TableSectionId[]       = "table";
--- a/js/src/asmjs/WasmCompile.h
+++ b/js/src/asmjs/WasmCompile.h
@@ -35,17 +35,17 @@ struct ScriptedCaller
 };
 
 // Describes all the parameters that control wasm compilation.
 
 struct CompileArgs
 {
     Assumptions assumptions;
     ScriptedCaller scriptedCaller;
-    bool alwaysBaseline;
+    MOZ_INIT_OUTSIDE_CTOR bool alwaysBaseline;
 
     CompileArgs(Assumptions&& assumptions, ScriptedCaller&& scriptedCaller)
       : assumptions(Move(assumptions)),
         scriptedCaller(Move(scriptedCaller)),
         alwaysBaseline(false)
     {}
 
     // If CompileArgs is constructed without arguments, initFromContext() must
--- a/js/src/asmjs/WasmModule.cpp
+++ b/js/src/asmjs/WasmModule.cpp
@@ -865,10 +865,13 @@ Module::instantiate(JSContext* cx,
                 return false;
         } else {
             uint32_t funcDefIndex = startFuncIndex - funcImports.length();
             if (!instance->instance().callExport(cx, funcDefIndex, args))
                 return false;
         }
     }
 
+    uint32_t mode = uint32_t(metadata().isAsmJS() ? Telemetry::ASMJS : Telemetry::WASM);
+    cx->runtime()->addTelemetry(JS_TELEMETRY_AOT_USAGE, mode);
+
     return true;
 }
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/for-in-iterator-1.js
@@ -0,0 +1,28 @@
+var values = {
+    input1: null,
+    input2: undefined,
+    input3: {},
+    input4: [],
+    input5: ""
+};
+
+var original = function (x) {
+    var res = { start: inIon(), end: false };
+    for (var i in x.input) {
+        throw "Iterator is not empty";
+    }
+    res.end = inIon();
+    return res;
+};
+
+for (var i = 1; i < 6; i++) {
+    // Reset type inference.
+    var res = false;
+    var test = eval(original.toSource().replace(".input", ".input" + i));
+
+    // Run until the end is running within Ion, or skip if we are unable to run
+    // in Ion.
+    while (!res.start)
+        res = test(values);
+    assertEq(!res.start || !res.end, false);
+}
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -7585,17 +7585,21 @@ static bool
 DoIteratorNewFallback(JSContext* cx, BaselineFrame* frame, ICIteratorNew_Fallback* stub,
                       HandleValue value, MutableHandleValue res)
 {
     jsbytecode* pc = stub->icEntry()->pc(frame->script());
     FallbackICSpew(cx, stub, "IteratorNew");
 
     uint8_t flags = GET_UINT8(pc);
     res.set(value);
-    return ValueToIterator(cx, flags, res);
+    RootedObject iterobj(cx, ValueToIterator(cx, flags, res));
+    if (!iterobj)
+        return false;
+    res.setObject(*iterobj);
+    return true;
 }
 
 typedef bool (*DoIteratorNewFallbackFn)(JSContext*, BaselineFrame*, ICIteratorNew_Fallback*,
                                         HandleValue, MutableHandleValue);
 static const VMFunction DoIteratorNewFallbackInfo =
     FunctionInfo<DoIteratorNewFallbackFn>(DoIteratorNewFallback, "DoIteratorNewFallback",
                                           TailCall, PopValues(1));
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -8734,22 +8734,34 @@ void
 CodeGenerator::visitArrayJoin(LArrayJoin* lir)
 {
     pushArg(ToRegister(lir->separator()));
     pushArg(ToRegister(lir->array()));
 
     callVM(ArrayJoinInfo, lir);
 }
 
+typedef JSObject* (*ValueToIteratorFn)(JSContext*, uint32_t, HandleValue);
+static const VMFunction ValueToIteratorInfo =
+    FunctionInfo<ValueToIteratorFn>(ValueToIterator, "ValueToIterator");
+
+void
+CodeGenerator::visitCallIteratorStartV(LCallIteratorStartV* lir)
+{
+    pushArg(ToValue(lir, LCallIteratorStartV::Value));
+    pushArg(Imm32(lir->mir()->flags()));
+    callVM(ValueToIteratorInfo, lir);
+}
+
 typedef JSObject* (*GetIteratorObjectFn)(JSContext*, HandleObject, uint32_t);
 static const VMFunction GetIteratorObjectInfo =
     FunctionInfo<GetIteratorObjectFn>(GetIteratorObject, "GetIteratorObject");
 
 void
-CodeGenerator::visitCallIteratorStart(LCallIteratorStart* lir)
+CodeGenerator::visitCallIteratorStartO(LCallIteratorStartO* lir)
 {
     pushArg(Imm32(lir->mir()->flags()));
     pushArg(ToRegister(lir->object()));
     callVM(GetIteratorObjectInfo, lir);
 }
 
 void
 CodeGenerator::branchIfNotEmptyObjectElements(Register obj, Label* target)
@@ -8762,17 +8774,17 @@ CodeGenerator::branchIfNotEmptyObjectEle
     masm.branchPtr(Assembler::NotEqual,
                    Address(obj, NativeObject::offsetOfElements()),
                    ImmPtr(js::emptyObjectElementsShared),
                    target);
     masm.bind(&emptyObj);
 }
 
 void
-CodeGenerator::visitIteratorStart(LIteratorStart* lir)
+CodeGenerator::visitIteratorStartO(LIteratorStartO* lir)
 {
     const Register obj = ToRegister(lir->object());
     const Register output = ToRegister(lir->output());
 
     uint32_t flags = lir->mir()->flags();
 
     OutOfLineCode* ool = oolCallVM(GetIteratorObjectInfo, lir,
                                    ArgList(obj, Imm32(flags)), StoreRegisterTo(output));
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -320,18 +320,19 @@ class CodeGenerator final : public CodeG
     void visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole* lir);
     void visitStoreUnboxedScalar(LStoreUnboxedScalar* lir);
     void visitStoreTypedArrayElementHole(LStoreTypedArrayElementHole* lir);
     void visitAtomicIsLockFree(LAtomicIsLockFree* lir);
     void visitGuardSharedTypedArray(LGuardSharedTypedArray* lir);
     void visitClampIToUint8(LClampIToUint8* lir);
     void visitClampDToUint8(LClampDToUint8* lir);
     void visitClampVToUint8(LClampVToUint8* lir);
-    void visitCallIteratorStart(LCallIteratorStart* lir);
-    void visitIteratorStart(LIteratorStart* lir);
+    void visitCallIteratorStartV(LCallIteratorStartV* lir);
+    void visitCallIteratorStartO(LCallIteratorStartO* lir);
+    void visitIteratorStartO(LIteratorStartO* lir);
     void visitIteratorMore(LIteratorMore* lir);
     void visitIsNoIterAndBranch(LIsNoIterAndBranch* lir);
     void visitIteratorEnd(LIteratorEnd* lir);
     void visitArgumentsLength(LArgumentsLength* lir);
     void visitGetFrameArgument(LGetFrameArgument* lir);
     void visitSetFrameArgumentT(LSetFrameArgumentT* lir);
     void visitSetFrameArgumentC(LSetFrameArgumentC* lir);
     void visitSetFrameArgumentV(LSetFrameArgumentV* lir);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -3901,23 +3901,32 @@ LIRGenerator::visitCallInitElementArray(
                                                                     useBoxAtStart(ins->value()));
     add(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
 LIRGenerator::visitIteratorStart(MIteratorStart* ins)
 {
+    if (ins->object()->type() == MIRType::Value) {
+        LCallIteratorStartV* lir = new(alloc()) LCallIteratorStartV(useBoxAtStart(ins->object()));
+        defineReturn(lir, ins);
+        assignSafepoint(lir, ins);
+        return;
+    }
+
+    MOZ_ASSERT(ins->object()->type() == MIRType::Object);
+
     // Call a stub if this is not a simple for-in loop.
     if (ins->flags() != JSITER_ENUMERATE) {
-        LCallIteratorStart* lir = new(alloc()) LCallIteratorStart(useRegisterAtStart(ins->object()));
+        LCallIteratorStartO* lir = new(alloc()) LCallIteratorStartO(useRegisterAtStart(ins->object()));
         defineReturn(lir, ins);
         assignSafepoint(lir, ins);
     } else {
-        LIteratorStart* lir = new(alloc()) LIteratorStart(useRegister(ins->object()), temp(), temp(), temp());
+        LIteratorStartO* lir = new(alloc()) LIteratorStartO(useRegister(ins->object()), temp(), temp(), temp());
         define(lir, ins);
         assignSafepoint(lir, ins);
     }
 }
 
 void
 LIRGenerator::visitIteratorMore(MIteratorMore* ins)
 {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -11961,17 +11961,17 @@ class MRound
         return true;
     }
 
     ALLOW_CLONE(MRound)
 };
 
 class MIteratorStart
   : public MUnaryInstruction,
-    public SingleObjectPolicy::Data
+    public BoxExceptPolicy<0, MIRType::Object>::Data
 {
     uint8_t flags_;
 
     MIteratorStart(MDefinition* obj, uint8_t flags)
       : MUnaryInstruction(obj), flags_(flags)
     {
         setResultType(MIRType::Object);
     }
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -641,21 +641,17 @@ bool
 BoxExceptPolicy<Op, Type>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
 {
     MDefinition* in = ins->getOperand(Op);
     if (in->type() == Type)
         return true;
     return BoxPolicy<Op>::staticAdjustInputs(alloc, ins);
 }
 
-template bool BoxExceptPolicy<0, MIRType::String>::staticAdjustInputs(TempAllocator& alloc,
-                                                                     MInstruction* ins);
-template bool BoxExceptPolicy<1, MIRType::String>::staticAdjustInputs(TempAllocator& alloc,
-                                                                     MInstruction* ins);
-template bool BoxExceptPolicy<2, MIRType::String>::staticAdjustInputs(TempAllocator& alloc,
+template bool BoxExceptPolicy<0, MIRType::Object>::staticAdjustInputs(TempAllocator& alloc,
                                                                      MInstruction* ins);
 
 template <unsigned Op>
 bool
 CacheIdPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins)
 {
     MDefinition* in = ins->getOperand(Op);
     switch (in->type()) {
@@ -1207,17 +1203,17 @@ FilterTypeSetPolicy::adjustInputs(TempAl
     _(TestPolicy)                               \
     _(AllDoublePolicy)                          \
     _(ToDoublePolicy)                           \
     _(ToInt32Policy)                            \
     _(ToStringPolicy)                           \
     _(TypeBarrierPolicy)
 
 #define TEMPLATE_TYPE_POLICY_LIST(_)                                    \
-    _(BoxExceptPolicy<0, MIRType::String>)                               \
+    _(BoxExceptPolicy<0, MIRType::Object>)                              \
     _(BoxPolicy<0>)                                                     \
     _(ConvertToInt32Policy<0>)                                          \
     _(ConvertToStringPolicy<0>)                                         \
     _(ConvertToStringPolicy<2>)                                         \
     _(DoublePolicy<0>)                                                  \
     _(FloatingPointPolicy<0>)                                           \
     _(IntPolicy<0>)                                                     \
     _(IntPolicy<1>)                                                     \
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7090,39 +7090,54 @@ class LSetPropertyCache : public LInstru
     }
     const LDefinition* tempFloat32() {
         if (hasUnaliasedDouble())
             return getTemp(3);
         return getTemp(2);
     }
 };
 
-class LCallIteratorStart : public LCallInstructionHelper<1, 1, 0>
-{
-  public:
-    LIR_HEADER(CallIteratorStart)
-
-    explicit LCallIteratorStart(const LAllocation& object) {
+class LCallIteratorStartV : public LCallInstructionHelper<1, BOX_PIECES, 0>
+{
+  public:
+    LIR_HEADER(CallIteratorStartV)
+
+    static const size_t Value = 0;
+
+    explicit LCallIteratorStartV(const LBoxAllocation& value) {
+        setBoxOperand(Value, value);
+    }
+    MIteratorStart* mir() const {
+        return mir_->toIteratorStart();
+    }
+};
+
+class LCallIteratorStartO : public LCallInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(CallIteratorStartO)
+
+    explicit LCallIteratorStartO(const LAllocation& object) {
         setOperand(0, object);
     }
     const LAllocation* object() {
         return getOperand(0);
     }
     MIteratorStart* mir() const {
         return mir_->toIteratorStart();
     }
 };
 
-class LIteratorStart : public LInstructionHelper<1, 1, 3>
-{
-  public:
-    LIR_HEADER(IteratorStart)
-
-    LIteratorStart(const LAllocation& object, const LDefinition& temp1,
-                   const LDefinition& temp2, const LDefinition& temp3) {
+class LIteratorStartO : public LInstructionHelper<1, 1, 3>
+{
+  public:
+    LIR_HEADER(IteratorStartO)
+
+    LIteratorStartO(const LAllocation& object, const LDefinition& temp1,
+                    const LDefinition& temp2, const LDefinition& temp3) {
         setOperand(0, object);
         setTemp(0, temp1);
         setTemp(1, temp2);
         setTemp(2, temp3);
     }
     const LAllocation* object() {
         return getOperand(0);
     }
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -329,18 +329,19 @@
     _(CallSetElement)               \
     _(CallInitElementArray)         \
     _(CallSetProperty)              \
     _(CallDeleteProperty)           \
     _(CallDeleteElement)            \
     _(SetPropertyCache)             \
     _(SetPropertyPolymorphicV)      \
     _(SetPropertyPolymorphicT)      \
-    _(CallIteratorStart)            \
-    _(IteratorStart)                \
+    _(CallIteratorStartV)           \
+    _(CallIteratorStartO)           \
+    _(IteratorStartO)               \
     _(IteratorMore)                 \
     _(IsNoIterAndBranch)            \
     _(IteratorEnd)                  \
     _(ArrayLength)                  \
     _(SetArrayLength)               \
     _(GetNextMapEntryForIterator)   \
     _(TypedArrayLength)             \
     _(TypedArrayElements)           \
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -128,16 +128,17 @@ enum {
     JS_TELEMETRY_GC_MINOR_REASON,
     JS_TELEMETRY_GC_MINOR_REASON_LONG,
     JS_TELEMETRY_GC_MINOR_US,
     JS_TELEMETRY_GC_NURSERY_BYTES,
     JS_TELEMETRY_GC_PRETENURE_COUNT,
     JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT,
     JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS,
     JS_TELEMETRY_ADDON_EXCEPTIONS,
+    JS_TELEMETRY_AOT_USAGE,
     JS_TELEMETRY_END
 };
 
 typedef void
 (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key);
 
 extern JS_FRIEND_API(void)
 JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback);
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -996,19 +996,20 @@ js::IteratorConstructor(JSContext* cx, u
         return false;
     }
 
     bool keyonly = false;
     if (args.length() >= 2)
         keyonly = ToBoolean(args[1]);
     unsigned flags = JSITER_OWNONLY | (keyonly ? 0 : (JSITER_FOREACH | JSITER_KEYVALUE));
 
-    if (!ValueToIterator(cx, flags, args[0]))
+    RootedObject iterobj(cx, ValueToIterator(cx, flags, args[0]));
+    if (!iterobj)
         return false;
-    args.rval().set(args[0]);
+    args.rval().setObject(*iterobj);
     return true;
 }
 
 MOZ_ALWAYS_INLINE bool
 NativeIteratorNext(JSContext* cx, NativeIterator* ni, MutableHandleValue rval, bool* done)
 {
     *done = false;
 
@@ -1174,48 +1175,46 @@ enum {
     ListIteratorSlotCount
 };
 
 const Class ListIteratorObject::class_ = {
     "List Iterator",
     JSCLASS_HAS_RESERVED_SLOTS(ListIteratorSlotCount)
 };
 
-bool
-js::ValueToIterator(JSContext* cx, unsigned flags, MutableHandleValue vp)
+JSObject*
+js::ValueToIterator(JSContext* cx, unsigned flags, HandleValue vp)
 {
     /* JSITER_KEYVALUE must always come with JSITER_FOREACH */
     MOZ_ASSERT_IF(flags & JSITER_KEYVALUE, flags & JSITER_FOREACH);
 
     RootedObject obj(cx);
     if (vp.isObject()) {
         /* Common case. */
         obj = &vp.toObject();
     } else if ((flags & JSITER_ENUMERATE) && vp.isNullOrUndefined()) {
         /*
          * Enumerating over null and undefined gives an empty enumerator, so
          * that |for (var p in <null or undefined>) <loop>;| never executes
          * <loop>, per ES5 12.6.4.
          */
         RootedObject iter(cx);
         if (!NewEmptyPropertyIterator(cx, flags, &iter))
-            return false;
-        vp.setObject(*iter);
-        return true;
+            return nullptr;
+        return iter;
     } else {
         obj = ToObject(cx, vp);
         if (!obj)
-            return false;
+            return nullptr;
     }
 
     RootedObject iter(cx);
     if (!GetIterator(cx, obj, flags, &iter))
-        return false;
-    vp.setObject(*iter);
-    return true;
+        return nullptr;
+    return iter;
 }
 
 bool
 js::CloseIterator(JSContext* cx, HandleObject obj)
 {
     if (obj->is<PropertyIteratorObject>()) {
         /* Remove enumerators from the active list, which is a stack. */
         NativeIterator* ni = obj->as<PropertyIteratorObject>().getNativeIterator();
--- a/js/src/jsiter.h
+++ b/js/src/jsiter.h
@@ -175,18 +175,18 @@ bool
 NewEmptyPropertyIterator(JSContext* cx, unsigned flags, MutableHandleObject objp);
 
 /*
  * Convert the value stored in *vp to its iteration object. The flags should
  * contain JSITER_ENUMERATE if js::ValueToIterator is called when enumerating
  * for-in semantics are required, and when the caller can guarantee that the
  * iterator will never be exposed to scripts.
  */
-bool
-ValueToIterator(JSContext* cx, unsigned flags, MutableHandleValue vp);
+JSObject*
+ValueToIterator(JSContext* cx, unsigned flags, HandleValue vp);
 
 bool
 CloseIterator(JSContext* cx, HandleObject iterObj);
 
 bool
 UnwindIteratorForException(JSContext* cx, HandleObject obj);
 
 void
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -2119,20 +2119,22 @@ CASE(JSOP_IN)
     REGS.sp[-1].setBoolean(found);
 }
 END_CASE(JSOP_IN)
 
 CASE(JSOP_ITER)
 {
     MOZ_ASSERT(REGS.stackDepth() >= 1);
     uint8_t flags = GET_UINT8(REGS.pc);
-    MutableHandleValue res = REGS.stackHandleAt(-1);
-    if (!ValueToIterator(cx, flags, res))
+    HandleValue val = REGS.stackHandleAt(-1);
+    ReservedRooted<JSObject*> iter(&rootObject0);
+    iter.set(ValueToIterator(cx, flags, val));
+    if (!iter)
         goto error;
-    MOZ_ASSERT(res.isObject());
+    REGS.sp[-1].setObject(*iter);
 }
 END_CASE(JSOP_ITER)
 
 CASE(JSOP_MOREITER)
 {
     MOZ_ASSERT(REGS.stackDepth() >= 1);
     MOZ_ASSERT(REGS.sp[-1].isObject());
     PUSH_NULL();
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -3154,16 +3154,19 @@ AccumulateTelemetryCallback(int id, uint
         Telemetry::Accumulate(Telemetry::JS_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT, sample);
         break;
       case JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS:
         Telemetry::Accumulate(Telemetry::JS_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS, sample);
         break;
       case JS_TELEMETRY_ADDON_EXCEPTIONS:
         Telemetry::Accumulate(Telemetry::JS_TELEMETRY_ADDON_EXCEPTIONS, nsDependentCString(key), sample);
         break;
+      case JS_TELEMETRY_AOT_USAGE:
+        Telemetry::Accumulate(Telemetry::JS_AOT_USAGE, sample);
+        break;
       default:
         MOZ_ASSERT_UNREACHABLE("Unexpected JS_TELEMETRY id");
     }
 }
 
 static void
 CompartmentNameCallback(JSContext* cx, JSCompartment* comp,
                         char* buf, size_t bufsize)
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -942,17 +942,17 @@ GetScrollableOverflowForPerspective(nsIF
         overhang.top /= bottomDelta;
         overhang.right /= rightDelta;
         overhang.bottom /= bottomDelta;
         overhang.left /= rightDelta;
 
         // Take the minimum overflow rect that would allow the current scroll
         // position, using the size of the scroll port and offset by the
         // inverse of the scroll position.
-        nsRect overflow(0, 0, aScrollPort.width, aScrollPort.height);
+        nsRect overflow = aScrollPort - scrollPos;
 
         // Expand it by our margins to get an overflow rect that would allow all
         // edges of our transformed content to be scrolled into view.
         overflow.Inflate(overhang);
 
         // Merge it with the combined overflow
         aScrolledFrameOverflowArea.UnionRect(aScrolledFrameOverflowArea,
                                              overflow);
--- a/layout/generic/test/test_bug1198135.html
+++ b/layout/generic/test/test_bug1198135.html
@@ -72,13 +72,18 @@ https://bugzilla.mozilla.org/show_bug.cg
   <div class="example__group">
     <div class="example__layer layer--c"></div>
     <div class="example__layer layer--e"></div>
   </div>
 </div>
 
 <script>
   is(document.getElementById("first").scrollHeight, 600, "Scroll height should be computed correctly");
+  document.getElementById("first").scrollTop = 150;
+  is(document.getElementById("first").scrollHeight, 600, "Scroll height should be a constant when scrolling");
+
   // The true height is 727.5 and we don't always snap the same direction.
   isfuzzy(document.getElementById("second").scrollHeight, 728, 1, "Scroll height should be computed correctly");
+  document.getElementById("second").scrollTop = 150;
+  isfuzzy(document.getElementById("second").scrollHeight, 728, 1, "Scroll height should be a constant when scrolling");
 </script>
 
 </body></html>
--- a/layout/svg/SVGContextPaint.h
+++ b/layout/svg/SVGContextPaint.h
@@ -77,19 +77,20 @@ public:
     return mDashOffset;
   }
 
   gfxFloat GetStrokeWidth() {
     return mStrokeWidth;
   }
 
 private:
+  // Member-vars are initialized in InitStrokeGeometry.
   FallibleTArray<gfxFloat> mDashes;
-  gfxFloat mDashOffset;
-  gfxFloat mStrokeWidth;
+  MOZ_INIT_OUTSIDE_CTOR gfxFloat mDashOffset;
+  MOZ_INIT_OUTSIDE_CTOR gfxFloat mStrokeWidth;
 };
 
 /**
  * RAII class used to temporarily set and remove an SVGContextPaint while a
  * piece of SVG is being painted.  The context paint is set on the SVG's owner
  * document, as expected by SVGContextPaint::GetContextPaint.  Any pre-existing
  * context paint is restored after this class removes the context paint that it
  * set.
@@ -162,17 +163,18 @@ public:
     }
 
     union {
       nsSVGPaintServerFrame* mPaintServerFrame;
       SVGContextPaint* mContextPaint;
       nscolor mColor;
     } mPaintDefinition;
 
-    nsIFrame* mFrame;
+    // Initialized (if needed) in SetPaintServer():
+    MOZ_INIT_OUTSIDE_CTOR nsIFrame* mFrame;
     // CTM defining the user space for the pattern we will use.
     gfxMatrix mContextMatrix;
     nsStyleSVGPaintType mPaintType;
 
     // Device-space-to-pattern-space
     gfxMatrix mPatternMatrix;
     nsRefPtrHashtable<nsFloatHashKey, gfxPattern> mPatternCache;
 
--- a/netwerk/protocol/http/AlternateServices.h
+++ b/netwerk/protocol/http/AlternateServices.h
@@ -100,31 +100,31 @@ private:
   RefPtr<DataStorage> mStorage;
   int32_t             mStorageEpoch;
   void Serialize (nsCString &out);
 
   nsCString mHashKey;
 
   // If you change any of these members, update Serialize()
   nsCString mAlternateHost;
-  int32_t mAlternatePort;
+  MOZ_INIT_OUTSIDE_CTOR int32_t mAlternatePort;
 
   nsCString mOriginHost;
-  int32_t mOriginPort;
+  MOZ_INIT_OUTSIDE_CTOR int32_t mOriginPort;
 
   nsCString mUsername;
-  bool mPrivate;
+  MOZ_INIT_OUTSIDE_CTOR bool mPrivate;
 
-  uint32_t mExpiresAt; // alt-svc mappping
+  MOZ_INIT_OUTSIDE_CTOR uint32_t mExpiresAt; // alt-svc mappping
 
-  bool mValidated;
-  bool mHttps; // origin is https://
-  bool mMixedScheme; // .wk allows http and https on same con
+  MOZ_INIT_OUTSIDE_CTOR bool mValidated;
+  MOZ_INIT_OUTSIDE_CTOR bool mHttps; // origin is https://
+  MOZ_INIT_OUTSIDE_CTOR bool mMixedScheme; // .wk allows http and https on same con
 
-  nsCString        mNPNToken;
+  nsCString mNPNToken;
 };
 
 class AltSvcOverride : public nsIInterfaceRequestor
                      , public nsISpeculativeConnectionOverrider
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSISPECULATIVECONNECTIONOVERRIDER
--- a/testing/web-platform/meta/encrypted-media/__dir__.ini
+++ b/testing/web-platform/meta/encrypted-media/__dir__.ini
@@ -1,2 +1,2 @@
 disabled:
-  if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1301418
\ No newline at end of file
+  if (os == "linux") or (os == "mac"): https://bugzilla.mozilla.org/show_bug.cgi?id=1301418
\ No newline at end of file
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -8554,16 +8554,24 @@
     "expires_in_version": "55",
     "description": "Time taken for a video to resume after decoding was suspended, in milliseconds. Keyed by audio presence, hw acceleration, and by height ranges (boundaries: 240. 480, 720, 1080, 2160), e.g.: 'V,0-240', 'AV(hw),2160+'; and 'All' will accumulate all percentages.",
     "keyed": true,
     "kind": "exponential",
     "high": 10000,
     "n_buckets": 100,
     "bug_numbers": [1294349]
   },
+  "VIDEO_AS_CONTENT_SOURCE" : {
+    "alert_emails": ["ajones@mozilla.com", "kaku@mozilla.com"],
+    "expires_in_version": "56",
+    "description": "Usage of a {visible / invisible} video element as the source of {drawImage(), createPattern(), createImageBitmap() and captureStream()} APIs. (0 = ALL_VISIBLE, 1 = ALL_INVISIBLE, 2 = drawImage_VISIBLE, 3 = drawImage_INVISIBLE, 4 = createPattern_VISIBLE, 5 = createPattern_INVISIBLE, 6 = createImageBitmap_VISIBLE, 7 = createImageBitmap_INVISIBLE, 8 = captureStream_VISIBLE, 9 = captureStream_INVISIBLE)",
+    "kind": "enumerated",
+    "n_values": 12,
+    "bug_numbers": [1299718]
+  },
   "VIDEO_UNLOAD_STATE": {
     "alert_emails": ["ajones@mozilla.com"],
     "expires_in_version": "55",
     "kind": "enumerated",
     "n_values": 5,
     "description": "HTML Media Element state when unloading. ended = 0, paused = 1, stalled = 2, seeking = 3, other = 4",
     "bug_numbers": [1261955, 1261955]
   },
@@ -10302,10 +10310,18 @@
   "WEB_PERMISSION_CLEARED": {
     "alert_emails": ["firefox-dev@mozilla.org"],
     "bug_numbers": [1286118],
     "expires_in_version": "55",
     "kind": "enumerated",
     "keyed": true,
     "n_values": 6,
     "description": "Number of revoke actions on permissions in the control center, keyed by permission id. Values represent the permission type that was revoked. (0=unknown, 1=permanently allowed, 2=permanently blocked, 3=temporarily allowed, 4=temporarily blocked)"
+  },
+  "JS_AOT_USAGE": {
+    "alert_emails": ["luke@mozilla.com", "bbouvier@mozilla.com"],
+    "bug_numbers": [1288778],
+    "expires_in_version": "56",
+    "kind": "enumerated",
+    "n_values": 4,
+    "description": "Counts the number of asm.js vs WebAssembly modules instanciations, at the time modules are getting instanciated."
   }
 }