Index: dependencies
===================================================================
--- a/dependencies
+++ b/dependencies
@@ -1,5 +1,5 @@
 _root = hg:https://hg.adblockplus.org/ git:https://github.com/adblockplus/
 _self = buildtools/ensure_dependencies.py
 buildtools = buildtools hg:33f115e8c1b3 git:f02a6f2
-adblockpluscore = adblockpluscore hg:d555190eee2b git:a9327e3
-adblockplusui = adblockplusui hg:7386698260f4 git:ab57a6b
\ No newline at end of file
+adblockpluscore = adblockpluscore hg:5cb695da5a40 git:b6ef032
+adblockplusui = adblockplusui hg:f86abf2efdfd git:1660877
Index: lib/devtools.js
===================================================================
--- a/lib/devtools.js
+++ b/lib/devtools.js
@@ -17,17 +17,17 @@
 
 "use strict";
 
 const {RegExpFilter,
        WhitelistFilter,
        ElemHideFilter} = require("../adblockpluscore/lib/filterClasses");
 const {SpecialSubscription} =
   require("../adblockpluscore/lib/subscriptionClasses");
-const {FilterStorage} = require("../adblockpluscore/lib/filterStorage");
+const {filterStorage} = require("../adblockpluscore/lib/filterStorage");
 const {defaultMatcher} = require("../adblockpluscore/lib/matcher");
 const {filterNotifier} = require("../adblockpluscore/lib/filterNotifier");
 const {extractHostFromFrame} = require("./url");
 const {port} = require("./messaging");
 const {HitLogger, nonRequestTypes} = require("./hitLogger");
 
 let panels = new Map();
 
@@ -152,18 +152,22 @@
   {
     browser.tabs.reload(tabId, {bypassCache: true});
 
     panel.reload = false;
     panel.reloading = true;
   }
 }
 
