Merge inbound to mozilla-central. a=merge
authorCiure Andrei <aciure@mozilla.com>
Thu, 05 Jul 2018 12:51:41 +0300
changeset 425152 085cdfb90903d4985f0de1dc7786522d9fb45596
parent 425140 1dad493abb2dc49890a5d6a23340afa0719efd96 (current diff)
parent 425151 78d32cf0c528ae55319aa20ea69539230e0969cc (diff)
child 425159 896729f4adcc934e5ad3d1c8e423e95be1c024e4
child 425181 35ae03d7cf2db9da4ab5ca26254d81414833cada
push id34236
push useraciure@mozilla.com
push dateThu, 05 Jul 2018 09:52:07 +0000
treeherdermozilla-central@085cdfb90903 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
085cdfb90903 / 63.0a1 / 20180705100105 / files
nightly linux64
085cdfb90903 / 63.0a1 / 20180705100105 / files
nightly mac
085cdfb90903 / 63.0a1 / 20180705100105 / files
nightly win32
085cdfb90903 / 63.0a1 / 20180705100105 / files
nightly win64
085cdfb90903 / 63.0a1 / 20180705100105 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
layout/style/nsComputedDOMStyle.cpp
testing/web-platform/meta/content-security-policy/script-src/script-src-1_4.html.ini
--- a/browser/base/content/test/performance/browser_startup_content.js
+++ b/browser/base/content/test/performance/browser_startup_content.js
@@ -37,17 +37,16 @@ const whitelist = {
     "resource://gre/modules/FileUtils.jsm",
     "resource://gre/modules/NetUtil.jsm",
     "resource://gre/modules/PromiseUtils.jsm",
     "resource://gre/modules/Services.jsm", // bug 1464542
     "resource://gre/modules/Timer.jsm",
     "resource://gre/modules/XPCOMUtils.jsm",
 
     // Logging related
-    "resource://gre/modules/Console.jsm", // bug 1470333
     "resource://gre/modules/Log.jsm",
 
     // Session store
     "resource:///modules/sessionstore/ContentRestore.jsm",
     "resource://gre/modules/sessionstore/SessionHistory.jsm",
 
     // Forms and passwords
     "resource://formautofill/FormAutofillContent.jsm",
--- a/browser/extensions/formautofill/FormAutofillContent.jsm
+++ b/browser/extensions/formautofill/FormAutofillContent.jsm
@@ -93,17 +93,17 @@ AutofillProfileAutoCompleteSearch.protot
    * @param {string} searchParam
    * @param {Object} previousResult a previous result to use for faster searchinig
    * @param {Object} listener the listener to notify when the search is complete
    */
   startSearch(searchString, searchParam, previousResult, listener) {
     let {activeInput, activeSection, activeFieldDetail, savedFieldNames} = FormAutofillContent;
     this.forceStop = false;
 
-    this.log.debug("startSearch: for", searchString, "with input", activeInput);
+    this.debug("startSearch: for", searchString, "with input", activeInput);
 
     let isAddressField = FormAutofillUtils.isAddressField(activeFieldDetail.fieldName);
     let isInputAutofilled = activeFieldDetail.state == FIELD_STATES.AUTO_FILLED;
     let allFieldNames = activeSection.allFieldNames;
     let filledRecordGUID = activeSection.filledRecordGUID;
     let searchPermitted = isAddressField ?
                           FormAutofillUtils.isAutofillAddressesEnabled :
                           FormAutofillUtils.isAutofillCreditCardsEnabled;
@@ -191,17 +191,17 @@ AutofillProfileAutoCompleteSearch.protot
    * @param  {string} data.searchString
    *         The typed string for filtering out the matched records.
    * @param  {string} data.info
    *         The input autocomplete property's information.
    * @returns {Promise}
    *          Promise that resolves when addresses returned from parent process.
    */
   _getRecords(data) {
-    this.log.debug("_getRecords with data:", data);
+    this.debug("_getRecords with data:", data);
     return new Promise((resolve) => {
       Services.cpmm.addMessageListener("FormAutofill:Records", function getResult(result) {
         Services.cpmm.removeMessageListener("FormAutofill:Records", getResult);
         resolve(result.data);
       });
 
       Services.cpmm.sendAsyncMessage("FormAutofill:GetRecords", data);
     });
@@ -217,30 +217,30 @@ let ProfileAutocomplete = {
   _factory: null,
 
   ensureRegistered() {
     if (this._registered) {
       return;
     }
 
     FormAutofillUtils.defineLazyLogGetter(this, "ProfileAutocomplete");
-    this.log.debug("ensureRegistered");
+    this.debug("ensureRegistered");
     this._factory = new AutocompleteFactory();
     this._factory.register(AutofillProfileAutoCompleteSearch);
     this._registered = true;
 
     Services.obs.addObserver(this, "autocomplete-will-enter-text");
   },
 
   ensureUnregistered() {
     if (!this._registered) {
       return;
     }
 
-    this.log.debug("ensureUnregistered");
+    this.debug("ensureUnregistered");
     this._factory.unregister();
     this._factory = null;
     this._registered = false;
     this._lastAutoCompleteResult = null;
 
     Services.obs.removeObserver(this, "autocomplete-will-enter-text");
   },
 
@@ -270,17 +270,17 @@ let ProfileAutocomplete = {
     if (selectedIndexResult.length != 1 || !Number.isInteger(selectedIndexResult[0])) {
       throw new Error("Invalid autocomplete selectedIndex");
     }
 
     return selectedIndexResult[0];
   },
 
   _fillFromAutocompleteRow(focusedInput) {
-    this.log.debug("_fillFromAutocompleteRow:", focusedInput);
+    this.debug("_fillFromAutocompleteRow:", focusedInput);
     let formDetails = FormAutofillContent.activeFormDetails;
     if (!formDetails) {
       // The observer notification is for a different frame.
       return;
     }
 
     let selectedIndex = this._getSelectedIndex(focusedInput.ownerGlobal);
     if (selectedIndex == -1 ||
@@ -383,31 +383,31 @@ var FormAutofillContent = {
    * 3. Number of filled fields is less than autofill threshold
    *
    * @param {HTMLElement} formElement Root element which receives earlyformsubmit event.
    * @param {Object} domWin Content window
    * @returns {boolean} Should always return true so form submission isn't canceled.
    */
   notify(formElement, domWin) {
     try {
-      this.log.debug("Notifying form early submission");
+      this.debug("Notifying form early submission");
 
       if (!FormAutofillUtils.isAutofillEnabled) {
-        this.log.debug("Form Autofill is disabled");
+        this.debug("Form Autofill is disabled");
         return true;
       }
 
       if (domWin && PrivateBrowsingUtils.isContentWindowPrivate(domWin)) {
-        this.log.debug("Ignoring submission in a private window");
+        this.debug("Ignoring submission in a private window");
         return true;
       }
 
       let handler = this._formsDetails.get(formElement);
       if (!handler) {
-        this.log.debug("Form element could not map to an existing handler");
+        this.debug("Form element could not map to an existing handler");
         return true;
       }
 
       let records = handler.createRecords();
       if (!Object.values(records).some(typeRecords => typeRecords.length)) {
         return true;
       }
 
@@ -525,36 +525,36 @@ var FormAutofillContent = {
           break;
         }
       }
     }
     return this._activeItems.fieldDetail;
   },
 
   identifyAutofillFields(element) {
-    this.log.debug("identifyAutofillFields:", "" + element.ownerDocument.location);
+    this.debug("identifyAutofillFields:", String(element.ownerDocument.location));
 
     if (!this.savedFieldNames) {
-      this.log.debug("identifyAutofillFields: savedFieldNames are not known yet");
+      this.debug("identifyAutofillFields: savedFieldNames are not known yet");
       Services.cpmm.sendAsyncMessage("FormAutofill:InitStorage");
     }
 
     let formHandler = this._getFormHandler(element);
     if (!formHandler) {
       let formLike = FormLikeFactory.createFromField(element);
       formHandler = new FormAutofillHandler(formLike);
     } else if (!formHandler.updateFormIfNeeded(element)) {
-      this.log.debug("No control is removed or inserted since last collection.");
+      this.debug("No control is removed or inserted since last collection.");
       return;
     }
 
     let validDetails = formHandler.collectFormFields();
 
     this._formsDetails.set(formHandler.form.rootElement, formHandler);
-    this.log.debug("Adding form handler to _formsDetails:", formHandler);
+    this.debug("Adding form handler to _formsDetails:", formHandler);
 
     validDetails.forEach(detail =>
       this._markAsAutofillField(detail.elementWeakRef.get())
     );
   },
 
   clearForm() {
     let focusedInput = this.activeInput || ProfileAutocomplete._lastAutoCompleteFocusedInput;
--- a/browser/extensions/formautofill/FormAutofillUtils.jsm
+++ b/browser/extensions/formautofill/FormAutofillUtils.jsm
@@ -40,16 +40,36 @@ const SECTION_TYPES = {
 // attacks that fill the user's hard drive(s).
 const MAX_FIELD_VALUE_LENGTH = 200;
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.defineModuleGetter(this, "CreditCard",
   "resource://gre/modules/CreditCard.jsm");
 
+XPCOMUtils.defineLazyPreferenceGetter(this, "logLevel", "extensions.formautofill.loglevel",
+                                      "Warn");
+
+// A logging helper for debug logging to avoid creating Console objects
+// or triggering expensive JS -> C++ calls when debug logging is not
+// enabled.
+//
+// Console objects, even natively-implemented ones, can consume a lot of
+// memory, and since this code may run in every content process, that
+// memory can add up quickly. And, even when debug-level messages are
+// being ignored, console.debug() calls can be expensive.
+//
+// This helper avoids both of those problems by never touching the
+// console object unless debug logging is enabled.
+function debug() {
+  if (logLevel == "debug") {
+    this.log.debug(...arguments);
+  }
+}
+
 let AddressDataLoader = {
   // Status of address data loading. We'll load all the countries with basic level 1
   // information while requesting conutry information, and set country to true.
   // Level 1 Set is for recording which country's level 1/level 2 data is loaded,
   // since we only load this when getCountryAddressData called with level 1 parameter.
   _dataLoaded: {
     country: false,
     level1: new Set(),
@@ -333,16 +353,18 @@ this.FormAutofillUtils = {
     for (let field in address) {
       if (field != "tel" && this.getCategoryFromFieldName(field) == "tel") {
         delete address[field];
       }
     }
   },
 
   defineLazyLogGetter(scope, logPrefix) {
+    scope.debug = debug;
+
     XPCOMUtils.defineLazyGetter(scope, "log", () => {
       let ConsoleAPI = ChromeUtils.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
       return new ConsoleAPI({
         maxLogLevelPref: "extensions.formautofill.loglevel",
         prefix: logPrefix,
       });
     });
   },
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -491,30 +491,33 @@ nsScriptSecurityManager::ContentSecurity
     {
         NS_WARNING("CSP: failed to get allowsEval");
         return true; // fail open to not break sites.
     }
 
     if (reportViolation) {
         nsAutoString fileName;
         unsigned lineNum = 0;
+        unsigned columnNum = 0;
         NS_NAMED_LITERAL_STRING(scriptSample, "call to eval() or related function blocked by CSP");
 
         JS::AutoFilename scriptFilename;
-        if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum)) {
+        if (JS::DescribeScriptedCaller(cx, &scriptFilename, &lineNum,
+                                       &columnNum)) {
             if (const char *file = scriptFilename.get()) {
                 CopyUTF8toUTF16(nsDependentCString(file), fileName);
             }
         } else {
             MOZ_ASSERT(!JS_IsExceptionPending(cx));
         }
         csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
                                  fileName,
                                  scriptSample,
                                  lineNum,
+                                 columnNum,
                                  EmptyString(),
                                  EmptyString());
     }
 
     return evalOK;
 }
 
 // static
--- a/dom/animation/DocumentTimeline.cpp
+++ b/dom/animation/DocumentTimeline.cpp
@@ -237,16 +237,21 @@ DocumentTimeline::NotifyRefreshDriverCre
              "Timeline should not be observing the refresh driver before"
              " it is created");
 
   if (!mAnimationOrder.isEmpty()) {
     MOZ_ASSERT(isInList(),
                "We should not register with the refresh driver if we are not"
                " in the document's list of timelines");
     ObserveRefreshDriver(aDriver);
+    // Although we have started observing the refresh driver, it's possible we
+    // could perform a paint before the first refresh driver tick happens.  To
+    // ensure we're in a consistent state in that case we run the first tick
+    // manually.
+    MostRecentRefreshTimeUpdated();
   }
 }
 
 void
 DocumentTimeline::DisconnectRefreshDriver(nsRefreshDriver* aDriver)
 {
   MOZ_ASSERT(mIsObservingRefreshDriver);
 
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -11944,16 +11944,17 @@ nsIDocument::InlineScriptAllowedByCSP()
   NS_ENSURE_SUCCESS(rv, true);
   bool allowsInlineScript = true;
   if (csp) {
     nsresult rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
                                        EmptyString(), // aNonce
                                        true,          // aParserCreated
                                        nullptr, // FIXME get script sample (bug 1314567)
                                        0,             // aLineNumber
+                                       0,             // aColumnNumber
                                        &allowsInlineScript);
     NS_ENSURE_SUCCESS(rv, true);
   }
   return allowsInlineScript;
 }
 
 static bool
 ReportExternalResourceUseCounters(nsIDocument* aDocument, void* aData)
--- a/dom/base/nsIStyleSheetLinkingElement.h
+++ b/dom/base/nsIStyleSheetLinkingElement.h
@@ -197,14 +197,27 @@ public:
 
   /**
    * Get the line number, as previously set by SetLineNumber.
    *
    * @return the line number of this element; or 1 if no line number
    *         was set
    */
   virtual uint32_t GetLineNumber() = 0;
+
+  // This doesn't entirely belong here since they only make sense for
+  // some types of linking elements, but it's a better place than
+  // anywhere else.
+  virtual void SetColumnNumber(uint32_t aColumnNumber) = 0;
+
+  /**
+   * Get the column number, as previously set by SetColumnNumber.
+   *
+   * @return the column number of this element; or 1 if no column number
+   *         was set
+   */
+  virtual uint32_t GetColumnNumber() = 0;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleSheetLinkingElement,
                               NS_ISTYLESHEETLINKINGELEMENT_IID)
 
 #endif // nsILinkingElement_h__
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -193,23 +193,25 @@ CheckCSPForEval(JSContext* aCx, nsGlobal
 
   if (reportViolation) {
     // TODO : need actual script sample in violation report.
     NS_NAMED_LITERAL_STRING(scriptSample,
                             "call to eval() or related function blocked by CSP");
 
     // Get the calling location.
     uint32_t lineNum = 0;
+    uint32_t columnNum = 0;
     nsAutoString fileNameString;
-    if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum)) {
+    if (!nsJSUtils::GetCallingLocation(aCx, fileNameString, &lineNum,
+                                       &columnNum)) {
       fileNameString.AssignLiteral("unknown");
     }
 
     csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
-                             fileNameString, scriptSample, lineNum,
+                             fileNameString, scriptSample, lineNum, columnNum,
                              EmptyString(), EmptyString());
   }
 
   return allowsEval;
 }
 
 nsJSScriptTimeoutHandler::nsJSScriptTimeoutHandler()
   : mLineNo(0)
--- a/dom/base/nsObjectLoadingContent.cpp
+++ b/dom/base/nsObjectLoadingContent.cpp
@@ -98,20 +98,20 @@
 // Thanks so much, Microsoft! :(
 #ifdef CreateEvent
 #undef CreateEvent
 #endif
 #endif // XP_WIN
 
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
-static const char *kPrefYoutubeRewrite = "plugins.rewrite_youtube_embeds";
-static const char *kPrefBlockURIs = "browser.safebrowsing.blockedURIs.enabled";
-static const char *kPrefFavorFallbackMode = "plugins.favorfallback.mode";
-static const char *kPrefFavorFallbackRules = "plugins.favorfallback.rules";
+static const char kPrefYoutubeRewrite[] = "plugins.rewrite_youtube_embeds";
+static const char kPrefBlockURIs[] = "browser.safebrowsing.blockedURIs.enabled";
+static const char kPrefFavorFallbackMode[] = "plugins.favorfallback.mode";
+static const char kPrefFavorFallbackRules[] = "plugins.favorfallback.rules";
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::net;
 
 static LogModule*
 GetObjectLog()
 {
--- a/dom/base/nsStyleLinkElement.cpp
+++ b/dom/base/nsStyleLinkElement.cpp
@@ -71,16 +71,17 @@ nsStyleLinkElement::SheetInfo::SheetInfo
 }
 
 nsStyleLinkElement::SheetInfo::~SheetInfo() = default;
 
 nsStyleLinkElement::nsStyleLinkElement()
   : mDontLoadStyle(false)
   , mUpdatesEnabled(true)
   , mLineNumber(1)
+  , mColumnNumber(1)
 {
 }
 
 nsStyleLinkElement::~nsStyleLinkElement()
 {
   nsStyleLinkElement::SetStyleSheet(nullptr);
 }
 
@@ -187,16 +188,28 @@ nsStyleLinkElement::SetLineNumber(uint32
 }
 
 /* virtual */ uint32_t
 nsStyleLinkElement::GetLineNumber()
 {
   return mLineNumber;
 }
 
+/* virtual */ void
+nsStyleLinkElement::SetColumnNumber(uint32_t aColumnNumber)
+{
+  mColumnNumber = aColumnNumber;
+}
+
+/* virtual */ uint32_t
+nsStyleLinkElement::GetColumnNumber()
+{
+  return mColumnNumber;
+}
+
 static uint32_t ToLinkMask(const nsAString& aLink)
 {
   // Keep this in sync with sRelValues in HTMLLinkElement.cpp
   if (aLink.EqualsLiteral("prefetch"))
     return nsStyleLinkElement::ePREFETCH;
   else if (aLink.EqualsLiteral("dns-prefetch"))
     return nsStyleLinkElement::eDNS_PREFETCH;
   else if (aLink.EqualsLiteral("stylesheet"))
@@ -376,17 +389,18 @@ nsStyleLinkElement::DoUpdateStyleSheet(n
     MOZ_ASSERT(thisContent->NodeInfo()->NameAtom() != nsGkAtoms::link,
                "<link> is not 'inline', and needs different CSP checks");
     MOZ_ASSERT(thisContent->IsElement());
     nsresult rv = NS_OK;
     if (!nsStyleUtil::CSPAllowsInlineStyle(thisContent->AsElement(),
                                            thisContent->NodePrincipal(),
                                            info->mTriggeringPrincipal,
                                            doc->GetDocumentURI(),
-                                           mLineNumber, text, &rv)) {
+                                           mLineNumber, mColumnNumber, text,
+                                           &rv)) {
       if (NS_FAILED(rv)) {
         return Err(rv);
       }
       return Update { };
     }
 
     // Parse the style sheet.
     return doc->CSSLoader()->LoadInlineStyle(*info, text, mLineNumber, aObserver);
--- a/dom/base/nsStyleLinkElement.h
+++ b/dom/base/nsStyleLinkElement.h
@@ -51,16 +51,18 @@ public:
     UpdateStyleSheet(nsICSSLoaderObserver*, ForceUpdate) override;
 
   void SetEnableUpdates(bool aEnableUpdates) override;
   void GetCharset(nsAString& aCharset) override;
 
   void OverrideBaseURI(nsIURI* aNewBaseURI) override;
   void SetLineNumber(uint32_t aLineNumber) override;
   uint32_t GetLineNumber() override;
+  void SetColumnNumber(uint32_t aColumnNumber) override;
+  uint32_t GetColumnNumber() override;
 
   enum RelValue {
     ePREFETCH =     0x00000001,
     eDNS_PREFETCH = 0x00000002,
     eSTYLESHEET =   0x00000004,
     eNEXT =         0x00000008,
     eALTERNATE =    0x00000010,
     ePRECONNECT =   0x00000020,
@@ -131,12 +133,13 @@ private:
                        ForceUpdate);
 
   RefPtr<mozilla::StyleSheet> mStyleSheet;
 protected:
   nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
   bool mDontLoadStyle;
   bool mUpdatesEnabled;
   uint32_t mLineNumber;
+  uint32_t mColumnNumber;
 };
 
 #endif /* nsStyleLinkElement_h___ */
 
--- a/dom/base/nsStyledElement.cpp
+++ b/dom/base/nsStyledElement.cpp
@@ -205,17 +205,17 @@ nsStyledElement::ParseStyleAttribute(con
                                      bool aForceInDataDoc)
 {
   nsIDocument* doc = OwnerDoc();
   bool isNativeAnon = IsInNativeAnonymousSubtree();
 
   if (!isNativeAnon &&
       !nsStyleUtil::CSPAllowsInlineStyle(nullptr, NodePrincipal(),
                                          aMaybeScriptedPrincipal,
-                                         doc->GetDocumentURI(), 0, aValue,
+                                         doc->GetDocumentURI(), 0, 0, aValue,
                                          nullptr))
     return;
 
   if (aForceInDataDoc ||
       !doc->IsLoadedAsData() ||
       GetExistingStyle() ||
       doc->IsStaticDocument()) {
     bool isCSS = true; // assume CSS until proven otherwise
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -879,16 +879,17 @@ EventListenerManager::SetEventHandler(ns
       }
 
       bool allowsInlineScript = true;
       rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
                                 EmptyString(), // aNonce
                                 true, // aParserCreated (true because attribute event handler)
                                 sampleIString,
                                 0,             // aLineNumber
+                                0,             // aColumnNumber
                                 &allowsInlineScript);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // return early if CSP wants us to block inline scripts
       if (!allowsInlineScript) {
         return NS_OK;
       }
     }
--- a/dom/html/HTMLScriptElement.cpp
+++ b/dom/html/HTMLScriptElement.cpp
@@ -226,26 +226,26 @@ HTMLScriptElement::FreezeExecutionAttrs(
 
       if (!mUri) {
         const char16_t* params[] = { u"src", src.get() };
 
         nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
           NS_LITERAL_CSTRING("HTML"), OwnerDoc(),
           nsContentUtils::eDOM_PROPERTIES, "ScriptSourceInvalidUri",
           params, ArrayLength(params), nullptr,
-          EmptyString(), GetScriptLineNumber());
+          EmptyString(), GetScriptLineNumber(), GetScriptColumnNumber());
       }
     } else {
       const char16_t* params[] = { u"src" };
 
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
         NS_LITERAL_CSTRING("HTML"), OwnerDoc(),
         nsContentUtils::eDOM_PROPERTIES, "ScriptSourceEmpty",
         params, ArrayLength(params), nullptr,
-        EmptyString(), GetScriptLineNumber());
+        EmptyString(), GetScriptLineNumber(), GetScriptColumnNumber());
     }
 
     // At this point mUri will be null for invalid URLs.
     mExternal = true;
   }
 
   bool async = (mExternal || mIsModule) && Async();
   bool defer = mExternal && Defer();
