Merge m-c to b2g-inbound
authorWes Kocher <wkocher@mozilla.com>
Mon, 02 Jun 2014 19:16:34 -0700
changeset 205508 a57177a4033416f67ed92a7a193cee817a7612a9
parent 205507 d65ec751af4f685b0b3a7f57c0d1bfb95e368a4e (current diff)
parent 205427 83ad75d867af7862a18a4b44a4874f5878c9024f (diff)
child 205509 dda81c6ce28fd7813b50527777d2ad3b655a4e56
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone32.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 m-c to b2g-inbound
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -4718,17 +4718,17 @@
       <field name="_lastAccessed">0</field>
 
       <field name="mOverCloseButton">false</field>
       <field name="mCorrespondingMenuitem">null</field>
       <field name="closing">false</field>
 
       <method name="_mouseenter">
         <body><![CDATA[
-          if (this.closing)
+          if (this.hidden || this.closing)
             return;
 
           let tabContainer = this.parentNode;
           let visibleTabs = tabContainer.tabbrowser.visibleTabs;
           let tabIndex = visibleTabs.indexOf(this);
           if (tabIndex == 0) {
             tabContainer._beforeHoveredTab = null;
           } else {
--- a/browser/base/content/test/general/browser_devices_get_user_media.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media.js
@@ -55,17 +55,17 @@ function expectObserverCalled(aTopic) {
     --gObservedTopics[aTopic];
 }
 
 function expectNoObserverCalled() {
   for (let topic in gObservedTopics) {
     if (gObservedTopics[topic])
       is(gObservedTopics[topic], 0, topic + " notification unexpected");
   }
-  gObservedTopics = {}
+  gObservedTopics = {};
 }
 
 function promiseMessage(aMessage, aAction) {
   let deferred = Promise.defer();
 
   content.addEventListener("message", function messageListener(event) {
     content.removeEventListener("message", messageListener);
     is(event.data, aMessage, "received " + aMessage);
@@ -811,17 +811,17 @@ function test() {
         // Cleanup before the next test
         expectNoObserverCalled();
       }
     }).then(finish, ex => {
      ok(false, "Unexpected Exception: " + ex);
      finish();
     });
   }, true);
-  let rootDir = getRootDirectory(gTestPath)
+  let rootDir = getRootDirectory(gTestPath);
   rootDir = rootDir.replace("chrome://mochitests/content/",
                             "https://example.com/");
   content.location = rootDir + "get_user_media.html";
 }
 
 
 function wait(time) {
   let deferred = Promise.defer();
--- a/browser/base/content/test/general/get_user_media.html
+++ b/browser/base/content/test/general/get_user_media.html
@@ -1,24 +1,40 @@
 <!DOCTYPE html>
 <html>
 <head><meta charset="UTF-8"></head>
 <body>
 <div id="message"></div>
 <script>
+// Specifies whether we are using fake streams to run this automation
+var useFakeStreams = true;
+try {
+  var audioDevice = SpecialPowers.getCharPref("media.audio_loopback_dev");
+  var videoDevice = SpecialPowers.getCharPref("media.video_loopback_dev");
+  dump("TEST DEVICES: Using media devices:\n");
+  dump("audio: " + audioDevice + "\nvideo: " + videoDevice + "\n");
+  useFakeStreams = false;
+} catch (e) {
+  dump("TEST DEVICES: No test devices found (in media.{audio,video}_loopback_dev, using fake streams.\n");
+  useFakeStreams = true;
+}
+
 function message(m) {
   document.getElementById("message").innerHTML = m;
   window.parent.postMessage(m, "*");
 }
 
 var gStream;
 
 function requestDevice(aAudio, aVideo) {
-  window.navigator.mozGetUserMedia({video: aVideo, audio: aAudio, fake: true},
-                                   function(stream) {
+  var opts = {video: aVideo, audio: aAudio};
+  if (useFakeStreams) {
+    opts.fake = true;
+  }
+  window.navigator.mozGetUserMedia(opts, function(stream) {
     gStream = stream;
     message("ok");
   }, function(err) { message("error: " + err); });
 }
 message("pending");
 
 function closeStream() {
   if (!gStream)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/bug1018621.js
@@ -0,0 +1,7 @@
+function strictSome(k) {
+  "use strict";
+  for (var i = 0; i < args.length; i++)
+    assertEq(arguments[i], args[i], "wrong argument " + i);
+}
+args = [8, 6, 7, NaN, undefined, 0.3];
+strictSome.call(NaN, 8, 6, 7, NaN, undefined, 0.3);
--- a/js/src/jit/CompileInfo.h
+++ b/js/src/jit/CompileInfo.h
@@ -420,18 +420,21 @@ class CompileInfo
         // preserve the scope chain, because it may be needed to construct the
         // arguments object during bailout. If we've already created an
         // arguments object (or got one via OSR), preserve that as well.
         if (hasArguments() && (slot == scopeChainSlot() || slot == argsObjSlot()))
             return true;
 
         // Function.arguments can be used to access all arguments in non-strict
         // scripts, so we can't optimize out any arguments.
-        if (!script()->strict() && firstArgSlot() <= slot && slot - firstArgSlot() < nargs())
+        if ((hasArguments() || !script()->strict()) &&
+            firstArgSlot() <= slot && slot - firstArgSlot() < nargs())
+        {
             return true;
+        }
 
         return false;
     }
 
   private:
     unsigned nimplicit_;
     unsigned nargs_;
     unsigned nfixedvars_;
--- a/js/src/jit/IonFrames.cpp
+++ b/js/src/jit/IonFrames.cpp
@@ -1651,35 +1651,74 @@ JitFrameIterator::safepoint() const
 
 const OsiIndex *
 JitFrameIterator::osiIndex() const
 {
     SafepointReader reader(ionScript(), safepoint());
     return ionScript()->getOsiIndex(reader.osiReturnPointOffset());
 }
 
-template <AllowGC allowGC>
+InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter)
+  : callee_(cx),
+    script_(cx)
+{
+    resetOn(iter);
+}
+
+InlineFrameIterator::InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter)
+  : callee_(rt),
+    script_(rt)
+{
+    resetOn(iter);
+}
+
+InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter)
+  : frame_(iter),
+    framesRead_(0),
+    frameCount_(UINT32_MAX),
+    callee_(cx),
+    script_(cx)
+{
+    if (iter) {
+        start_ = SnapshotIterator(*iter);
+        findNextFrame();
+    }
+}
+
+InlineFrameIterator::InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter)
+  : frame_(iter ? iter->frame_ : nullptr),
+    framesRead_(0),
+    frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
+    callee_(cx),
+    script_(cx)
+{
+    if (frame_) {
+        start_ = SnapshotIterator(*frame_);
+        // findNextFrame will iterate to the next frame and init. everything.
+        // Therefore to settle on the same frame, we report one frame less readed.
+        framesRead_ = iter->framesRead_ - 1;
+        findNextFrame();
+    }
+}
+
 void