-function updateFilters(filters, added)
+function updateFilters(subscription, filters, added)
 {
+  let includes = subscription ?
+                   filter => filter && subscription.searchfilter(filter) != -1 :
+                   filters.includes.bind(filters);
+
   for (let panel of panels.values())
   {
     for (let i = 0; i < panel.records.length; i++)
     {
       let record = panel.records[i];
 
       // If an added filter matches a request shown in the devtools panel,
       // update that record to show the new filter. Ignore filters that aren't
@@ -171,30 +175,31 @@
       // if they don't already match. In particular, in case of element hiding
       // filters, we also wouldn't know if any new element matches.
       if (added)
       {
         if (nonRequestTypes.includes(record.request.type))
           continue;
 
         let filter = matchRequest(record.request);
-        if (!filters.includes(filter))
+
+        if (!includes(filter))
           continue;
 
         record.filter = filter;
       }
 
       // If a filter shown in the devtools panel got removed, update that
       // record to show the filter that matches now, or none, instead.
       // For filters that aren't associated with any sub-resource request,
       // just remove the record. We wouldn't know whether another filter
       // matches instead until the page is reloaded.
       else
       {
-        if (!filters.includes(record.filter))
+        if (!includes(record.filter))
           continue;
 
         if (nonRequestTypes.includes(record.request.type))
         {
           panel.port.postMessage({
             type: "remove-record",
             index: i
           });
@@ -212,28 +217,28 @@
         filter: getFilterInfo(record.filter)
       });
     }
   }
 }
 
 function onFilterAdded(filter)
 {
-  updateFilters([filter], true);
+  updateFilters(null, [filter], true);
 }
 
 function onFilterRemoved(filter)
 {
-  updateFilters([filter], false);
+  updateFilters(null, [filter], false);
 }
 
 function onSubscriptionAdded(subscription)
 {
   if (subscription instanceof SpecialSubscription)
-    updateFilters(subscription.filters, true);
+    updateFilters(subscription, null, true);
 }
 
 browser.runtime.onConnect.addListener(newPort =>
 {
   let match = newPort.name.match(/^devtools-(\d+)$/);
   if (!match)
     return;
 
Index: lib/filterComposer.js
===================================================================
--- a/lib/filterComposer.js
+++ b/lib/filterComposer.js
@@ -86,23 +86,23 @@
     let docDomain = extractHostFromFrame(frame);
     let specificOnly = checkWhitelisted(page, frame, null,
                                         RegExpFilter.typeMap.GENERICBLOCK);
 
     // Add a blocking filter for each URL of the element that can be blocked
     for (let url of details.urls)
     {
       let urlObj = new URL(url, details.baseURL);
-      let filter = defaultMatcher.whitelist.matchesAny(
+      let whitelisted = defaultMatcher.isWhitelisted(
         urlObj.href, typeMask, docDomain,
         isThirdParty(urlObj, docDomain),
         getKey(page, frame), specificOnly
       );
 
-      if (!filter)
+      if (!whitelisted)
       {
         let filterText = urlObj.href.replace(/^[\w-]+:\/+(?:www\.)?/, "||");
 
         if (specificOnly)
           filterText += "$domain=" + docDomain;
 
         if (!filters.includes(filterText))
           filters.push(filterText);
Index: lib/firefoxDataCleanup.js
===================================================================
--- a/lib/firefoxDataCleanup.js
+++ b/lib/firefoxDataCleanup.js
@@ -14,27 +14,27 @@
  * You should have received a copy of the GNU General Public License
  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 "use strict";
 
 const {Filter, ActiveFilter} = require("../adblockpluscore/lib/filterClasses");
 const {filterNotifier} = require("../adblockpluscore/lib/filterNotifier");
-const {FilterStorage} = require("../adblockpluscore/lib/filterStorage");
+const {filterStorage} = require("../adblockpluscore/lib/filterStorage");
 const {Prefs} = require("./prefs");
 const {SpecialSubscription} =
   require("../adblockpluscore/lib/subscriptionClasses");
 
 Promise.all([filterNotifier.once("load"), Prefs.untilLoaded]).then(() =>
 {
   if (Prefs.data_cleanup_done)
     return;
 
-  if (FilterStorage.firstRun)
+  if (filterStorage.firstRun)
   {
     Prefs.data_cleanup_done = true;
     return;
   }
 
   let haveHitCounts = [];
 
   for (let key in Filter.knownFilters)
@@ -49,34 +49,34 @@
       filter.disabled = false;
 
       for (let subscription of filter.subscriptions())
       {
         if (subscription instanceof SpecialSubscription)
         {
           while (true)
           {
-            let position = subscription.filters.indexOf(filter);
+            let position = subscription.searchFilter(filter);
             if (position < 0)
               break;
 
             let newFilter = Filter.fromText("! " + filter.text);
-            FilterStorage.removeFilter(filter, subscription, position);
-            FilterStorage.addFilter(newFilter, subscription, position);
+            filterStorage.removeFilter(filter, subscription, position);
+            filterStorage.addFilter(newFilter, subscription, position);
           }
         }
       }
     }
 
     if (filter.hitCount || filter.lastHit)
       haveHitCounts.push(filter);
   }
 
   // Reset hit statistics on any filters having them
-  FilterStorage.resetHitCounts(haveHitCounts);
+  filterStorage.resetHitCounts(haveHitCounts);
 
   // Remove any existing automatic backups
   let backups = [];
   for (let i = 1; i < 100; i++)
     backups.push(`file:patterns-backup${i}.ini`);
   browser.storage.local.remove(backups, () =>
   {
     Prefs.data_cleanup_done = true;
Index: lib/hitLogger.js
===================================================================
--- a/lib/hitLogger.js
+++ b/lib/hitLogger.js
@@ -16,17 +16,17 @@
  */
 
 /** @module hitLogger */
 
 "use strict";
 
 const {extractHostFromFrame} = require("./url");
 const {EventEmitter} = require("../adblockpluscore/lib/events");
-const {FilterStorage} = require("../adblockpluscore/lib/filterStorage");
+const {filterStorage} = require("../adblockpluscore/lib/filterStorage");
 const {port} = require("./messaging");
 const {RegExpFilter,
        ElemHideFilter} = require("../adblockpluscore/lib/filterClasses");
 
 const nonRequestTypes = exports.nonRequestTypes = [
   "DOCUMENT", "ELEMHIDE", "SNIPPET", "GENERICBLOCK", "GENERICHIDE", "CSP"
 ];
 
@@ -104,22 +104,22 @@
  * @param {string[]} selectors  The selectors of applied ElemHideFilters
  * @param {string[]} filters    The text of applied ElemHideEmulationFilters
  * @param {string}   docDomain  The hostname of the document
  */
 function logHiddenElements(tabId, selectors, filters, docDomain)
 {
   if (HitLogger.hasListener(tabId))
   {
-    for (let subscription of FilterStorage.subscriptions)
+    for (let subscription of filterStorage.subscriptions())
     {
       if (subscription.disabled)
         continue;
 
-      for (let filter of subscription.filters)
+      for (let filter of subscription.filters())
       {
         // We only know the exact filter in case of element hiding emulation.
         // For regular element hiding filters, the content script only knows
         // the selector, so we have to find a filter that has an identical
         // selector and is active on the domain the match was reported from.
         let isActiveElemHideFilter = filter instanceof ElemHideFilter &&
                                      selectors.includes(filter.selector) &&
                                      filter.isActiveOnDomain(docDomain);
Index: lib/indexedDBBackup.js
===================================================================
--- a/lib/indexedDBBackup.js
+++ b/lib/indexedDBBackup.js
@@ -13,17 +13,17 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 "use strict";
 
 const {filterNotifier} = require("../adblockpluscore/lib/filterNotifier");
-const {FilterStorage} = require("../adblockpluscore/lib/filterStorage");
+const {filterStorage} = require("../adblockpluscore/lib/filterStorage");
 const {DownloadableSubscription, SpecialSubscription} =
   require("../adblockpluscore/lib/subscriptionClasses");
 
 const BACKUP_NAME = "file:indexedDB-backup";
 
 let backupDelay;
 let pendingBackup = false;
 
@@ -60,17 +60,17 @@
     }
   });
 }
 
 function serialize()
 {
   let buffer = [];
 
-  for (let subscription of FilterStorage.subscriptions)
+  for (let subscription of filterStorage.subscriptions())
   {
     if (subscription instanceof SpecialSubscription)
     {
       subscription.serialize(buffer);
       buffer.push("[Subscription filters]");
       subscription.serializeFilters(buffer);
     }
     else if (subscription instanceof DownloadableSubscription)
Index: lib/requestBlocker.js
===================================================================
--- a/lib/requestBlocker.js
+++ b/lib/requestBlocker.js
@@ -298,17 +298,17 @@
 
   // Ignore disabled subscriptions and filters, unless they just got
   // disabled, otherwise they have no effect on the handler behavior.
   if (arg && arg.disabled && !isDisabledAction)
     return;
 
   // Ignore empty subscriptions. This includes subscriptions
   // that have just been added, but not downloaded yet.
-  if (arg instanceof Subscription && arg.filters.length == 0)
+  if (arg instanceof Subscription && arg.filterCount == 0)
     return;
 
   // Ignore all types of filters but request filters,
   // only these have an effect on the handler behavior.
   if (arg instanceof Filter && !(arg instanceof RegExpFilter))
     return;
 
   ignoreFilterNotifications = true;
Index: lib/subscriptionInit.js
===================================================================
--- a/lib/subscriptionInit.js
+++ b/lib/subscriptionInit.js
@@ -18,17 +18,17 @@
 /** @module subscriptionInit */
 
 "use strict";
 
 const {Subscription,
        DownloadableSubscription,
        SpecialSubscription} =
   require("../adblockpluscore/lib/subscriptionClasses");
-const {FilterStorage} = require("../adblockpluscore/lib/filterStorage");
+const {filterStorage} = require("../adblockpluscore/lib/filterStorage");
 const {filterNotifier} = require("../adblockpluscore/lib/filterNotifier");
 const info = require("info");
 const {Prefs} = require("./prefs");
 const {Synchronizer} = require("../adblockpluscore/lib/synchronizer");
 const {Utils} = require("./utils");
 const {initNotifications} = require("./notificationHelper");
 const {updatesVersion} = require("../adblockplusui/lib/prefs");
 
@@ -44,19 +44,19 @@
  * first run, but something went wrong.
  *
  * This function detects the first run, and makes sure that the user
  * gets notified (on the first run page) if the data appears incomplete
  * and therefore will be reinitialized.
  */
 function detectFirstRun()
 {
-  firstRun = FilterStorage.subscriptions.length == 0;
+  firstRun = filterStorage.subscriptionCount == 0;
 
-  if (firstRun && (!FilterStorage.firstRun || Prefs.currentVersion))
+  if (firstRun && (!filterStorage.firstRun || Prefs.currentVersion))
     reinitialized = true;
 
   Prefs.currentVersion = info.addonVersion;
 }
 
 /**
  * Determines whether to add the default ad blocking subscriptions.
  * Returns true, if there are no filter subscriptions besides those
@@ -66,26 +66,26 @@
  * is no data and therefore no subscriptions. But it also causes the
  * default ad blocking subscriptions to be added again after some
  * data corruption or misconfiguration.
  *
  * @return {boolean}
  */
 function shouldAddDefaultSubscriptions()
 {
-  for (let subscription of FilterStorage.subscriptions)
+  for (let subscription of filterStorage.subscriptions())
   {
     if (subscription instanceof DownloadableSubscription &&
         subscription.url != Prefs.subscriptions_exceptionsurl &&
         subscription.url != Prefs.subscriptions_antiadblockurl &&
         subscription.type != "circumvention")
       return false;
 
     if (subscription instanceof SpecialSubscription &&
-        subscription.filters.length > 0)
+        subscription.filterCount > 0)
       return false;
   }
 
   return true;
 }
 
 /**
  * @typedef {object} DefaultSubscriptions
@@ -261,17 +261,17 @@
 
 function addSubscriptionsAndNotifyUser(subscriptions)
 {
   if (subscriptionsCallback)
     subscriptions = subscriptionsCallback(subscriptions);
 
   for (let subscription of subscriptions)
   {
-    FilterStorage.addSubscription(subscription);
+    filterStorage.addSubscription(subscription);
     if (subscription instanceof DownloadableSubscription &&
         !subscription.lastDownload)
       Synchronizer.execute(subscription);
   }
 
   // Show first run page or the updates page. The latter is only shown
   // on Chromium (since the current updates page announces features that
   // aren't new to Firefox users), and only if this version of the
Index: lib/whitelisting.js
===================================================================
--- a/lib/whitelisting.js
+++ b/lib/whitelisting.js
@@ -17,32 +17,32 @@
 
 /** @module whitelisting */
 
 "use strict";
 
 const {defaultMatcher} = require("../adblockpluscore/lib/matcher");
 const {Filter, RegExpFilter} = require("../adblockpluscore/lib/filterClasses");
 const {filterNotifier} = require("../adblockpluscore/lib/filterNotifier");
-const {FilterStorage} = require("../adblockpluscore/lib/filterStorage");
+const {filterStorage} = require("../adblockpluscore/lib/filterStorage");
 const {extractHostFromFrame, isThirdParty} = require("./url");
 const {port} = require("./messaging");
 const {logWhitelistedDocument} = require("./hitLogger");
 const {verifySignature} = require("../adblockpluscore/lib/rsa");
 
 let sitekeys = new ext.PageMap();
 
 function match(page, url, typeMask, docDomain, sitekey)
 {
   let thirdParty = !!docDomain && isThirdParty(url, docDomain);
 
   if (!docDomain)
     docDomain = url.hostname;
 
-  let filter = defaultMatcher.whitelist.matchesAny(
+  let filter = defaultMatcher.matchesAny(
     url.href, typeMask, docDomain, thirdParty, sitekey
   );
 
   if (filter && page)
     logWhitelistedDocument(page.id, url.href, typeMask, docDomain, filter);
 
   return filter;
 }
@@ -95,28 +95,28 @@
   let filter = Filter.fromText("@@||" + host + "^$document");
   if (filter.subscriptionCount && filter.disabled)
   {
     filter.disabled = false;
   }
   else
   {
     filter.disabled = false;
-    FilterStorage.addFilter(filter);
+    filterStorage.addFilter(filter);
   }
 });
 
 port.on("filters.unwhitelist", message =>
 {
   let page = new ext.Page(message.tab);
   // Remove any exception rules applying to this URL
   let filter = checkWhitelisted(page);
   while (filter)
   {
-    FilterStorage.removeFilter(filter);
+    filterStorage.removeFilter(filter);
     if (filter.subscriptionCount)
       filter.disabled = true;
     filter = checkWhitelisted(page);
   }
 });
 
 function revalidateWhitelistingState(page)
 {
Index: qunit/tests/indexedDBBackup.js
===================================================================
--- a/qunit/tests/indexedDBBackup.js
+++ b/qunit/tests/indexedDBBackup.js
@@ -1,14 +1,14 @@
 "use strict";
 
 {
   const {IndexedDBBackup} = require("../../lib/indexedDBBackup");
   const info = require("info");
-  const {FilterStorage} = require("../../adblockpluscore/lib/filterStorage");
+  const {filterStorage} = require("../../adblockpluscore/lib/filterStorage");
   const {Filter} = require("../../adblockpluscore/lib/filterClasses");
   const {Subscription, SpecialSubscription} =
     require("../../adblockpluscore/lib/subscriptionClasses");
 
   let backupDelay = 100;
   let subscription = Subscription.fromObject({
     title: "test",
     url: "test.com",
@@ -79,18 +79,18 @@
             "first write is deferred"
           );
           deepEqual(
             data.content,
             expectedFormat,
             "saved data has the correct information"
           );
 
-          FilterStorage.removeSubscription(subscription);
-          FilterStorage.removeSubscription(specialSubscription);
+          filterStorage.removeSubscription(subscription);
+          filterStorage.removeSubscription(specialSubscription);
         }
       },
       {
         done: assert.async(),
         check(data)
         {
           ok(
             saveTimes[1] - saveTimes[0] >= backupDelay,
@@ -115,12 +115,12 @@
       }, 0);
     };
 
     Object.defineProperty(
       browser.storage.local, "set",
       {value: mockSave, enumerable: true}
     );
 
-    FilterStorage.addSubscription(specialSubscription);
-    FilterStorage.addSubscription(subscription);
+    filterStorage.addSubscription(specialSubscription);
+    filterStorage.addSubscription(subscription);
   }
 }