--- a/dom/interfaces/security/nsIContentSecurityPolicy.idl
+++ b/dom/interfaces/security/nsIContentSecurityPolicy.idl
@@ -122,25 +122,28 @@ interface nsIContentSecurityPolicy : nsI
    * @param aContentPolicyType Either TYPE_SCRIPT or TYPE_STYLESHEET
    * @param aNonce The nonce string to check against the policy
    * @param aParserCreated If the script element was created by the HTML Parser
    * @param aElementOrContent The script element of the inline resource to hash
    *        or the content of the psuedo-script to compare to hash
    *        (and compare to the hashes listed in the policy)
    * @param aLineNumber The line number of the inline resource
    *        (used for reporting)
+   * @param aColumnNumber The column number of the inline resource
+   *        (used for reporting)
    * @return
    *     Whether or not the effects of the inline style should be allowed
    *     (block the rules if false).
    */
   boolean getAllowsInline(in nsContentPolicyType aContentPolicyType,
                           in AString aNonce,
                           in boolean aParserCreated,
                           in nsISupports aElementOrContent,
-                          in unsigned long aLineNumber);
+                          in unsigned long aLineNumber,
+                          in unsigned long aColumnNumber);
 
   /**
    * whether this policy allows eval and eval-like functions
    * such as setTimeout("code string", time).
    * @param shouldReportViolations
    *     Whether or not the use of eval should be reported.
    *     This function returns "true" when violating report-only policies, but
    *     when any policy (report-only or otherwise) is violated,
@@ -170,30 +173,33 @@ interface nsIContentSecurityPolicy : nsI
    * @param violationType
    *     one of the VIOLATION_TYPE_* constants, e.g. inline-script or eval
    * @param sourceFile
    *     name of the source file containing the violation (if available)
    * @param contentSample
    *     sample of the violating content (to aid debugging)
    * @param lineNum
    *     source line number of the violation (if available)
+   * @param columnNum
+   *     source column number of the violation (if available)
    * @param aNonce
    *     (optional) If this is a nonce violation, include the nonce so we can
    *     recheck to determine which policies were violated and send the
    *     appropriate reports.
    * @param aContent
    *     (optional) If this is a hash violation, include contents of the inline
    *     resource in the question so we can recheck the hash in order to
    *     determine which policies were violated and send the appropriate
    *     reports.
    */
   void logViolationDetails(in unsigned short violationType,
                            in AString sourceFile,
                            in AString scriptSample,
                            in int32_t lineNum,
+                           in int32_t columnNum,
                            [optional] in AString nonce,
                            [optional] in AString content);
 
   const unsigned short VIOLATION_TYPE_INLINE_SCRIPT          = 1;
   const unsigned short VIOLATION_TYPE_EVAL                   = 2;
   const unsigned short VIOLATION_TYPE_INLINE_STYLE           = 3;
   const unsigned short VIOLATION_TYPE_NONCE_SCRIPT           = 4;
   const unsigned short VIOLATION_TYPE_NONCE_STYLE            = 5;
--- a/dom/jsurl/nsJSProtocolHandler.cpp
+++ b/dom/jsurl/nsJSProtocolHandler.cpp
@@ -177,16 +177,17 @@ nsresult nsJSThunk::EvaluateScript(nsICh
     NS_ENSURE_SUCCESS(rv, rv);
     if (csp) {
         bool allowsInlineScript = true;
         rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
                                   EmptyString(), // aNonce
                                   true,         // aParserCreated
                                   nullptr, // aContent
                                   0,             // aLineNumber
+                                  0,             // aColumnNumber
                                   &allowsInlineScript);
 
         //return early if inline scripts are not allowed
         if (!allowsInlineScript) {
           return NS_ERROR_DOM_RETVAL_UNDEFINED;
         }
     }
 
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -2011,40 +2011,34 @@ PluginOfflineObserver::Observe(nsISuppor
                                const char *aTopic,
                                const char16_t *aData)
 {
     MOZ_ASSERT(!strcmp(aTopic, "ipc:network:set-offline"));
     mPmp->CachedSettingChanged();
     return NS_OK;
 }
 
-static const char* kSettingsPrefs[] =
-    {"javascript.enabled",
-     "dom.ipc.plugins.nativeCursorSupport"};
-
 void
 PluginModuleChromeParent::RegisterSettingsCallbacks()
 {
-    for (size_t i = 0; i < ArrayLength(kSettingsPrefs); i++) {
-        Preferences::RegisterCallback(CachedSettingChanged, kSettingsPrefs[i], this);
-    }
+    Preferences::RegisterCallback(CachedSettingChanged, "javascript.enabled", this);
+    Preferences::RegisterCallback(CachedSettingChanged, "dom.ipc.plugins.nativeCursorSupport", this);
 
     nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
     if (observerService) {
         mPluginOfflineObserver = new PluginOfflineObserver(this);
         observerService->AddObserver(mPluginOfflineObserver, "ipc:network:set-offline", false);
     }
 }
 
 void
 PluginModuleChromeParent::UnregisterSettingsCallbacks()
 {
-    for (size_t i = 0; i < ArrayLength(kSettingsPrefs); i++) {
-        Preferences::UnregisterCallback(CachedSettingChanged, kSettingsPrefs[i], this);
-    }
+    Preferences::UnregisterCallback(CachedSettingChanged, "javascript.enabled", this);
+    Preferences::UnregisterCallback(CachedSettingChanged, "dom.ipc.plugins.nativeCursorSupport", this);
 
     nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
     if (observerService) {
         observerService->RemoveObserver(mPluginOfflineObserver, "ipc:network:set-offline");
         mPluginOfflineObserver = nullptr;
     }
 }
 
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -1220,16 +1220,17 @@ CSPAllowsInlineScript(nsIScriptElement* 
   nsAutoString nonce;
   scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
   bool parserCreated = aElement->GetParserCreated() != mozilla::dom::NOT_FROM_PARSER;
 
   bool allowInlineScript = false;
   rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
                             nonce, parserCreated, aElement,
                             aElement->GetScriptLineNumber(),
+                            aElement->GetScriptColumnNumber(),
                             &allowInlineScript);
   return allowInlineScript;
 }
 
 ScriptLoadRequest*
 ScriptLoader::CreateLoadRequest(ScriptKind aKind,
                                 nsIURI* aURI,
                                 nsIScriptElement* aElement,
@@ -2863,20 +2864,21 @@ ScriptLoader::VerifySRI(ScriptLoadReques
     if (loadInfo && loadInfo->GetEnforceSRI()) {
       MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
               ("ScriptLoader::OnStreamComplete, required SRI not found"));
       nsCOMPtr<nsIContentSecurityPolicy> csp;
       loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp));
       nsAutoCString violationURISpec;
       mDocument->GetDocumentURI()->GetAsciiSpec(violationURISpec);
       uint32_t lineNo = aRequest->mElement ? aRequest->mElement->GetScriptLineNumber() : 0;
+      uint32_t columnNo = aRequest->mElement ? aRequest->mElement->GetScriptColumnNumber() : 0;
       csp->LogViolationDetails(
         nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT,
         NS_ConvertUTF8toUTF16(violationURISpec),
-        EmptyString(), lineNo, EmptyString(), EmptyString());
+        EmptyString(), lineNo, columnNo, EmptyString(), EmptyString());
       rv = NS_ERROR_SRI_CORRUPT;
     }
   }
 
   return rv;
 }
 
 nsresult
@@ -2948,22 +2950,23 @@ ScriptLoader::ReportErrorToConsole(Scrip
     message =
       isScript ? "ScriptSourceLoadFailed" : "ModuleSourceLoadFailed";
   }
 
   NS_ConvertUTF8toUTF16 url(aRequest->mURI->GetSpecOrDefault());
   const char16_t* params[] = { url.get() };
 
   uint32_t lineNo = aRequest->mElement->GetScriptLineNumber();
+  uint32_t columnNo = aRequest->mElement->GetScriptColumnNumber();
 
   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                   NS_LITERAL_CSTRING("Script Loader"), mDocument,
                                   nsContentUtils::eDOM_PROPERTIES, message,
                                   params, ArrayLength(params), nullptr,
-                                  EmptyString(), lineNo);
+                                  EmptyString(), lineNo, columnNo);
 }
 
 void
 ScriptLoader::HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult)
 {
   /*
    * Handle script not loading error because source was a tracking URL.
    * We make a note of this script node by including it in a dedicated
--- a/dom/script/nsIScriptElement.h
+++ b/dom/script/nsIScriptElement.h
@@ -27,16 +27,17 @@
  */
 class nsIScriptElement : public nsIScriptLoaderObserver
 {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID)
 
   explicit nsIScriptElement(mozilla::dom::FromParser aFromParser)
     : mLineNumber(1),
+      mColumnNumber(1),
       mAlreadyStarted(false),
       mMalformed(false),
       mDoneAddingChildren(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
                           aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
       mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
                   aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
       mFrozen(false),
       mIsModule(false),
@@ -141,16 +142,26 @@ public:
     mLineNumber = aLineNumber;
   }
 
   uint32_t GetScriptLineNumber()
   {
     return mLineNumber;
   }
 
+  void SetScriptColumnNumber(uint32_t aColumnNumber)
+  {
+    mColumnNumber = aColumnNumber;
+  }
+
+  uint32_t GetScriptColumnNumber()
+  {
+    return mColumnNumber;
+  }
+
   void SetIsMalformed()
   {
     mMalformed = true;
   }
 
   bool IsMalformed()
   {
     return mMalformed;
@@ -293,16 +304,21 @@ protected:
   virtual bool GetAsyncState() = 0;
 
   /**
    * The start line number of the script.
    */
   uint32_t mLineNumber;
 
   /**
+   * The start column number of the script.
+   */
+  uint32_t mColumnNumber;
+
+  /**
    * The "already started" flag per HTML5.
    */
   bool mAlreadyStarted;
 
   /**
    * The script didn't have an end tag.
    */
   bool mMalformed;
--- a/dom/security/nsCSPContext.cpp
+++ b/dom/security/nsCSPContext.cpp
@@ -272,17 +272,18 @@ nsCSPContext::permitsInternal(CSPDirecti
         this->AsyncReportViolation((aSendContentLocationInViolationReports ?
                                     aContentLocation : nullptr),
                                    aOriginalURI,  /* in case of redirect originalURI is not null */
                                    violatedDirective,
                                    p,             /* policy index        */
                                    EmptyString(), /* no observer subject */
                                    EmptyString(), /* no source file      */
                                    EmptyString(), /* no script sample    */
-                                   0);            /* no line number      */
+                                   0,             /* no line number      */
+                                   0);            /* no column number    */
       }
     }
   }
 
   return permits;
 }
 
 
@@ -452,17 +453,18 @@ nsCSPContext::GetAllowsEval(bool* outSho
 
 // Helper function to report inline violations
 void
 nsCSPContext::reportInlineViolation(nsContentPolicyType aContentType,
                                     const nsAString& aNonce,
                                     const nsAString& aContent,
                                     const nsAString& aViolatedDirective,
                                     uint32_t aViolatedPolicyIndex, // TODO, use report only flag for that
-                                    uint32_t aLineNumber)
+                                    uint32_t aLineNumber,
+                                    uint32_t aColumnNumber)
 {
   nsString observerSubject;
   // if the nonce is non empty, then we report the nonce error, otherwise
   // let's report the hash error; no need to report the unsafe-inline error
   // anymore.
   if (!aNonce.IsEmpty()) {
     observerSubject = (aContentType == nsIContentPolicy::TYPE_SCRIPT)
                       ? NS_LITERAL_STRING(SCRIPT_NONCE_VIOLATION_OBSERVER_TOPIC)
@@ -494,25 +496,27 @@ nsCSPContext::reportInlineViolation(nsCo
   }
   AsyncReportViolation(selfISupports,                      // aBlockedContentSource
                        mSelfURI,                           // aOriginalURI
                        aViolatedDirective,                 // aViolatedDirective
                        aViolatedPolicyIndex,               // aViolatedPolicyIndex
                        observerSubject,                    // aObserverSubject
                        NS_ConvertUTF8toUTF16(sourceFile),  // aSourceFile
                        codeSample,                         // aScriptSample
-                       aLineNumber);                       // aLineNum
+                       aLineNumber,                        // aLineNum
+                       aColumnNumber);                     // aColumnNum
 }
 
 NS_IMETHODIMP
 nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
                               const nsAString& aNonce,
                               bool aParserCreated,
                               nsISupports* aElementOrContent,
                               uint32_t aLineNumber,
+                              uint32_t aColumnNumber,
                               bool* outAllowsInline)
 {
   *outAllowsInline = true;
 
   MOZ_ASSERT(aContentType == nsContentUtils::InternalContentPolicyTypeToExternal(aContentType),
              "We should only see external content policy types here.");
 
   if (aContentType != nsIContentPolicy::TYPE_SCRIPT &&
@@ -560,17 +564,18 @@ nsCSPContext::GetAllowsInline(nsContentP
       }
       nsAutoString violatedDirective;
       mPolicies[i]->getDirectiveStringForContentType(aContentType, violatedDirective);
       reportInlineViolation(aContentType,
                             aNonce,
                             content,
                             violatedDirective,
                             i,
-                            aLineNumber);
+                            aLineNumber,
+                            aColumnNumber);
     }
   }
   return NS_OK;
 }
 
 
 /**
  * Reduces some code repetition for the various logging situations in
@@ -579,17 +584,18 @@ nsCSPContext::GetAllowsInline(nsContentP
  * Call-sites for the eval/inline checks recieve two return values: allows
  * and violates.  Based on those, they must choose whether to call
  * LogViolationDetails or not.  Policies that are report-only allow the
  * loads/compilations but violations should still be reported.  Not all
  * policies in this nsIContentSecurityPolicy instance will be violated,
  * which is why we must check allows() again here.
  *
  * Note: This macro uses some parameters from its caller's context:
- * p, mPolicies, this, aSourceFile, aScriptSample, aLineNum, selfISupports
+ * p, mPolicies, this, aSourceFile, aScriptSample, aLineNum, aColumnNum,
+ * selfISupports
  *
  * @param violationType: the VIOLATION_TYPE_* constant (partial symbol)
  *                 such as INLINE_SCRIPT
  * @param contentPolicyType: a constant from nsIContentPolicy such as TYPE_STYLESHEET
  * @param nonceOrHash: for NONCE and HASH violations, it's the nonce or content
  *               string. For other violations, it is an empty string.
  * @param keyword: the keyword corresponding to violation (UNSAFE_INLINE for most)
  * @param observerTopic: the observer topic string to send with the CSP
@@ -607,48 +613,52 @@ nsCSPContext::GetAllowsInline(nsContentP
                               keyword, nonceOrHash, false))                    \
     {                                                                          \
       nsAutoString violatedDirective;                                          \
       mPolicies[p]->getDirectiveStringForContentType(                          \
                         nsIContentPolicy::TYPE_ ## contentPolicyType,          \
                         violatedDirective);                                    \
       this->AsyncReportViolation(selfISupports, nullptr, violatedDirective, p, \
                                  NS_LITERAL_STRING(observerTopic),             \
-                                 aSourceFile, aScriptSample, aLineNum);        \
+                                 aSourceFile, aScriptSample, aLineNum,         \
+                                 aColumnNum);                                  \
     }                                                                          \
     PR_END_MACRO;                                                              \
     break
 
 /**
  * For each policy, log any violation on the Error Console and send a report
  * if a report-uri is present in the policy
  *
  * @param aViolationType
  *     one of the VIOLATION_TYPE_* constants, e.g. inline-script or eval
  * @param aSourceFile
  *     name of the source file containing the violation (if available)
  * @param aContentSample
  *     sample of the violating content (to aid debugging)
  * @param aLineNum
  *     source line number of the violation (if available)
+ * @param aColumnNum
+ *     source column number of the violation (if available)
  * @param aNonce
  *     (optional) If this is a nonce violation, include the nonce so we can
  *     recheck to determine which policies were violated and send the
  *     appropriate reports.
  * @param aContent
  *     (optional) If this is a hash violation, include contents of the inline
  *     resource in the question so we can recheck the hash in order to
  *     determine which policies were violated and send the appropriate
  *     reports.
  */
 NS_IMETHODIMP
 nsCSPContext::LogViolationDetails(uint16_t aViolationType,
                                   const nsAString& aSourceFile,
                                   const nsAString& aScriptSample,
                                   int32_t aLineNum,
+                                  int32_t aColumnNum,
                                   const nsAString& aNonce,
                                   const nsAString& aContent)
 {
   for (uint32_t p = 0; p < mPolicies.Length(); p++) {
     NS_ASSERTION(mPolicies[p], "null pointer in nsTArray<nsCSPPolicy>");
 
     nsCOMPtr<nsISupportsCString> selfICString(do_CreateInstance(NS_SUPPORTS_CSTRING_CONTRACTID));
     if (selfICString) {
@@ -855,16 +865,17 @@ nsresult
 nsCSPContext::GatherSecurityPolicyViolationEventData(
   nsIURI* aBlockedURI,
   nsIURI* aOriginalURI,
   nsAString& aViolatedDirective,
   uint32_t aViolatedPolicyIndex,
   nsAString& aSourceFile,
   nsAString& aScriptSample,
   uint32_t aLineNum,
+  uint32_t aColumnNum,
   mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit)
 {
   NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
 
   MOZ_ASSERT(ValidateDirectiveName(aViolatedDirective), "Invalid directive name");
 
   nsresult rv;
 
@@ -935,18 +946,17 @@ nsCSPContext::GatherSecurityPolicyViolat
     }
   }
   aViolationEventInit.mStatusCode = statusCode;
 
   // line-number
   aViolationEventInit.mLineNumber = aLineNum;
 
   // column-number
-  // TODO: Set correct column number.
-  aViolationEventInit.mColumnNumber = 0;
+  aViolationEventInit.mColumnNumber = aColumnNum;
 
   aViolationEventInit.mBubbles = true;
   aViolationEventInit.mComposed = true;
 
   return NS_OK;
 }
 
 nsresult
@@ -986,16 +996,21 @@ nsCSPContext::SendReports(
   }
 
   // line-number
   if (aViolationEventInit.mLineNumber != 0) {
     report.mCsp_report.mLine_number.Construct();
     report.mCsp_report.mLine_number.Value() = aViolationEventInit.mLineNumber;
   }
 
+  if (aViolationEventInit.mLineNumber != 0) {
+    report.mCsp_report.mColumn_number.Construct();
+    report.mCsp_report.mColumn_number.Value() = aViolationEventInit.mColumnNumber;
+  }
+
   nsString csp_report;
   if (!report.ToJSON(csp_report)) {
     return NS_ERROR_FAILURE;
   }
 
   // ---------- Assembled, now send it to all the report URIs ----------- //
 
   nsTArray<nsString> reportURIs;
@@ -1011,17 +1026,19 @@ nsCSPContext::SendReports(
     // try to create a new uri from every report-uri string
     rv = NS_NewURI(getter_AddRefs(reportURI), reportURIs[r]);
     if (NS_FAILED(rv)) {
       const char16_t* params[] = { reportURIs[r].get() };
       CSPCONTEXTLOG(("Could not create nsIURI for report URI %s",
                      reportURICstring.get()));
       logToConsole("triedToSendReport", params, ArrayLength(params),
                    aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
-                   aViolationEventInit.mLineNumber, 0, nsIScriptError::errorFlag);
+                   aViolationEventInit.mLineNumber,
+                   aViolationEventInit.mColumnNumber,
+                   nsIScriptError::errorFlag);
       continue; // don't return yet, there may be more URIs
     }
 
     // try to create a new channel for every report-uri
     nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL | nsIChannel::LOAD_CLASSIFY_URI;
     if (doc) {
       rv = NS_NewChannel(getter_AddRefs(reportChannel),
                          reportURI,
@@ -1055,17 +1072,19 @@ nsCSPContext::SendReports(
     bool isHttpScheme =
       (NS_SUCCEEDED(reportURI->SchemeIs("http", &isHttpScheme)) && isHttpScheme) ||
       (NS_SUCCEEDED(reportURI->SchemeIs("https", &isHttpScheme)) && isHttpScheme);
 
     if (!isHttpScheme) {
       const char16_t* params[] = { reportURIs[r].get() };
       logToConsole("reportURInotHttpsOrHttp2", params, ArrayLength(params),
                    aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
-                   aViolationEventInit.mLineNumber, 0, nsIScriptError::errorFlag);
+                   aViolationEventInit.mLineNumber,
+                   aViolationEventInit.mColumnNumber,
+                   nsIScriptError::errorFlag);
       continue;
     }
 
     // make sure this is an anonymous request (no cookies) so in case the
     // policy URI is injected, it can't be abused for CSRF.
     nsLoadFlags flags;
     rv = reportChannel->GetLoadFlags(&flags);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1121,17 +1140,19 @@ nsCSPContext::SendReports(
     // not return an error since it's really ok if reports don't go out, but
     // it's good to log the error locally.
 
     if (NS_FAILED(rv)) {
       const char16_t* params[] = { reportURIs[r].get() };
       CSPCONTEXTLOG(("AsyncOpen failed for report URI %s", NS_ConvertUTF16toUTF8(params[0]).get()));
       logToConsole("triedToSendReport", params, ArrayLength(params),
                    aViolationEventInit.mSourceFile, aViolationEventInit.mSample,
-                   aViolationEventInit.mLineNumber, 0, nsIScriptError::errorFlag);
+                   aViolationEventInit.mLineNumber,
+                   aViolationEventInit.mColumnNumber,
+                   nsIScriptError::errorFlag);
     } else {
       CSPCONTEXTLOG(("Sent violation report to URI %s", reportURICstring.get()));
     }
   }
   return NS_OK;
 }
 
 nsresult
@@ -1169,26 +1190,28 @@ class CSPReportSenderRunnable final : pu
                             nsIURI* aOriginalURI,
                             uint32_t aViolatedPolicyIndex,
                             bool aReportOnlyFlag,
                             const nsAString& aViolatedDirective,
                             const nsAString& aObserverSubject,
                             const nsAString& aSourceFile,
                             const nsAString& aScriptSample,
                             uint32_t aLineNum,
+                            uint32_t aColumnNum,
                             nsCSPContext* aCSPContext)
       : mozilla::Runnable("CSPReportSenderRunnable")
       , mBlockedContentSource(aBlockedContentSource)
       , mOriginalURI(aOriginalURI)
       , mViolatedPolicyIndex(aViolatedPolicyIndex)
       , mReportOnlyFlag(aReportOnlyFlag)
       , mViolatedDirective(aViolatedDirective)
       , mSourceFile(aSourceFile)
       , mScriptSample(aScriptSample)
       , mLineNum(aLineNum)