-InlineFrameIteratorMaybeGC<allowGC>::resetOn(const JitFrameIterator *iter)
+InlineFrameIterator::resetOn(const JitFrameIterator *iter)
 {
     frame_ = iter;
     framesRead_ = 0;
     frameCount_ = UINT32_MAX;
 
     if (iter) {
         start_ = SnapshotIterator(*iter);
         findNextFrame();
     }
 }
-template void InlineFrameIteratorMaybeGC<NoGC>::resetOn(const JitFrameIterator *iter);
-template void InlineFrameIteratorMaybeGC<CanGC>::resetOn(const JitFrameIterator *iter);
 
-template <AllowGC allowGC>
 void
-InlineFrameIteratorMaybeGC<allowGC>::findNextFrame()
+InlineFrameIterator::findNextFrame()
 {
     JS_ASSERT(more());
 
     si_ = start_;
 
     // Read the initial frame out of the C stack.
     callee_ = frame_->maybeCallee();
     script_ = frame_->script();
@@ -1751,65 +1790,75 @@ InlineFrameIteratorMaybeGC<allowGC>::fin
     // iteration that we have done.
     if (frameCount_ == UINT32_MAX) {
         MOZ_ASSERT(!si_.moreFrames());
         frameCount_ = i;
     }
 
     framesRead_++;
 }
-template void InlineFrameIteratorMaybeGC<NoGC>::findNextFrame();
-template void InlineFrameIteratorMaybeGC<CanGC>::findNextFrame();
+
+JSObject *
+InlineFrameIterator::computeScopeChain(Value scopeChainValue) const
+{
+    if (scopeChainValue.isObject())
+        return &scopeChainValue.toObject();
 
-template <AllowGC allowGC>
+    if (isFunctionFrame()) {
+        // Heavyweight functions should always have a scope chain.
+        MOZ_ASSERT(!callee()->isHeavyweight());
+        return callee()->environment();
+    }
+
+    // Ion does not handle scripts that are not compile-and-go.
+    MOZ_ASSERT(!script()->isForEval());
+    MOZ_ASSERT(script()->compileAndGo());
+    return &script()->global();
+}
+
 bool
-InlineFrameIteratorMaybeGC<allowGC>::isFunctionFrame() const
+InlineFrameIterator::isFunctionFrame() const
 {
     return !!callee_;
 }
-template bool InlineFrameIteratorMaybeGC<NoGC>::isFunctionFrame() const;
-template bool InlineFrameIteratorMaybeGC<CanGC>::isFunctionFrame() const;
 
 MachineState
 MachineState::FromBailout(mozilla::Array<uintptr_t, Registers::Total> &regs,
                           mozilla::Array<double, FloatRegisters::Total> &fpregs)
 {
     MachineState machine;
 
     for (unsigned i = 0; i < Registers::Total; i++)
         machine.setRegisterLocation(Register::FromCode(i), &regs[i]);
     for (unsigned i = 0; i < FloatRegisters::Total; i++)
         machine.setRegisterLocation(FloatRegister::FromCode(i), &fpregs[i]);
 
     return machine;
 }
 
-template <AllowGC allowGC>
 bool
-InlineFrameIteratorMaybeGC<allowGC>::isConstructing() const
+InlineFrameIterator::isConstructing() const
 {
     // Skip the current frame and look at the caller's.
     if (more()) {
-        InlineFrameIteratorMaybeGC<allowGC> parent(GetJSContextFromJitCode(), this);
+        InlineFrameIterator parent(GetJSContextFromJitCode(), this);
         ++parent;
 
         // Inlined Getters and Setters are never constructing.
         if (IsGetPropPC(parent.pc()) || IsSetPropPC(parent.pc()))
             return false;
 
         // In the case of a JS frame, look up the pc from the snapshot.
         JS_ASSERT(IsCallPC(parent.pc()));
 
         return (JSOp)*parent.pc() == JSOP_NEW;
     }
 
     return frame_->isConstructing();
 }
-template bool InlineFrameIteratorMaybeGC<NoGC>::isConstructing() const;
-template bool InlineFrameIteratorMaybeGC<CanGC>::isConstructing() const;
 
 bool
 JitFrameIterator::isConstructing() const
 {
     JitFrameIterator parent(*this);
 
     // Skip the current frame and look at the caller's.
     do {
@@ -1916,19 +1965,18 @@ JitFrameIterator::dumpBaseline() const
         Value *v = frame->valueSlot(i);
         js_DumpValue(*v);
 #else
         fprintf(stderr, "?\n");
 #endif
     }
 }
 
-template <AllowGC allowGC>
 void
-InlineFrameIteratorMaybeGC<allowGC>::dump() const
+InlineFrameIterator::dump() const
 {
     if (more())
         fprintf(stderr, " JS frame (inlined)\n");
     else
         fprintf(stderr, " JS frame\n");
 
     bool isFunction = false;
     if (isFunctionFrame()) {
@@ -1977,18 +2025,16 @@ InlineFrameIteratorMaybeGC<allowGC>::dum
         js_DumpValue(si.maybeRead());
 #else
         fprintf(stderr, "?\n");
 #endif
     }
 
     fputc('\n', stderr);
 }
