Index: lib/domain.js
===================================================================
--- a/lib/domain.js
+++ b/lib/domain.js
@@ -41,29 +41,37 @@
 
 /**
  * Yields all suffixes for a domain. For example, given the domain
  * <code>www.example.com</code>, this function yields
  * <code>www.example.com</code>, <code>example.com</code>, and
  * <code>com</code>, in that order.
  *
  * @param {string} domain The domain.
+ * @param {boolean} [includeBlank] Whether to include the blank suffix at the
+ *   end.
+ *
  * @yields {string} The next suffix for the domain.
  */
-function* suffixes(domain)
+function* suffixes(domain, includeBlank = false)
 {
   while (domain != "")
   {
     yield domain;
 
     let dotIndex = domain.indexOf(".");
     domain = dotIndex == -1 ? "" : domain.substr(dotIndex + 1);
   }
+
+  if (includeBlank)
+    yield "";
 }
 
+exports.suffixes = suffixes;
+
 /**
  * Checks whether the given hostname is a domain.
  *
  * @param {string} hostname
  * @returns {boolean}
  */
 function isDomain(hostname)
 {
Index: lib/elemHide.js
===================================================================
--- a/lib/elemHide.js
+++ b/lib/elemHide.js
@@ -18,16 +18,17 @@
 "use strict";
 
 /**
  * @fileOverview Element hiding implementation.
  */
 
 const {ElemHideExceptions} = require("./elemHideExceptions");
 const {filterNotifier} = require("./filterNotifier");
+const {suffixes} = require("./domain");
 
 /**
  * The maximum number of selectors in a CSS rule. This is used by
  * <code>{@link createStyleSheet}</code> to split up a long list of selectors
  * into multiple rules.
  * @const {number}
  * @default
  */
@@ -164,25 +165,19 @@
  *
  * @returns {Array.<string>} The list of selectors.
  */
 function getConditionalSelectors(domain, specificOnly)
 {
   let selectors = [];
 
   let excluded = new Set();
-  let currentDomain = domain;
 
-  // This code is a performance hot-spot, which is why we've made certain
-  // micro-optimisations. Please be careful before making changes.
-  while (true)
+  for (let currentDomain of suffixes(domain, !specificOnly))
   {
-    if (specificOnly && currentDomain == "")
-      break;
-
     let filters = filtersByDomain.get(currentDomain);
     if (filters)
     {
       for (let [filter, isIncluded] of filters)
       {
         if (!isIncluded)
         {
           excluded.add(filter);
@@ -193,22 +188,16 @@
           if ((excluded.size == 0 || !excluded.has(filter)) &&
               !ElemHideExceptions.getException(selector, domain))
           {
             selectors.push(selector);
           }
         }
       }
     }
-
-    if (currentDomain == "")
-      break;
-
-    let nextDot = currentDomain.indexOf(".");
-    currentDomain = nextDot == -1 ? "" : currentDomain.substr(nextDot + 1);
   }
 
   return selectors;
 }
 
 /**
  * Returns the default style sheet that applies on all domains.
  * @returns {string}
Index: lib/filterClasses.js
===================================================================
--- a/lib/filterClasses.js
+++ b/lib/filterClasses.js
@@ -16,19 +16,21 @@
  */
 
 "use strict";
 
 /**
  * @fileOverview Definition of Filter class and its subclasses.
  */
 
-const {filterNotifier} = require("./filterNotifier");
 const {extend} = require("./coreUtils");
 const {filterToRegExp} = require("./common");
+const {suffixes} = require("./domain");
+const {filterNotifier} = require("./filterNotifier");
+
 const resources = require("../data/resources.json");
 
 /**
  * Map of internal resources for URL rewriting.
  * @type {Map.<string,string>}
  */
 let resourceMap = new Map(
   Object.keys(resources).map(key => [key, resources[key]])
@@ -604,27 +606,23 @@
     if (!docDomain)
       return domains.get("");
 
     if (docDomain[docDomain.length - 1] == ".")
       docDomain = docDomain.replace(/\.+$/, "");
 
     docDomain = docDomain.toLowerCase();
 
-    while (true)
+    for (docDomain of suffixes(docDomain))
     {
       let isDomainIncluded = domains.get(docDomain);
       if (typeof isDomainIncluded != "undefined")
         return isDomainIncluded;
+    }
 
-      let nextDot = docDomain.indexOf(".");
-      if (nextDot < 0)
-        break;
-      docDomain = docDomain.substr(nextDot + 1);
-    }
     return domains.get("");
   },
 
   /**
    * Checks whether this filter is active only on a domain and its subdomains.
    * @param {string} docDomain
    * @return {boolean}
    */