+      , mColumnNum(aColumnNum)
       , mCSPContext(aCSPContext)
     {
       NS_ASSERTION(!aViolatedDirective.IsEmpty(), "Can not send reports without a violated directive");
       // the observer subject is an nsISupports: either an nsISupportsCString
       // from the arg passed in directly, or if that's empty, it's the blocked
       // source.
       if (aObserverSubject.IsEmpty()) {
         mObserverSubject = aBlockedContentSource;
@@ -1209,26 +1232,26 @@ class CSPReportSenderRunnable final : pu
 
       // 0) prepare violation data
       mozilla::dom::SecurityPolicyViolationEventInit init;
       // mBlockedContentSource could be a URI or a string.
       nsCOMPtr<nsIURI> blockedURI = do_QueryInterface(mBlockedContentSource);
       rv = mCSPContext->GatherSecurityPolicyViolationEventData(
         blockedURI, mOriginalURI,
         mViolatedDirective, mViolatedPolicyIndex,
-        mSourceFile, mScriptSample, mLineNum,
+        mSourceFile, mScriptSample, mLineNum, mColumnNum,
         init);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // 1) notify observers
       nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
       NS_ASSERTION(observerService, "needs observer service");
       rv = observerService->NotifyObservers(mObserverSubject,
-                                                     CSP_VIOLATION_TOPIC,
-                                                     mViolatedDirective.get());
+                                            CSP_VIOLATION_TOPIC,
+                                            mViolatedDirective.get());
       NS_ENSURE_SUCCESS(rv, rv);
 
       // 2) send reports for the policy that was violated
       mCSPContext->SendReports(init, mViolatedPolicyIndex);
 
       // 3) log to console (one per policy violation)
       // if mBlockedContentSource is not a URI, it could be a string
       nsCOMPtr<nsISupportsCString> blockedString = do_QueryInterface(mBlockedContentSource);
@@ -1251,17 +1274,17 @@ class CSPReportSenderRunnable final : pu
 
       if (blockedDataStr.Length() > 0) {
         nsString blockedDataChar16 = NS_ConvertUTF8toUTF16(blockedDataStr);
         const char16_t* params[] = { mViolatedDirective.get(),
                                      blockedDataChar16.get() };
         mCSPContext->logToConsole(mReportOnlyFlag ? "CSPROViolationWithURI" :
                                                     "CSPViolationWithURI",
                                   params, ArrayLength(params), mSourceFile, mScriptSample,
-                                  mLineNum, 0, nsIScriptError::errorFlag);
+                                  mLineNum, mColumnNum, nsIScriptError::errorFlag);
       }
 
       // 4) fire violation event
       mCSPContext->FireViolationEvent(init);
 
       return NS_OK;
     }
 
@@ -1270,16 +1293,17 @@ class CSPReportSenderRunnable final : pu
     nsCOMPtr<nsIURI>        mOriginalURI;
     uint32_t                mViolatedPolicyIndex;
     bool                    mReportOnlyFlag;
     nsString                mViolatedDirective;
     nsCOMPtr<nsISupports>   mObserverSubject;
     nsString                mSourceFile;
     nsString                mScriptSample;
     uint32_t                mLineNum;
+    uint32_t                mColumnNum;
     RefPtr<nsCSPContext>    mCSPContext;
 };
 
 /**
  * Asynchronously notifies any nsIObservers listening to the CSP violation
  * topic that a violation occurred.  Also triggers report sending and console
  * logging.  All asynchronous on the main thread.
  *
@@ -1297,39 +1321,43 @@ class CSPReportSenderRunnable final : pu
  *        optional, subject sent to the nsIObservers listening to the CSP
  *        violation topic.
  * @param aSourceFile
  *        name of the file containing the inline script violation
  * @param aScriptSample
  *        a sample of the violating inline script
  * @param aLineNum
  *        source line number of the violation (if available)
+ * @param aColumnNum
+ *        source column number of the violation (if available)
  */
 nsresult
 nsCSPContext::AsyncReportViolation(nsISupports* aBlockedContentSource,
                                    nsIURI* aOriginalURI,
                                    const nsAString& aViolatedDirective,
                                    uint32_t aViolatedPolicyIndex,
                                    const nsAString& aObserverSubject,
                                    const nsAString& aSourceFile,
                                    const nsAString& aScriptSample,
-                                   uint32_t aLineNum)
+                                   uint32_t aLineNum,
+                                   uint32_t aColumnNum)
 {
   NS_ENSURE_ARG_MAX(aViolatedPolicyIndex, mPolicies.Length() - 1);
 
   nsCOMPtr<nsIRunnable> task =
     new CSPReportSenderRunnable(aBlockedContentSource,
                                 aOriginalURI,
                                 aViolatedPolicyIndex,
                                 mPolicies[aViolatedPolicyIndex]->getReportOnlyFlag(),
                                 aViolatedDirective,
                                 aObserverSubject,
                                 aSourceFile,
                                 aScriptSample,
                                 aLineNum,
+                                aColumnNum,
                                 this);
 
   if (XRE_IsContentProcess()) {
     if (mEventTarget) {
       mEventTarget->Dispatch(task.forget(), NS_DISPATCH_NORMAL);
       return NS_OK;
     }
   }
--- a/dom/security/nsCSPContext.h
+++ b/dom/security/nsCSPContext.h
@@ -71,44 +71,48 @@ class nsCSPContext : public nsIContentSe
      * @param aViolatedDirective
      *        the directive that was violated (string).
      * @param aSourceFile
      *        name of the file containing the inline script violation
      * @param aScriptSample
      *        a sample of the violating inline script
      * @param aLineNum
      *        source line number of the violation (if available)
+     * @param aColumnNum
+     *        source column number of the violation (if available)
      * @param aViolationEventInit
      *        The output
      */
     nsresult GatherSecurityPolicyViolationEventData(
       nsIURI* aBlockedURI,
       nsIURI* aOriginalURI,
       nsAString& aViolatedDirective,
       uint32_t aViolatedPolicyIndex,
       nsAString& aSourceFile,
       nsAString& aScriptSample,
       uint32_t aLineNum,
+      uint32_t aColumnNum,
       mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit);
 
     nsresult SendReports(
       const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit,
       uint32_t aViolatedPolicyIndex);
 
     nsresult FireViolationEvent(
       const mozilla::dom::SecurityPolicyViolationEventInit& aViolationEventInit);
 
     nsresult AsyncReportViolation(nsISupports* aBlockedContentSource,
                                   nsIURI* aOriginalURI,
                                   const nsAString& aViolatedDirective,
                                   uint32_t aViolatedPolicyIndex,
                                   const nsAString& aObserverSubject,
                                   const nsAString& aSourceFile,
                                   const nsAString& aScriptSample,
-                                  uint32_t aLineNum);
+                                  uint32_t aLineNum,
+                                  uint32_t aColumnNum);
 
     // Hands off! Don't call this method unless you know what you
     // are doing. It's only supposed to be called from within
     // the principal destructor to avoid a tangling pointer.
     void clearLoadingPrincipal() {
       mLoadingPrincipal = nullptr;
     }
 
@@ -129,17 +133,18 @@ class nsCSPContext : public nsIContentSe
                          bool aParserCreated);
 
     // helper to report inline script/style violations
     void reportInlineViolation(nsContentPolicyType aContentType,
                                const nsAString& aNonce,
                                const nsAString& aContent,
                                const nsAString& aViolatedDirective,
                                uint32_t aViolatedPolicyIndex,
-                               uint32_t aLineNumber);
+                               uint32_t aLineNumber,
+                               uint32_t aColumnNumber);
 
     static int32_t sScriptSampleMaxLength;
 
     static uint32_t ScriptSampleMaxLength()
     {
       return std::max(sScriptSampleMaxLength, 0);
     }
 
--- a/dom/security/test/unit/test_csp_reports.js
+++ b/dom/security/test/unit/test_csp_reports.js
@@ -108,26 +108,29 @@ function run_test() {
   // test that inline script violations cause a report.
   makeTest(0, {"blocked-uri": ""}, false,
       function(csp) {
         let inlineOK = true;
         inlineOK = csp.getAllowsInline(Ci.nsIContentPolicy.TYPE_SCRIPT,
                                        "", // aNonce
                                        false, // aParserCreated
                                        content, // aContent
-                                       0); // aLineNumber
+                                       0, // aLineNumber
+                                       0); // aColumnNumber
 
         // this is not a report only policy, so it better block inline scripts
         Assert.ok(!inlineOK);
       });
 
   // test that eval violations cause a report.
   makeTest(1, {"blocked-uri": "",
                // JSON script-sample is UTF8 encoded
-               "script-sample" : "\xc2\xa3\xc2\xa5\xc2\xb5\xe5\x8c\x97\xf0\xa0\x9d\xb9"}, false,
+               "script-sample" : "\xc2\xa3\xc2\xa5\xc2\xb5\xe5\x8c\x97\xf0\xa0\x9d\xb9",
+               "line-number": 1,
+               "column-number": 2}, false,
       function(csp) {
         let evalOK = true, oReportViolation = {'value': false};
         evalOK = csp.getAllowsEval(oReportViolation);
 
         // this is not a report only policy, so it better block eval
         Assert.ok(!evalOK);
         // ... and cause reports to go out
         Assert.ok(oReportViolation.value);
@@ -135,17 +138,18 @@ function run_test() {
         if (oReportViolation.value) {
           // force the logging, since the getter doesn't.
           csp.logViolationDetails(Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_EVAL,
                                   selfuri.asciiSpec,
                                   // sending UTF-16 script sample to make sure
                                   // csp report in JSON is not cut-off, please
                                   // note that JSON is UTF8 encoded.
                                   "\u00a3\u00a5\u00b5\u5317\ud841\udf79",
-                                  1);
+                                  1, // line number
+                                  2); // column number
         }
       });
 
   makeTest(2, {"blocked-uri": "http://blocked.test"}, false,
       function(csp) {
         // shouldLoad creates and sends out the report here.
         csp.shouldLoad(Ci.nsIContentPolicy.TYPE_SCRIPT,
                       NetUtil.newURI("http://blocked.test/foo.js"),
@@ -158,17 +162,18 @@ function run_test() {
         let inlineOK = true;
         let content = Cc["@mozilla.org/supports-string;1"].
                          createInstance(Ci.nsISupportsString);
         content.data = "";
         inlineOK = csp.getAllowsInline(Ci.nsIContentPolicy.TYPE_SCRIPT,
                                        "", // aNonce
                                        false, // aParserCreated
                                        content, // aContent
-                                       0); // aLineNumber
+                                       0, // aLineNumber
+                                       0); // aColumnNumber
 
         // this is a report only policy, so it better allow inline scripts
         Assert.ok(inlineOK);
       });
 
   // test that eval violations cause a report in report-only policy
   makeTest(4, {"blocked-uri": ""}, true,
       function(csp) {
@@ -180,17 +185,18 @@ function run_test() {
         // ... but still cause reports to go out
         Assert.ok(oReportViolation.value);
 
         if (oReportViolation.value) {
           // force the logging, since the getter doesn't.
           csp.logViolationDetails(Ci.nsIContentSecurityPolicy.VIOLATION_TYPE_INLINE_SCRIPT,
                                   selfuri.asciiSpec,
                                   "script sample",
-                                  4);
+                                  4, // line number
+                                  5); // column number
         }
       });
 
   // test that only the uri's scheme is reported for globally unique identifiers
   makeTest(5, {"blocked-uri": "data"}, false,
     function(csp) {
       var base64data =
         "iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12" +
--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -518,17 +518,17 @@ nsSMILCSSValueType::ValueFromString(nsCS
     return;
   }
 
   nsIDocument* doc = aTargetElement->GetUncomposedDoc();
   if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
                                                 doc->NodePrincipal(),
                                                 nullptr,
                                                 doc->GetDocumentURI(),
-                                                0, aString, nullptr)) {
+                                                0, 0, aString, nullptr)) {
     return;
   }
 
   RefPtr<ComputedStyle> computedStyle =
     nsComputedDOMStyle::GetComputedStyle(aTargetElement, nullptr);
   if (!computedStyle) {
     return;
   }
@@ -562,17 +562,18 @@ nsSMILCSSValueType::ValueFromAnimationVa
   // and an intermediate CSS value is not likely to be particularly useful
   // in that case, we just use a generic placeholder string instead.
   static const nsLiteralString kPlaceholderText =
     NS_LITERAL_STRING("[SVG animation of CSS]");
   if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
                                                 doc->NodePrincipal(),
                                                 nullptr,
                                                 doc->GetDocumentURI(),
-                                                0, kPlaceholderText, nullptr)) {
+                                                0, 0, kPlaceholderText,
+                                                nullptr)) {
     return result;
   }
 
   sSingleton.Init(result);
   result.mU.mPtr = new ValueWrapper(aPropID, aValue);
 
   return result;
 }
--- a/dom/svg/SVGScriptElement.cpp
+++ b/dom/svg/SVGScriptElement.cpp
@@ -163,26 +163,26 @@ SVGScriptElement::FreezeExecutionAttrs(n
 
       if (!mUri) {
         const char16_t* params[] = { isHref ? u"href" : u"xlink:href", src.get() };
 
         nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
           NS_LITERAL_CSTRING("SVG"), OwnerDoc(),
           nsContentUtils::eDOM_PROPERTIES, "ScriptSourceInvalidUri",
           params, ArrayLength(params), nullptr,
-          EmptyString(), GetScriptLineNumber());
+          EmptyString(), GetScriptLineNumber(), GetScriptColumnNumber());
       }
     } else {
       const char16_t* params[] = { isHref ? u"href" : u"xlink:href" };
 
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
         NS_LITERAL_CSTRING("SVG"), OwnerDoc(),
         nsContentUtils::eDOM_PROPERTIES, "ScriptSourceEmpty",
         params, ArrayLength(params), nullptr,
-        EmptyString(), GetScriptLineNumber());
+        EmptyString(), GetScriptLineNumber(), GetScriptColumnNumber());
     }
 
     // At this point mUri will be null for invalid URLs.
     mExternal = true;
   }
 
   mFrozen = true;
 }
--- a/dom/webidl/CSPReport.webidl
+++ b/dom/webidl/CSPReport.webidl
@@ -11,13 +11,14 @@ dictionary CSPReportProperties {
   DOMString document-uri = "";
   DOMString referrer = "";
   DOMString blocked-uri = "";
   DOMString violated-directive = "";
   DOMString original-policy= "";
   DOMString source-file;
   DOMString script-sample;
   long line-number;
+  long column-number;
 };
 
 dictionary CSPReport {
   CSPReportProperties csp-report;
 };
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -579,24 +579,28 @@ InterruptCallback(JSContext* aCx)
 
   return worker->InterruptCallback(aCx);
 }
 
 class LogViolationDetailsRunnable final : public WorkerMainThreadRunnable
 {
   nsString mFileName;
   uint32_t mLineNum;
+  uint32_t mColumnNum;
 
 public:
   LogViolationDetailsRunnable(WorkerPrivate* aWorker,
                               const nsString& aFileName,
-                              uint32_t aLineNum)
+                              uint32_t aLineNum,
+                              uint32_t aColumnNum)
     : WorkerMainThreadRunnable(aWorker,
                                NS_LITERAL_CSTRING("RuntimeService :: LogViolationDetails"))
-    , mFileName(aFileName), mLineNum(aLineNum)
+    , mFileName(aFileName)
+    , mLineNum(aLineNum)
+    , mColumnNum(aColumnNum)
   {
     MOZ_ASSERT(aWorker);
   }
 
   virtual bool MainThreadRun() override;
 
 private:
   ~LogViolationDetailsRunnable() {}
@@ -606,26 +610,27 @@ bool
 ContentSecurityPolicyAllows(JSContext* aCx)
 {
   WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
   worker->AssertIsOnWorkerThread();
 
   if (worker->GetReportCSPViolations()) {
     nsString fileName;
     uint32_t lineNum = 0;
+    uint32_t columnNum = 0;
 
     JS::AutoFilename file;
-    if (JS::DescribeScriptedCaller(aCx, &file, &lineNum) && file.get()) {
+    if (JS::DescribeScriptedCaller(aCx, &file, &lineNum, &columnNum) && file.get()) {
       fileName = NS_ConvertUTF8toUTF16(file.get());
     } else {
       MOZ_ASSERT(!JS_IsExceptionPending(aCx));
     }
 
     RefPtr<LogViolationDetailsRunnable> runnable =
-        new LogViolationDetailsRunnable(worker, fileName, lineNum);
+        new LogViolationDetailsRunnable(worker, fileName, lineNum, columnNum);
 
     ErrorResult rv;
     runnable->Dispatch(Killing, rv);
     if (NS_WARN_IF(rv.Failed())) {
       rv.SuppressException();
     }
   }
 
@@ -2615,17 +2620,17 @@ LogViolationDetailsRunnable::MainThreadR
   AssertIsOnMainThread();
 
   nsIContentSecurityPolicy* csp = mWorkerPrivate->GetCSP();
   if (csp) {
     NS_NAMED_LITERAL_STRING(scriptSample,
         "Call to eval() or related function blocked by CSP.");
     if (mWorkerPrivate->GetReportCSPViolations()) {
       csp->LogViolationDetails(nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL,
-                               mFileName, scriptSample, mLineNum,
+                               mFileName, scriptSample, mLineNum, mColumnNum,
                                EmptyString(), EmptyString());
     }
   }
 
   return true;
 }
 
 NS_IMETHODIMP
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -1221,17 +1221,17 @@ private:
       MOZ_LOG(SRILogHelper::GetSriLog(), mozilla::LogLevel::Debug,
             ("Scriptloader::Load, SRI required but not supported in workers"));
       nsCOMPtr<nsIContentSecurityPolicy> wcsp;
       chanLoadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(wcsp));
       MOZ_ASSERT(wcsp, "We sould have a CSP for the worker here");
       if (wcsp) {
         wcsp->LogViolationDetails(
             nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_SCRIPT,
-            aLoadInfo.mURL, EmptyString(), 0, EmptyString(), EmptyString());
+            aLoadInfo.mURL, EmptyString(), 0, 0, EmptyString(), EmptyString());
       }
       return NS_ERROR_SRI_CORRUPT;
     }
 
     // Update the principal of the worker and its base URI if we just loaded the
     // worker's primary script.
     if (IsMainWorkerScript()) {
       // Take care of the base URI first.
--- a/dom/workers/test/test_csp.js
+++ b/dom/workers/test/test_csp.js
@@ -23,26 +23,26 @@ xhr = new XMLHttpRequest;
 xhr.open("GET", "csp_worker.js");
 xhr.responseType = "blob";
 xhr.send();
 xhr.onload = (e) => {
   uri = URL.createObjectURL(e.target.response);
   worker = new Worker(uri);
   worker.postMessage({ do: "eval" })
   worker.onmessage = function(event) {
-    is(event.data, "Error: call to eval() blocked by CSP", "Eval threw");
+    is(event.data, "EvalError: call to eval() blocked by CSP", "Eval threw");
     testDone();
   }
 }
 
 xhr = new XMLHttpRequest;
 xhr.open("GET", "csp_worker.js");
 xhr.responseType = "blob";
 xhr.send();
 xhr.onload = (e) => {
   uri = URL.createObjectURL(e.target.response);
   worker = new Worker(uri);
   worker.postMessage({ do: "nest", uri: uri, level: 3 })
   worker.onmessage = function(event) {
-    is(event.data, "Error: call to eval() blocked by CSP", "Eval threw in nested worker");
+    is(event.data, "EvalError: call to eval() blocked by CSP", "Eval threw in nested worker");
     testDone();
   }
 }
--- a/dom/xbl/nsXBLContentSink.cpp
+++ b/dom/xbl/nsXBLContentSink.cpp
@@ -242,20 +242,21 @@ nsXBLContentSink::AddField(nsXBLProtoImp
 
   mImplField = aField; // Adjust our pointer to point to the new last field in the chain.
 }
 
 NS_IMETHODIMP
 nsXBLContentSink::HandleStartElement(const char16_t *aName,
                                      const char16_t **aAtts,
                                      uint32_t aAttsCount,
-                                     uint32_t aLineNumber)
+                                     uint32_t aLineNumber,
+                                     uint32_t aColumnNumber)
 {
   nsresult rv = nsXMLContentSink::HandleStartElement(aName, aAtts, aAttsCount,
-                                                     aLineNumber);
+                                                     aLineNumber, aColumnNumber);
   if (NS_FAILED(rv))
     return rv;
 
   if (mState == eXBL_InBinding && !mBinding) {
     rv = ConstructBinding(aLineNumber);
     if (NS_FAILED(rv))
       return rv;
 
@@ -845,25 +846,26 @@ nsXBLContentSink::ConstructParameter(con
   const char16_t* name = nullptr;
   if (FindValue(aAtts, nsGkAtoms::name, &name)) {
     mMethod->AddParameter(nsDependentString(name));
   }
 }
 
 nsresult
 nsXBLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
-                                mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
+                                mozilla::dom::NodeInfo* aNodeInfo,
+                                uint32_t aLineNumber, uint32_t aColumnNumber,
                                 nsIContent** aResult, bool* aAppendContent,
                                 FromParser aFromParser)
 {
 #ifdef MOZ_XUL
   if (!aNodeInfo->NamespaceEquals(kNameSpaceID_XUL)) {
 #endif
     return nsXMLContentSink::CreateElement(aAtts, aAttsCount, aNodeInfo,
-                                           aLineNumber, aResult,
+                                           aLineNumber, aColumnNumber, aResult,
                                            aAppendContent, aFromParser);
 #ifdef MOZ_XUL
   }
 
   // Note that this needs to match the code in nsXBLPrototypeBinding::ReadContentNode.
 
   *aAppendContent = true;
   RefPtr<nsXULPrototypeElement> prototype = new nsXULPrototypeElement();
--- a/dom/xbl/nsXBLContentSink.h
+++ b/dom/xbl/nsXBLContentSink.h
@@ -63,17 +63,18 @@ public:
   nsresult Init(nsIDocument* aDoc,
                 nsIURI* aURL,
                 nsISupports* aContainer);
 
   // nsIContentSink overrides
   NS_IMETHOD HandleStartElement(const char16_t *aName,
                                 const char16_t **aAtts,
                                 uint32_t aAttsCount,
-                                uint32_t aLineNumber) override;
+                                uint32_t aLineNumber,
+                                uint32_t aColumnNumber) override;
 
   NS_IMETHOD HandleEndElement(const char16_t *aName) override;
 
   NS_IMETHOD HandleCDataSection(const char16_t *aData,
                                 uint32_t aLength) override;
 
 protected:
     // nsXMLContentSink overrides
@@ -83,17 +84,18 @@ protected:
                            uint32_t aAttsCount,
                            int32_t aNameSpaceID,
                            nsAtom* aTagName,
                            uint32_t aLineNumber) override;
 
     bool NotifyForDocElement() override { return false; }
 
     nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