-template void InlineFrameIteratorMaybeGC<NoGC>::dump() const;
-template void InlineFrameIteratorMaybeGC<CanGC>::dump() const;
 
 void
 JitFrameIterator::dump() const
 {
     switch (type_) {
       case JitFrame_Entry:
         fprintf(stderr, " Entry frame\n");
         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
--- a/js/src/jit/JitFrameIterator-inl.h
+++ b/js/src/jit/JitFrameIterator-inl.h
@@ -13,32 +13,16 @@
 
 #include "jit/Bailouts.h"
 #include "jit/BaselineFrame.h"
 #include "jit/IonFrames.h"
 
 namespace js {
 namespace jit {
 
-template <AllowGC allowGC>
-inline
-InlineFrameIteratorMaybeGC<allowGC>::InlineFrameIteratorMaybeGC(ThreadSafeContext *cx,
-                                                                const IonBailoutIterator *iter)
-  : frame_(iter),
-    framesRead_(0),
-    frameCount_(UINT32_MAX),
-    callee_(cx),
-    script_(cx)
-{
-    if (iter) {
-        start_ = SnapshotIterator(*iter);
-        findNextFrame();
-    }
-}
-
 inline BaselineFrame *
 JitFrameIterator::baselineFrame() const
 {
     JS_ASSERT(isBaselineJS());
     return (BaselineFrame *)(fp() - BaselineFrame::FramePointerOffset - BaselineFrame::Size());
 }
 
 template <typename T>
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -448,90 +448,47 @@ class SnapshotIterator
     void spewBailingFrom() const {
         snapshot_.spewBailingFrom();
     }
 #endif
 };
 
 // Reads frame information in callstack order (that is, innermost frame to
 // outermost frame).
-template <AllowGC allowGC=CanGC>
-class InlineFrameIteratorMaybeGC
+class InlineFrameIterator
 {
     const JitFrameIterator *frame_;
     SnapshotIterator start_;
     SnapshotIterator si_;
     uint32_t framesRead_;
 
     // When the inline-frame-iterator is created, this variable is defined to
     // UINT32_MAX. Then the first iteration of findNextFrame, which settle on
     // the innermost frame, is used to update this counter to the number of
     // frames contained in the recover buffer.
     uint32_t frameCount_;
 
-    typename MaybeRooted<JSFunction*, allowGC>::RootType callee_;
-    typename MaybeRooted<JSScript*, allowGC>::RootType script_;
+    RootedFunction callee_;
+    RootedScript script_;
     jsbytecode *pc_;
     uint32_t numActualArgs_;
 
     struct Nop {
         void operator()(const Value &v) { }
     };
 
   private:
     void findNextFrame();
-
-    JSObject *computeScopeChain(Value scopeChainValue) const {
-        if (scopeChainValue.isObject())
-            return &scopeChainValue.toObject();
-
-        if (isFunctionFrame()) {
-            // Heavyweight functions should always have a scope chain.
-            MOZ_ASSERT(!callee()->isHeavyweight());
-            return callee()->environment();
-        }
-
-        // Ion does not handle scripts that are not compile-and-go.
-        MOZ_ASSERT(!script()->isForEval());
-        MOZ_ASSERT(script()->compileAndGo());
-        return &script()->global();
-    }
+    JSObject *computeScopeChain(Value scopeChainValue) const;
 
   public:
-    InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, const JitFrameIterator *iter)
-      : callee_(cx),
-        script_(cx)
-    {
-        resetOn(iter);
-    }
-
-    InlineFrameIteratorMaybeGC(JSRuntime *rt, const JitFrameIterator *iter)
-      : callee_(rt),
-        script_(rt)
-    {
-        resetOn(iter);
-    }
-
-    InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, const IonBailoutIterator *iter);
-
-    InlineFrameIteratorMaybeGC(ThreadSafeContext *cx, const InlineFrameIteratorMaybeGC *iter)
-      : frame_(iter ? iter->frame_ : nullptr),
-        framesRead_(0),
-        frameCount_(iter ? iter->frameCount_ : UINT32_MAX),
-        callee_(cx),
-        script_(cx)
-    {
-        if (frame_) {
-            start_ = SnapshotIterator(*frame_);
-            // findNextFrame will iterate to the next frame and init. everything.
-            // Therefore to settle on the same frame, we report one frame less readed.
-            framesRead_ = iter->framesRead_ - 1;
-            findNextFrame();
-        }
-    }
+    InlineFrameIterator(ThreadSafeContext *cx, const JitFrameIterator *iter);
+    InlineFrameIterator(JSRuntime *rt, const JitFrameIterator *iter);
+    InlineFrameIterator(ThreadSafeContext *cx, const IonBailoutIterator *iter);
+    InlineFrameIterator(ThreadSafeContext *cx, const InlineFrameIterator *iter);
 
     bool more() const {
         return frame_ && framesRead_ < frameCount_;
     }
     JSFunction *callee() const {
         JS_ASSERT(callee_);
         return callee_;
     }
@@ -582,17 +539,17 @@ class InlineFrameIteratorMaybeGC
                     // There is still a parent frame of this inlined frame.  All
                     // arguments (also the overflown) are the last pushed values
                     // in the parent frame.  To get the overflown arguments, we
                     // need to take them from there.
 
                     // The overflown arguments are not available in current frame.
                     // They are the last pushed arguments in the parent frame of
                     // this inlined frame.
-                    InlineFrameIteratorMaybeGC it(cx, this);
+                    InlineFrameIterator it(cx, this);
                     ++it;
                     unsigned argsObjAdj = it.script()->argumentsHasVarBinding() ? 1 : 0;
                     SnapshotIterator parent_s(it.snapshotIterator());
 
                     // Skip over all slots until we get to the last slots
                     // (= arguments slots of callee) the +3 is for [this], [returnvalue],
                     // [scopechain], and maybe +1 for [argsObj]
                     JS_ASSERT(parent_s.numAllocations() >= nactual + 3 + argsObjAdj);
@@ -668,17 +625,17 @@ class InlineFrameIteratorMaybeGC
 
         // Arguments object.
         if (script()->argumentsHasVarBinding())
             s.skip();
 
         return s.read();
     }
 
-    InlineFrameIteratorMaybeGC &operator++() {
+    InlineFrameIterator &operator++() {
         findNextFrame();
         return *this;
     }
 
     void dump() const;
 
     void resetOn(const JitFrameIterator *iter);
 
@@ -691,20 +648,18 @@ class InlineFrameIteratorMaybeGC
         return frameCount() - framesRead_;
     }
     size_t frameCount() const {
         MOZ_ASSERT(frameCount_ != UINT32_MAX);
         return frameCount_;
     }
 
   private:
-    InlineFrameIteratorMaybeGC() MOZ_DELETE;
-    InlineFrameIteratorMaybeGC(const InlineFrameIteratorMaybeGC &iter) MOZ_DELETE;
+    InlineFrameIterator() MOZ_DELETE;
+    InlineFrameIterator(const InlineFrameIterator &iter) MOZ_DELETE;
 };
