| Index: lib/matcher.js | 
| diff --git a/lib/matcher.js b/lib/matcher.js | 
| index 9381ad77c4268718f5f89415fb78c2ba6f2a6a84..d402b61f1b76fdf61b97e24782c605e64d6628bf 100644 | 
| --- a/lib/matcher.js | 
| +++ b/lib/matcher.js | 
| @@ -37,13 +37,13 @@ exports.Matcher = Matcher; | 
| Matcher.prototype = { | 
| /** | 
| * Lookup table for filters by their associated keyword | 
| - * @type {Object} | 
| + * @type {Map.<string,Filter>} | 
| */ | 
| filterByKeyword: null, | 
| /** | 
| - * Lookup table for keywords by the filter text | 
| - * @type {Object} | 
| + * Lookup table for keywords by the filter | 
| + * @type {Map.<Filter,string>} | 
| */ | 
| keywordByFilter: null, | 
| @@ -52,8 +52,8 @@ Matcher.prototype = { | 
| */ | 
| clear() | 
| { | 
| - this.filterByKeyword = Object.create(null); | 
| - this.keywordByFilter = Object.create(null); | 
| + this.filterByKeyword = new Map(); | 
| + this.keywordByFilter = new Map(); | 
| }, | 
| /** | 
| @@ -62,19 +62,19 @@ Matcher.prototype = { | 
| */ | 
| add(filter) | 
| { | 
| - if (filter.text in this.keywordByFilter) | 
| + if (this.keywordByFilter.has(filter)) | 
| return; | 
| // Look for a suitable keyword | 
| let keyword = this.findKeyword(filter); | 
| - let oldEntry = this.filterByKeyword[keyword]; | 
| + let oldEntry = this.filterByKeyword.get(keyword); | 
| if (typeof oldEntry == "undefined") | 
| - this.filterByKeyword[keyword] = filter; | 
| + this.filterByKeyword.set(keyword, filter); | 
| else if (oldEntry.length == 1) | 
| - this.filterByKeyword[keyword] = [oldEntry, filter]; | 
| + this.filterByKeyword.set(keyword, [oldEntry, filter]); | 
| else | 
| oldEntry.push(filter); | 
| - this.keywordByFilter[filter.text] = keyword; | 
| + this.keywordByFilter.set(filter, keyword); | 
| }, | 
| /** | 
| @@ -83,13 +83,13 @@ Matcher.prototype = { | 
| */ | 
| remove(filter) | 
| { | 
| - if (!(filter.text in this.keywordByFilter)) | 
| + let keyword = this.keywordByFilter.get(filter); | 
| + if (typeof keyword == "undefined") | 
| return; | 
| - let keyword = this.keywordByFilter[filter.text]; | 
| - let list = this.filterByKeyword[keyword]; | 
| + let list = this.filterByKeyword.get(keyword); | 
| if (list.length <= 1) | 
| - delete this.filterByKeyword[keyword]; | 
| + this.filterByKeyword.delete(keyword); | 
| else | 
| { | 
| let index = list.indexOf(filter); | 
| @@ -97,11 +97,11 @@ Matcher.prototype = { | 
| { | 
| list.splice(index, 1); | 
| if (list.length == 1) | 
| - this.filterByKeyword[keyword] = list[0]; | 
| + this.filterByKeyword.set(keyword, list[0]); | 
| } | 
| } | 
| - delete this.keywordByFilter[filter.text]; | 
| + this.keywordByFilter.delete(filter); | 
| }, | 
| /** | 
| @@ -137,7 +137,8 @@ Matcher.prototype = { | 
| for (let i = 0, l = candidates.length; i < l; i++) | 
| { | 
| let candidate = candidates[i].substr(1); | 
| - let count = (candidate in hash ? hash[candidate].length : 0); | 
| + let filters = hash.get(candidate); | 
| + let count = typeof filters != "undefined" ? filters.length : 0; | 
| if (count < resultCount || | 
| (count == resultCount && candidate.length > resultLength)) | 
| { | 
| @@ -156,19 +157,18 @@ Matcher.prototype = { | 
| */ | 
| hasFilter(filter) | 
| { | 
| - return (filter.text in this.keywordByFilter); | 
| + return this.keywordByFilter.has(filter); | 
| }, | 
| /** | 
| * Returns the keyword used for a filter, null for unknown filters. | 
| * @param {RegExpFilter} filter | 
| - * @return {string} | 
| + * @return {?string} | 
| */ | 
| getKeywordForFilter(filter) | 
| { | 
| - if (filter.text in this.keywordByFilter) | 
| - return this.keywordByFilter[filter.text]; | 
| - return null; | 
| + let keyword = this.keywordByFilter.get(filter); | 
| + return typeof keyword != "undefined" ? keyword : null; | 
| }, | 
| /** | 
| @@ -185,7 +185,9 @@ Matcher.prototype = { | 
| _checkEntryMatch(keyword, location, typeMask, docDomain, thirdParty, sitekey, | 
| specificOnly) | 
| { | 
| - let list = this.filterByKeyword[keyword]; | 
| + let list = this.filterByKeyword.get(keyword); | 
| + if (typeof list == "undefined") | 
| + return null; | 
| for (let i = 0; i < list.length; i++) | 
| { | 
| let filter = list[i]; | 
| @@ -225,15 +227,11 @@ Matcher.prototype = { | 
| candidates.push(""); | 
| for (let i = 0, l = candidates.length; i < l; i++) | 
| { | 
| - let substr = candidates[i]; | 
| - if (substr in this.filterByKeyword) | 
| - { | 
| - let result = this._checkEntryMatch(substr, location, typeMask, | 
| - docDomain, thirdParty, sitekey, | 
| - specificOnly); | 
| - if (result) | 
| - return result; | 
| - } | 
| + let result = this._checkEntryMatch(candidates[i], location, typeMask, | 
| + docDomain, thirdParty, sitekey, | 
| + specificOnly); | 
| + if (result) | 
| + return result; | 
| } | 
| return null; | 
| @@ -402,15 +400,12 @@ CombinedMatcher.prototype = | 
| for (let i = 0, l = candidates.length; i < l; i++) | 
| { | 
| let substr = candidates[i]; | 
| - if (substr in this.whitelist.filterByKeyword) | 
| - { | 
| - let result = this.whitelist._checkEntryMatch( | 
| - substr, location, typeMask, docDomain, thirdParty, sitekey | 
| - ); | 
| - if (result) | 
| - return result; | 
| - } | 
| - if (substr in this.blacklist.filterByKeyword && blacklistHit === null) | 
| + let result = this.whitelist._checkEntryMatch( | 
| + substr, location, typeMask, docDomain, thirdParty, sitekey | 
| + ); | 
| + if (result) | 
| + return result; | 
| + if (blacklistHit === null) | 
| { | 
| blacklistHit = this.blacklist._checkEntryMatch( | 
| substr, location, typeMask, docDomain, thirdParty, sitekey, |