-                           mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
+                           mozilla::dom::NodeInfo* aNodeInfo,
+                           uint32_t aLineNumber, uint32_t aColumnNumber,
                            nsIContent** aResult, bool* aAppendContent,
                            mozilla::dom::FromParser aFromParser) override;
 
     nsresult AddAttributes(const char16_t** aAtts, Element* aElement) override;
 
 #ifdef MOZ_XUL
     nsresult AddAttributesToXULPrototype(const char16_t **aAtts,
                                          uint32_t aAttsCount,
--- a/dom/xml/nsXMLContentSink.cpp
+++ b/dom/xml/nsXMLContentSink.cpp
@@ -476,17 +476,18 @@ FindIsAttrValue(const char16_t** aAtts, 
     }
   }
 
   return false;
 }
 
 nsresult
 nsXMLContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
-                                mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
+                                mozilla::dom::NodeInfo* aNodeInfo,
+                                uint32_t aLineNumber, uint32_t aColumnNumber,
                                 nsIContent** aResult, bool* aAppendContent,
                                 FromParser aFromParser)
 {
   NS_ASSERTION(aNodeInfo, "can't create element without nodeinfo");
 
   *aResult = nullptr;
   *aAppendContent = true;
   nsresult rv = NS_OK;
@@ -507,16 +508,17 @@ nsXMLContentSink::CreateElement(const ch
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_XHTML)
       || aNodeInfo->Equals(nsGkAtoms::script, kNameSpaceID_SVG)
     ) {
     nsCOMPtr<nsIScriptElement> sele = do_QueryInterface(content);
     if (sele) {
       sele->SetScriptLineNumber(aLineNumber);
+      sele->SetScriptColumnNumber(aColumnNumber);
       sele->SetCreatorParser(GetParser());
     } else {
       MOZ_ASSERT(nsNameSpaceManager::GetInstance()->mSVGDisabled, "Node didn't QI to script, but SVG wasn't disabled.");
     }
   }
 
   // XHTML needs some special attention
   if (aNodeInfo->NamespaceEquals(kNameSpaceID_XHTML)) {
@@ -544,16 +546,17 @@ nsXMLContentSink::CreateElement(const ch
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
     if (ssle) {
       ssle->InitStyleLinkElement(false);
       if (aFromParser) {
         ssle->SetEnableUpdates(false);
       }
       if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
         ssle->SetLineNumber(aFromParser ? aLineNumber : 0);
+        ssle->SetColumnNumber(aFromParser ? aColumnNumber : 0);
       }
     }
   }
 
   content.forget(aResult);
 
   return NS_OK;
 }
@@ -983,27 +986,29 @@ nsXMLContentSink::SetDocElement(int32_t 
 
   return true;
 }
 
 NS_IMETHODIMP
 nsXMLContentSink::HandleStartElement(const char16_t *aName,
                                      const char16_t **aAtts,
                                      uint32_t aAttsCount,
-                                     uint32_t aLineNumber)
+                                     uint32_t aLineNumber,
+                                     uint32_t aColumnNumber)
 {
   return HandleStartElement(aName, aAtts, aAttsCount, aLineNumber,
-                            true);
+                            aColumnNumber, true);
 }
 
 nsresult
 nsXMLContentSink::HandleStartElement(const char16_t *aName,
                                      const char16_t **aAtts,
                                      uint32_t aAttsCount,
                                      uint32_t aLineNumber,
+                                     uint32_t aColumnNumber,
                                      bool aInterruptable)
 {
   MOZ_ASSERT(aAttsCount % 2 == 0, "incorrect aAttsCount");
   // Adjust aAttsCount so it's the actual number of attributes
   aAttsCount /= 2;
 
   nsresult result = NS_OK;
   bool appendContent = true;
@@ -1028,17 +1033,17 @@ nsXMLContentSink::HandleStartElement(con
     return NS_OK;
   }
 
   RefPtr<mozilla::dom::NodeInfo> nodeInfo;
   nodeInfo = mNodeInfoManager->GetNodeInfo(localName, prefix, nameSpaceID,
                                            nsINode::ELEMENT_NODE);
 
   result = CreateElement(aAtts, aAttsCount, nodeInfo, aLineNumber,
-                         getter_AddRefs(content), &appendContent,
+                         aColumnNumber, getter_AddRefs(content), &appendContent,
                          FROM_PARSER_NETWORK);
   NS_ENSURE_SUCCESS(result, result);
 
   // Have to do this before we push the new content on the stack... and have to
   // do that before we set attributes, call BindToTree, etc.  Ideally we'd push
   // on the stack inside CreateElement (which is effectively what the HTML sink
   // does), but that's hard with all the subclass overrides going on.
   nsCOMPtr<nsIContent> parent = GetCurrentContent();
--- a/dom/xml/nsXMLContentSink.h
+++ b/dom/xml/nsXMLContentSink.h
@@ -112,17 +112,18 @@ protected:
   // Set the given content as the root element for the created document
   //  don't set if root element was already set.
   //  return TRUE if this call set the root element
   virtual bool SetDocElement(int32_t aNameSpaceID,
                                nsAtom *aTagName,
                                nsIContent *aContent);
   virtual bool NotifyForDocElement() { return true; }
   virtual nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
-                                 mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
+                                 mozilla::dom::NodeInfo* aNodeInfo,
+                                 uint32_t aLineNumber, uint32_t aColumnNumber,
                                  nsIContent** aResult, bool* aAppendContent,
                                  mozilla::dom::FromParser aFromParser);
 
   // aParent is allowed to be null here if this is the root content
   // being closed
   virtual nsresult CloseElement(nsIContent* aContent);
 
   virtual nsresult FlushText(bool aReleaseTextNode = true);
@@ -176,17 +177,17 @@ protected:
   bool CanStillPrettyPrint();
 
   nsresult MaybePrettyPrint();
 
   bool IsMonolithicContainer(mozilla::dom::NodeInfo* aNodeInfo);
 
   nsresult HandleStartElement(const char16_t *aName, const char16_t **aAtts,
                               uint32_t aAttsCount, uint32_t aLineNumber,
-                              bool aInterruptable);
+                              uint32_t aColumnNumber, bool aInterruptable);
   nsresult HandleEndElement(const char16_t *aName, bool aInterruptable);
   nsresult HandleCharacterData(const char16_t *aData, uint32_t aLength,
                                bool aInterruptable);
 
   nsCOMPtr<nsIContent> mDocElement;
   nsCOMPtr<nsIContent> mCurrentHead;  // When set, we're in an XHTML <haed>
 
   XMLContentSinkState mState;
--- a/dom/xml/nsXMLFragmentContentSink.cpp
+++ b/dom/xml/nsXMLFragmentContentSink.cpp
@@ -77,17 +77,18 @@ public:
 
 protected:
   virtual ~nsXMLFragmentContentSink();
 
   virtual bool SetDocElement(int32_t aNameSpaceID,
                                nsAtom* aTagName,
                                nsIContent* aContent) override;
   virtual nsresult CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
-                                 mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
+                                 mozilla::dom::NodeInfo* aNodeInfo,
+                                 uint32_t aLineNumber, uint32_t aColumnNumber,
                                  nsIContent** aResult, bool* aAppendContent,
                                  mozilla::dom::FromParser aFromParser) override;
   virtual nsresult CloseElement(nsIContent* aContent) override;
 
   virtual void MaybeStartLayout(bool aIgnorePendingSheets) override;
 
   // nsContentSink overrides
   virtual nsresult ProcessStyleLinkFromHeader(
@@ -203,24 +204,26 @@ nsXMLFragmentContentSink::SetDocElement(
                                         nsIContent *aContent)
 {
   // this is a fragment, not a document
   return false;
 }
 
 nsresult
 nsXMLFragmentContentSink::CreateElement(const char16_t** aAtts, uint32_t aAttsCount,
-                                        mozilla::dom::NodeInfo* aNodeInfo, uint32_t aLineNumber,
+                                        mozilla::dom::NodeInfo* aNodeInfo,
+                                        uint32_t aLineNumber, uint32_t aColumnNumber,
                                         nsIContent** aResult, bool* aAppendContent,
                                         FromParser /*aFromParser*/)
 {
   // Claim to not be coming from parser, since we don't do any of the
   // fancy CloseElement stuff.
   nsresult rv = nsXMLContentSink::CreateElement(aAtts, aAttsCount,
                                                 aNodeInfo, aLineNumber,
+                                                aColumnNumber,
                                                 aResult, aAppendContent,
                                                 NOT_FROM_PARSER);
 
   // When we aren't grabbing all of the content we, never open a doc
   // element, we run into trouble on the first element, so we don't append,
   // and simply push this onto the content stack.
   if (mContentStack.Length() == 0) {
     *aAppendContent = false;
--- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
+++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp
@@ -116,17 +116,18 @@ NS_IMPL_ISUPPORTS(txStylesheetSink,
                   nsIStreamListener,
                   nsIRequestObserver,
                   nsIInterfaceRequestor)
 
 NS_IMETHODIMP
 txStylesheetSink::HandleStartElement(const char16_t *aName,
                                      const char16_t **aAtts,
                                      uint32_t aAttsCount,
-                                     uint32_t aLineNumber)
+                                     uint32_t aLineNumber,
+                                     uint32_t aColumnNumber)
 {
     MOZ_ASSERT(aAttsCount % 2 == 0, "incorrect aAttsCount");
 
     nsresult rv =
         mCompiler->startElement(aName, aAtts, aAttsCount / 2);
     if (NS_FAILED(rv)) {
         mCompiler->cancel(rv);
 
--- a/dom/xul/nsXULContentSink.cpp
+++ b/dom/xul/nsXULContentSink.cpp
@@ -402,17 +402,18 @@ XULContentSinkImpl::CreateElement(mozill
 }
 
 /**** BEGIN NEW APIs ****/
 
 NS_IMETHODIMP
 XULContentSinkImpl::HandleStartElement(const char16_t *aName,
                                        const char16_t **aAtts,
                                        uint32_t aAttsCount,
-                                       uint32_t aLineNumber)
+                                       uint32_t aLineNumber,
+                                       uint32_t aColumnNumber)
 {
   // XXX Hopefully the parser will flag this before we get here. If
   // we're in the epilog, there should be no new elements
   MOZ_ASSERT(mState != eInEpilog, "tag in XUL doc epilog");
   MOZ_ASSERT(aAttsCount % 2 == 0, "incorrect aAttsCount");
 
   // Adjust aAttsCount so it's the actual number of attributes
   aAttsCount /= 2;
@@ -661,27 +662,27 @@ XULContentSinkImpl::ReportError(const ch
 
   NS_NAMED_LITERAL_STRING(errorNs,
                           "http://www.mozilla.org/newlayout/xml/parsererror.xml");
 
   nsAutoString parsererror(errorNs);
   parsererror.Append((char16_t)0xFFFF);
   parsererror.AppendLiteral("parsererror");
 
-  rv = HandleStartElement(parsererror.get(), noAtts, 0, 0);
+  rv = HandleStartElement(parsererror.get(), noAtts, 0, 0, 0);
   NS_ENSURE_SUCCESS(rv,rv);
 
   rv = HandleCharacterData(aErrorText, NS_strlen(aErrorText));
   NS_ENSURE_SUCCESS(rv,rv);
 
   nsAutoString sourcetext(errorNs);
   sourcetext.Append((char16_t)0xFFFF);
   sourcetext.AppendLiteral("sourcetext");
 
-  rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0);
+  rv = HandleStartElement(sourcetext.get(), noAtts, 0, 0, 0);
   NS_ENSURE_SUCCESS(rv,rv);
 
   rv = HandleCharacterData(aSourceText, NS_strlen(aSourceText));
   NS_ENSURE_SUCCESS(rv,rv);
 
   rv = HandleEndElement(sourcetext.get());
   NS_ENSURE_SUCCESS(rv,rv);
 
--- a/gfx/thebes/gfxPrefs.cpp
+++ b/gfx/thebes/gfxPrefs.cpp
@@ -136,73 +136,73 @@ gfxPrefs::IsPrefsServiceAvailable()
 
 /* static */ bool
 gfxPrefs::IsParentProcess()
 {
   return XRE_IsParentProcess();
 }
 
 void gfxPrefs::PrefAddVarCache(bool* aVariable,
-                               const char* aPref,
+                               const nsACString& aPref,
                                bool aDefault)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
   Preferences::AddBoolVarCache(aVariable, aPref, aDefault);
 }
 
 void gfxPrefs::PrefAddVarCache(int32_t* aVariable,
-                               const char* aPref,
+                               const nsACString& aPref,
                                int32_t aDefault)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
   Preferences::AddIntVarCache(aVariable, aPref, aDefault);
 }
 
 void gfxPrefs::PrefAddVarCache(uint32_t* aVariable,
-                               const char* aPref,
+                               const nsACString& aPref,
                                uint32_t aDefault)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
   Preferences::AddUintVarCache(aVariable, aPref, aDefault);
 }
 
 void gfxPrefs::PrefAddVarCache(float* aVariable,
-                               const char* aPref,
+                               const nsACString& aPref,
                                float aDefault)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
   Preferences::AddFloatVarCache(aVariable, aPref, aDefault);
 }
 
 void gfxPrefs::PrefAddVarCache(std::string* aVariable,
-                               const char* aPref,
+                               const nsCString& aPref,
                                std::string aDefault)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
-  Preferences::SetCString(aPref, aVariable->c_str());
+  Preferences::SetCString(aPref.get(), aVariable->c_str());
 }
 
 void gfxPrefs::PrefAddVarCache(AtomicBool* aVariable,
-                               const char* aPref,
+                               const nsACString& aPref,
                                bool aDefault)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
   Preferences::AddAtomicBoolVarCache(aVariable, aPref, aDefault);
 }
 
 void gfxPrefs::PrefAddVarCache(AtomicInt32* aVariable,
-                               const char* aPref,
+                               const nsACString& aPref,
                                int32_t aDefault)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
   Preferences::AddAtomicIntVarCache(aVariable, aPref, aDefault);
 }
 
 void gfxPrefs::PrefAddVarCache(AtomicUint32* aVariable,
-                               const char* aPref,
+                               const nsACString& aPref,
                                uint32_t aDefault)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
   Preferences::AddAtomicUintVarCache(aVariable, aPref, aDefault);
 }
 
 bool gfxPrefs::PrefGet(const char* aPref, bool aDefault)
 {
@@ -276,24 +276,27 @@ static void
 OnGfxPrefChanged(const char* aPrefname, void* aClosure)
 {
   reinterpret_cast<gfxPrefs::Pref*>(aClosure)->OnChange();
 }
 
 void gfxPrefs::WatchChanges(const char* aPrefname, Pref* aPref)
 {
   MOZ_ASSERT(IsPrefsServiceAvailable());
-  Preferences::RegisterCallback(OnGfxPrefChanged, aPrefname, aPref);
+  nsCString name;
+  name.AssignLiteral(aPrefname, strlen(aPrefname));
+  Preferences::RegisterCallback(OnGfxPrefChanged, name, aPref);
 }
 
 void gfxPrefs::UnwatchChanges(const char* aPrefname, Pref* aPref)
 {
   // The Preferences service can go offline before gfxPrefs is destroyed.
   if (IsPrefsServiceAvailable()) {
-    Preferences::UnregisterCallback(OnGfxPrefChanged, aPrefname, aPref);
+    Preferences::UnregisterCallback(OnGfxPrefChanged, nsDependentCString(aPrefname),
+                                    aPref);
   }
 }
 
 void gfxPrefs::CopyPrefValue(const bool* aValue, GfxPrefValue* aOutValue)
 {
   *aOutValue = *aValue;
 }
 
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -8,16 +8,17 @@
 
 #include <cmath>                 // for M_PI
 #include <stdint.h>
 #include <string>
 #include "mozilla/Assertions.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/gfx/LoggingConstants.h"
 #include "nsTArray.h"
+#include "nsString.h"
 
 // First time gfxPrefs::GetSingleton() needs to be called on the main thread,
 // before any of the methods accessing the values are used, but after
 // the Preferences system has been initialized.
 
 // The static methods to access the preference value are safe to call
 // from any thread after that first call.
 
@@ -236,17 +237,21 @@ private:
       AssertMainThread();
       switch (aUpdate) {
         case UpdatePolicy::Skip:
           break;
         case UpdatePolicy::Once:
           this->mValue = PrefGet(aPreference, this->mValue);
           break;
         case UpdatePolicy::Live:
-          PrefAddVarCache(&this->mValue, aPreference, this->mValue);
+          {
+            nsCString pref;
+            pref.AssignLiteral(aPreference, strlen(aPreference));
+            PrefAddVarCache(&this->mValue, pref, this->mValue);
+          }
           break;
         default:
           MOZ_CRASH("Incomplete switch");
       }
     }
     void Set(UpdatePolicy aUpdate, const char* aPref, T aValue)
     {
       AssertMainThread();
@@ -807,24 +812,24 @@ private:
   // The constructor cannot access GetSingleton(), since sInstance (necessarily)
   // has not been assigned yet. Follow-up initialization that needs GetSingleton()
   // must be added to Init().
   void Init();
 
   static bool IsPrefsServiceAvailable();
   static bool IsParentProcess();
   // Creating these to avoid having to include Preferences.h in the .h
-  static void PrefAddVarCache(bool*, const char*, bool);
-  static void PrefAddVarCache(int32_t*, const char*, int32_t);
-  static void PrefAddVarCache(uint32_t*, const char*, uint32_t);
-  static void PrefAddVarCache(float*, const char*, float);
-  static void PrefAddVarCache(std::string*, const char*, std::string);
-  static void PrefAddVarCache(AtomicBool*, const char*, bool);
-  static void PrefAddVarCache(AtomicInt32*, const char*, int32_t);
-  static void PrefAddVarCache(AtomicUint32*, const char*, uint32_t);
+  static void PrefAddVarCache(bool*, const nsACString&, bool);
+  static void PrefAddVarCache(int32_t*, const nsACString&, int32_t);
+  static void PrefAddVarCache(uint32_t*, const nsACString&, uint32_t);
+  static void PrefAddVarCache(float*, const nsACString&, float);
+  static void PrefAddVarCache(std::string*, const nsCString&, std::string);
+  static void PrefAddVarCache(AtomicBool*, const nsACString&, bool);
+  static void PrefAddVarCache(AtomicInt32*, const nsACString&, int32_t);
+  static void PrefAddVarCache(AtomicUint32*, const nsACString&, uint32_t);
   static bool PrefGet(const char*, bool);
   static int32_t PrefGet(const char*, int32_t);
   static uint32_t PrefGet(const char*, uint32_t);
   static float PrefGet(const char*, float);
   static std::string PrefGet(const char*, std::string);
   static void PrefSet(const char* aPref, bool aValue);
   static void PrefSet(const char* aPref, int32_t aValue);
   static void PrefSet(const char* aPref, uint32_t aValue);
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -146,17 +146,17 @@ MSG_DEF(JSMSG_BAD_FORMAL,              0
 MSG_DEF(JSMSG_CALLER_IS_STRICT,        0, JSEXN_TYPEERR, "access to strict mode caller function is censored")
 MSG_DEF(JSMSG_DEPRECATED_USAGE,        1, JSEXN_REFERENCEERR, "deprecated {0} usage")
 MSG_DEF(JSMSG_NOT_SCRIPTED_FUNCTION,   1, JSEXN_TYPEERR, "{0} is not a scripted function")
 MSG_DEF(JSMSG_NO_REST_NAME,            0, JSEXN_SYNTAXERR, "no parameter name after ...")
 MSG_DEF(JSMSG_PARAMETER_AFTER_REST,    0, JSEXN_SYNTAXERR, "parameter after rest parameter")
 MSG_DEF(JSMSG_TOO_MANY_ARGUMENTS,      0, JSEXN_RANGEERR, "too many arguments provided for a function call")
 
 // CSP
-MSG_DEF(JSMSG_CSP_BLOCKED_EVAL,        0, JSEXN_ERR, "call to eval() blocked by CSP")
+MSG_DEF(JSMSG_CSP_BLOCKED_EVAL,        0, JSEXN_EVALERR, "call to eval() blocked by CSP")
 MSG_DEF(JSMSG_CSP_BLOCKED_FUNCTION,    0, JSEXN_ERR, "call to Function() blocked by CSP")
 
 // Wrappers
 MSG_DEF(JSMSG_ACCESSOR_DEF_DENIED,     1, JSEXN_ERR, "Permission denied to define accessor property {0}")
 MSG_DEF(JSMSG_DEAD_OBJECT,             0, JSEXN_TYPEERR, "can't access dead object")
 MSG_DEF(JSMSG_OBJECT_ACCESS_DENIED,    0, JSEXN_ERR, "Permission denied to access object")
 MSG_DEF(JSMSG_PROPERTY_ACCESS_DENIED,  1, JSEXN_ERR, "Permission denied to access property {0}")
 
--- a/layout/base/PositionedEventTargeting.cpp
+++ b/layout/base/PositionedEventTargeting.cpp
@@ -107,37 +107,37 @@ GetPrefsFor(EventClassID aEventClassID)
   } else {
     return nullptr;
   }
 
   if (!prefs->mRegistered) {
     prefs->mRegistered = true;
 
     nsPrintfCString enabledPref("ui.%s.radius.enabled", prefBranch);
-    Preferences::AddBoolVarCache(&prefs->mEnabled, enabledPref.get(), false);
+    Preferences::AddBoolVarCache(&prefs->mEnabled, enabledPref, false);
 
     nsPrintfCString visitedWeightPref("ui.%s.radius.visitedWeight", prefBranch);
-    Preferences::AddUintVarCache(&prefs->mVisitedWeight, visitedWeightPref.get(), 100);
+    Preferences::AddUintVarCache(&prefs->mVisitedWeight, visitedWeightPref, 100);
 
     static const char prefNames[4][9] =
       { "topmm", "rightmm", "bottommm", "leftmm" };
     for (int32_t i = 0; i < 4; ++i) {
       nsPrintfCString radiusPref("ui.%s.radius.%s", prefBranch, prefNames[i]);
-      Preferences::AddUintVarCache(&prefs->mSideRadii[i], radiusPref.get(), 0);
+      Preferences::AddUintVarCache(&prefs->mSideRadii[i], radiusPref, 0);
     }
 
     if (aEventClassID == eMouseEventClass) {
       Preferences::AddBoolVarCache(&prefs->mTouchOnly,
           "ui.mouse.radius.inputSource.touchOnly", true);
     } else {
       prefs->mTouchOnly = false;
     }
 
     nsPrintfCString repositionPref("ui.%s.radius.reposition", prefBranch);
-    Preferences::AddBoolVarCache(&prefs->mRepositionEventCoords, repositionPref.get(), false);
+    Preferences::AddBoolVarCache(&prefs->mRepositionEventCoords, repositionPref, false);
 
     // These values were formerly set by ui.zoomedview preferences.
     prefs->mTouchClusterDetectionEnabled = false;
     prefs->mSimplifiedClusterDetection = false;
     prefs->mLimitReadableSize = 8;
     prefs->mKeepLimitSizeForCluster = 16;
   }
 
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -780,17 +780,17 @@ SheetLoadData::VerifySheetReadyToParse(n
       nsCOMPtr<nsIContentSecurityPolicy> csp;
       loadInfo->LoadingPrincipal()->GetCsp(getter_AddRefs(csp));
       nsAutoCString spec;
       mLoader->mDocument->GetDocumentURI()->GetAsciiSpec(spec);
       // line number unknown. mRequestingNode doesn't bear this info.
       csp->LogViolationDetails(
         nsIContentSecurityPolicy::VIOLATION_TYPE_REQUIRE_SRI_FOR_STYLE,
         NS_ConvertUTF8toUTF16(spec), EmptyString(),
-        0, EmptyString(), EmptyString());
+        0, 0, EmptyString(), EmptyString());
       return NS_OK;
     }
   } else {
     nsAutoCString sourceUri;
     if (mLoader->mDocument && mLoader->mDocument->GetDocumentURI()) {
       mLoader->mDocument->GetDocumentURI()->GetAsciiSpec(sourceUri);
     }
     nsresult rv = VerifySheetIntegrity(
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -121,18 +121,20 @@ nsCSSProps::AddRefTable(void)
       }
     }
 
     static bool prefObserversInited = false;
     if (!prefObserversInited) {
       prefObserversInited = true;
       for (const PropertyPref* pref = kPropertyPrefTable;
            pref->mPropID != eCSSProperty_UNKNOWN; pref++) {
+        nsCString prefName;
+        prefName.AssignLiteral(pref->mPref, strlen(pref->mPref));
         bool* enabled = &gPropertyEnabled[pref->mPropID];
-        Preferences::AddBoolVarCache(enabled, pref->mPref);
+        Preferences::AddBoolVarCache(enabled, prefName);
       }
     }
   }
 }
 
 #undef  DEBUG_SHORTHANDS_CONTAINING
 
 void
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5518,21 +5518,24 @@ nsComputedDOMStyle::RegisterPrefChangeCa
 {
   // Note that this will register callbacks for all properties with prefs, not
   // just those that are implemented on computed style objects, as it's not
   // easy to grab specific property data from ServoCSSPropList.h based on the
   // entries iterated in nsComputedDOMStylePropertyList.h.
   ComputedStyleMap* data = GetComputedStyleMap();
   for (const auto* p = nsCSSProps::kPropertyPrefTable;
        p->mPropID != eCSSProperty_UNKNOWN; p++) {
-    Preferences::RegisterCallback(MarkComputedStyleMapDirty, p->mPref, data);
+    nsCString name;
+    name.AssignLiteral(p->mPref, strlen(p->mPref));
+    Preferences::RegisterCallback(MarkComputedStyleMapDirty, name, data);
   }
 }
 
 /* static */ void
 nsComputedDOMStyle::UnregisterPrefChangeCallbacks()
 {
   ComputedStyleMap* data = GetComputedStyleMap();
   for (const auto* p = nsCSSProps::kPropertyPrefTable;
        p->mPropID != eCSSProperty_UNKNOWN; p++) {
-    Preferences::UnregisterCallback(MarkComputedStyleMapDirty, p->mPref, data);
-  }
-}
+    Preferences::UnregisterCallback(MarkComputedStyleMapDirty,
+                                    nsDependentCString(p->mPref), data);
+  }
+}
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -768,16 +768,17 @@ nsStyleUtil::ObjectPropsMightCauseOverfl
 
 
 /* static */ bool
 nsStyleUtil::CSPAllowsInlineStyle(Element* aElement,
                                   nsIPrincipal* aPrincipal,
                                   nsIPrincipal* aTriggeringPrincipal,
                                   nsIURI* aSourceURI,
                                   uint32_t aLineNumber,
+                                  uint32_t aColumnNumber,
                                   const nsAString& aStyleText,
                                   nsresult* aRv)
 {
   nsresult rv;
 
   if (aRv) {
     *aRv = NS_OK;
   }
@@ -816,17 +817,17 @@ nsStyleUtil::CSPAllowsInlineStyle(Elemen
   if (styleText) {
     styleText->SetData(aStyleText);
   }
 
   bool allowInlineStyle = true;
   rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_STYLESHEET,
                             nonce,
                             false, // aParserCreated only applies to scripts
-                            styleText, aLineNumber,
+                            styleText, aLineNumber, aColumnNumber,
                             &allowInlineStyle);
   NS_ENSURE_SUCCESS(rv, false);
 
   return allowInlineStyle;
 }
 
 void
 nsStyleUtil::AppendFontSlantStyle(const FontSlantStyle& aStyle, nsAString& aOut)