-typedef InlineFrameIteratorMaybeGC<CanGC> InlineFrameIterator;
-typedef InlineFrameIteratorMaybeGC<NoGC> InlineFrameIteratorNoGC;
 
 } // namespace jit
 } // namespace js
 
 #endif // JS_ION
 
 #endif /* jit_JitFrameIterator_h */
--- a/mobile/android/base/db/FormHistoryProvider.java
+++ b/mobile/android/base/db/FormHistoryProvider.java
@@ -1,16 +1,17 @@
 /* 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/. */
 
 package org.mozilla.gecko.db;
 
 import java.lang.IllegalArgumentException;
 import java.util.HashMap;
+
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.db.BrowserContract.FormHistory;
 import org.mozilla.gecko.db.BrowserContract.DeletedFormHistory;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.sqlite.SQLiteBridge;
 import org.mozilla.gecko.sync.Utils;
 
@@ -28,16 +29,17 @@ public class FormHistoryProvider extends
     private static final int DELETED_FORM_HISTORY = 101;
 
     private static final UriMatcher URI_MATCHER;
 
 
     // This should be kept in sync with the db version in toolkit/components/satchel/nsFormHistory.js
     private static int DB_VERSION = 4;
     private static String DB_FILENAME = "formhistory.sqlite";
+    private static final String TELEMETRY_TAG = "SQLITEBRIDGE_PROVIDER_FORMS";
 
     private static final String WHERE_GUID_IS_NULL = BrowserContract.DeletedFormHistory.GUID + " IS NULL";
     private static final String WHERE_GUID_IS_VALUE = BrowserContract.DeletedFormHistory.GUID + " = ?";
 
     private static final String LOG_TAG = "FormHistoryProvider";
 
     static {
         URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
@@ -149,12 +151,17 @@ public class FormHistoryProvider extends
     public void onPostQuery(Cursor cursor, Uri uri, SQLiteBridge db) { }
 
     @Override
     protected String getDBName(){
         return DB_FILENAME;
     }
 
     @Override
+    protected String getTelemetryPrefix() {
+        return TELEMETRY_TAG;
+    }
+
+    @Override
     protected int getDBVersion(){
         return DB_VERSION;
     }
 }
