Bug 1249157: prefapi enums into class enums, explicit conversion, cleanup. r=bsmedberg
☠☠ backed out by effc082711b0 ☠ ☠
authorMilan Sreckovic <milan@mozilla.com>
Thu, 18 Feb 2016 13:27:06 -0500
changeset 321388 dd911452e3f78c761b68936fbfdc6a39a66a4640
parent 321387 3a5db049a13e9ee603136c1c4832bac03e64342a
child 321389 effc082711b030dc1aa11542509f4ee9a7d3a71f
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs1249157
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1249157: prefapi enums into class enums, explicit conversion, cleanup. r=bsmedberg MozReview-Commit-ID: nvvOD8ajV4
modules/libpref/Preferences.cpp
modules/libpref/nsPrefBranch.cpp
modules/libpref/prefapi.cpp
modules/libpref/prefapi.h
modules/libpref/prefread.cpp
modules/libpref/prefread.h
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -1310,17 +1310,17 @@ static nsresult pref_InitInitialObjects(
   rv = pref_LoadPrefsInDirList(NS_APP_PREFS_DEFAULTS_DIR_LIST);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Set up the correct default for toolkit.telemetry.enabled.
   // If this build has MOZ_TELEMETRY_ON_BY_DEFAULT *or* we're on the beta
   // channel, telemetry is on by default, otherwise not. This is necessary
   // so that beta users who are testing final release builds don't flipflop
   // defaults.
-  if (Preferences::GetDefaultType(kTelemetryPref) == PREF_INVALID) {
+  if (Preferences::GetDefaultType(kTelemetryPref) == nsIPrefBranch::PREF_INVALID) {
     bool prerelease = false;
 #ifdef MOZ_TELEMETRY_ON_BY_DEFAULT
     prerelease = true;
 #else
     if (Preferences::GetDefaultCString(kChannelPref).EqualsLiteral("beta")) {
       prerelease = true;
     }
 #endif
--- a/modules/libpref/nsPrefBranch.cpp
+++ b/modules/libpref/nsPrefBranch.cpp
@@ -122,17 +122,31 @@ NS_IMETHODIMP nsPrefBranch::GetRoot(char
   *aRoot = ToNewCString(mPrefRoot);
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPrefBranch::GetPrefType(const char *aPrefName, int32_t *_retval)
 {
   NS_ENSURE_ARG(aPrefName);
   const char *pref = getPrefName(aPrefName);
-  *_retval = PREF_GetPrefType(pref);
+  switch (PREF_GetPrefType(pref)) {
+    case PrefType::String:
+      *_retval = PREF_STRING;
+      break;
+    case PrefType::Int:
+      *_retval = PREF_INT;
+      break;
+    case PrefType::Bool:
+      *_retval = PREF_BOOL;
+        break;
+    case PrefType::Invalid:
+    default:
+      *_retval = PREF_INVALID;
+      break;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsPrefBranch::GetBoolPref(const char *aPrefName, bool *_retval)
 {
   NS_ENSURE_ARG(aPrefName);
   const char *pref = getPrefName(aPrefName);
   return PREF_GetBoolPref(pref, _retval, mIsDefault);
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -35,17 +35,17 @@
 #include "prlink.h"
 
 using namespace mozilla;
 
 static void
 clearPrefEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
 {
     PrefHashEntry *pref = static_cast<PrefHashEntry *>(entry);
-    if (pref->flags & PREF_STRING)
+    if (pref->prefFlags.IsTypeString())
     {
         if (pref->defaultPref.stringVal)
             PL_strfree(pref->defaultPref.stringVal);
         if (pref->userPref.stringVal)
             PL_strfree(pref->userPref.stringVal);
     }
     // don't need to free this as it's allocated in memory owned by
     // gPrefNameArena
@@ -112,23 +112,17 @@ static char *ArenaStrDup(const char* str
     PL_ARENA_ALLOCATE(mem, aArena, len+1);
     if (mem)
         memcpy(mem, str, len+1);
     return static_cast<char*>(mem);
 }
 
 /*---------------------------------------------------------------------------*/
 
-#define PREF_IS_LOCKED(pref)            ((pref)->flags & PREF_LOCKED)
-#define PREF_HAS_DEFAULT_VALUE(pref)    ((pref)->flags & PREF_HAS_DEFAULT)
-#define PREF_HAS_USER_VALUE(pref)       ((pref)->flags & PREF_USERSET)
-#define PREF_TYPE(pref)                 (PrefType)((pref)->flags & PREF_VALUETYPE_MASK)
-
 static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type);
-
 /* -- Privates */
 struct CallbackNode {
     char*                   domain;
     // If someone attempts to remove the node from the callback list while
     // pref_DoCallback is running, |func| is set to nullptr. Such nodes will
     // be removed at the end of pref_DoCallback.
     PrefChangedFunc         func;
     void*                   data;
@@ -244,35 +238,35 @@ PREF_SetCharPref(const char *pref_name, 
 {
     if ((uint32_t)strlen(value) > MAX_PREF_LENGTH) {
         return NS_ERROR_ILLEGAL_VALUE;
     }
 
     PrefValue pref;
     pref.stringVal = (char*)value;
 
-    return pref_HashPref(pref_name, pref, PREF_STRING, set_default ? kPrefSetDefault : 0);
+    return pref_HashPref(pref_name, pref, PrefType::String, set_default ? kPrefSetDefault : 0);
 }
 
 nsresult
 PREF_SetIntPref(const char *pref_name, int32_t value, bool set_default)
 {
     PrefValue pref;
     pref.intVal = value;
 
-    return pref_HashPref(pref_name, pref, PREF_INT, set_default ? kPrefSetDefault : 0);
+    return pref_HashPref(pref_name, pref, PrefType::Int, set_default ? kPrefSetDefault : 0);
 }
 
 nsresult
 PREF_SetBoolPref(const char *pref_name, bool value, bool set_default)
 {
     PrefValue pref;
     pref.boolVal = value;
 
-    return pref_HashPref(pref_name, pref, PREF_BOOL, set_default ? kPrefSetDefault : 0);
+    return pref_HashPref(pref_name, pref, PrefType::Bool, set_default ? kPrefSetDefault : 0);
 }
 
 enum WhichValue { DEFAULT_VALUE, USER_VALUE };
 static nsresult
 SetPrefValue(const char* aPrefName, const dom::PrefValue& aValue,
              WhichValue aWhich)
 {
     bool setDefault = (aWhich == DEFAULT_VALUE);
@@ -330,38 +324,38 @@ pref_savePrefs(PLDHashTable* aTable)
 
         nsAutoCString prefValue;
         nsAutoCString prefPrefix;
         prefPrefix.AssignLiteral("user_pref(\"");
 
         // where we're getting our pref from
         PrefValue* sourcePref;
 
-        if (PREF_HAS_USER_VALUE(pref) &&
+        if (pref->prefFlags.HasUserValue() &&
             (pref_ValueChanged(pref->defaultPref,
                                pref->userPref,
-                               (PrefType) PREF_TYPE(pref)) ||
-             !(pref->flags & PREF_HAS_DEFAULT) ||
-             pref->flags & PREF_STICKY_DEFAULT)) {
+                               pref->prefFlags.GetPrefType()) ||
+             !(pref->prefFlags.HasDefault()) ||
+             pref->prefFlags.HasStickyDefault())) {
             sourcePref = &pref->userPref;
         } else {
             // do not save default prefs that haven't changed
             continue;
         }
 
         // strings are in quotes!
-        if (pref->flags & PREF_STRING) {
+        if (pref->prefFlags.IsTypeString()) {
             prefValue = '\"';
             str_escape(sourcePref->stringVal, prefValue);
             prefValue += '\"';
 
-        } else if (pref->flags & PREF_INT) {
+        } else if (pref->prefFlags.IsTypeInt()) {
             prefValue.AppendInt(sourcePref->intVal);
 
-        } else if (pref->flags & PREF_BOOL) {
+        } else if (pref->prefFlags.IsTypeBool()) {
             prefValue = (sourcePref->boolVal) ? "true" : "false";
         }
 
         nsAutoCString prefName;
         str_escape(pref->key, prefName);
 
         savedPrefs[j++] = ToNewCString(prefPrefix +
                                        prefName +
@@ -384,41 +378,41 @@ GetPrefValueFromEntry(PrefHashEntry *aHa
         aPref->userValue() = dom::PrefValue();
         settingValue = &aPref->userValue().get_PrefValue();
     } else {
         value = &aHashEntry->defaultPref;
         aPref->defaultValue() = dom::PrefValue();
         settingValue = &aPref->defaultValue().get_PrefValue();
     }
 
-    switch (aHashEntry->flags & PREF_VALUETYPE_MASK) {
-    case PREF_STRING:
+    switch (aHashEntry->prefFlags.GetPrefType()) {
+      case PrefType::String:
         *settingValue = nsDependentCString(value->stringVal);
         return;
-    case PREF_INT:
+      case PrefType::Int:
         *settingValue = value->intVal;
         return;
-    case PREF_BOOL:
+      case PrefType::Bool:
         *settingValue = !!value->boolVal;
         return;
     default:
         MOZ_CRASH();
     }
 }
 
 void
 pref_GetPrefFromEntry(PrefHashEntry *aHashEntry, dom::PrefSetting* aPref)
 {
     aPref->name() = aHashEntry->key;
-    if (PREF_HAS_DEFAULT_VALUE(aHashEntry)) {
+    if (aHashEntry->prefFlags.HasDefault()) {
         GetPrefValueFromEntry(aHashEntry, aPref, DEFAULT_VALUE);
     } else {
         aPref->defaultValue() = null_t();
     }
-    if (PREF_HAS_USER_VALUE(aHashEntry)) {
+    if (aHashEntry->prefFlags.HasUserValue()) {
         GetPrefValueFromEntry(aHashEntry, aPref, USER_VALUE);
     } else {
         aPref->userValue() = null_t();
     }
 
     MOZ_ASSERT(aPref->defaultValue().type() == dom::MaybePrefValue::Tnull_t ||
                aPref->userValue().type() == dom::MaybePrefValue::Tnull_t ||
                (aPref->defaultValue().get_PrefValue().type() ==
@@ -446,92 +440,84 @@ pref_CompareStrings(const void *v1, cons
 }
 
 bool PREF_HasUserPref(const char *pref_name)
 {
     if (!gHashTable)
         return false;
 
     PrefHashEntry *pref = pref_HashTableLookup(pref_name);
-    if (!pref) return false;
-
-    /* convert PREF_HAS_USER_VALUE to bool */
-    return (PREF_HAS_USER_VALUE(pref) != 0);
-
+    return pref && pref->prefFlags.HasUserValue();
 }
 
 nsresult
 PREF_CopyCharPref(const char *pref_name, char ** return_buffer, bool get_default)
 {
     if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     nsresult rv = NS_ERROR_UNEXPECTED;
     char* stringVal;
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
 
-    if (pref && (pref->flags & PREF_STRING))
-    {
-        if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
+    if (pref && (pref->prefFlags.IsTypeString())) {
+        if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) {
             stringVal = pref->defaultPref.stringVal;
-        else
+        } else {
             stringVal = pref->userPref.stringVal;
+        }
 
         if (stringVal) {
             *return_buffer = NS_strdup(stringVal);
             rv = NS_OK;
         }
     }
     return rv;
 }
 
 nsresult PREF_GetIntPref(const char *pref_name,int32_t * return_int, bool get_default)
 {
     if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     nsresult rv = NS_ERROR_UNEXPECTED;
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
-    if (pref && (pref->flags & PREF_INT))
-    {
-        if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
-        {
+    if (pref && (pref->prefFlags.IsTypeInt())) {
+        if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) {
             int32_t tempInt = pref->defaultPref.intVal;
             /* check to see if we even had a default */
-            if (!(pref->flags & PREF_HAS_DEFAULT))
+            if (!pref->prefFlags.HasDefault()) {
                 return NS_ERROR_UNEXPECTED;
+            }
             *return_int = tempInt;
+        } else {
+            *return_int = pref->userPref.intVal;
         }
-        else
-            *return_int = pref->userPref.intVal;
         rv = NS_OK;
     }
     return rv;
 }
 
 nsresult PREF_GetBoolPref(const char *pref_name, bool * return_value, bool get_default)
 {
     if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     nsresult rv = NS_ERROR_UNEXPECTED;
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
     //NS_ASSERTION(pref, pref_name);
-    if (pref && (pref->flags & PREF_BOOL))
-    {
-        if (get_default || PREF_IS_LOCKED(pref) || !PREF_HAS_USER_VALUE(pref))
-        {
+    if (pref && (pref->prefFlags.IsTypeBool())) {
+        if (get_default || pref->prefFlags.IsLocked() || !pref->prefFlags.HasUserValue()) {
             bool tempBool = pref->defaultPref.boolVal;
             /* check to see if we even had a default */
-            if (pref->flags & PREF_HAS_DEFAULT) {
+            if (pref->prefFlags.HasDefault()) {
                 *return_value = tempBool;
                 rv = NS_OK;
             }
-        }
-        else {
+        } else {
             *return_value = pref->userPref.boolVal;
             rv = NS_OK;
         }
     }
     return rv;
 }
 
 nsresult
@@ -579,21 +565,20 @@ PREF_DeleteBranch(const char *branch_nam
 
 nsresult
 PREF_ClearUserPref(const char *pref_name)
 {
     if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     PrefHashEntry* pref = pref_HashTableLookup(pref_name);
-    if (pref && PREF_HAS_USER_VALUE(pref))
-    {
-        pref->flags &= ~PREF_USERSET;
+    if (pref && pref->prefFlags.HasUserValue()) {
+        pref->prefFlags.SetHasUserValue(false);
 
-        if (!(pref->flags & PREF_HAS_DEFAULT)) {
+        if (!pref->prefFlags.HasDefault()) {
             gHashTable->RemoveEntry(pref);
         }
 
         pref_DoCallback(pref_name);
         gDirty = true;
     }
     return NS_OK;
 }
@@ -607,21 +592,21 @@ PREF_ClearAllUserPrefs()
 
     if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     std::vector<std::string> prefStrings;
     for (auto iter = gHashTable->Iter(); !iter.Done(); iter.Next()) {
         auto pref = static_cast<PrefHashEntry*>(iter.Get());
 
-        if (PREF_HAS_USER_VALUE(pref)) {
+        if (pref->prefFlags.HasUserValue()) {
             prefStrings.push_back(std::string(pref->key));
 
-            pref->flags &= ~PREF_USERSET;
-            if (!(pref->flags & PREF_HAS_DEFAULT)) {
+            pref->prefFlags.SetHasUserValue(false);
+            if (!pref->prefFlags.HasDefault()) {
                 iter.Remove();
             }
         }
     }
 
     for (std::string& prefString : prefStrings) {
         pref_DoCallback(prefString.c_str());
     }
@@ -635,71 +620,76 @@ nsresult PREF_LockPref(const char *key, 
     if (!gHashTable)
         return NS_ERROR_NOT_INITIALIZED;
 
     PrefHashEntry* pref = pref_HashTableLookup(key);
     if (!pref)
         return NS_ERROR_UNEXPECTED;
 
     if (lockit) {
-        if (!PREF_IS_LOCKED(pref))
-        {
-            pref->flags |= PREF_LOCKED;
+        if (!pref->prefFlags.IsLocked()) {
+            pref->prefFlags.SetLocked(true);
             gIsAnyPrefLocked = true;
             pref_DoCallback(key);
         }
-    }
-    else
-    {
-        if (PREF_IS_LOCKED(pref))
-        {
-            pref->flags &= ~PREF_LOCKED;
+    } else {
+        if (pref->prefFlags.IsLocked()) {
+            pref->prefFlags.SetLocked(false);
             pref_DoCallback(key);
         }
     }
     return NS_OK;
 }
 
 /*
  * Hash table functions
  */
 static bool pref_ValueChanged(PrefValue oldValue, PrefValue newValue, PrefType type)
 {
     bool changed = true;
-    if (type & PREF_STRING)
-    {
-        if (oldValue.stringVal && newValue.stringVal)
+    switch(type) {
+      case PrefType::String:
+        if (oldValue.stringVal && newValue.stringVal) {
             changed = (strcmp(oldValue.stringVal, newValue.stringVal) != 0);
+        }
+        break;
+      case PrefType::Int:
+        changed = oldValue.intVal != newValue.intVal;
+        break;
+      case PrefType::Bool:
+        changed = oldValue.boolVal != newValue.boolVal;
+        break;
+      case PrefType::Invalid:
+      default:
+        changed = false;
+        break;
     }
-    else if (type & PREF_INT)
-        changed = oldValue.intVal != newValue.intVal;
-    else if (type & PREF_BOOL)
-        changed = oldValue.boolVal != newValue.boolVal;
     return changed;
 }
 
 /*
  * Overwrite the type and value of an existing preference. Caller must
  * ensure that they are not changing the type of a preference that has
  * a default value.
  */
-static void pref_SetValue(PrefValue* existingValue, uint16_t *existingFlags,
-                          PrefValue newValue, PrefType newType)
+static PrefTypeFlags pref_SetValue(PrefValue* existingValue, PrefTypeFlags flags,
+                                   PrefValue newValue, PrefType newType)
 {
-    if ((*existingFlags & PREF_STRING) && existingValue->stringVal) {
+    if (flags.IsTypeString() && existingValue->stringVal) {
         PL_strfree(existingValue->stringVal);
     }
-    *existingFlags = (*existingFlags & ~PREF_VALUETYPE_MASK) | newType;
-    if (newType & PREF_STRING) {
+    flags.SetPrefType(newType);
+    if (flags.IsTypeString()) {
         PR_ASSERT(newValue.stringVal);
         existingValue->stringVal = newValue.stringVal ? PL_strdup(newValue.stringVal) : nullptr;
     }
     else {
         *existingValue = newValue;
     }
+    return flags;
 }
 
 PrefHashEntry* pref_HashTableLookup(const char *key)
 {
 #ifndef MOZ_B2G
     MOZ_ASSERT(NS_IsMainThread());
 #endif
 
@@ -718,73 +708,63 @@ nsresult pref_HashPref(const char *key, 
     auto pref = static_cast<PrefHashEntry*>(gHashTable->Add(key, fallible));
     if (!pref)
         return NS_ERROR_OUT_OF_MEMORY;
 
     // new entry, better initialize
     if (!pref->key) {
 
         // initialize the pref entry
-        pref->flags = type;
+        pref->prefFlags.Reset().SetPrefType(type);
         pref->key = ArenaStrDup(key, &gPrefNameArena);
         memset(&pref->defaultPref, 0, sizeof(pref->defaultPref));
         memset(&pref->userPref, 0, sizeof(pref->userPref));
-    }
-    else if ((pref->flags & PREF_HAS_DEFAULT) && PREF_TYPE(pref) != type)
-    {
+    } else if (pref->prefFlags.HasDefault() && !pref->prefFlags.IsPrefType(type)) {
         NS_WARNING(nsPrintfCString("Trying to overwrite value of default pref %s with the wrong type!", key).get());
         return NS_ERROR_UNEXPECTED;
     }
 
     bool valueChanged = false;
-    if (flags & kPrefSetDefault)
-    {
-        if (!PREF_IS_LOCKED(pref))
-        {       /* ?? change of semantics? */
+    if (flags & kPrefSetDefault) {
+        if (!pref->prefFlags.IsLocked()) {
+            /* ?? change of semantics? */
             if (pref_ValueChanged(pref->defaultPref, value, type) ||
-                !(pref->flags & PREF_HAS_DEFAULT))
-            {
-                pref_SetValue(&pref->defaultPref, &pref->flags, value, type);
-                pref->flags |= PREF_HAS_DEFAULT;
-                if (flags & kPrefStickyDefault)
-                    pref->flags |= PREF_STICKY_DEFAULT;
-                if (!PREF_HAS_USER_VALUE(pref))
+                !pref->prefFlags.HasDefault()) {
+                pref->prefFlags = pref_SetValue(&pref->defaultPref, pref->prefFlags, value, type).SetHasDefault(true);
+                if (flags & kPrefStickyDefault) {
+                    pref->prefFlags.SetHasStickyDefault(true);
+                }
+                if (!pref->prefFlags.HasUserValue()) {
                     valueChanged = true;
+                }
             }
             // What if we change the default to be the same as the user value?
             // Should we clear the user value?
         }
-    }
-    else
-    {
+    } else {
         /* If new value is same as the default value and it's not a "sticky"
            pref, then un-set the user value.
            Otherwise, set the user value only if it has changed */
-        if ((pref->flags & PREF_HAS_DEFAULT) &&
-            !(pref->flags & PREF_STICKY_DEFAULT) &&
+        if ((pref->prefFlags.HasDefault()) &&
+            !(pref->prefFlags.HasStickyDefault()) &&
             !pref_ValueChanged(pref->defaultPref, value, type) &&
-            !(flags & kPrefForceSet))
-        {
-            if (PREF_HAS_USER_VALUE(pref))
-            {
+            !(flags & kPrefForceSet)) {
+            if (pref->prefFlags.HasUserValue()) {
                 /* XXX should we free a user-set string value if there is one? */
-                pref->flags &= ~PREF_USERSET;
-                if (!PREF_IS_LOCKED(pref)) {
+                pref->prefFlags.SetHasUserValue(false);
+                if (!pref->prefFlags.IsLocked()) {
                     gDirty = true;
                     valueChanged = true;
                 }
             }
-        }
-        else if (!PREF_HAS_USER_VALUE(pref) ||
-                 PREF_TYPE(pref) != type ||
-                 pref_ValueChanged(pref->userPref, value, type) )
-        {
-            pref_SetValue(&pref->userPref, &pref->flags, value, type);
-            pref->flags |= PREF_USERSET;
-            if (!PREF_IS_LOCKED(pref)) {
+        } else if (!pref->prefFlags.HasUserValue() ||
+                 !pref->prefFlags.IsPrefType(type) ||
+                 pref_ValueChanged(pref->userPref, value, type) ) {
+            pref->prefFlags = pref_SetValue(&pref->userPref, pref->prefFlags, value, type).SetHasUserValue(true);
+            if (!pref->prefFlags.IsLocked()) {
                 gDirty = true;
                 valueChanged = true;
             }
         }
     }
 
     if (valueChanged) {
         return pref_DoCallback(key);
@@ -803,39 +783,34 @@ pref_SizeOfPrivateData(MallocSizeOf aMal
     return n;
 }
 
 PrefType
 PREF_GetPrefType(const char *pref_name)
 {
     if (gHashTable) {
         PrefHashEntry* pref = pref_HashTableLookup(pref_name);
-        if (pref)
-        {
-            if (pref->flags & PREF_STRING)
-                return PREF_STRING;
-            else if (pref->flags & PREF_INT)
-                return PREF_INT;
-            else if (pref->flags & PREF_BOOL)
-                return PREF_BOOL;
+        if (pref) {
+            return pref->prefFlags.GetPrefType();
         }
     }
-    return PREF_INVALID;
+    return PrefType::Invalid;
 }
 
 /* -- */
 
 bool
 PREF_PrefIsLocked(const char *pref_name)
 {
     bool result = false;
     if (gIsAnyPrefLocked && gHashTable) {
         PrefHashEntry* pref = pref_HashTableLookup(pref_name);
-        if (pref && PREF_IS_LOCKED(pref))
+        if (pref && pref->prefFlags.IsLocked()) {
             result = true;
+        }
     }
 
     return result;
 }
 
 /* Adds a node to the beginning of the callback list. */
 void
 PREF_RegisterCallback(const char *pref_node,
@@ -968,15 +943,21 @@ static nsresult pref_DoCallback(const ch
 }
 
 void PREF_ReaderCallback(void       *closure,
                          const char *pref,
                          PrefValue   value,
                          PrefType    type,
                          bool        isDefault,
                          bool        isStickyDefault)
+
 {
-    uint32_t flags = isDefault ? kPrefSetDefault : kPrefForceSet;
-    if (isDefault && isStickyDefault) {
-        flags |= kPrefStickyDefault;
+    uint32_t flags = 0;
+    if (isDefault) {
+        flags |= kPrefSetDefault;
+        if (isStickyDefault) {
+            flags |= kPrefStickyDefault;
+        }
+    } else {
+        flags |= kPrefForceSet;
     }
     pref_HashPref(pref, value, type, flags);
 }
--- a/modules/libpref/prefapi.h
+++ b/modules/libpref/prefapi.h
@@ -23,58 +23,115 @@ static const uint32_t MAX_ADVISABLE_PREF
 
 typedef union
 {
     char*       stringVal;
     int32_t     intVal;
     bool        boolVal;
 } PrefValue;
 
-struct PrefHashEntry : PLDHashEntryHdr
-{
-    uint16_t flags; // This field goes first to minimize struct size on 64-bit.
-    const char *key;
-    PrefValue defaultPref;
-    PrefValue userPref;
-};
-
 /*
 // <font color=blue>
 // The Init function initializes the preference context and creates
 // the preference hashtable.
 // </font>
 */
 void        PREF_Init();
 
 /*
-// Cleanup should be called at program exit to free the 
+// Cleanup should be called at program exit to free the
 // list of registered callbacks.
 */
 void        PREF_Cleanup();
 void        PREF_CleanupPrefs();
 
 /*
 // <font color=blue>
-// Preference flags, including the native type of the preference
+// Preference flags, including the native type of the preference. Changing any of these
+// values will require modifying the code inside of PrefTypeFlags class.
 // </font>
 */
 
-typedef enum { PREF_INVALID = 0,
-               PREF_LOCKED = 1, PREF_USERSET = 2, PREF_CONFIG = 4, PREF_REMOTE = 8,
-               PREF_LILOCAL = 16, PREF_STRING = 32, PREF_INT = 64, PREF_BOOL = 128,
-               PREF_HAS_DEFAULT = 256,
-               // pref is default pref with "sticky" semantics
-               PREF_STICKY_DEFAULT = 512,
-               PREF_VALUETYPE_MASK = (PREF_STRING | PREF_INT | PREF_BOOL)
-             } PrefType;
+enum class PrefType {
+  Invalid = 0,
+  String = 1,
+  Int = 2,
+  Bool = 3,
+};
+
+// Keep the type of the preference, as well as the flags guiding its behaviour.
+class PrefTypeFlags
+{
+public:
+  PrefTypeFlags() : mValue(AsInt(PrefType::Invalid)) {}
+  PrefTypeFlags(PrefType aType) : mValue(AsInt(aType)) {}
+  PrefTypeFlags& Reset() { mValue = AsInt(PrefType::Invalid); return *this; }
+
+  bool IsTypeValid() const { return !IsPrefType(PrefType::Invalid); }
+  bool IsTypeString() const { return IsPrefType(PrefType::String); }
+  bool IsTypeInt() const { return IsPrefType(PrefType::Int); }
+  bool IsTypeBool() const { return IsPrefType(PrefType::Bool); }
+  bool IsPrefType(PrefType type) const { return GetPrefType() == type; }
+
+  PrefTypeFlags& SetPrefType(PrefType aType) {
+    mValue = mValue - AsInt(GetPrefType()) + AsInt(aType);
+    return *this;
+  }
+  PrefType GetPrefType() const {
+    return (PrefType)(mValue & (AsInt(PrefType::String) |
+                                AsInt(PrefType::Int) |
+                                AsInt(PrefType::Bool)));
+  }
+
+  bool HasDefault() const { return mValue & PREF_FLAG_HAS_DEFAULT; }
+  PrefTypeFlags& SetHasDefault(bool aSetOrUnset) { return SetFlag(PREF_FLAG_HAS_DEFAULT, aSetOrUnset); }
+
+  bool HasStickyDefault() const { return mValue & PREF_FLAG_STICKY_DEFAULT; }
+  PrefTypeFlags& SetHasStickyDefault(bool aSetOrUnset) { return SetFlag(PREF_FLAG_STICKY_DEFAULT, aSetOrUnset); }
+
+  bool IsLocked() const { return mValue & PREF_FLAG_LOCKED; }
+  PrefTypeFlags& SetLocked(bool aSetOrUnset) { return SetFlag(PREF_FLAG_LOCKED, aSetOrUnset); }
+
+  bool HasUserValue() const { return mValue & PREF_FLAG_USERSET; }
+  PrefTypeFlags& SetHasUserValue(bool aSetOrUnset) { return SetFlag(PREF_FLAG_USERSET, aSetOrUnset); }
+
+private:
+  static uint16_t AsInt(PrefType aType) { return (uint16_t)aType; }
+
+  PrefTypeFlags& SetFlag(uint16_t aFlag, bool aSetOrUnset) {
+    mValue = aSetOrUnset ? mValue | aFlag : mValue & ~aFlag;
+    return *this;
+  }
+
+  // Pack both the value of type (PrefType) and flags into the same int.  This is why
+  // the flag enum starts at 4, as PrefType occupies the bottom two bits.
+  enum {
+    PREF_FLAG_LOCKED = 4,
+    PREF_FLAG_USERSET = 8,
+    PREF_FLAG_CONFIG = 16,
+    PREF_FLAG_REMOTE = 32,
+    PREF_FLAG_LILOCAL = 64,
+    PREF_FLAG_HAS_DEFAULT = 128,
+    PREF_FLAG_STICKY_DEFAULT = 256,
+  };
+  uint16_t mValue;
+};
+
+struct PrefHashEntry : PLDHashEntryHdr
+{
+    PrefTypeFlags prefFlags; // This field goes first to minimize struct size on 64-bit.
+    const char *key;
+    PrefValue defaultPref;
+    PrefValue userPref;
+};
 
 /*
 // <font color=blue>
 // Set the various types of preferences.  These functions take a dotted
-// notation of the preference name (e.g. "browser.startup.homepage").  
+// notation of the preference name (e.g. "browser.startup.homepage").
 // Note that this will cause the preference to be saved to the file if
 // it is different from the default.  In other words, these are used
 // to set the _user_ preferences.
 //
 // If set_default is set to true however, it sets the default value.
 // This will only affect the program behavior if the user does not have a value
 // saved over it for the particular preference.  In addition, these will never
 // be saved out to disk.
@@ -98,18 +155,18 @@ bool     PREF_HasUserPref(const char* pr
 // error value.  At the moment, this is simply an int but it may
 // be converted to an enum once the global error strategy is worked out.
 //
 // They will perform conversion if the type doesn't match what was requested.
 // (if it is reasonably possible)
 // </font>
 */
 nsresult PREF_GetIntPref(const char *pref,
-                           int32_t * return_int, bool get_default);	
-nsresult PREF_GetBoolPref(const char *pref, bool * return_val, bool get_default);	
+                           int32_t * return_int, bool get_default);
+nsresult PREF_GetBoolPref(const char *pref, bool * return_val, bool get_default);
 /*
 // <font color=blue>
 // These functions are similar to the above "Get" version with the significant
 // difference that the preference module will alloc the memory (e.g. XP_STRDUP) and
 // the caller will need to be responsible for freeing it...
 // </font>
 */
 nsresult PREF_CopyCharPref(const char *pref, char ** return_buf, bool get_default);
@@ -168,20 +225,20 @@ typedef void (*PrefChangedFunc) (const c
 /*
 // <font color=blue>
 // Register a callback.  This takes a node in the preference tree and will
 // call the callback function if anything below that node is modified.
 // Unregister returns PREF_NOERROR if a callback was found that
 // matched all the parameters; otherwise it returns PREF_ERROR.
 // </font>
 */
-void PREF_RegisterCallback( const char* domain,
-								PrefChangedFunc callback, void* instance_data );
-nsresult PREF_UnregisterCallback( const char* domain,
-								PrefChangedFunc callback, void* instance_data );
+void PREF_RegisterCallback(const char* domain,
+                           PrefChangedFunc callback, void* instance_data );
+nsresult PREF_UnregisterCallback(const char* domain,
+                                 PrefChangedFunc callback, void* instance_data );
 
 /*
  * Used by nsPrefService as the callback function of the 'pref' parser
  */
 void PREF_ReaderCallback( void *closure,
                           const char *pref,
                           PrefValue   value,
                           PrefType    type,
--- a/modules/libpref/prefread.cpp
+++ b/modules/libpref/prefread.cpp
@@ -109,27 +109,27 @@ pref_GrowBuf(PrefParseState *ps)
  * @return false to indicate a fatal error.
  */
 static bool
 pref_DoCallback(PrefParseState *ps)
 {
     PrefValue  value;
 
     switch (ps->vtype) {
-    case PREF_STRING:
+    case PrefType::String:
         value.stringVal = ps->vb;
         break;
-    case PREF_INT:
+    case PrefType::Int:
         if ((ps->vb[0] == '-' || ps->vb[0] == '+') && ps->vb[1] == '\0') {
             NS_WARNING("malformed integer value");
             return false;
         }
         value.intVal = atoi(ps->vb);
         break;
-    case PREF_BOOL:
+    case PrefType::Bool:
         value.boolVal = (ps->vb == kTrue);
         break;
     default:
         break;
     }
     (*ps->reader)(ps->closure, ps->lb, value, ps->vtype, ps->fdefault,
                   ps->fstickydefault);
     return true;
@@ -149,17 +149,17 @@ PREF_FinalizeParseState(PrefParseState *
     if (ps->lb)
         free(ps->lb);
 }
 
 /**
  * Pseudo-BNF
  * ----------
  * function      = LJUNK function-name JUNK function-args
- * function-name = "user_pref" | "pref"
+ * function-name = "user_pref" | "pref" | "sticky_pref"
  * function-args = "(" JUNK pref-name JUNK "," JUNK pref-value JUNK ")" JUNK ";"
  * pref-name     = quoted-string
  * pref-value    = quoted-string | "true" | "false" | integer-value
  * JUNK          = *(WS | comment-block | comment-line)
  * LJUNK         = *(WS | comment-block | comment-line | bcomment-line)
  * WS            = SP | HT | LF | VT | FF | CR
  * SP            = <US-ASCII SP, space (32)>
  * HT            = <US-ASCII HT, horizontal-tab (9)>
@@ -183,32 +183,37 @@ PREF_ParseBuf(PrefParseState *ps, const 
     for (end = buf + bufLen; buf != end; ++buf) {
         c = *buf;
         switch (state) {
         /* initial state */
         case PREF_PARSE_INIT:
             if (ps->lbcur != ps->lb) { /* reset state */
                 ps->lbcur = ps->lb;
                 ps->vb    = nullptr;
-                ps->vtype = PREF_INVALID;
+                ps->vtype = PrefType::Invalid;
                 ps->fdefault = false;
                 ps->fstickydefault = false;
             }
             switch (c) {
             case '/':       /* begin comment block or line? */
                 state = PREF_PARSE_COMMENT_MAYBE_START;
                 break;
             case '#':       /* accept shell style comments */
                 state = PREF_PARSE_UNTIL_EOL;
                 break;
             case 'u':       /* indicating user_pref */
+            case 's':       /* indicating sticky_pref */
             case 'p':       /* indicating pref */
-            case 's':       /* indicating sticky_pref */
-                ps->smatch = (c == 'u' ? kUserPref :
-                             (c == 's' ? kPrefSticky : kPref));
+                if (c == 'u') {
+                  ps->smatch = kUserPref;
+                } else if (c == 's') {
+                  ps->smatch = kPrefSticky;
+                } else {
+                  ps->smatch = kPref;
+                }
                 ps->sindex = 1;
                 ps->nextstate = PREF_PARSE_UNTIL_OPEN_PAREN;
                 state = PREF_PARSE_MATCH_STRING;
                 break;
             /* else skip char */
             }
             break;
 
@@ -243,16 +248,18 @@ PREF_ParseBuf(PrefParseState *ps, const 
             else
                 *ps->lbcur++ = c;
             break;
 
         /* name parsing */
         case PREF_PARSE_UNTIL_NAME:
             if (c == '\"' || c == '\'') {
                 ps->fdefault = (ps->smatch == kPref || ps->smatch == kPrefSticky);
+                ps->fdefault = (ps->smatch == kPref ||
+                                ps->smatch == kPrefSticky);
                 ps->fstickydefault = (ps->smatch == kPrefSticky);
                 ps->quotechar = c;
                 ps->nextstate = PREF_PARSE_UNTIL_COMMA; /* return here when done */
                 state = PREF_PARSE_QUOTED_STRING;
             }
             else if (c == '/') {       /* allow embedded comment */
                 ps->nextstate = state; /* return here when done with comment */
                 state = PREF_PARSE_COMMENT_MAYBE_START;
@@ -279,31 +286,31 @@ PREF_ParseBuf(PrefParseState *ps, const 
             }
             break;
 
         /* value parsing */
         case PREF_PARSE_UNTIL_VALUE:
             /* the pref value type is unknown.  so, we scan for the first
              * character of the value, and determine the type from that. */
             if (c == '\"' || c == '\'') {
-                ps->vtype = PREF_STRING;
+                ps->vtype = PrefType::String;
                 ps->quotechar = c;
                 ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
                 state = PREF_PARSE_QUOTED_STRING;
             }
             else if (c == 't' || c == 'f') {
                 ps->vb = (char *) (c == 't' ? kTrue : kFalse);
-                ps->vtype = PREF_BOOL;
+                ps->vtype = PrefType::Bool;
                 ps->smatch = ps->vb;
                 ps->sindex = 1;
                 ps->nextstate = PREF_PARSE_UNTIL_CLOSE_PAREN;
                 state = PREF_PARSE_MATCH_STRING;
             }
             else if (isdigit(c) || (c == '-') || (c == '+')) {
-                ps->vtype = PREF_INT;
+                ps->vtype = PrefType::Int;
                 /* write c to line buffer... */
                 if (ps->lbcur == ps->lbend && !pref_GrowBuf(ps))
                     return false; /* out of memory */
                 *ps->lbcur++ = c;
                 state = PREF_PARSE_INT_VALUE;
             }
             else if (c == '/') {       /* allow embedded comment */
                 ps->nextstate = state; /* return here when done with comment */
@@ -506,23 +513,22 @@ PREF_ParseBuf(PrefParseState *ps, const 
             }
             else if (!isspace(c)) {
                 NS_WARNING("malformed pref file");
                 return false;
             }
             break;
         case PREF_PARSE_UNTIL_CLOSE_PAREN:
             /* tolerate only whitespace and embedded comments  */
-            if (c == ')')
+            if (c == ')') {
                 state = PREF_PARSE_UNTIL_SEMICOLON;
-            else if (c == '/') {
+            } else if (c == '/') {
                 ps->nextstate = state; /* return here when done with comment */
                 state = PREF_PARSE_COMMENT_MAYBE_START;
-            }
-            else if (!isspace(c)) {
+            } else if (!isspace(c)) {
                 NS_WARNING("malformed pref file");
                 return false;
             }
             break;
 
         /* function terminator ';' parsing */
         case PREF_PARSE_UNTIL_SEMICOLON:
             /* tolerate only whitespace and embedded comments */
--- a/modules/libpref/prefread.h
+++ b/modules/libpref/prefread.h
@@ -49,17 +49,17 @@ typedef struct PrefParseState {
     int         esclen;     /* length in esctmp              */
     char        esctmp[6];  /* raw escape to put back if err */
     char        quotechar;  /* char delimiter for quotations */
     char       *lb;         /* line buffer (only allocation) */
     char       *lbcur;      /* line buffer cursor            */
     char       *lbend;      /* line buffer end               */
     char       *vb;         /* value buffer (ptr into lb)    */
     PrefType    vtype;      /* PREF_STRING,INT,BOOL          */
-    bool        fdefault;   /* true if (default) pref     */
+    bool        fdefault;   /* true if (default) pref        */
     bool        fstickydefault; /* true if (sticky) pref     */
 } PrefParseState;
 
 /**
  * PREF_InitParseState
  *
  * Called to initialize a PrefParseState instance.
  *