--- a/layout/style/nsStyleUtil.h
+++ b/layout/style/nsStyleUtil.h
@@ -197,28 +197,32 @@ public:
    *  @param aTriggeringPrincipal
    *      The principal of the scripted caller which added the inline
    *      stylesheet, or null if no scripted caller can be identified.
    *  @param aSourceURI
    *      URI of document containing inline style (for reporting violations)
    *  @param aLineNumber
    *      Line number of inline style element in the containing document (for
    *      reporting violations)
+   *  @param aColumnNumber
+   *      Column number of inline style element in the containing document (for
+   *      reporting violations)
    *  @param aStyleText
    *      Contents of the inline style element (for reporting violations)
    *  @param aRv
    *      Return error code in case of failure
    *  @return
    *      Does CSP allow application of the specified inline style?
    */
   static bool CSPAllowsInlineStyle(mozilla::dom::Element* aContent,
                                    nsIPrincipal* aPrincipal,
                                    nsIPrincipal* aTriggeringPrincipal,
                                    nsIURI* aSourceURI,
                                    uint32_t aLineNumber,
+                                   uint32_t aColumnNumber,
                                    const nsAString& aStyleText,
                                    nsresult* aRv);
 
   template<size_t N>
   static bool MatchesLanguagePrefix(const char16_t* aLang, size_t aLen,
                                     const char16_t (&aPrefix)[N])
   {
     return !NS_strncmp(aLang, aPrefix, N - 1) &&
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -66,17 +66,17 @@ int8_t nsMenuPopupFrame::sDefaultLevelIs
 DOMTimeStamp nsMenuPopupFrame::sLastKeyTime = 0;
 
 // XXX, kyle.yuan@sun.com, there are 4 definitions for the same purpose:
 //  nsMenuPopupFrame.h, nsListControlFrame.cpp, listbox.xml, tree.xml
 //  need to find a good place to put them together.
 //  if someone changes one, please also change the other.
 uint32_t nsMenuPopupFrame::sTimeoutOfIncrementalSearch = 1000;
 
-const char* kPrefIncrementalSearchTimeout =
+const char kPrefIncrementalSearchTimeout[] =
   "ui.menu.incremental_search.timeout";
 
 // NS_NewMenuPopupFrame
 //
 // Wrapper for creating a new menu popup container
 //
 nsIFrame*
 NS_NewMenuPopupFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -128,17 +128,17 @@ nsMenuChainItem::CheckForAnchorChange()
 {
   if (mFollowAnchor) {
     mFrame->CheckForAnchorChange(mCurrentRect);
   }
 }
 
 bool nsXULPopupManager::sDevtoolsDisableAutoHide = false;
 
-const char* kPrefDevtoolsDisableAutoHide =
+const char kPrefDevtoolsDisableAutoHide[] =
   "ui.popup.disable_autohide";
 
 NS_IMPL_ISUPPORTS(nsXULPopupManager,
                   nsIDOMEventListener,
                   nsIObserver)
 
 nsXULPopupManager::nsXULPopupManager() :
   mRangeOffset(0),
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -78,16 +78,20 @@
 #include "nsXPCOM.h"
 #include "nsXULAppAPI.h"
 #include "nsZipArchive.h"
 #include "plbase64.h"
 #include "PLDHashTable.h"
 #include "plstr.h"
 #include "prlink.h"
 
+#ifdef MOZ_MEMORY
+#include "mozmemory.h"
+#endif
+
 #ifdef XP_WIN
 #include "windows.h"
 #endif
 
 using namespace mozilla;
 
 #ifdef DEBUG
 
@@ -199,17 +203,20 @@ union PrefValue {
     if (aType == PrefType::String) {
       free(const_cast<char*>(mStringVal));
     }
 
     // Zero the entire value (regardless of type) via mStringVal.
     mStringVal = nullptr;
   }
 
-  void Replace(bool aHasValue, PrefType aOldType, PrefType aNewType, PrefValue aNewValue)
+  void Replace(bool aHasValue,
+               PrefType aOldType,
+               PrefType aNewType,
+               PrefValue aNewValue)
   {
     if (aHasValue) {
       Clear(aOldType);
     }
     Init(aNewType, aNewValue);
   }
 
   void ToDomPrefValue(PrefType aType, dom::PrefValue* aDomValue)
@@ -992,30 +999,30 @@ public:
     delete entry->mPref;
     entry->mPref = nullptr;
   }
 };
 
 class CallbackNode
 {
 public:
-  CallbackNode(const char* aDomain,
+  CallbackNode(const nsACString& aDomain,
                PrefChangedFunc aFunc,
                void* aData,
                Preferences::MatchKind aMatchKind)
-    : mDomain(moz_xstrdup(aDomain))
+    : mDomain(aDomain)
     , mFunc(aFunc)
     , mData(aData)
     , mNextAndMatchKind(aMatchKind)
   {
   }
 
   // mDomain is a UniquePtr<>, so any uses of Domain() should only be temporary
   // borrows.
-  const char* Domain() const { return mDomain.get(); }
+  const nsCString& Domain() const { return mDomain; }
 
   PrefChangedFunc Func() const { return mFunc; }
   void ClearFunc() { mFunc = nullptr; }
 
   void* Data() const { return mData; }
 
   Preferences::MatchKind MatchKind() const
   {
@@ -1034,24 +1041,25 @@ public:
     mNextAndMatchKind = reinterpret_cast<uintptr_t>(aNext);
     MOZ_ASSERT((mNextAndMatchKind & kMatchKindMask) == 0);
     mNextAndMatchKind |= matchKind;
   }
 
   void AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, PrefsSizes& aSizes)
   {
     aSizes.mCallbacksObjects += aMallocSizeOf(this);
-    aSizes.mCallbacksDomains += aMallocSizeOf(mDomain.get());
+    aSizes.mCallbacksDomains +=
+      mDomain.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
   }
 
 private:
   static const uintptr_t kMatchKindMask = uintptr_t(0x1);
   static const uintptr_t kNextMask = ~kMatchKindMask;
 
-  UniqueFreePtr<const char> mDomain;
+  nsCString mDomain;
 
   // If someone attempts to remove the node from the callback list while
   // NotifyCallbacks() is running, |func| is set to nullptr. Such nodes will
   // be removed at the end of NotifyCallbacks().
   PrefChangedFunc mFunc;
   void* mData;
 
   // Conceptually this is two fields:
@@ -1231,22 +1239,23 @@ NotifyCallbacks(const char* aPrefName)
   bool reentered = gCallbacksInProgress;
 
   // Nodes must not be deleted while gCallbacksInProgress is true.
   // Nodes that need to be deleted are marked for deletion by nulling
   // out the |func| pointer. We release them at the end of this function
   // if we haven't reentered.
   gCallbacksInProgress = true;
 
+  nsDependentCString prefName(aPrefName);
+
   for (CallbackNode* node = gFirstCallback; node; node = node->Next()) {
     if (node->Func()) {
-      bool matches =
-        node->MatchKind() == Preferences::ExactMatch
-          ? strcmp(node->Domain(), aPrefName) == 0
-          : strncmp(node->Domain(), aPrefName, strlen(node->Domain())) == 0;
+      bool matches = node->MatchKind() == Preferences::ExactMatch
+                       ? node->Domain() == prefName
+                       : StringBeginsWith(prefName, node->Domain());
       if (matches) {
         (node->Func())(aPrefName, node->Data());
       }
     }
   }
 
   gCallbacksInProgress = reentered;
 
@@ -1454,31 +1463,31 @@ public:
   static PLDHashNumber HashKey(const PrefCallback* aKey)
   {
     uint32_t hash = mozilla::HashString(aKey->mDomain);
     return mozilla::AddToHash(hash, aKey->mCanonical);
   }
 
 public:
   // Create a PrefCallback with a strong reference to its observer.
-  PrefCallback(const char* aDomain,
+  PrefCallback(const nsACString& aDomain,
                nsIObserver* aObserver,
                nsPrefBranch* aBranch)
     : mDomain(aDomain)
     , mBranch(aBranch)
     , mWeakRef(nullptr)
     , mStrongRef(aObserver)
   {
     MOZ_COUNT_CTOR(PrefCallback);
     nsCOMPtr<nsISupports> canonical = do_QueryInterface(aObserver);
     mCanonical = canonical;
   }
 
   // Create a PrefCallback with a weak reference to its observer.
-  PrefCallback(const char* aDomain,
+  PrefCallback(const nsACString& aDomain,
                nsISupportsWeakReference* aObserver,
                nsPrefBranch* aBranch)
     : mDomain(aDomain)
     , mBranch(aBranch)
     , mWeakRef(do_GetWeakReference(aObserver))
     , mStrongRef(nullptr)
   {
     MOZ_COUNT_CTOR(PrefCallback);
@@ -1624,28 +1633,40 @@ private:
     PrefName& operator=(const PrefName&) = delete;
 
     struct PtrMatcher
     {
       static const char* match(const char* aVal) { return aVal; }
       static const char* match(const nsCString& aVal) { return aVal.get(); }
     };
 
+    struct CStringMatcher
+    {
+      // Note: This is a reference, not an instance. It's used to pass our outer
+      // method argument through to our matcher methods.
+      nsACString& mStr;
+
+      void match(const char* aVal) { mStr.Assign(aVal); }
+      void match(const nsCString& aVal) { mStr.Assign(aVal); }
+    };
+
     struct LenMatcher
     {
       static size_t match(const char* aVal) { return strlen(aVal); }
       static size_t match(const nsCString& aVal) { return aVal.Length(); }
     };
 
     const char* get() const
     {
       static PtrMatcher m;
       return match(m);
     }
 
+    void get(nsACString& aStr) const { match(CStringMatcher{ aStr }); }
+
     size_t Length() const
     {
       static LenMatcher m;
       return match(m);
     }
   };
 
   virtual ~nsPrefBranch();
@@ -1664,17 +1685,22 @@ private:
                                      const nsAString& aValue);
   nsresult CheckSanityOfStringLength(const char* aPrefName,
                                      const nsACString& aValue);
   nsresult CheckSanityOfStringLength(const char* aPrefName,
                                      const uint32_t aLength);
 
   void RemoveExpiredCallback(PrefCallback* aCallback);
 
-  PrefName GetPrefName(const char* aPrefName) const;
+  PrefName GetPrefName(const char* aPrefName) const
+  {
+    return GetPrefName(nsDependentCString(aPrefName));
+  }
+
+  PrefName GetPrefName(const nsACString& aPrefName) const;
 
   void FreeObserverList(void);
 
   const nsCString mPrefRoot;
   PrefValueKind mKind;
 
   bool mFreeingObserverList;
   nsClassHashtable<PrefCallback, PrefCallback> mObservers;
@@ -2358,69 +2384,70 @@ nsPrefBranch::GetChildList(const char* a
     *aChildArray = outArray;
   }
   *aCount = numPrefs;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPrefBranch::AddObserver(const char* aDomain,
-                          nsIObserver* aObserver,
-                          bool aHoldWeak)
+nsPrefBranch::AddObserverImpl(const nsACString& aDomain,
+                              nsIObserver* aObserver,
+                              bool aHoldWeak)
 {
   PrefCallback* pCallback;
 
-  NS_ENSURE_ARG(aDomain);
   NS_ENSURE_ARG(aObserver);
 
+  nsCString prefName;
+  GetPrefName(aDomain).get(prefName);
+
   // Hold a weak reference to the observer if so requested.
   if (aHoldWeak) {
     nsCOMPtr<nsISupportsWeakReference> weakRefFactory =
       do_QueryInterface(aObserver);
     if (!weakRefFactory) {
       // The caller didn't give us a object that supports weak reference...
       // tell them.
       return NS_ERROR_INVALID_ARG;
     }
 
     // Construct a PrefCallback with a weak reference to the observer.
-    pCallback = new PrefCallback(aDomain, weakRefFactory, this);
+    pCallback = new PrefCallback(prefName, weakRefFactory, this);
 
   } else {
     // Construct a PrefCallback with a strong reference to the observer.
-    pCallback = new PrefCallback(aDomain, aObserver, this);
+    pCallback = new PrefCallback(prefName, aObserver, this);
   }
 
   auto p = mObservers.LookupForAdd(pCallback);
   if (p) {
     NS_WARNING("Ignoring duplicate observer.");
     delete pCallback;
     return NS_OK;
   }
 
   p.OrInsert([&pCallback]() { return pCallback; });
 
   // We must pass a fully qualified preference name to the callback
   // aDomain == nullptr is the only possible failure, and we trapped it with
   // NS_ENSURE_ARG above.
-  const PrefName& pref = GetPrefName(aDomain);
   Preferences::RegisterCallback(NotifyObserver,
-                                pref.get(),
+                                prefName,
                                 pCallback,
                                 Preferences::PrefixMatch,
                                 /* isPriority */ false);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
-nsPrefBranch::RemoveObserver(const char* aDomain, nsIObserver* aObserver)
+nsPrefBranch::RemoveObserverImpl(const nsACString& aDomain,
+                                 nsIObserver* aObserver)
 {
-  NS_ENSURE_ARG(aDomain);
   NS_ENSURE_ARG(aObserver);
 
   nsresult rv = NS_OK;
 
   // If we're in the middle of a call to FreeObserverList, don't process this
   // RemoveObserver call -- the observer in question will be removed soon, if
   // it hasn't been already.
   //
@@ -2429,24 +2456,24 @@ nsPrefBranch::RemoveObserver(const char*
   // break the iteration in FreeObserverList.
   if (mFreeingObserverList) {
     return NS_OK;
   }
 
   // Remove the relevant PrefCallback from mObservers and get an owning pointer
   // to it. Unregister the callback first, and then let the owning pointer go
   // out of scope and destroy the callback.
-  PrefCallback key(aDomain, aObserver, this);
+  nsCString prefName;
+  GetPrefName(aDomain).get(prefName);
+  PrefCallback key(prefName, aObserver, this);
   nsAutoPtr<PrefCallback> pCallback;
   mObservers.Remove(&key, &pCallback);
   if (pCallback) {
-    // aDomain == nullptr is the only possible failure, trapped above.
-    const PrefName& pref = GetPrefName(aDomain);
     rv = Preferences::UnregisterCallback(
-      NotifyObserver, pref.get(), pCallback, Preferences::PrefixMatch);
+      NotifyObserver, prefName, pCallback, Preferences::PrefixMatch);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsPrefBranch::Observe(nsISupports* aSubject,
                       const char* aTopic,
@@ -2470,17 +2497,17 @@ nsPrefBranch::NotifyObserver(const char*
     // The observer has expired.  Let's remove this callback.
     pCallback->GetPrefBranch()->RemoveExpiredCallback(pCallback);
     return;
   }
 
   // Remove any root this string may contain so as to not confuse the observer
   // by passing them something other than what they passed us as a topic.
   uint32_t len = pCallback->GetPrefBranch()->GetRootLength();
-  nsAutoCString suffix(aNewPref + len);
+  nsDependentCString suffix(aNewPref + len);
 
   observer->Observe(static_cast<nsIPrefBranch*>(pCallback->GetPrefBranch()),
                     NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
                     NS_ConvertASCIItoUTF16(suffix).get());
 }
 
 size_t
 nsPrefBranch::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
@@ -2503,20 +2530,18 @@ nsPrefBranch::FreeObserverList()
 {
   // We need to prevent anyone from modifying mObservers while we're iterating
   // over it. In particular, some clients will call RemoveObserver() when
   // they're removed and destructed via the iterator; we set
   // mFreeingObserverList to keep those calls from touching mObservers.
   mFreeingObserverList = true;
   for (auto iter = mObservers.Iter(); !iter.Done(); iter.Next()) {
     nsAutoPtr<PrefCallback>& callback = iter.Data();
-    nsPrefBranch* prefBranch = callback->GetPrefBranch();
-    const PrefName& pref = prefBranch->GetPrefName(callback->GetDomain().get());
     Preferences::UnregisterCallback(nsPrefBranch::NotifyObserver,
-                                    pref.get(),
+                                    callback->GetDomain(),
                                     callback,
                                     Preferences::PrefixMatch);
     iter.Remove();
   }
   mFreeingObserverList = false;
 }
 
 void
@@ -2551,26 +2576,23 @@ nsPrefBranch::GetDefaultFromPropertiesFi
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return bundle->GetStringFromName(aPrefName, aReturn);
 }
 
 nsPrefBranch::PrefName
-nsPrefBranch::GetPrefName(const char* aPrefName) const
+nsPrefBranch::GetPrefName(const nsACString& aPrefName) const
 {
-  MOZ_ASSERT(aPrefName);
-
-  // For speed, avoid strcpy if we can.
   if (mPrefRoot.IsEmpty()) {
-    return PrefName(aPrefName);
-  }
-
-  return PrefName(mPrefRoot + nsDependentCString(aPrefName));
+    return PrefName(PromiseFlatCString(aPrefName));
+  }
+
+  return PrefName(mPrefRoot + aPrefName);
 }
 
 //----------------------------------------------------------------------------
 // nsPrefLocalizedString
 //----------------------------------------------------------------------------
 
 nsPrefLocalizedString::nsPrefLocalizedString() = default;
 
@@ -2886,16 +2908,24 @@ AssertNotAlreadyCached(const char* aPref
       aPref,
       aPtr);
     MOZ_ASSERT(false,
                "Should not have an existing pref cache for this address");
   }
 #endif
 }
 
+static void
+AssertNotAlreadyCached(const char* aPrefType,
+                       const nsACString& aPref,
+                       void* aPtr)
+{
+  AssertNotAlreadyCached(aPrefType, PromiseFlatCString(aPref).get(), aPtr);
+}
+
 // Although this is a member of Preferences, it measures sPreferences and
 // several other global structures.
 /* static */ void
 Preferences::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf,
                                     PrefsSizes& aSizes)
 {
   if (!sPreferences) {
     return;
@@ -3025,40 +3055,37 @@ PreferenceServiceReporter::CollectReport
   size_t numWeakAlive = 0;
   size_t numWeakDead = 0;
   nsTArray<nsCString> suspectPreferences;
   // Count of the number of referents for each preference.
   nsDataHashtable<nsCStringHashKey, uint32_t> prefCounter;
 
   for (auto iter = rootBranch->mObservers.Iter(); !iter.Done(); iter.Next()) {
     nsAutoPtr<PrefCallback>& callback = iter.Data();
-    nsPrefBranch* prefBranch = callback->GetPrefBranch();
-    const auto& pref = prefBranch->GetPrefName(callback->GetDomain().get());
 
     if (callback->IsWeak()) {
       nsCOMPtr<nsIObserver> callbackRef = do_QueryReferent(callback->mWeakRef);
       if (callbackRef) {
         numWeakAlive++;
       } else {
         numWeakDead++;
       }
     } else {
       numStrong++;
     }
 
-    nsDependentCString prefString(pref.get());
     uint32_t oldCount = 0;
-    prefCounter.Get(prefString, &oldCount);
+    prefCounter.Get(callback->GetDomain(), &oldCount);
     uint32_t currentCount = oldCount + 1;
-    prefCounter.Put(prefString, currentCount);
+    prefCounter.Put(callback->GetDomain(), currentCount);
 
     // Keep track of preferences that have a suspiciously large number of
     // referents (a symptom of a leak).
     if (currentCount == kSuspectReferentCount) {
-      suspectPreferences.AppendElement(prefString);
+      suspectPreferences.AppendElement(callback->GetDomain());
     }
   }
 
   for (uint32_t i = 0; i < suspectPreferences.Length(); i++) {
     nsCString& suspect = suspectPreferences[i];
     uint32_t totalReferentCount = 0;
     prefCounter.Get(suspect, &totalReferentCount);
 
@@ -4555,90 +4582,108 @@ Preferences::GetType(const char* aPrefNa
       return PREF_BOOL;
 
     default:
       MOZ_CRASH();
   }
 }
 
 /* static */ nsresult
-Preferences::AddStrongObserver(nsIObserver* aObserver, const char* aPref)
+Preferences::AddStrongObserver(nsIObserver* aObserver, const nsACString& aPref)
 {
   MOZ_ASSERT(aObserver);
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
   return sPreferences->mRootBranch->AddObserver(aPref, aObserver, false);
 }
 
 /* static */ nsresult
-Preferences::AddWeakObserver(nsIObserver* aObserver, const char* aPref)
+Preferences::AddWeakObserver(nsIObserver* aObserver, const nsACString& aPref)
 {
   MOZ_ASSERT(aObserver);
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
   return sPreferences->mRootBranch->AddObserver(aPref, aObserver, true);
 }
 
 /* static */ nsresult
-Preferences::RemoveObserver(nsIObserver* aObserver, const char* aPref)
+Preferences::RemoveObserver(nsIObserver* aObserver, const nsACString& aPref)
 {
   MOZ_ASSERT(aObserver);
   if (sShutdown) {
     MOZ_ASSERT(!sPreferences);
     return NS_OK; // Observers have been released automatically.
   }
   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
   return sPreferences->mRootBranch->RemoveObserver(aPref, aObserver);
 }
 
+template<typename T>
+static void
+AssertNotMallocAllocated(T* aPtr)
+{
+#if defined(DEBUG) && defined(MOZ_MEMORY)
+  jemalloc_ptr_info_t info;
+  jemalloc_ptr_info((void*)aPtr, &info);
+  MOZ_ASSERT(info.tag == TagUnknown);
+#endif
+}
+
 /* static */ nsresult
 Preferences::AddStrongObservers(nsIObserver* aObserver, const char** aPrefs)
 {
   MOZ_ASSERT(aObserver);
   for (uint32_t i = 0; aPrefs[i]; i++) {
-    nsresult rv = AddStrongObserver(aObserver, aPrefs[i]);
+    AssertNotMallocAllocated(aPrefs[i]);
+
+    nsCString pref;
+    pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i]));
+    nsresult rv = AddStrongObserver(aObserver, pref);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 /* static */ nsresult
 Preferences::AddWeakObservers(nsIObserver* aObserver, const char** aPrefs)
 {
   MOZ_ASSERT(aObserver);
   for (uint32_t i = 0; aPrefs[i]; i++) {
-    nsresult rv = AddWeakObserver(aObserver, aPrefs[i]);
+    AssertNotMallocAllocated(aPrefs[i]);
+
+    nsCString pref;
+    pref.AssignLiteral(aPrefs[i], strlen(aPrefs[i]));
+    nsresult rv = AddWeakObserver(aObserver, pref);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 /* static */ nsresult
 Preferences::RemoveObservers(nsIObserver* aObserver, const char** aPrefs)
 {
   MOZ_ASSERT(aObserver);
   if (sShutdown) {
     MOZ_ASSERT(!sPreferences);
     return NS_OK; // Observers have been released automatically.
   }
   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
 
   for (uint32_t i = 0; aPrefs[i]; i++) {
-    nsresult rv = RemoveObserver(aObserver, aPrefs[i]);
+    nsresult rv = RemoveObserver(aObserver, nsDependentCString(aPrefs[i]));
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
 /* static */ nsresult
 Preferences::RegisterCallback(PrefChangedFunc aCallback,
-                              const char* aPrefNode,
+                              const nsACString& aPrefNode,
                               void* aData,
                               MatchKind aMatchKind,
                               bool aIsPriority)
 {
-  NS_ENSURE_ARG(aPrefNode);
   NS_ENSURE_ARG(aCallback);
 
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
 
   auto node = new CallbackNode(aPrefNode, aCallback, aData, aMatchKind);
 
   if (aIsPriority) {
     // Add to the start of the list.
@@ -4658,49 +4703,48 @@ Preferences::RegisterCallback(PrefChange
     }
   }
 
   return NS_OK;
 }
 
 /* static */ nsresult
 Preferences::RegisterCallbackAndCall(PrefChangedFunc aCallback,
-                                     const char* aPref,
+                                     const nsACString& aPref,
                                      void* aClosure,
                                      MatchKind aMatchKind)
 {
   MOZ_ASSERT(aCallback);
   nsresult rv = RegisterCallback(aCallback, aPref, aClosure, aMatchKind);
   if (NS_SUCCEEDED(rv)) {
-    (*aCallback)(aPref, aClosure);
+    (*aCallback)(PromiseFlatCString(aPref).get(), aClosure);
   }
   return rv;
 }
 
 /* static */ nsresult
 Preferences::UnregisterCallback(PrefChangedFunc aCallback,
-                                const char* aPrefNode,
+                                const nsACString& aPrefNode,
                                 void* aData,
                                 MatchKind aMatchKind)
 {
   MOZ_ASSERT(aCallback);
   if (sShutdown) {
     MOZ_ASSERT(!sPreferences);
     return NS_OK; // Observers have been released automatically.
   }
   NS_ENSURE_TRUE(sPreferences, NS_ERROR_NOT_AVAILABLE);
 
   nsresult rv = NS_ERROR_FAILURE;
   CallbackNode* node = gFirstCallback;
   CallbackNode* prev_node = nullptr;
 
   while (node) {
     if (node->Func() == aCallback && node->Data() == aData &&
-        node->MatchKind() == aMatchKind &&
-        strcmp(node->Domain(), aPrefNode) == 0) {
+        node->MatchKind() == aMatchKind && node->Domain() == aPrefNode) {
       if (gCallbacksInProgress) {
         // Postpone the node removal until after callbacks enumeration is
         // finished.
         node->ClearFunc();
         gShouldCleanupDeadNodes = true;
         prev_node = node;
         node = node->Next();
       } else {
@@ -4729,23 +4773,23 @@ BoolVarChanged(const char* aPref, void* 
 {
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *static_cast<bool*>(cache->mCacheLocation) =
     Preferences::GetBool(aPref, cache->mDefaultValueBool);
 }
 
 /* static */ nsresult
 Preferences::AddBoolVarCache(bool* aCache,
-                             const char* aPref,
+                             const nsACString& aPref,
                              bool aDefault,
                              bool aSkipAssignment)
 {
   AssertNotAlreadyCached("bool", aPref, aCache);
   if (!aSkipAssignment) {
-    *aCache = GetBool(aPref, aDefault);
+    *aCache = GetBool(PromiseFlatCString(aPref).get(), aDefault);
   }
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueBool = aDefault;
   CacheDataAppendElement(data);
   Preferences::RegisterCallback(BoolVarChanged,
                                 aPref,
                                 data,
@@ -4761,23 +4805,23 @@ AtomicBoolVarChanged(const char* aPref, 
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *static_cast<Atomic<bool, Order>*>(cache->mCacheLocation) =
     Preferences::GetBool(aPref, cache->mDefaultValueBool);
 }
 
 template<MemoryOrdering Order>
 /* static */ nsresult
 Preferences::AddAtomicBoolVarCache(Atomic<bool, Order>* aCache,
-                                   const char* aPref,
+                                   const nsACString& aPref,
                                    bool aDefault,
                                    bool aSkipAssignment)
 {
   AssertNotAlreadyCached("bool", aPref, aCache);
   if (!aSkipAssignment) {
-    *aCache = GetBool(aPref, aDefault);
+    *aCache = GetBool(PromiseFlatCString(aPref).get(), aDefault);
   }
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueBool = aDefault;
   CacheDataAppendElement(data);
   Preferences::RegisterCallback(AtomicBoolVarChanged<Order>,
                                 aPref,
                                 data,
@@ -4791,23 +4835,23 @@ IntVarChanged(const char* aPref, void* a
 {
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *static_cast<int32_t*>(cache->mCacheLocation) =
     Preferences::GetInt(aPref, cache->mDefaultValueInt);
 }
 
 /* static */ nsresult
 Preferences::AddIntVarCache(int32_t* aCache,
-                            const char* aPref,
+                            const nsACString& aPref,
                             int32_t aDefault,
                             bool aSkipAssignment)
 {
   AssertNotAlreadyCached("int", aPref, aCache);
   if (!aSkipAssignment) {
-    *aCache = GetInt(aPref, aDefault);
+    *aCache = GetInt(PromiseFlatCString(aPref).get(), aDefault);
   }
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueInt = aDefault;
   CacheDataAppendElement(data);
   Preferences::RegisterCallback(
     IntVarChanged, aPref, data, Preferences::ExactMatch, /* isPriority */ true);
   return NS_OK;
@@ -4820,23 +4864,23 @@ AtomicIntVarChanged(const char* aPref, v
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *static_cast<Atomic<int32_t, Order>*>(cache->mCacheLocation) =
     Preferences::GetInt(aPref, cache->mDefaultValueUint);
 }
 
 template<MemoryOrdering Order>
 /* static */ nsresult
 Preferences::AddAtomicIntVarCache(Atomic<int32_t, Order>* aCache,
-                                  const char* aPref,
+                                  const nsACString& aPref,
                                   int32_t aDefault,
                                   bool aSkipAssignment)
 {
   AssertNotAlreadyCached("int", aPref, aCache);
   if (!aSkipAssignment) {
-    *aCache = GetInt(aPref, aDefault);
+    *aCache = GetInt(PromiseFlatCString(aPref).get(), aDefault);
   }
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueUint = aDefault;
   CacheDataAppendElement(data);
   Preferences::RegisterCallback(AtomicIntVarChanged<Order>,
                                 aPref,
                                 data,
@@ -4850,23 +4894,23 @@ UintVarChanged(const char* aPref, void* 
 {
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *static_cast<uint32_t*>(cache->mCacheLocation) =
     Preferences::GetUint(aPref, cache->mDefaultValueUint);
 }
 
 /* static */ nsresult
 Preferences::AddUintVarCache(uint32_t* aCache,
-                             const char* aPref,
+                             const nsACString& aPref,
                              uint32_t aDefault,
                              bool aSkipAssignment)
 {
   AssertNotAlreadyCached("uint", aPref, aCache);
   if (!aSkipAssignment) {
-    *aCache = GetUint(aPref, aDefault);
+    *aCache = GetUint(PromiseFlatCString(aPref).get(), aDefault);
   }
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueUint = aDefault;
   CacheDataAppendElement(data);
   Preferences::RegisterCallback(UintVarChanged,
                                 aPref,
                                 data,
@@ -4882,23 +4926,23 @@ AtomicUintVarChanged(const char* aPref, 
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *static_cast<Atomic<uint32_t, Order>*>(cache->mCacheLocation) =
     Preferences::GetUint(aPref, cache->mDefaultValueUint);
 }
 
 template<MemoryOrdering Order>
 /* static */ nsresult
 Preferences::AddAtomicUintVarCache(Atomic<uint32_t, Order>* aCache,
-                                   const char* aPref,
+                                   const nsACString& aPref,
                                    uint32_t aDefault,
                                    bool aSkipAssignment)
 {
   AssertNotAlreadyCached("uint", aPref, aCache);
   if (!aSkipAssignment) {
-    *aCache = GetUint(aPref, aDefault);
+    *aCache = GetUint(PromiseFlatCString(aPref).get(), aDefault);
   }
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueUint = aDefault;
   CacheDataAppendElement(data);
   Preferences::RegisterCallback(AtomicUintVarChanged<Order>,
                                 aPref,
                                 data,
@@ -4907,73 +4951,73 @@ Preferences::AddAtomicUintVarCache(Atomi
   return NS_OK;
 }
 
 // Since the definition of template functions is not in a header file, we
 // need to explicitly specify the instantiations that are required. Currently
 // limited orders are needed and therefore implemented.
 template nsresult
 Preferences::AddAtomicBoolVarCache(Atomic<bool, Relaxed>*,
-                                   const char*,
+                                   const nsACString&,
                                    bool,
                                    bool);
 
 template nsresult
 Preferences::AddAtomicBoolVarCache(Atomic<bool, ReleaseAcquire>*,
-                                   const char*,
+                                   const nsACString&,
                                    bool,
                                    bool);
 
 template nsresult
 Preferences::AddAtomicBoolVarCache(Atomic<bool, SequentiallyConsistent>*,
-                                   const char*,
+                                   const nsACString&,
                                    bool,
                                    bool);
 
 template nsresult
 Preferences::AddAtomicIntVarCache(Atomic<int32_t, Relaxed>*,
-                                  const char*,
+                                  const nsACString&,
                                   int32_t,
                                   bool);
 
 template nsresult
 Preferences::AddAtomicUintVarCache(Atomic<uint32_t, Relaxed>*,
-                                   const char*,
+                                   const nsACString&,
                                    uint32_t,
                                    bool);
 
 template nsresult
 Preferences::AddAtomicUintVarCache(Atomic<uint32_t, ReleaseAcquire>*,
-                                   const char*,
+                                   const nsACString&,
                                    uint32_t,
                                    bool);
 
 template nsresult
 Preferences::AddAtomicUintVarCache(Atomic<uint32_t, SequentiallyConsistent>*,
-                                   const char*,
+                                   const nsACString&,
                                    uint32_t,
                                    bool);
 
 static void
 FloatVarChanged(const char* aPref, void* aClosure)
 {
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *static_cast<float*>(cache->mCacheLocation) =
     Preferences::GetFloat(aPref, cache->mDefaultValueFloat);
 }
 
 /* static */ nsresult
 Preferences::AddFloatVarCache(float* aCache,
-                              const char* aPref,
+                              const nsACString& aPref,
                               float aDefault,
                               bool aSkipAssignment)
 {
   AssertNotAlreadyCached("float", aPref, aCache);
   if (!aSkipAssignment) {
-    *aCache = GetFloat(aPref, aDefault);
+    *aCache = GetFloat(PromiseFlatCString(aPref).get(), aDefault);
   }
   CacheData* data = new CacheData();
   data->mCacheLocation = aCache;
   data->mDefaultValueFloat = aDefault;
   CacheDataAppendElement(data);
   Preferences::RegisterCallback(FloatVarChanged,
                                 aPref,
                                 data,
@@ -5054,105 +5098,107 @@ SetPref_String(const char* aName, const 
                PrefValueKind::Default,
                value,
                /* isSticky */ false,
                /* isLocked */ false,
                /* fromInit */ true);
 }
 
 static void
-InitVarCachePref(const char* aName,
+InitVarCachePref(const nsACString& aName,
                  bool* aCache,
                  bool aDefaultValue,
                  bool aIsStartup)
 {
-  SetPref_bool(aName, aDefaultValue);
+  SetPref_bool(PromiseFlatCString(aName).get(), aDefaultValue);
   *aCache = aDefaultValue;
   if (aIsStartup) {
     Preferences::AddBoolVarCache(aCache, aName, aDefaultValue, true);
   }
 }
 
 template<MemoryOrdering Order>
 static void
-InitVarCachePref(const char* aName,
+InitVarCachePref(const nsACString& aName,
                  Atomic<bool, Order>* aCache,
                  bool aDefaultValue,
                  bool aIsStartup)
 {
-  SetPref_bool(aName, aDefaultValue);
+  SetPref_bool(PromiseFlatCString(aName).get(), aDefaultValue);
   *aCache = aDefaultValue;
   if (aIsStartup) {
     Preferences::AddAtomicBoolVarCache(aCache, aName, aDefaultValue, true);
   }
 }
 
 // XXX: this will eventually become used
 MOZ_MAYBE_UNUSED static void
-InitVarCachePref(const char* aName,
+InitVarCachePref(const nsACString& aName,
                  int32_t* aCache,
                  int32_t aDefaultValue,
                  bool aIsStartup)
 {
-  SetPref_int32_t(aName, aDefaultValue);
+  SetPref_int32_t(PromiseFlatCString(aName).get(), aDefaultValue);
   *aCache = aDefaultValue;
   if (aIsStartup) {
     Preferences::AddIntVarCache(aCache, aName, aDefaultValue, true);
   }
 }
 
 template<MemoryOrdering Order>
 static void
-InitVarCachePref(const char* aName,
+InitVarCachePref(const nsACString& aName,
                  Atomic<int32_t, Order>* aCache,
                  int32_t aDefaultValue,
                  bool aIsStartup)
 {
-  SetPref_int32_t(aName, aDefaultValue);
+  SetPref_int32_t(PromiseFlatCString(aName).get(), aDefaultValue);
   *aCache = aDefaultValue;
   if (aIsStartup) {
     Preferences::AddAtomicIntVarCache(aCache, aName, aDefaultValue, true);
   }
 }
 
 static void
-InitVarCachePref(const char* aName,
+InitVarCachePref(const nsACString& aName,
                  uint32_t* aCache,
                  uint32_t aDefaultValue,
                  bool aIsStartup)
 {
-  SetPref_int32_t(aName, static_cast<int32_t>(aDefaultValue));
+  SetPref_int32_t(PromiseFlatCString(aName).get(),
+                  static_cast<int32_t>(aDefaultValue));
   *aCache = aDefaultValue;
   if (aIsStartup) {
     Preferences::AddUintVarCache(aCache, aName, aDefaultValue, true);
   }
 }
 
 template<MemoryOrdering Order>
 static void
-InitVarCachePref(const char* aName,
+InitVarCachePref(const nsACString& aName,
                  Atomic<uint32_t, Order>* aCache,
                  uint32_t aDefaultValue,
                  bool aIsStartup)
 {
-  SetPref_int32_t(aName, static_cast<int32_t>(aDefaultValue));
+  SetPref_int32_t(PromiseFlatCString(aName).get(),
+                  static_cast<int32_t>(aDefaultValue));
   *aCache = aDefaultValue;
   if (aIsStartup) {
     Preferences::AddAtomicUintVarCache(aCache, aName, aDefaultValue, true);
   }
 }
 
 // XXX: this will eventually become used
 MOZ_MAYBE_UNUSED static void
-InitVarCachePref(const char* aName,
+InitVarCachePref(const nsACString& aName,
                  float* aCache,
                  float aDefaultValue,
                  bool aIsStartup)
 {
-  SetPref_float(aName, aDefaultValue);
+  SetPref_float(PromiseFlatCString(aName).get(), aDefaultValue);
   *aCache = aDefaultValue;
   if (aIsStartup) {
     Preferences::AddFloatVarCache(aCache, aName, aDefaultValue, true);
   }
 }
 
 /* static */ void
 StaticPrefs::InitAll(bool aIsStartup)
@@ -5169,17 +5215,20 @@ StaticPrefs::InitAll(bool aIsStartup)
 //                    aIsStartup);
 //
 // The SetPref_*() functions have a type suffix to avoid ambiguity between
 // prefs having int32_t and float default values. That suffix is not needed for
 // the InitVarCachePref() functions because they take a pointer parameter,
 // which prevents automatic int-to-float coercion.
 #define PREF(name, cpp_type, value) SetPref_##cpp_type(name, value);
 #define VARCACHE_PREF(name, id, cpp_type, value)                               \
-  InitVarCachePref(name, &StaticPrefs::sVarCache_##id, value, aIsStartup);
+  InitVarCachePref(NS_LITERAL_CSTRING(name),                                   \
+                   &StaticPrefs::sVarCache_##id,                               \
+                   value,                                                      \
+                   aIsStartup);
 #include "mozilla/StaticPrefList.h"
 #undef PREF
 #undef VARCACHE_PREF
 }
 
 } // namespace mozilla
 
 #undef ENSURE_PARENT_PROCESS
--- a/modules/libpref/Preferences.h
+++ b/modules/libpref/Preferences.h
@@ -232,114 +232,255 @@ public:
   // Clears user set pref. Fails if run outside the parent process.
   static nsresult ClearUser(const char* aPrefName);
 
   // Whether the pref has a user value or not.
   static bool HasUserValue(const char* aPref);
 
   // Adds/Removes the observer for the root pref branch. See nsIPrefBranch.idl
   // for details.
-  static nsresult AddStrongObserver(nsIObserver* aObserver, const char* aPref);
-  static nsresult AddWeakObserver(nsIObserver* aObserver, const char* aPref);
-  static nsresult RemoveObserver(nsIObserver* aObserver, const char* aPref);
+  static nsresult AddStrongObserver(nsIObserver* aObserver,
+                                    const nsACString& aPref);
+  static nsresult AddWeakObserver(nsIObserver* aObserver,
+                                  const nsACString& aPref);
+  static nsresult RemoveObserver(nsIObserver* aObserver,
+                                 const nsACString& aPref);
+
+  template<int N>
+  static nsresult AddStrongObserver(nsIObserver* aObserver,
+                                    const char (&aPref)[N])
+  {
+    return AddStrongObserver(aObserver, nsLiteralCString(aPref));
+  }
+  template<int N>
+  static nsresult AddWeakObserver(nsIObserver* aObserver,
+                                  const char (&aPref)[N])
+  {
+    return AddWeakObserver(aObserver, nsLiteralCString(aPref));
+  }
+  template<int N>
+  static nsresult RemoveObserver(nsIObserver* aObserver, const char (&aPref)[N])
+  {
+    return RemoveObserver(aObserver, nsLiteralCString(aPref));
+  }
 
   // Adds/Removes two or more observers for the root pref branch. Pass to
   // aPrefs an array of const char* whose last item is nullptr.
+  // Note: All preference strings *must* be statically-allocated string
+  // literals.
   static nsresult AddStrongObservers(nsIObserver* aObserver,
                                      const char** aPrefs);
   static nsresult AddWeakObservers(nsIObserver* aObserver, const char** aPrefs);
   static nsresult RemoveObservers(nsIObserver* aObserver, const char** aPrefs);
 
   // Registers/Unregisters the callback function for the aPref.
   static nsresult RegisterCallback(PrefChangedFunc aCallback,
-                                   const char* aPref,
+                                   const nsACString& aPref,
                                    void* aClosure = nullptr)
   {
     return RegisterCallback(aCallback, aPref, aClosure, ExactMatch);
   }
 
   static nsresult UnregisterCallback(PrefChangedFunc aCallback,
-                                     const char* aPref,
+                                     const nsACString& aPref,
                                      void* aClosure = nullptr)
   {
     return UnregisterCallback(aCallback, aPref, aClosure, ExactMatch);
   }
 
   // Like RegisterCallback, but also calls the callback immediately for
   // initialization.
   static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback,
-                                          const char* aPref,
+                                          const nsACString& aPref,
                                           void* aClosure = nullptr)
   {
     return RegisterCallbackAndCall(aCallback, aPref, aClosure, ExactMatch);
   }
 
   // Like RegisterCallback, but registers a callback for a prefix of multiple
   // pref names, not a single pref name.
   static nsresult RegisterPrefixCallback(PrefChangedFunc aCallback,
-                                         const char* aPref,
+                                         const nsACString& aPref,
                                          void* aClosure = nullptr)
   {
     return RegisterCallback(aCallback, aPref, aClosure, PrefixMatch);
   }
 
   // Like RegisterPrefixCallback, but also calls the callback immediately for
   // initialization.
   static nsresult RegisterPrefixCallbackAndCall(PrefChangedFunc aCallback,
-                                                const char* aPref,
+                                                const nsACString& aPref,
                                                 void* aClosure = nullptr)
   {
     return RegisterCallbackAndCall(aCallback, aPref, aClosure, PrefixMatch);
   }
 
   // Unregister a callback registered with RegisterPrefixCallback or
   // RegisterPrefixCallbackAndCall.
   static nsresult UnregisterPrefixCallback(PrefChangedFunc aCallback,
-                                           const char* aPref,
+                                           const nsACString& aPref,
                                            void* aClosure = nullptr)
   {
     return UnregisterCallback(aCallback, aPref, aClosure, PrefixMatch);
   }
 
+  template<int N>
+  static nsresult RegisterCallback(PrefChangedFunc aCallback,
+                                   const char (&aPref)[N],
+                                   void* aClosure = nullptr)
+  {
+    return RegisterCallback(
+      aCallback, nsLiteralCString(aPref), aClosure, ExactMatch);
+  }
+
+  template<int N>
+  static nsresult UnregisterCallback(PrefChangedFunc aCallback,
+                                     const char (&aPref)[N],
+                                     void* aClosure = nullptr)
+  {
+    return UnregisterCallback(
+      aCallback, nsLiteralCString(aPref), aClosure, ExactMatch);
+  }
+
+  template<int N>
+  static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback,
+                                          const char (&aPref)[N],
+                                          void* aClosure = nullptr)
+  {
+    return RegisterCallbackAndCall(
+      aCallback, nsLiteralCString(aPref), aClosure, ExactMatch);
+  }
+
+  template<int N>
+  static nsresult RegisterPrefixCallback(PrefChangedFunc aCallback,
+                                         const char (&aPref)[N],
+                                         void* aClosure = nullptr)
+  {
+    return RegisterCallback(
+      aCallback, nsLiteralCString(aPref), aClosure, PrefixMatch);
+  }
+
+  template<int N>
+  static nsresult RegisterPrefixCallbackAndCall(PrefChangedFunc aCallback,
+                                                const char (&aPref)[N],
+                                                void* aClosure = nullptr)
+  {
+    return RegisterCallbackAndCall(
+      aCallback, nsLiteralCString(aPref), aClosure, PrefixMatch);
+  }
+
+  template<int N>
+  static nsresult UnregisterPrefixCallback(PrefChangedFunc aCallback,
+                                           const char (&aPref)[N],
+                                           void* aClosure = nullptr)
+  {
+    return UnregisterCallback(
+      aCallback, nsLiteralCString(aPref), aClosure, PrefixMatch);
+  }
+
   // Adds the aVariable to cache table. |aVariable| must be a pointer for a
   // static variable. The value will be modified when the pref value is changed
   // but note that even if you modified it, the value isn't assigned to the
   // pref.
   static nsresult AddBoolVarCache(bool* aVariable,
-                                  const char* aPref,
+                                  const nsACString& aPref,
                                   bool aDefault = false,
                                   bool aSkipAssignment = false);
   template<MemoryOrdering Order>
   static nsresult AddAtomicBoolVarCache(Atomic<bool, Order>* aVariable,
-                                        const char* aPref,
+                                        const nsACString& aPref,
                                         bool aDefault = false,
                                         bool aSkipAssignment = false);
   static nsresult AddIntVarCache(int32_t* aVariable,
-                                 const char* aPref,
+                                 const nsACString& aPref,
                                  int32_t aDefault = 0,
                                  bool aSkipAssignment = false);
   template<MemoryOrdering Order>
   static nsresult AddAtomicIntVarCache(Atomic<int32_t, Order>* aVariable,
-                                       const char* aPref,
+                                       const nsACString& aPref,
                                        int32_t aDefault = 0,
                                        bool aSkipAssignment = false);
   static nsresult AddUintVarCache(uint32_t* aVariable,
-                                  const char* aPref,
+                                  const nsACString& aPref,
                                   uint32_t aDefault = 0,
                                   bool aSkipAssignment = false);
   template<MemoryOrdering Order>
   static nsresult AddAtomicUintVarCache(Atomic<uint32_t, Order>* aVariable,
-                                        const char* aPref,
+                                        const nsACString& aPref,
                                         uint32_t aDefault = 0,
                                         bool aSkipAssignment = false);
   static nsresult AddFloatVarCache(float* aVariable,
-                                   const char* aPref,
+                                   const nsACString& aPref,
                                    float aDefault = 0.0f,
                                    bool aSkipAssignment = false);
 
+  template<int N>
+  static nsresult AddBoolVarCache(bool* aVariable,
+                                  const char (&aPref)[N],
+                                  bool aDefault = false,
+                                  bool aSkipAssignment = false)
+  {
+    return AddBoolVarCache(
+      aVariable, nsLiteralCString(aPref), aDefault, aSkipAssignment);
+  }
+  template<MemoryOrdering Order, int N>
+  static nsresult AddAtomicBoolVarCache(Atomic<bool, Order>* aVariable,
+                                        const char (&aPref)[N],
+                                        bool aDefault = false,
+                                        bool aSkipAssignment = false)
+  {
+    return AddAtomicBoolVarCache<Order>(
+      aVariable, nsLiteralCString(aPref), aDefault, aSkipAssignment);
+  }
+  template<int N>
+  static nsresult AddIntVarCache(int32_t* aVariable,
+                                 const char (&aPref)[N],
+                                 int32_t aDefault = 0,
+                                 bool aSkipAssignment = false)
+  {
+    return AddIntVarCache(
+      aVariable, nsLiteralCString(aPref), aDefault, aSkipAssignment);
+  }
+  template<MemoryOrdering Order, int N>
+  static nsresult AddAtomicIntVarCache(Atomic<int32_t, Order>* aVariable,
+                                       const char (&aPref)[N],
+                                       int32_t aDefault = 0,
+                                       bool aSkipAssignment = false)
+  {
+    return AddAtomicIntVarCache<Order>(
+      aVariable, nsLiteralCString(aPref), aDefault, aSkipAssignment);
+  }
+  template<int N>
+  static nsresult AddUintVarCache(uint32_t* aVariable,
+                                  const char (&aPref)[N],
+                                  uint32_t aDefault = 0,
+                                  bool aSkipAssignment = false)
+  {
+    return AddUintVarCache(
+      aVariable, nsLiteralCString(aPref), aDefault, aSkipAssignment);
+  }
+  template<MemoryOrdering Order, int N>
+  static nsresult AddAtomicUintVarCache(Atomic<uint32_t, Order>* aVariable,
+                                        const char (&aPref)[N],
+                                        uint32_t aDefault = 0,
+                                        bool aSkipAssignment = false)
+  {
+    return AddAtomicUintVarCache<Order>(
+      aVariable, nsLiteralCString(aPref), aDefault, aSkipAssignment);
+  }
+  template<int N>
+  static nsresult AddFloatVarCache(float* aVariable,
+                                   const char (&aPref)[N],
+                                   float aDefault = 0.0f,
+                                   bool aSkipAssignment = false)
+  {
+    return AddFloatVarCache(
+      aVariable, nsLiteralCString(aPref), aDefault, aSkipAssignment);
+  }
+
   // When a content process is created these methods are used to pass changed
   // prefs in bulk from the parent process, via shared memory.
   static void SerializePreferences(nsCString& aStr);
   static void DeserializePreferences(char* aStr, size_t aPrefsLen);
 
   // When a single pref is changed in the parent process, these methods are
   // used to pass the update to content processes.
   static void GetPreference(dom::Pref* aPref);
@@ -400,28 +541,54 @@ public:
   };
 
 private:
   static void SetupTelemetryPref();
   static mozilla::Result<mozilla::Ok, const char*> InitInitialObjects(
     bool aIsStartup);
 
   static nsresult RegisterCallback(PrefChangedFunc aCallback,
-                                   const char* aPref,
+                                   const nsACString& aPref,
                                    void* aClosure,
                                    MatchKind aMatchKind,
                                    bool aIsPriority = false);
   static nsresult UnregisterCallback(PrefChangedFunc aCallback,
-                                     const char* aPref,
+                                     const nsACString& aPref,
                                      void* aClosure,
                                      MatchKind aMatchKind);
   static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback,
+                                          const nsACString& aPref,
+                                          void* aClosure,
+                                          MatchKind aMatchKind);
+
+  static nsresult RegisterCallback(PrefChangedFunc aCallback,
+                                   const char* aPref,
+                                   void* aClosure,
+                                   MatchKind aMatchKind,
+                                   bool aIsPriority = false)
+  {
+    return RegisterCallback(
+      aCallback, nsDependentCString(aPref), aClosure, aMatchKind, aIsPriority);
+  }
+  static nsresult UnregisterCallback(PrefChangedFunc aCallback,
+                                     const char* aPref,
+                                     void* aClosure,
+                                     MatchKind aMatchKind)
+  {
+    return UnregisterCallback(
+      aCallback, nsDependentCString(aPref), aClosure, aMatchKind);
+  }
+  static nsresult RegisterCallbackAndCall(PrefChangedFunc aCallback,
                                           const char* aPref,
                                           void* aClosure,
-                                          MatchKind aMatchKind);
+                                          MatchKind aMatchKind)
+  {
+    return RegisterCallbackAndCall(
+      aCallback, nsDependentCString(aPref), aClosure, aMatchKind);
+  }
 
 private:
   nsCOMPtr<nsIFile> mCurrentFile;
   bool mDirty = false;
   bool mProfileShutdown = false;
   // We wait a bit after prefs are dirty before writing them. In this period,
   // mDirty and mSavePending will both be true.
   bool mSavePending = false;
--- a/modules/libpref/StaticPrefs.h
+++ b/modules/libpref/StaticPrefs.h
@@ -43,20 +43,24 @@ struct StripAtomicImpl<Atomic<T, Order>>
 {
   typedef T Type;
 };
 
 template<typename T>
 using StripAtomic = typename StripAtomicImpl<T>::Type;
 
 template<typename T>
-struct IsAtomic : FalseType {};
+struct IsAtomic : FalseType
+{
+};
 
 template<typename T, MemoryOrdering Order>
-struct IsAtomic<Atomic<T, Order>> : TrueType {};
+struct IsAtomic<Atomic<T, Order>> : TrueType
+{
+};
 
 class StaticPrefs
 {
 // For a VarCache pref like this:
 //
 //   VARCACHE_PREF("my.varcache", my_varcache, int32_t, 99)
 //
 // we generate a static variable declaration and a getter definition:
@@ -65,18 +69,20 @@ class StaticPrefs
 //     static int32_t sVarCache_my_varcache;
 //   public:
 //     static int32_t my_varcache() { return sVarCache_my_varcache; }
 //
 #define PREF(str, cpp_type, default_value)
 #define VARCACHE_PREF(str, id, cpp_type, default_value)                        \
 private:                                                                       \
   static cpp_type sVarCache_##id;                                              \
+                                                                               \
 public:                                                                        \
-  static StripAtomic<cpp_type> id() {                                          \
+  static StripAtomic<cpp_type> id()                                            \
+  {                                                                            \
     MOZ_ASSERT(IsAtomic<cpp_type>::value || NS_IsMainThread(),                 \
                "Non-atomic static pref '" str                                  \
                "' being accessed on background thread");                       \
     return sVarCache_##id;                                                     \
   }
 #include "mozilla/StaticPrefList.h"
 #undef PREF
 #undef VARCACHE_PREF
--- a/modules/libpref/nsIPrefBranch.idl
+++ b/modules/libpref/nsIPrefBranch.idl
@@ -1,15 +1,19 @@
 /* -*- Mode: IDL; 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/. */
 
 #include "nsISupports.idl"
 
+%{C++
+#include "nsLiteralString.h"
+%}
+
 interface nsIObserver;
 
 /**
  * The nsIPrefBranch interface is used to manipulate the preferences data. This
  * object may be obtained from the preferences service (nsIPrefService) and
  * used to get and set default and/or user preferences across the application.
  *
  * This object is created with a "root" value which describes the base point in
@@ -18,17 +22,17 @@ interface nsIObserver;
  * For example, if this object is created with the root "browser.startup.",
  * the preferences "browser.startup.page", "browser.startup.homepage",
  * and "browser.startup.homepage_override" can be accessed by simply passing
  * "page", "homepage", or "homepage_override" to the various Get/Set methods.
  *
  * @see nsIPrefService
  */
 
-[scriptable, uuid(55d25e49-793f-4727-a69f-de8b15f4b985)]
+[scriptable, builtinclass, uuid(55d25e49-793f-4727-a69f-de8b15f4b985)]
 interface nsIPrefBranch : nsISupports
 {
 
   /**
    * Values describing the basic preference types.
    *
    * @see getPrefType
    */
@@ -416,34 +420,62 @@ interface nsIPrefBranch : nsISupports
    * @note
    * It is not safe to change observers during this callback in Gecko 
    * releases before 1.9. If you want a safe way to remove a pref observer,
    * please use an nsITimer.
    *
    * @see nsIObserver
    * @see removeObserver
    */
-  void addObserver(in string aDomain, in nsIObserver aObserver,
+  [binaryname(AddObserverImpl)]
+  void addObserver(in ACString aDomain, in nsIObserver aObserver,
                    [optional] in boolean aHoldWeak);
 
   /**
    * Remove a preference change observer.
    *
    * @param aDomain   The preference which is being observed for changes.
    * @param aObserver An observer previously registered with addObserver().
    *
    * @note
    * Note that you must call removeObserver() on the same nsIPrefBranch
    * instance on which you called addObserver() in order to remove aObserver;
    * otherwise, the observer will not be removed.
    *
    * @see nsIObserver
    * @see addObserver
    */
-  void removeObserver(in string aDomain, in nsIObserver aObserver);
+  [binaryname(RemoveObserverImpl)]
+  void removeObserver(in ACString aDomain, in nsIObserver aObserver);
+
+  %{C++
+  nsresult AddObserver(const nsACString& aDomain, nsIObserver* aObserver,
+                       bool aHoldWeak = false)
+  {
+    return AddObserverImpl(aDomain, aObserver, aHoldWeak);
+  }
+
+  template <int N>
+  nsresult AddObserver(const char (&aDomain)[N], nsIObserver* aObserver,
+                       bool aHoldWeak = false)
+  {
+    return AddObserverImpl(nsLiteralCString(aDomain), aObserver, aHoldWeak);
+  }
+
+  nsresult RemoveObserver(const nsACString& aDomain, nsIObserver* aObserver)
+  {
+    return RemoveObserverImpl(aDomain, aObserver);
+  }
+
+  template <int N>
+  nsresult RemoveObserver(const char (&aDomain)[N], nsIObserver* aObserver)
+  {
+    return RemoveObserverImpl(nsLiteralCString(aDomain), aObserver);
+  }
+  %}
 };
 
 
 %{C++
 
 #define NS_PREFBRANCH_CONTRACTID "@mozilla.org/preferencesbranch;1"
 /**
  * Notification sent when a preference changes.
--- a/modules/libpref/test/gtest/CallbackAndVarCacheOrder.cpp
+++ b/modules/libpref/test/gtest/CallbackAndVarCacheOrder.cpp
@@ -25,115 +25,119 @@ VarChanged(const char* aPrefName, void* 
 {
   auto closure = static_cast<Closure<T, U>*>(aData);
   ASSERT_EQ(*closure->mLocation, closure->mExpected);
   ASSERT_FALSE(closure->mCalled);
   closure->mCalled = true;
 }
 
 void
-SetFunc(const char* aPrefName, bool aValue)
+SetFunc(const nsCString& aPrefName, bool aValue)
 {
-  nsresult rv = Preferences::SetBool(aPrefName, aValue);
+  nsresult rv = Preferences::SetBool(aPrefName.get(), aValue);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-SetFunc(const char* aPrefName, int32_t aValue)
+SetFunc(const nsCString& aPrefName, int32_t aValue)
 {
-  nsresult rv = Preferences::SetInt(aPrefName, aValue);
+  nsresult rv = Preferences::SetInt(aPrefName.get(), aValue);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-SetFunc(const char* aPrefName, uint32_t aValue)
+SetFunc(const nsCString& aPrefName, uint32_t aValue)
 {
-  nsresult rv = Preferences::SetUint(aPrefName, aValue);
+  nsresult rv = Preferences::SetUint(aPrefName.get(), aValue);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-SetFunc(const char* aPrefName, float aValue)
+SetFunc(const nsCString& aPrefName, float aValue)
 {
-  nsresult rv = Preferences::SetFloat(aPrefName, aValue);
+  nsresult rv = Preferences::SetFloat(aPrefName.get(), aValue);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-AddVarCacheFunc(bool* aVar, const char* aPrefName)
+AddVarCacheFunc(bool* aVar, const nsCString& aPrefName)
 {
   nsresult rv = Preferences::AddBoolVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-AddVarCacheFunc(Atomic<bool, Relaxed>* aVar, const char* aPrefName)
+AddVarCacheFunc(Atomic<bool, Relaxed>* aVar, const nsCString& aPrefName)
 {
   nsresult rv = Preferences::AddAtomicBoolVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-AddVarCacheFunc(Atomic<bool, ReleaseAcquire>* aVar, const char* aPrefName)
+AddVarCacheFunc(Atomic<bool, ReleaseAcquire>* aVar, const nsCString& aPrefName)
 {
   nsresult rv = Preferences::AddAtomicBoolVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-AddVarCacheFunc(int32_t* aVar, const char* aPrefName)
+AddVarCacheFunc(int32_t* aVar, const nsCString& aPrefName)
 {
   nsresult rv = Preferences::AddIntVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-AddVarCacheFunc(Atomic<int32_t, Relaxed>* aVar, const char* aPrefName)
+AddVarCacheFunc(Atomic<int32_t, Relaxed>* aVar, const nsCString& aPrefName)
 {
   nsresult rv = Preferences::AddAtomicIntVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-AddVarCacheFunc(uint32_t* aVar, const char* aPrefName)
+AddVarCacheFunc(uint32_t* aVar, const nsCString& aPrefName)
 {
   nsresult rv = Preferences::AddUintVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-AddVarCacheFunc(Atomic<uint32_t, Relaxed>* aVar, const char* aPrefName)
+AddVarCacheFunc(Atomic<uint32_t, Relaxed>* aVar, const nsCString& aPrefName)
 {
   nsresult rv = Preferences::AddAtomicUintVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-AddVarCacheFunc(Atomic<uint32_t, ReleaseAcquire>* aVar, const char* aPrefName)
+AddVarCacheFunc(Atomic<uint32_t, ReleaseAcquire>* aVar,
+                const nsCString& aPrefName)
 {
   nsresult rv = Preferences::AddAtomicUintVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void
-AddVarCacheFunc(float* aVar, const char* aPrefName)
+AddVarCacheFunc(float* aVar, const nsCString& aPrefName)
 {
   nsresult rv = Preferences::AddFloatVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 template<typename T, typename U = T>
 void
-RunTest(const char* aPrefName1, const char* aPrefName2, T aValue1, T aValue2)
+RunTest(const nsCString& aPrefName1,
+        const nsCString& aPrefName2,
+        T aValue1,
+        T aValue2)
 {
   static U var1, var2;
   static Closure<T, U> closure1, closure2;
   nsresult rv;
 
-  ASSERT_STRNE(aPrefName1, aPrefName2);
+  ASSERT_STRNE(aPrefName1.get(), aPrefName2.get());
   ASSERT_NE(aValue1, aValue2);
 
   // Call Add*VarCache first.
 
   SetFunc(aPrefName1, aValue1);
 
   AddVarCacheFunc(&var1, aPrefName1);
   ASSERT_EQ(var1, aValue1);
@@ -161,57 +165,84 @@ RunTest(const char* aPrefName1, const ch
   ASSERT_FALSE(closure2.mCalled);
   SetFunc(aPrefName2, aValue2);
   ASSERT_EQ(var2, aValue2);
   ASSERT_TRUE(closure2.mCalled);
 }
 
 TEST(CallbackAndVarCacheOrder, Bool)
 {
-  RunTest<bool>("test_pref.bool.1", "test_pref.bool.2", false, true);
+  RunTest<bool>(NS_LITERAL_CSTRING("test_pref.bool.1"),
+                NS_LITERAL_CSTRING("test_pref.bool.2"),
+                false,
+                true);
 }
 
 TEST(CallbackAndVarCacheOrder, AtomicBoolRelaxed)
 {
   RunTest<bool, Atomic<bool, Relaxed>>(
-    "test_pref.atomic_bool.1", "test_pref.atomic_bool.2", false, true);
+    NS_LITERAL_CSTRING("test_pref.atomic_bool.1"),
+    NS_LITERAL_CSTRING("test_pref.atomic_bool.2"),
+    false,
+    true);
 }
 
 TEST(CallbackAndVarCacheOrder, AtomicBoolReleaseAcquire)
 {
   RunTest<bool, Atomic<bool, ReleaseAcquire>>(
-    "test_pref.atomic_bool.3", "test_pref.atomic_bool.4", false, true);
+    NS_LITERAL_CSTRING("test_pref.atomic_bool.3"),
+    NS_LITERAL_CSTRING("test_pref.atomic_bool.4"),
+    false,
+    true);
 }
 
 TEST(CallbackAndVarCacheOrder, Int)
 {
-  RunTest<int32_t>("test_pref.int.1", "test_pref.int.2", -2, 3);
+  RunTest<int32_t>(NS_LITERAL_CSTRING("test_pref.int.1"),
+                   NS_LITERAL_CSTRING("test_pref.int.2"),
+                   -2,
+                   3);
 }
 
 TEST(CallbackAndVarCacheOrder, AtomicInt)
 {
   RunTest<int32_t, Atomic<int32_t, Relaxed>>(
-    "test_pref.atomic_int.1", "test_pref.atomic_int.2", -3, 4);
+    NS_LITERAL_CSTRING("test_pref.atomic_int.1"),
+    NS_LITERAL_CSTRING("test_pref.atomic_int.2"),
+    -3,
+    4);
 }
 
 TEST(CallbackAndVarCacheOrder, Uint)
 {
-  RunTest<uint32_t>("test_pref.uint.1", "test_pref.uint.2", 4u, 5u);
+  RunTest<uint32_t>(NS_LITERAL_CSTRING("test_pref.uint.1"),
+                    NS_LITERAL_CSTRING("test_pref.uint.2"),
+                    4u,
+                    5u);
 }
 
 TEST(CallbackAndVarCacheOrder, AtomicUintRelaxed)
 {
   RunTest<uint32_t, Atomic<uint32_t, Relaxed>>(
-    "test_pref.atomic_uint.1", "test_pref.atomic_uint.2", 6u, 7u);
+    NS_LITERAL_CSTRING("test_pref.atomic_uint.1"),
+    NS_LITERAL_CSTRING("test_pref.atomic_uint.2"),
+    6u,
+    7u);
 }
 
 TEST(CallbackAndVarCacheOrder, AtomicUintReleaseAcquire)
 {
   RunTest<uint32_t, Atomic<uint32_t, ReleaseAcquire>>(
-    "test_pref.atomic_uint.3", "test_pref.atomic_uint.4", 8u, 9u);
+    NS_LITERAL_CSTRING("test_pref.atomic_uint.3"),
+    NS_LITERAL_CSTRING("test_pref.atomic_uint.4"),
+    8u,
+    9u);
 }
 
 TEST(CallbackAndVarCacheOrder, Float)
 {
-  RunTest<float>("test_pref.float.1", "test_pref.float.2", -10.0f, 11.0f);
+  RunTest<float>(NS_LITERAL_CSTRING("test_pref.float.1"),
+                 NS_LITERAL_CSTRING("test_pref.float.2"),
+                 -10.0f,
+                 11.0f);
 }
 
 } // namespace mozilla
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -334,17 +334,19 @@ nsCacheProfilePrefObserver::Install()
             rv2 = rv;
     }
 
     // install preferences observer
     nsCOMPtr<nsIPrefBranch> branch = do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (!branch) return NS_ERROR_FAILURE;
 
     for (auto& pref : prefList) {
-        rv = branch->AddObserver(pref, this, false);
+        nsCString prefStr;
+        prefStr.AssignLiteral(pref, strlen(pref));
+        rv = branch->AddObserver(prefStr, this, false);
         if (NS_FAILED(rv))
             rv2 = rv;
     }
 
     // Determine if we have a profile already
     //     Install() is called *after* the profile-after-change notification
     //     when there is only a single profile, or it is specified on the
     //     commandline at startup.
@@ -377,17 +379,17 @@ nsCacheProfilePrefObserver::Remove()
     }
 
     // remove Pref Service observers
     nsCOMPtr<nsIPrefBranch> prefs =
         do_GetService(NS_PREFSERVICE_CONTRACTID);
     if (!prefs)
         return;
     for (auto& pref : prefList)
-        prefs->RemoveObserver(pref, this); // remove cache pref observers
+        prefs->RemoveObserver(nsDependentCString(pref), this); // remove cache pref observers
 }
 
 void
 nsCacheProfilePrefObserver::SetDiskCacheCapacity(int32_t capacity)
 {
     mDiskCacheCapacity = std::max(0, capacity);
 }
 
--- a/parser/htmlparser/nsExpatDriver.cpp
+++ b/parser/htmlparser/nsExpatDriver.cpp
@@ -317,17 +317,18 @@ nsExpatDriver::HandleStartElement(const 
        aAtts[attrArrayLength];
        attrArrayLength += 2) {
     // Just looping till we find out what the length is
   }
 
   if (mSink) {
     nsresult rv = mSink->
       HandleStartElement(aValue, aAtts, attrArrayLength,
-                         XML_GetCurrentLineNumber(mExpatParser));
+                         XML_GetCurrentLineNumber(mExpatParser),
+                         XML_GetCurrentColumnNumber(mExpatParser));
     MaybeStopParser(rv);
   }
 
   return NS_OK;
 }
 
 nsresult
 nsExpatDriver::HandleEndElement(const char16_t *aValue)
--- a/parser/htmlparser/nsIExpatSink.idl
+++ b/parser/htmlparser/nsIExpatSink.idl
@@ -23,21 +23,23 @@ interface nsIExpatSink : nsISupports
    *        elements in the array is aAttsCount.  The names and values
    *        alternate.  Thus, if we number attributes starting with 0,
    *        aAtts[2*k] is the name of the k-th attribute and aAtts[2*k+1] is
    *        the value of that attribute  Both explicitly specified attributes
    *        and attributes that are defined to have default values in a DTD are
    *        present in aAtts.
    * @param aAttsCount the number of elements in aAtts.
    * @param aLineNumber the line number of the start tag in the data stream.
+   * @param aColumnNumber the column number of the start tag in the data stream.
    */
   void HandleStartElement(in wstring aName,
                           [array, size_is(aAttsCount)] in wstring aAtts,
                           in unsigned long aAttsCount,
-                          in unsigned long aLineNumber);
+                          in unsigned long aLineNumber,
+                          in unsigned long aColumnNumber);
 
   /**
    * Called to handle the closing tag of an element.
    * @param aName the fully qualified tagname of the element
    */
   void HandleEndElement(in wstring aName);
 
   /**
--- a/parser/xml/nsSAXXMLReader.cpp
+++ b/parser/xml/nsSAXXMLReader.cpp
@@ -74,17 +74,18 @@ nsSAXXMLReader::SetParser(nsParserBase *
 }
 
 // nsIExpatSink
 
 NS_IMETHODIMP
 nsSAXXMLReader::HandleStartElement(const char16_t *aName,
                                    const char16_t **aAtts,
                                    uint32_t aAttsCount,
-                                   uint32_t aLineNumber)
+                                   uint32_t aLineNumber,
+                                   uint32_t aColumnNumber)
 {
   if (!mContentHandler)
     return NS_OK;
 
   RefPtr<nsSAXAttributes> atts = new nsSAXAttributes();
   if (!atts)
     return NS_ERROR_OUT_OF_MEMORY;
   nsAutoString uri, localName, qName;
--- a/python/mozbuild/mozbuild/action/check_binary.py
+++ b/python/mozbuild/mozbuild/action/check_binary.py
@@ -96,17 +96,17 @@ def iter_readelf_symbols(target, binary)
                 'name': name,
                 'version': ver,
             }
 
 
 def iter_readelf_dynamic(target, binary):
     for line in get_output(target['readelf'], '-d', binary):
         data = line.split(None, 2)
-        if data and data[0].startswith('0x'):
+        if data and len(data) == 3 and data[0].startswith('0x'):
             yield data[1].rstrip(')').lstrip('('), data[2]
 
 
 def check_dep_versions(target, binary, lib, prefix, max_version):
     if get_type(binary) != ELF:
         raise Skip()
     unwanted = []
     prefix = prefix + '_'
deleted file mode 100644
--- a/testing/web-platform/meta/content-security-policy/script-src/script-src-1_4.html.ini
+++ /dev/null
@@ -1,4 +0,0 @@
-[script-src-1_4.html]
-  [eval() should throw without 'unsafe-eval' keyword source in script-src directive.]
-    expected: FAIL
-
--- a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-eval.html
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-eval.html
@@ -2,17 +2,18 @@
 <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
     async_test(t => {
         var watcher = new EventWatcher(t, document, 'securitypolicyviolation');
         watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => {
             assert_equals(e.blockedURI, "eval");
-            assert_equals(e.lineNumber, 14);
+            assert_equals(e.lineNumber, 15);
+            assert_equals(e.columnNumber, 12);
         }));
 
         try {
             eval("assert_unreached('eval() should be blocked.");
         } catch (e) {
             assert_equals(e.name, 'EvalError');
         }
     }, "Eval violations have a blockedURI of 'eval'");
--- a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-inline.html
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/blockeduri-inline.html
@@ -2,17 +2,18 @@
 <meta http-equiv="Content-Security-Policy" content="script-src 'nonce-abc'">
 <script nonce="abc" src="/resources/testharness.js"></script>
 <script nonce="abc" src="/resources/testharnessreport.js"></script>
 <script nonce="abc">
     async_test(t => {
         var watcher = new EventWatcher(t, document, 'securitypolicyviolation');
         watcher.wait_for('securitypolicyviolation').then(t.step_func_done(e => {
             assert_equals(e.blockedURI, "inline");
-            assert_equals(e.lineNumber, 14);
+            assert_equals(e.lineNumber, 15);
+            assert_equals(e.columnNumber, 1);
         }));
     }, "Inline violations have a blockedURI of 'inline'");
 </script>
 <script>
     test(t => {
         assert_unreached();
     }, "Blocked script shouldn't execute.");
 </script>
--- a/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html
+++ b/testing/web-platform/tests/content-security-policy/securitypolicyviolation/targeting.html
@@ -30,29 +30,32 @@
             }))
             .then(t.step_func(e => {
                 assert_equals(e.blockedURI, "inline");
                 assert_equals(e.target, document.querySelector('#block5'));
                 return watcher.wait_for('securitypolicyviolation');
             }))
             .then(t.step_func(e => {
                 assert_equals(e.blockedURI, "inline");
-                assert_equals(e.lineNumber, 132);
+                assert_equals(e.lineNumber, 135);
+                assert_equals(e.columnNumber, 7);
                 assert_equals(e.target, document, "Disconnected elements target the document");
                 return watcher.wait_for('securitypolicyviolation');
             }))
             .then(t.step_func(e => {
                 assert_equals(e.blockedURI, "inline");
-                assert_equals(e.lineNumber, 143);
+                assert_equals(e.lineNumber, 146);
+                assert_equals(e.columnNumber, 7);
                 assert_equals(e.target, document, "Elements disconnected after triggering target the document.");
                 return watcher.wait_for('securitypolicyviolation');
             }))
             .then(t.step_func(e => {
                 assert_equals(e.blockedURI, "inline");
-                assert_equals(e.lineNumber, 157);
+                assert_equals(e.lineNumber, 160);
+                assert_equals(e.columnNumber, 7);
                 assert_equals(e.target, document, "Elements in DocumentFragments target the document");
             }))
             .then(t.step_func_done(_ => {
                 unexecuted_test.done();
             }));
     }, "Inline violations target the right element.");
 
 </script>
--- a/toolkit/components/extensions/WebExtensionPolicy.cpp
+++ b/toolkit/components/extensions/WebExtensionPolicy.cpp
@@ -277,19 +277,19 @@ namespace {
   class AtomSetPref : public nsIObserver
                     , public nsSupportsWeakReference
   {
   public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
 
     static already_AddRefed<AtomSetPref>
-    Create(const char* aPref)
+    Create(const nsCString& aPref)
     {
-      RefPtr<AtomSetPref> self = new AtomSetPref(aPref);
+      RefPtr<AtomSetPref> self = new AtomSetPref(aPref.get());
       Preferences::AddWeakObserver(self, aPref);
       return self.forget();
     }
 
     const AtomSet& Get() const;
 
     bool Contains(const nsAtom* aAtom) const
     {
@@ -349,17 +349,17 @@ WebExtensionPolicy::IsRestrictedDoc(cons
   return IsRestrictedURI(aDoc.PrincipalURL());
 }
 
 /* static */ bool
 WebExtensionPolicy::IsRestrictedURI(const URLInfo &aURI)
 {
   static RefPtr<AtomSetPref> domains;
   if (!domains) {
-    domains = AtomSetPref::Create(kRestrictedDomainPref);
+    domains = AtomSetPref::Create(nsLiteralCString(kRestrictedDomainPref));
     ClearOnShutdown(&domains);
   }
 
   if (domains->Contains(aURI.HostAtom())) {
     return true;
   }
 
   if (AddonManagerWebAPI::IsValidSite(aURI.URI())) {
--- a/toolkit/components/passwordmgr/LoginHelper.jsm
+++ b/toolkit/components/passwordmgr/LoginHelper.jsm
@@ -35,34 +35,61 @@ var LoginHelper = {
   schemeUpgrades: Services.prefs.getBoolPref("signon.schemeUpgrades"),
   insecureAutofill: Services.prefs.getBoolPref("signon.autofillForms.http"),
 
   createLogger(aLogPrefix) {
     let getMaxLogLevel = () => {
       return this.debug ? "debug" : "warn";
     };
 
-    // Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
-    let ConsoleAPI = ChromeUtils.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
-    let consoleOptions = {
-      maxLogLevel: getMaxLogLevel(),
-      prefix: aLogPrefix,
-    };
-    let logger = new ConsoleAPI(consoleOptions);
+    let logger;
+    function getConsole() {
+      if (!logger) {
+        // Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
+        let ConsoleAPI = ChromeUtils.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+        let consoleOptions = {
+          maxLogLevel: getMaxLogLevel(),
+          prefix: aLogPrefix,
+        };
+        logger = new ConsoleAPI(consoleOptions);
+      }
+      return logger;
+    }
 
     // Watch for pref changes and update this.debug and the maxLogLevel for created loggers
     Services.prefs.addObserver("signon.", () => {
       this.debug = Services.prefs.getBoolPref("signon.debug");
       this.formlessCaptureEnabled = Services.prefs.getBoolPref("signon.formlessCapture.enabled");
       this.schemeUpgrades = Services.prefs.getBoolPref("signon.schemeUpgrades");
       this.insecureAutofill = Services.prefs.getBoolPref("signon.autofillForms.http");
-      logger.maxLogLevel = getMaxLogLevel();
+      if (logger) {
+        logger.maxLogLevel = getMaxLogLevel();
+      }
     });
 
-    return logger;
+    return {
+      log: (...args) => {
+        if (this.debug) {
+          getConsole().log(...args);
+        }
+      },
+      error: (...args) => {
+        getConsole().error(...args);
+      },
+      debug: (...args) => {
+        if (this.debug) {
+          getConsole().debug(...args);
+        }
+      },
+      warn: (...args) => {
+        if (this.debug) {
+          getConsole().warn(...args);
+        }
+      },
+    };
   },
 
   /**
    * Due to the way the signons2.txt file is formatted, we need to make
    * sure certain field values or characters do not cause the file to
    * be parsed incorrectly.  Reject hostnames that we can't store correctly.
    *
    * @throws String with English message in case validation failed.
--- a/toolkit/components/reputationservice/LoginReputation.cpp
+++ b/toolkit/components/reputationservice/LoginReputation.cpp
@@ -25,16 +25,17 @@ static bool sPasswordProtectionEnabled =
 LazyLogModule gLoginReputationLogModule("LoginReputation");
 #define LR_LOG(args) MOZ_LOG(gLoginReputationLogModule, mozilla::LogLevel::Debug, args)
 #define LR_LOG_ENABLED() MOZ_LOG_TEST(gLoginReputationLogModule, mozilla::LogLevel::Debug)
 
 static Atomic<bool> gShuttingDown(false);
 
 static const char* kObservedPrefs[] = {
   PREF_PASSWORD_ALLOW_TABLE,
+  nullptr,
 };
 
 // -------------------------------------------------------------------------
 // ReputationQueryParam
 //
 // Concrete class for nsILoginReputationQuery to hold query parameters
 //
 class ReputationQueryParam final : public nsILoginReputationQuery
@@ -268,19 +269,17 @@ LoginReputationService::Enable()
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(sPasswordProtectionEnabled);
 
   LR_LOG(("Enable login reputation service"));
 
   nsresult rv = mLoginWhitelist->Init();
   Unused << NS_WARN_IF(NS_FAILED(rv));
 
-  for (const char* pref : kObservedPrefs) {
-    Preferences::AddStrongObserver(this, pref);
-  }
+  Preferences::AddStrongObservers(this, kObservedPrefs);
 
   return NS_OK;
 }
 
 nsresult
 LoginReputationService::Disable()
 {
   MOZ_ASSERT(XRE_IsParentProcess());
@@ -289,19 +288,17 @@ LoginReputationService::Disable()
 
   nsresult rv = mLoginWhitelist->Uninit();
   Unused << NS_WARN_IF(NS_FAILED(rv));
 
   mQueryRequests.Clear();
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefs) {
-    for (const char* pref : kObservedPrefs) {
-      prefs->RemoveObserver(pref, this);
-    }
+    Preferences::RemoveObservers(this, kObservedPrefs);
   }
 
   return NS_OK;
 }
 
 nsresult
 LoginReputationService::Shutdown()
 {
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -1668,17 +1668,17 @@ nsUrlClassifierDBService::Init()
   // XXX: Do we *really* need to be able to change all of these at runtime?
   // Note: These observers should only be added when everything else above has
   //       succeeded. Failing to do so can cause long shutdown times in certain
   //       situations. See Bug 1247798 and Bug 1244803.
   Preferences::AddUintVarCache(&sGethashNoise, GETHASH_NOISE_PREF,
     GETHASH_NOISE_DEFAULT);
 
   for (uint8_t i = 0; i < kObservedPrefs.Length(); i++) {
-    Preferences::AddStrongObserver(this, kObservedPrefs[i].get());
+    Preferences::AddStrongObserver(this, kObservedPrefs[i]);
   }
 
   return NS_OK;
 }
 
 // nsChannelClassifier is the only consumer of this interface.
 NS_IMETHODIMP
 nsUrlClassifierDBService::Classify(nsIPrincipal* aPrincipal,
@@ -2491,17 +2491,17 @@ nsUrlClassifierDBService::Shutdown()
 
   Telemetry::AutoTimer<Telemetry::URLCLASSIFIER_SHUTDOWN_TIME> timer;
 
   mCompleters.Clear();
 
   nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
   if (prefs) {
     for (uint8_t i = 0; i < kObservedPrefs.Length(); i++) {
-      prefs->RemoveObserver(kObservedPrefs[i].get(), this);
+      prefs->RemoveObserver(kObservedPrefs[i], this);
     }
   }
 
   // 1. Synchronize with worker thread and update thread by
   //    *synchronously* dispatching an event to worker thread
   //    for shutting down the update thread. The reason not
   //    shutting down update thread directly from main thread
   //    is to avoid racing for Classifier::mUpdateThread
--- a/widget/android/PrefsHelper.h
+++ b/widget/android/PrefsHelper.h
@@ -259,32 +259,32 @@ public:
         nsTArray<jni::Object::LocalRef> nameRefArray(
                 aPrefsToObserve->GetElements());
         nsAppShell* const appShell = nsAppShell::Get();
         MOZ_ASSERT(appShell);
 
         for (jni::Object::LocalRef& nameRef : nameRefArray) {
             jni::String::LocalRef nameStr(std::move(nameRef));
             MOZ_ALWAYS_SUCCEEDS(Preferences::AddStrongObserver(
-                    appShell, nameStr->ToCString().get()));
+                    appShell, nameStr->ToCString()));
         }
     }
 
     static void RemoveObserver(const jni::Class::LocalRef& aCls,
                                jni::ObjectArray::Param aPrefsToUnobserve)
     {
         nsTArray<jni::Object::LocalRef> nameRefArray(
                 aPrefsToUnobserve->GetElements());
         nsAppShell* const appShell = nsAppShell::Get();
         MOZ_ASSERT(appShell);
 
         for (jni::Object::LocalRef& nameRef : nameRefArray) {
             jni::String::LocalRef nameStr(std::move(nameRef));
             MOZ_ALWAYS_SUCCEEDS(Preferences::RemoveObserver(
-                    appShell, nameStr->ToCString().get()));
+                    appShell, nameStr->ToCString()));
         }
     }
 
     static void OnPrefChange(const char16_t* aData)
     {
         const nsCString& name = NS_LossyConvertUTF16toASCII(aData);
 
         int32_t type = -1;
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -3388,17 +3388,20 @@ debug_RegisterPrefCallbacks()
   nsCOMPtr<nsIObserver> obs(new Debug_PrefObserver());
   for (uint32_t i = 0; i < ArrayLength(debug_PrefValues); i++) {
     // Initialize the pref values
     debug_PrefValues[i].value =
       Preferences::GetBool(debug_PrefValues[i].name, false);
 
     if (obs) {
       // Register callbacks for when these change
-      Preferences::AddStrongObserver(obs, debug_PrefValues[i].name);
+      nsCString name;
+      name.AssignLiteral(debug_PrefValues[i].name,
+                         strlen(debug_PrefValues[i].name));
+      Preferences::AddStrongObserver(obs, name);
     }
   }
 }
 //////////////////////////////////////////////////////////////
 static int32_t
 _GetPrintCount()
 {
   static int32_t sCount = 0;
--- a/xpcom/base/nsDumpUtils.cpp
+++ b/xpcom/base/nsDumpUtils.cpp
@@ -44,17 +44,17 @@ using namespace mozilla;
  * But that uses libevent, which does not handle the realtime signals (bug
  * 794074).
  */
 
 // This is the write-end of a pipe that we use to notice when a
 // specific signal occurs.
 static Atomic<int> sDumpPipeWriteFd(-1);
 
-const char* const FifoWatcher::kPrefName =
+const char FifoWatcher::kPrefName[] =
   "memory_info_dumper.watch_fifo.enabled";
 
 static void
 DumpSignalHandler(int aSignum)
 {
   // This is a signal handler, so everything in here needs to be
   // async-signal-safe.  Be careful!
 
--- a/xpcom/base/nsDumpUtils.h
+++ b/xpcom/base/nsDumpUtils.h
@@ -105,17 +105,20 @@ struct FifoInfo
 typedef nsTArray<FifoInfo> FifoInfoArray;
 
 class FifoWatcher : public FdWatcher
 {
 public:
   /**
    * The name of the preference used to enable/disable the FifoWatcher.
    */
-  static const char* const kPrefName;
+  // The length of this array must match the size of the string constant in
+  // the definition in nsDumpUtils.cpp. A mismatch will result in a compile-time
+  // error.
+  static const char kPrefName[38];
 
   static FifoWatcher* GetSingleton();
 
   static bool MaybeCreate();
 
   void RegisterCallback(const nsCString& aCommand, FifoCallback aCallback);
 
   virtual ~FifoWatcher();