--- a/mobile/android/base/db/HomeProvider.java
+++ b/mobile/android/base/db/HomeProvider.java
@@ -24,16 +24,17 @@ import android.net.Uri;
 import android.util.Log;
 
 public class HomeProvider extends SQLiteBridgeContentProvider {
     private static final String LOGTAG = "GeckoHomeProvider";
 
     // This should be kept in sync with the db version in mobile/android/modules/HomeProvider.jsm
     private static int DB_VERSION = 2;
     private static String DB_FILENAME = "home.sqlite";
+    private static final String TELEMETRY_TAG = "SQLITEBRIDGE_PROVIDER_HOME";
 
     private static final String TABLE_ITEMS = "items";
 
     // Endpoint to return static fake data.
     static final int ITEMS_FAKE = 100;
     static final int ITEMS = 101;
     static final int ITEMS_ID = 102;
 
@@ -140,16 +141,21 @@ public class HomeProvider extends SQLite
      */
 
     @Override
     protected String getDBName(){
         return DB_FILENAME;
     }
 
     @Override
+    protected String getTelemetryPrefix() {
+        return TELEMETRY_TAG;
+    }
+
+    @Override
     protected int getDBVersion(){
         return DB_VERSION;
     }
 
     @Override
     public String getTable(Uri uri) {
         final int match = URI_MATCHER.match(uri);
         switch (match) {
--- a/mobile/android/base/db/PasswordsProvider.java
+++ b/mobile/android/base/db/PasswordsProvider.java
@@ -24,16 +24,18 @@ import android.database.Cursor;
 import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
 
 public class PasswordsProvider extends SQLiteBridgeContentProvider {
     static final String TABLE_PASSWORDS = "moz_logins";
     static final String TABLE_DELETED_PASSWORDS = "moz_deleted_logins";
 
+    private static final String TELEMETRY_TAG = "SQLITEBRIDGE_PROVIDER_PASSWORDS";
+
     private static final int PASSWORDS = 100;
     private static final int DELETED_PASSWORDS = 101;
 
     static final String DEFAULT_PASSWORDS_SORT_ORDER = Passwords.HOSTNAME + " ASC";
     static final String DEFAULT_DELETED_PASSWORDS_SORT_ORDER = DeletedPasswords.TIME_DELETED + " ASC";
 
     private static final UriMatcher URI_MATCHER;
 
@@ -87,16 +89,21 @@ public class PasswordsProvider extends S
     }
 
     @Override
     protected String getDBName(){
         return DB_FILENAME;
     }
 
     @Override
+    protected String getTelemetryPrefix() {
+        return TELEMETRY_TAG;
+    }
+
+    @Override
     protected int getDBVersion(){
         return DB_VERSION;
     }
 
     @Override
     public String getType(Uri uri) {
         final int match = URI_MATCHER.match(uri);
 
--- a/mobile/android/base/db/SQLiteBridgeContentProvider.java
+++ b/mobile/android/base/db/SQLiteBridgeContentProvider.java
@@ -1,24 +1,24 @@
 /* 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/. */
 
 package org.mozilla.gecko.db;
 
 import java.io.File;
 import java.util.HashMap;
-import java.util.Collection;
-import java.util.Iterator;
+
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.GeckoThread;
-import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.sqlite.SQLiteBridge;
 import org.mozilla.gecko.sqlite.SQLiteBridgeException;
+
 import android.content.ContentProvider;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
@@ -30,24 +30,62 @@ import android.util.Log;
  *
  *  public abstract String getTable(Uri uri);
  *  public abstract String getSortOrder(Uri uri, String aRequested);
  *  public abstract void setupDefaults(Uri uri, ContentValues values);
  *  public abstract void initGecko();
  */
 
 public abstract class SQLiteBridgeContentProvider extends ContentProvider {
+    private static final String ERROR_MESSAGE_DATABASE_IS_LOCKED = "Can't step statement: (5) database is locked";
+
     private HashMap<String, SQLiteBridge> mDatabasePerProfile;
     protected Context mContext = null;
     private final String mLogTag;
 
     protected SQLiteBridgeContentProvider(String logTag) {
         mLogTag = logTag;
     }
 
+    /**
+     * Subclasses must override this to allow error reporting code to compose
+     * the correct histogram name.
+     *
+     * Ensure that you define the new histograms if you define a new class!
+     */
+    protected abstract String getTelemetryPrefix();
+
+    /**
+     * Errors are recorded in telemetry using an enumerated histogram.
+     *
+     * <https://developer.mozilla.org/en-US/docs/Mozilla/Performance/
+     * Adding_a_new_Telemetry_probe#Choosing_a_Histogram_Type>
+     *
+     * These are the allowable enumeration values. Keep these in sync with the
+     * histogram definition!
+     *
+     */
+    private static enum TelemetryErrorOp {
+        BULKINSERT (0),
+        DELETE     (1),
+        INSERT     (2),
+        QUERY      (3),
+        UPDATE     (4);
+
+        private final int bucket;
+
+        TelemetryErrorOp(final int bucket) {
+            this.bucket = bucket;
+        }
+
+        public int getBucket() {
+            return bucket;
+        }
+    }
+
     @Override
     public void shutdown() {
         if (mDatabasePerProfile == null) {
             return;
         }
 
         synchronized (this) {
             for (SQLiteBridge bridge : mDatabasePerProfile.values()) {
@@ -250,17 +288,17 @@ public abstract class SQLiteBridgeConten
         final SQLiteBridge db = getDatabase(uri);
         if (db == null) {
             return deleted;
         }
 
         try {
             deleted = db.delete(getTable(uri), selection, selectionArgs);
         } catch (SQLiteBridgeException ex) {
-            Log.e(mLogTag, "Error deleting record", ex);
+            reportError(ex, TelemetryErrorOp.DELETE);
             throw ex;
         }
 
         return deleted;
     }
 
     @Override
     public Uri insert(Uri uri, ContentValues values) {
@@ -286,17 +324,17 @@ public abstract class SQLiteBridgeConten
             // so we put it inside this transaction
             onPreInsert(values, uri, db);
             id = db.insert(getTable(uri), null, values);
 
             if (useTransaction) {
                 db.setTransactionSuccessful();
             }
         } catch (SQLiteBridgeException ex) {
-            Log.e(mLogTag, "Error inserting in db", ex);
+            reportError(ex, TelemetryErrorOp.INSERT);
             throw ex;
         } finally {
             if (useTransaction) {
                 db.endTransaction();
             }
         }
 
         return ContentUris.withAppendedId(uri, id);
@@ -307,33 +345,32 @@ public abstract class SQLiteBridgeConten
         final SQLiteBridge db = getDatabase(uri);
         // If we can not get a SQLiteBridge instance, its likely that the database
         // has not been set up and Gecko is not running. We return 0 and expect
         // callers to try again later
         if (db == null) {
             return 0;
         }
 
-        long id = -1;
         int rowsAdded = 0;
 
         String table = getTable(uri);
 
         try {
             db.beginTransaction();
             for (ContentValues initialValues : allValues) {
                 ContentValues values = new ContentValues(initialValues);
                 setupDefaults(uri, values);
                 onPreInsert(values, uri, db);
-                id = db.insert(table, null, values);
+                db.insert(table, null, values);
                 rowsAdded++;
             }
             db.setTransactionSuccessful();
         } catch (SQLiteBridgeException ex) {
-            Log.e(mLogTag, "Error inserting in db", ex);
+            reportError(ex, TelemetryErrorOp.BULKINSERT);
             throw ex;
         } finally {
             db.endTransaction();
         }
 
         if (rowsAdded > 0) {
             final boolean shouldSyncToNetwork = !isCallerSync(uri);
             mContext.getContentResolver().notifyChange(uri, null, shouldSyncToNetwork);
@@ -355,17 +392,17 @@ public abstract class SQLiteBridgeConten
             return updated;
         }
 
         onPreUpdate(values, uri, db);
 
         try {
             updated = db.update(getTable(uri), values, selection, selectionArgs);
         } catch (SQLiteBridgeException ex) {
-            Log.e(mLogTag, "Error updating table", ex);
+            reportError(ex, TelemetryErrorOp.UPDATE);
             throw ex;
         }
 
         return updated;
     }
 
     @Override
     public Cursor query(Uri uri, String[] projection, String selection,
@@ -381,23 +418,42 @@ public abstract class SQLiteBridgeConten
         }
 
         sortOrder = getSortOrder(uri, sortOrder);
 
         try {
             cursor = db.query(getTable(uri), projection, selection, selectionArgs, null, null, sortOrder, null);
             onPostQuery(cursor, uri, db);
         } catch (SQLiteBridgeException ex) {
-            Log.e(mLogTag, "Error querying database", ex);
+            reportError(ex, TelemetryErrorOp.QUERY);
             throw ex;
         }
 
         return cursor;
     }
 
+    private String getHistogram(SQLiteBridgeException e) {
+        // If you add values here, make sure to update
+        // toolkit/components/telemetry/Histograms.json.
+        if (ERROR_MESSAGE_DATABASE_IS_LOCKED.equals(e.getMessage())) {
+            return getTelemetryPrefix() + "_LOCKED";
+        }
+        return null;
+    }
+
+    protected void reportError(SQLiteBridgeException e, TelemetryErrorOp op) {
+        Log.e(mLogTag, "Error in database " + op.name(), e);
+        final String histogram = getHistogram(e);
+        if (histogram == null) {
+            return;
+        }
+
+        Telemetry.HistogramAdd(histogram, op.getBucket());
+    }
+
     protected abstract String getDBName();
 
     protected abstract int getDBVersion();
 
     protected abstract String getTable(Uri uri);
 
     protected abstract String getSortOrder(Uri uri, String aRequested);
 
--- a/testing/config/mozharness/linux_config.py
+++ b/testing/config/mozharness/linux_config.py
@@ -7,17 +7,18 @@ config = {
         "--appname=%(binary_path)s", "--utility-path=tests/bin",
         "--extra-profile-file=tests/bin/plugins", "--symbols-path=%(symbols_path)s"
     ],
     "mochitest_options": [
         "--appname=%(binary_path)s", "--utility-path=tests/bin",
         "--extra-profile-file=tests/bin/plugins", "--symbols-path=%(symbols_path)s",
         "--certificate-path=tests/certs", "--autorun", "--close-when-done",
         "--console-level=INFO", "--setpref=webgl.force-enabled=true",
-        "--quiet"
+        "--quiet",
+        "--use-test-media-devices"
     ],
     "webapprt_options": [
         "--app=%(app_path)s", "--utility-path=tests/bin",
         "--extra-profile-file=tests/bin/plugins", "--symbols-path=%(symbols_path)s",
         "--certificate-path=tests/certs", "--autorun", "--close-when-done",
         "--console-level=INFO", "--testing-modules-dir=tests/modules",
         "--quiet"
     ],
--- a/toolkit/components/downloads/ApplicationReputation.cpp
+++ b/toolkit/components/downloads/ApplicationReputation.cpp
@@ -99,16 +99,20 @@ private:
   // Telemetry states.
   // Status of the remote response (valid or not).
   enum SERVER_RESPONSE_TYPES {
     SERVER_RESPONSE_VALID = 0,
     SERVER_RESPONSE_FAILED = 1,
     SERVER_RESPONSE_INVALID = 2,
   };
 
+  // Number of blocklist and allowlist hits we have seen.
+  uint32_t mBlocklistCount;
+  uint32_t mAllowlistCount;
+
   // The query containing metadata about the downloaded file.
   nsCOMPtr<nsIApplicationReputationQuery> mQuery;
 
   // The callback with which to report the verdict.
   nsCOMPtr<nsIApplicationReputationCallback> mCallback;
 
   // An array of strings created from certificate information used to whitelist
   // the downloaded file.
@@ -238,17 +242,17 @@ PendingDBLookup::~PendingDBLookup()
   LOG(("Destroying pending DB lookup [this = %p]", this));
   mPendingLookup = nullptr;
 }
 
 nsresult
 PendingDBLookup::LookupSpec(const nsACString& aSpec,
                             bool aAllowlistOnly)
 {
-  LOG(("Checking principal %s", aSpec.Data()));
+  LOG(("Checking principal %s [this=%p]", aSpec.Data(), this));
   mSpec = aSpec;
   mAllowlistOnly = aAllowlistOnly;
   nsresult rv = LookupSpecInternal(aSpec);
   if (NS_FAILED(rv)) {
     LOG(("Error in LookupSpecInternal"));
     return mPendingLookup->OnComplete(false, NS_OK);
   }
   // LookupSpecInternal has called nsIUrlClassifierCallback.lookup, which is
@@ -293,46 +297,51 @@ PendingDBLookup::LookupSpecInternal(cons
   }
   return dbService->Lookup(principal, tables, this);
 }
 
 NS_IMETHODIMP
 PendingDBLookup::HandleEvent(const nsACString& tables)
 {
   // HandleEvent is guaranteed to call either:
-  // 1) PendingLookup::OnComplete if the URL can be classified locally, or
-  // 2) PendingLookup::LookupNext if the URL can be cannot classified locally.
+  // 1) PendingLookup::OnComplete if the URL matches the blocklist, or
+  // 2) PendingLookup::LookupNext if the URL does not match the blocklist.
   // Blocklisting trumps allowlisting.
   nsAutoCString blockList;
   Preferences::GetCString(PREF_DOWNLOAD_BLOCK_TABLE, &blockList);
   if (!mAllowlistOnly && FindInReadable(blockList, tables)) {
+    mPendingLookup->mBlocklistCount++;
     Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_LOCAL, BLOCK_LIST);
     LOG(("Found principal %s on blocklist [this = %p]", mSpec.get(), this));
     return mPendingLookup->OnComplete(true, NS_OK);
   }
 
   nsAutoCString allowList;
   Preferences::GetCString(PREF_DOWNLOAD_ALLOW_TABLE, &allowList);
   if (FindInReadable(allowList, tables)) {
+    mPendingLookup->mAllowlistCount++;
     Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_LOCAL, ALLOW_LIST);
     LOG(("Found principal %s on allowlist [this = %p]", mSpec.get(), this));
-    return mPendingLookup->OnComplete(false, NS_OK);
+    // Don't call onComplete, since blocklisting trumps allowlisting
+  } else {
+    LOG(("Didn't find principal %s on any list [this = %p]", mSpec.get(),
+         this));
+    Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_LOCAL, NO_LIST);
   }
-
-  LOG(("Didn't find principal %s on any list [this = %p]", mSpec.get(), this));
-  Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_LOCAL, NO_LIST);
   return mPendingLookup->LookupNext();
 }
 
 NS_IMPL_ISUPPORTS(PendingLookup,
                   nsIStreamListener,
                   nsIRequestObserver)
 
 PendingLookup::PendingLookup(nsIApplicationReputationQuery* aQuery,
                              nsIApplicationReputationCallback* aCallback) :
