Index: lib/matcher.js
===================================================================
--- a/lib/matcher.js
+++ b/lib/matcher.js
@@ -66,72 +66,87 @@
   constructor()
   {
     /**
      * Lookup table for filters by their associated keyword
      * @type {Map.<string,(Filter|Set.<Filter>)>}
      * @private
      */
     this._filterByKeyword = new Map();
+
+    /**
+     * Lookup table for location only filters by their associated keyword
+     * for shortcut matching.
+     * @private
+     * @type {Map.<string,(Filter|Set.<Filter>)>}
+     */
+    this._fastFilterByKeyword = new Map();
   }
 
   /**
    * Removes all known filters
    */
   clear()
   {
     this._filterByKeyword.clear();
+    this._fastFilterByKeyword.clear();
   }
 
   /**
    * Adds a filter to the matcher
    * @param {RegExpFilter} filter
    */
   add(filter)
   {
     // Look for a suitable keyword
     let keyword = this.findKeyword(filter);
-    let set = this._filterByKeyword.get(keyword);
+    let filterMap = filter.isLocationOnly() ? this._fastFilterByKeyword :
+      this._filterByKeyword;
+    let set = filterMap.get(keyword);
+
     if (typeof set == "undefined")
     {
-      this._filterByKeyword.set(keyword, filter);
+      filterMap.set(keyword, filter);
     }
     else if (set.size == 1)
     {
       if (filter != set)
-        this._filterByKeyword.set(keyword, new Set([set, filter]));
+        filterMap.set(keyword, new Set([set, filter]));
     }
     else
     {
       set.add(filter);
     }
   }
 
   /**
    * Removes a filter from the matcher
    * @param {RegExpFilter} filter
    */
   remove(filter)
   {
     let keyword = this.findKeyword(filter);
-    let set = this._filterByKeyword.get(keyword);
+    let filterMap = filter.isLocationOnly() ? this._fastFilterByKeyword :
+      this._filterByKeyword;
+    let set = filterMap.get(keyword);
+
     if (typeof set == "undefined")
       return;
 
     if (set.size == 1)
     {
       if (filter == set)
-        this._filterByKeyword.delete(keyword);
+        filterMap.delete(keyword);
     }
     else
     {
       set.delete(filter);
 
       if (set.size == 1)
-        this._filterByKeyword.set(keyword, [...set][0]);
+        filterMap.set(keyword, [...set][0]);
     }
   }
 
   /**
    * Chooses a keyword to be associated with the filter
    * @param {Filter} filter
    * @returns {string} keyword or an empty string if no keyword could be found
    * @protected
@@ -142,17 +157,19 @@
     let {pattern} = filter;
     if (pattern == null)
       return result;
 
     let candidates = pattern.toLowerCase().match(allKeywordsRegExp);
     if (!candidates)
       return result;
 
-    let hash = this._filterByKeyword;
+    let hash = filter.isLocationOnly() ? this._fastFilterByKeyword :
+      this._filterByKeyword;
+
     let resultCount = 0xFFFFFF;
     let resultLength = 0;
     for (let i = 0, l = candidates.length; i < l; i++)
     {
       let candidate = candidates[i].substr(1);
       let filters = hash.get(candidate);
       let count = typeof filters != "undefined" ? filters.size : 0;
       if (count < resultCount ||
@@ -178,17 +195,32 @@
    * @returns {?Filter}
    * @protected
    */
   checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey,
                   specificOnly)
   {
     let set = this._filterByKeyword.get(keyword);
     if (typeof set == "undefined")
+    {
+      let fastSet = this._fastFilterByKeyword.get(keyword);
+      if (typeof fastSet == "undefined")
+        return null;
+
+      for (let filter of fastSet)
+      {
+        if (specificOnly && filter.isGeneric() &&
+            !(filter instanceof WhitelistFilter))
+          continue;
+
+        if (filter.matchesLocation(location))
+          return filter;
+      }
       return null;
+    }
 
     for (let filter of set)
     {
       if (specificOnly && filter.isGeneric() &&
           !(filter instanceof WhitelistFilter))
         continue;
 
       if (filter.matches(location, typeMask, docDomain, thirdParty, sitekey))