+  mBlocklistCount(0),
+  mAllowlistCount(0),
   mQuery(aQuery),
   mCallback(aCallback)
 {
   LOG(("Created pending lookup [this = %p]", this));
 }
 
 PendingLookup::~PendingLookup()
 {
@@ -366,52 +375,62 @@ PendingLookup::IsBinaryFile()
     StringEndsWith(fileName, NS_LITERAL_STRING(".vbs")) ||
     StringEndsWith(fileName, NS_LITERAL_STRING(".zip"));
 }
 
 nsresult
 PendingLookup::LookupNext()
 {
   // We must call LookupNext or SendRemoteQuery upon return.
-  // Look up all of the URLs that could whitelist this download.
-  // Blacklist first.
+  // Look up all of the URLs that could allow or block this download.
+  // Blocklist first.
+  if (mBlocklistCount > 0) {
+    return OnComplete(true, NS_OK);
+  }
   int index = mAnylistSpecs.Length() - 1;
   nsCString spec;
-  bool allowlistOnly = false;
   if (index >= 0) {
-    // Check the source URI and referrer.
+    // Check the source URI, referrer and redirect chain.
     spec = mAnylistSpecs[index];
     mAnylistSpecs.RemoveElementAt(index);
-  } else {
-    // Check the allowlists next.
-    index = mAllowlistSpecs.Length() - 1;
-    if (index >= 0) {
-      allowlistOnly = true;
-      spec = mAllowlistSpecs[index];
-      mAllowlistSpecs.RemoveElementAt(index);
-    }
+    nsRefPtr<PendingDBLookup> lookup(new PendingDBLookup(this));
+    return lookup->LookupSpec(spec, false);
+  }
+  // If any of mAnylistSpecs matched the blocklist, go ahead and block.
+  if (mBlocklistCount > 0) {
+    return OnComplete(true, NS_OK);
   }
+  // If any of mAnylistSpecs matched the allowlist, go ahead and pass.
+  if (mAllowlistCount > 0) {
+    return OnComplete(false, NS_OK);
+  }
+  // Only binary signatures remain.
+  index = mAllowlistSpecs.Length() - 1;
   if (index >= 0) {
+    spec = mAllowlistSpecs[index];
+    LOG(("PendingLookup::LookupNext: checking %s on allowlist", spec.get()));
+    mAllowlistSpecs.RemoveElementAt(index);
     nsRefPtr<PendingDBLookup> lookup(new PendingDBLookup(this));
-    return lookup->LookupSpec(spec, allowlistOnly);
+    return lookup->LookupSpec(spec, true);
   }
 #ifdef XP_WIN
   // There are no more URIs to check against local list. If the file is not
   // eligible for remote lookup, bail.
   if (!IsBinaryFile()) {
     LOG(("Not eligible for remote lookups [this=%x]", this));
     return OnComplete(false, NS_OK);
   }
   // Send the remote query if we are on Windows.
   nsresult rv = SendRemoteQuery();
   if (NS_FAILED(rv)) {
     return OnComplete(false, rv);
   }
   return NS_OK;
 #else
+  LOG(("PendingLookup: Nothing left to check [this=%p]", this));
   return OnComplete(false, NS_OK);
 #endif
 }
 
 nsCString
 PendingLookup::EscapeCertificateAttribute(const nsACString& aAttribute)
 {
   // Escape '/' because it's a field separator, and '%' because Chrome does
@@ -625,17 +644,17 @@ PendingLookup::DoLookupInternal()
     mAnylistSpecs.AppendElement(spec);
     resource->set_referrer(spec.get());
   }
   nsCOMPtr<nsIArray> redirects;
   rv = mQuery->GetRedirects(getter_AddRefs(redirects));
   if (redirects) {
     AddRedirects(redirects);
   } else {
-    LOG(("ApplicationReputation: Got no redirects"));
+    LOG(("ApplicationReputation: Got no redirects [this=%p]", this));
   }
 
   // Extract the signature and parse certificates so we can use it to check
   // whitelists.
   nsCOMPtr<nsIArray> sigArray;
   rv = mQuery->GetSignatureInfo(getter_AddRefs(sigArray));
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -971,17 +990,17 @@ ApplicationReputationService::Applicatio
 ApplicationReputationService::~ApplicationReputationService() {
   LOG(("Application reputation service shutting down"));
 }
 
 NS_IMETHODIMP
 ApplicationReputationService::QueryReputation(
     nsIApplicationReputationQuery* aQuery,
     nsIApplicationReputationCallback* aCallback) {
-  LOG(("Starting application reputation check"));
+  LOG(("Starting application reputation check [query=%p]", aQuery));
   NS_ENSURE_ARG_POINTER(aQuery);
   NS_ENSURE_ARG_POINTER(aCallback);
 
   Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_COUNT, true);
   nsresult rv = QueryReputationInternal(aQuery, aCallback);
   if (NS_FAILED(rv)) {
     Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SHOULD_BLOCK,
       false);
--- a/toolkit/components/downloads/test/unit/test_app_rep.js
+++ b/toolkit/components/downloads/test/unit/test_app_rep.js
@@ -63,21 +63,25 @@ function run_test() {
                              "http://localhost:4444/download");
   // Ensure safebrowsing is enabled for this test, even if the app
   // doesn't have it enabled.
   Services.prefs.setBoolPref("browser.safebrowsing.malware.enabled", true);
   do_register_cleanup(function() {
     Services.prefs.clearUserPref("browser.safebrowsing.malware.enabled");
   });
 
-  // Set download_block_table explicitly.
+  // Set block and allow tables explicitly, since the allowlist is normally
+  // disabled on non-Windows platforms.
   Services.prefs.setCharPref("urlclassifier.downloadBlockTable",
                              "goog-badbinurl-shavar");
+  Services.prefs.setCharPref("urlclassifier.downloadAllowTable",
+                             "goog-downloadwhite-digest256");
   do_register_cleanup(function() {
     Services.prefs.clearUserPref("urlclassifier.downloadBlockTable");
+    Services.prefs.clearUserPref("urlclassifier.downloadAllowTable");
   });
 
   gHttpServ = new HttpServer();
   gHttpServ.registerDirectory("/", do_get_cwd());
   gHttpServ.registerPathHandler("/download", function(request, response) {
     do_throw("This test should never make a remote lookup");
   });
   gHttpServ.start(4444);
@@ -92,19 +96,23 @@ function check_telemetry(aCount,
                 .getService(Ci.nsITelemetry)
                 .getHistogramById("APPLICATION_REPUTATION_COUNT")
                 .snapshot();
   do_check_eq(count.counts[1], aCount);
   let local = Cc["@mozilla.org/base/telemetry;1"]
                 .getService(Ci.nsITelemetry)
                 .getHistogramById("APPLICATION_REPUTATION_LOCAL")
                 .snapshot();
-  do_check_eq(local.counts[ALLOW_LIST], aListCounts[ALLOW_LIST]);
-  do_check_eq(local.counts[BLOCK_LIST], aListCounts[BLOCK_LIST]);
-  do_check_eq(local.counts[NO_LIST], aListCounts[NO_LIST]);
+  do_check_eq(local.counts[ALLOW_LIST], aListCounts[ALLOW_LIST],
+              "Allow list counts don't match");
+  do_check_eq(local.counts[BLOCK_LIST], aListCounts[BLOCK_LIST],
+              "Block list counts don't match");
+  do_check_eq(local.counts[NO_LIST], aListCounts[NO_LIST],
+              "No list counts don't match");
+
   let shouldBlock = Cc["@mozilla.org/base/telemetry;1"]
                 .getService(Ci.nsITelemetry)
                 .getHistogramById("APPLICATION_REPUTATION_SHOULD_BLOCK")
                 .snapshot();
   // SHOULD_BLOCK = true
   do_check_eq(shouldBlock.counts[1], aShouldBlockCount);
   // Sanity check that SHOULD_BLOCK total adds up to the COUNT.
   do_check_eq(shouldBlock.counts[0] + shouldBlock.counts[1], aCount);
@@ -195,19 +203,19 @@ add_test(function test_local_list() {
     response.bodyOutputStream.write(blob, blob.length);
   });
 
   let streamUpdater = Cc["@mozilla.org/url-classifier/streamupdater;1"]
     .getService(Ci.nsIUrlClassifierStreamUpdater);
   streamUpdater.updateUrl = "http://localhost:4444/downloads";
 
   // Load up some update chunks for the safebrowsing server to serve.
-  // This chunk contains the hash of whitelisted.com/.
+  // This chunk contains the hash of blocklisted.com/.
   registerTableUpdate("goog-badbinurl-shavar", "data/block_digest.chunk");
-  // This chunk contains the hash of blocklisted.com/.
+  // This chunk contains the hash of whitelisted.com/.
   registerTableUpdate("goog-downloadwhite-digest256", "data/digest.chunk");
 
   // Download some updates, and don't continue until the downloads are done.
   function updateSuccess(aEvent) {
     // Timeout of n:1000 is constructed in processUpdateRequest above and
     // passed back in the callback in nsIUrlClassifierStreamUpdater on success.
     do_check_eq("1000", aEvent);
     do_print("All data processed");
@@ -294,25 +302,26 @@ add_test(function test_blocklist_trumps_
 });
 
 add_test(function test_redirect_on_blocklist() {
   Services.prefs.setCharPref("browser.safebrowsing.appRepURL",
                              "http://localhost:4444/download");
   let counts = get_telemetry_counts();
   let listCounts = counts.listCounts;
   listCounts[BLOCK_LIST]++;
+  listCounts[ALLOW_LIST]++;
   let secman = Services.scriptSecurityManager;
   let badRedirects = Cc["@mozilla.org/array;1"]
                        .createInstance(Ci.nsIMutableArray);
-  badRedirects.appendElement(secman.getNoAppCodebasePrincipal(whitelistedURI),
-                             false);
   badRedirects.appendElement(secman.getNoAppCodebasePrincipal(exampleURI),
                              false);
   badRedirects.appendElement(secman.getNoAppCodebasePrincipal(blocklistedURI),
                              false);
+  badRedirects.appendElement(secman.getNoAppCodebasePrincipal(whitelistedURI),
+                             false);
   gAppRep.queryReputation({
     sourceURI: whitelistedURI,
     referrerURI: exampleURI,
     redirects: badRedirects,
     fileSize: 12,
   }, function onComplete(aShouldBlock, aStatus) {
     do_check_eq(Cr.NS_OK, aStatus);
     do_check_true(aShouldBlock);
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -5903,16 +5903,34 @@
   "NETWORK_CACHE_V1_HIT_TIME_MS": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "10000",
     "n_buckets": 50,
     "extended_statistics_ok": true,
     "description": "Time spent to open an existing cache entry"
   },
+  "SQLITEBRIDGE_PROVIDER_PASSWORDS_LOCKED": {
+    "expires_in_version": "never",
+    "kind": "enumerated",
+    "n_values": "10",
+    "description": "The number of errors using the PasswordsProvider due to a locked DB."
+  },
+  "SQLITEBRIDGE_PROVIDER_FORMS_LOCKED": {
+    "expires_in_version": "never",
+    "kind": "enumerated",
+    "n_values": "10",
+    "description": "The number of errors using the FormHistoryProvider due to a locked DB."
+  },
+  "SQLITEBRIDGE_PROVIDER_HOME_LOCKED": {
+    "expires_in_version": "never",
+    "kind": "enumerated",
+    "n_values": "10",
+    "description": "The number of errors using the HomeProvider due to a locked DB."
+  },
   "SSL_TLS12_INTOLERANCE_REASON_PRE": {
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 64,
     "description": "detected symptom of TLS 1.2 intolerance, before considering historical info"
   },
   "SSL_TLS12_INTOLERANCE_REASON_POST": {
     "expires_in_version": "never",
--- a/toolkit/components/url-classifier/LookupCache.cpp
+++ b/toolkit/components/url-classifier/LookupCache.cpp
@@ -176,17 +176,17 @@ LookupCache::Build(AddPrefixArray& aAddP
 void
 LookupCache::Dump()
 {
   if (!LOG_ENABLED())
     return;
 
   for (uint32_t i = 0; i < mCompletions.Length(); i++) {
     nsAutoCString str;
-    mCompletions[i].ToString(str);
+    mCompletions[i].ToHexString(str);
     LOG(("Completion: %s", str.get()));
   }
 }
 #endif
 
 nsresult
 LookupCache::Has(const Completion& aCompletion,
                  bool* aHas, bool* aComplete)