mirror of
https://github.com/gorhill/uBlock.git
synced 2024-09-01 08:39:37 +02:00
Squashed commit of the following:
commit 7c6cacc59b27660fabacb55d668ef099b222a9e6 Author: Raymond Hill <rhill@raymondhill.net> Date: Sat Nov 3 08:52:51 2018 -0300 code review: finalize support for wasm-based hntrie commit 8596ed80e3bdac2c36e3c860b51e7189f6bc8487 Merge: cbe1f2e000eb82
Author: Raymond Hill <rhill@raymondhill.net> Date: Sat Nov 3 08:41:40 2018 -0300 Merge branch 'master' of github.com:gorhill/uBlock into trie-wasm commit cbe1f2e2f38484d42af3204ec7f1b5decd30f99e Merge: 270fc7fdbb7e80
Author: Raymond Hill <rhill@raymondhill.net> Date: Fri Nov 2 17:43:20 2018 -0300 Merge branch 'master' of github.com:gorhill/uBlock into trie-wasm commit 270fc7f9b3b73d79e6355522c1a42ce782fe7e5c Merge: d2a89cfd693d4f
Author: Raymond Hill <rhill@raymondhill.net> Date: Fri Nov 2 16:21:08 2018 -0300 Merge branch 'master' of github.com:gorhill/uBlock into trie-wasm commit d2a89cf28f0816ffd4617c2c7b4ccfcdcc30e1b4 Merge: d7afc78649f82f
Author: Raymond Hill <rhill@raymondhill.net> Date: Fri Nov 2 14:54:58 2018 -0300 Merge branch 'master' of github.com:gorhill/uBlock into trie-wasm commit d7afc78b5f5675d7d34c5a1d0ec3099a77caef49 Author: Raymond Hill <rhill@raymondhill.net> Date: Fri Nov 2 13:56:11 2018 -0300 finalize wasm-based hntrie implementation commit e7b9e043cf36ad055791713e34eb0322dec84627 Author: Raymond Hill <rhill@raymondhill.net> Date: Fri Nov 2 08:14:02 2018 -0300 add first-pass implementation of wasm version of hntrie commit 1015cb34624f3ef73ace58b58fe4e03dfc59897f Author: Raymond Hill <rhill@raymondhill.net> Date: Wed Oct 31 17:16:47 2018 -0300 back up draft work toward experimenting with wasm hntries
This commit is contained in:
parent
000eb82f08
commit
d7d544cda0
@ -33,12 +33,12 @@ if ( vAPI.webextFlavor === undefined ) {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var µBlock = (function() { // jshint ignore:line
|
||||
const µBlock = (function() { // jshint ignore:line
|
||||
|
||||
var oneSecond = 1000,
|
||||
oneMinute = 60 * oneSecond;
|
||||
const oneSecond = 1000,
|
||||
oneMinute = 60 * oneSecond;
|
||||
|
||||
var hiddenSettingsDefault = {
|
||||
const hiddenSettingsDefault = {
|
||||
assetFetchTimeout: 30,
|
||||
autoUpdateAssetFetchPeriod: 120,
|
||||
autoUpdatePeriod: 7,
|
||||
@ -56,7 +56,7 @@ var µBlock = (function() { // jshint ignore:line
|
||||
userResourcesLocation: 'unset'
|
||||
};
|
||||
|
||||
var whitelistDefault = [
|
||||
const whitelistDefault = [
|
||||
'about-scheme',
|
||||
'chrome-extension-scheme',
|
||||
'chrome-scheme',
|
||||
|
974
src/js/hntrie.js
974
src/js/hntrie.js
File diff suppressed because it is too large
Load Diff
@ -29,7 +29,7 @@
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var µb = µBlock;
|
||||
const µb = µBlock;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@ -287,7 +287,12 @@ var onFirstFetchReady = function(fetched) {
|
||||
onVersionReady(fetched.version);
|
||||
onCommandShortcutsReady(fetched.commandShortcuts);
|
||||
|
||||
µb.loadPublicSuffixList(onPSLReady);
|
||||
Promise.all([
|
||||
µb.loadPublicSuffixList(),
|
||||
µb.staticNetFilteringEngine.readyToUse()
|
||||
]).then(( ) => {
|
||||
onPSLReady();
|
||||
});
|
||||
µb.loadRedirectResources();
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
/* jshint bitwise: false */
|
||||
/* global punycode, HNTrieBuilder */
|
||||
/* global punycode, hnTrieManager */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var µb = µBlock;
|
||||
const µb = µBlock;
|
||||
|
||||
// fedcba9876543210
|
||||
// | | |||
|
||||
@ -43,15 +43,15 @@ var µb = µBlock;
|
||||
// | +-------- bit 4- 8: type [0 - 31]
|
||||
// +------------- bit 9-15: unused
|
||||
|
||||
var BlockAction = 0 << 0;
|
||||
var AllowAction = 1 << 0;
|
||||
var Important = 1 << 1;
|
||||
var AnyParty = 0 << 2;
|
||||
var FirstParty = 1 << 2;
|
||||
var ThirdParty = 2 << 2;
|
||||
const BlockAction = 0 << 0;
|
||||
const AllowAction = 1 << 0;
|
||||
const Important = 1 << 1;
|
||||
const AnyParty = 0 << 2;
|
||||
const FirstParty = 1 << 2;
|
||||
const ThirdParty = 2 << 2;
|
||||
|
||||
var AnyType = 0 << 4;
|
||||
var typeNameToTypeValue = {
|
||||
const AnyType = 0 << 4;
|
||||
const typeNameToTypeValue = {
|
||||
'no_type': 0 << 4,
|
||||
'stylesheet': 1 << 4,
|
||||
'image': 2 << 4,
|
||||
@ -75,9 +75,9 @@ var typeNameToTypeValue = {
|
||||
'webrtc': 19 << 4,
|
||||
'unsupported': 20 << 4
|
||||
};
|
||||
var otherTypeBitValue = typeNameToTypeValue.other;
|
||||
const otherTypeBitValue = typeNameToTypeValue.other;
|
||||
|
||||
var typeValueToTypeName = {
|
||||
const typeValueToTypeName = {
|
||||
1: 'stylesheet',
|
||||
2: 'image',
|
||||
3: 'object',
|
||||
@ -100,16 +100,16 @@ var typeValueToTypeName = {
|
||||
20: 'unsupported'
|
||||
};
|
||||
|
||||
var BlockAnyTypeAnyParty = BlockAction | AnyType | AnyParty;
|
||||
var BlockAnyType = BlockAction | AnyType;
|
||||
var BlockAnyParty = BlockAction | AnyParty;
|
||||
const BlockAnyTypeAnyParty = BlockAction | AnyType | AnyParty;
|
||||
const BlockAnyType = BlockAction | AnyType;
|
||||
const BlockAnyParty = BlockAction | AnyParty;
|
||||
|
||||
var AllowAnyTypeAnyParty = AllowAction | AnyType | AnyParty;
|
||||
var AllowAnyType = AllowAction | AnyType;
|
||||
var AllowAnyParty = AllowAction | AnyParty;
|
||||
const AllowAnyTypeAnyParty = AllowAction | AnyType | AnyParty;
|
||||
const AllowAnyType = AllowAction | AnyType;
|
||||
const AllowAnyParty = AllowAction | AnyParty;
|
||||
|
||||
var genericHideException = AllowAction | AnyParty | typeNameToTypeValue.generichide,
|
||||
genericHideImportant = BlockAction | AnyParty | typeNameToTypeValue.generichide | Important;
|
||||
const genericHideException = AllowAction | AnyParty | typeNameToTypeValue.generichide,
|
||||
genericHideImportant = BlockAction | AnyParty | typeNameToTypeValue.generichide | Important;
|
||||
|
||||
// ABP filters: https://adblockplus.org/en/filters
|
||||
// regex tester: http://regex101.com/
|
||||
@ -119,7 +119,7 @@ var genericHideException = AllowAction | AnyParty | typeNameToTypeValue.generich
|
||||
// See the following as short-lived registers, used during evaluation. They are
|
||||
// valid until the next evaluation.
|
||||
|
||||
var pageHostnameRegister = '',
|
||||
let pageHostnameRegister = '',
|
||||
requestHostnameRegister = '';
|
||||
//var filterRegister = null;
|
||||
//var categoryRegister = '';
|
||||
@ -127,13 +127,13 @@ var pageHostnameRegister = '',
|
||||
// Local helpers
|
||||
|
||||
// Be sure to not confuse 'example.com' with 'anotherexample.com'
|
||||
var isFirstParty = function(domain, hostname) {
|
||||
const isFirstParty = function(domain, hostname) {
|
||||
return hostname.endsWith(domain) &&
|
||||
(hostname.length === domain.length ||
|
||||
hostname.charCodeAt(hostname.length - domain.length - 1) === 0x2E /* '.' */);
|
||||
};
|
||||
|
||||
var normalizeRegexSource = function(s) {
|
||||
const normalizeRegexSource = function(s) {
|
||||
try {
|
||||
var re = new RegExp(s);
|
||||
return re.source;
|
||||
@ -143,12 +143,12 @@ var normalizeRegexSource = function(s) {
|
||||
return '';
|
||||
};
|
||||
|
||||
var rawToRegexStr = function(s, anchor) {
|
||||
var me = rawToRegexStr;
|
||||
const rawToRegexStr = function(s, anchor) {
|
||||
let me = rawToRegexStr;
|
||||
// https://www.loggly.com/blog/five-invaluable-techniques-to-improve-regex-performance/
|
||||
// https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions
|
||||
// Also: remove leading/trailing wildcards -- there is no point.
|
||||
var reStr = s.replace(me.escape1, '\\$&')
|
||||
let reStr = s.replace(me.escape1, '\\$&')
|
||||
.replace(me.escape2, '(?:[^%.0-9a-z_-]|$)')
|
||||
.replace(me.escape3, '')
|
||||
.replace(me.escape4, '[^ ]*?');
|
||||
@ -175,7 +175,7 @@ rawToRegexStr.reTextHostnameAnchor2 = '^[a-z-]+://(?:[^/?#]+)?';
|
||||
|
||||
const filterDataSerialize = µb.CompiledLineIO.serialize;
|
||||
|
||||
var toLogDataInternal = function(categoryBits, tokenHash, filter) {
|
||||
const toLogDataInternal = function(categoryBits, tokenHash, filter) {
|
||||
if ( filter === null ) { return undefined; }
|
||||
let logData = filter.logData();
|
||||
logData.compiled = filterDataSerialize([
|
||||
@ -209,7 +209,7 @@ var toLogDataInternal = function(categoryBits, tokenHash, filter) {
|
||||
};
|
||||
|
||||
// First character of match must be within the hostname part of the url.
|
||||
var isHnAnchored = function(url, matchStart) {
|
||||
const isHnAnchored = function(url, matchStart) {
|
||||
var hnStart = url.indexOf('://');
|
||||
if ( hnStart === -1 ) { return false; }
|
||||
hnStart += 3;
|
||||
@ -222,9 +222,9 @@ var isHnAnchored = function(url, matchStart) {
|
||||
return url.charCodeAt(matchStart - 1) === 0x2E;
|
||||
};
|
||||
|
||||
var reURLPostHostnameAnchors = /[\/?#]/;
|
||||
const reURLPostHostnameAnchors = /[\/?#]/;
|
||||
|
||||
var arrayStrictEquals = function(a, b) {
|
||||
const arrayStrictEquals = function(a, b) {
|
||||
var n = a.length;
|
||||
if ( n !== b.length ) { return false; }
|
||||
var isArray, x, y;
|
||||
@ -251,22 +251,22 @@ var arrayStrictEquals = function(a, b) {
|
||||
|
||||
**/
|
||||
|
||||
var filterClasses = [],
|
||||
filterClassIdGenerator = 0;
|
||||
const filterClasses = [];
|
||||
let filterClassIdGenerator = 0;
|
||||
|
||||
var registerFilterClass = function(ctor) {
|
||||
var fid = filterClassIdGenerator++;
|
||||
const registerFilterClass = function(ctor) {
|
||||
let fid = filterClassIdGenerator++;
|
||||
ctor.fid = ctor.prototype.fid = fid;
|
||||
filterClasses[fid] = ctor;
|
||||
};
|
||||
|
||||
var filterFromCompiledData = function(args) {
|
||||
const filterFromCompiledData = function(args) {
|
||||
return filterClasses[args[0]].load(args);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterTrue = function() {
|
||||
const FilterTrue = function() {
|
||||
};
|
||||
|
||||
FilterTrue.prototype.match = function() {
|
||||
@ -297,7 +297,7 @@ registerFilterClass(FilterTrue);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterPlain = function(s, tokenBeg) {
|
||||
const FilterPlain = function(s, tokenBeg) {
|
||||
this.s = s;
|
||||
this.tokenBeg = tokenBeg;
|
||||
};
|
||||
@ -330,7 +330,7 @@ registerFilterClass(FilterPlain);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterPlainPrefix0 = function(s) {
|
||||
const FilterPlainPrefix0 = function(s) {
|
||||
this.s = s;
|
||||
};
|
||||
|
||||
@ -362,7 +362,7 @@ registerFilterClass(FilterPlainPrefix0);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterPlainPrefix1 = function(s) {
|
||||
const FilterPlainPrefix1 = function(s) {
|
||||
this.s = s;
|
||||
};
|
||||
|
||||
@ -394,7 +394,7 @@ registerFilterClass(FilterPlainPrefix1);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterPlainHostname = function(s) {
|
||||
const FilterPlainHostname = function(s) {
|
||||
this.s = s;
|
||||
};
|
||||
|
||||
@ -429,7 +429,7 @@ registerFilterClass(FilterPlainHostname);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterPlainLeftAnchored = function(s) {
|
||||
const FilterPlainLeftAnchored = function(s) {
|
||||
this.s = s;
|
||||
};
|
||||
|
||||
@ -461,7 +461,7 @@ registerFilterClass(FilterPlainLeftAnchored);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterPlainRightAnchored = function(s) {
|
||||
const FilterPlainRightAnchored = function(s) {
|
||||
this.s = s;
|
||||
};
|
||||
|
||||
@ -493,7 +493,7 @@ registerFilterClass(FilterPlainRightAnchored);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterExactMatch = function(s) {
|
||||
const FilterExactMatch = function(s) {
|
||||
this.s = s;
|
||||
};
|
||||
|
||||
@ -525,7 +525,7 @@ registerFilterClass(FilterExactMatch);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterPlainHnAnchored = function(s) {
|
||||
const FilterPlainHnAnchored = function(s) {
|
||||
this.s = s;
|
||||
};
|
||||
|
||||
@ -558,7 +558,7 @@ registerFilterClass(FilterPlainHnAnchored);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterGeneric = function(s, anchor) {
|
||||
const FilterGeneric = function(s, anchor) {
|
||||
this.s = s;
|
||||
this.anchor = anchor;
|
||||
};
|
||||
@ -603,7 +603,7 @@ registerFilterClass(FilterGeneric);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterGenericHnAnchored = function(s) {
|
||||
const FilterGenericHnAnchored = function(s) {
|
||||
this.s = s;
|
||||
};
|
||||
|
||||
@ -642,7 +642,7 @@ registerFilterClass(FilterGenericHnAnchored);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterGenericHnAndRightAnchored = function(s) {
|
||||
const FilterGenericHnAndRightAnchored = function(s) {
|
||||
FilterGenericHnAnchored.call(this, s);
|
||||
};
|
||||
|
||||
@ -682,7 +682,7 @@ registerFilterClass(FilterGenericHnAndRightAnchored);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterRegex = function(s) {
|
||||
const FilterRegex = function(s) {
|
||||
this.re = s;
|
||||
};
|
||||
|
||||
@ -723,7 +723,7 @@ registerFilterClass(FilterRegex);
|
||||
|
||||
// Filtering according to the origin.
|
||||
|
||||
var FilterOrigin = function() {
|
||||
const FilterOrigin = function() {
|
||||
};
|
||||
|
||||
FilterOrigin.prototype.wrapped = {
|
||||
@ -766,7 +766,7 @@ FilterOrigin.prototype.compile = function() {
|
||||
|
||||
// *** start of specialized origin matchers
|
||||
|
||||
var FilterOriginHit = function(domainOpt) {
|
||||
const FilterOriginHit = function(domainOpt) {
|
||||
FilterOrigin.call(this);
|
||||
this.hostname = domainOpt;
|
||||
};
|
||||
@ -792,7 +792,7 @@ FilterOriginHit.prototype = Object.create(FilterOrigin.prototype, {
|
||||
|
||||
//
|
||||
|
||||
var FilterOriginMiss = function(domainOpt) {
|
||||
const FilterOriginMiss = function(domainOpt) {
|
||||
FilterOrigin.call(this);
|
||||
this.hostname = domainOpt.slice(1);
|
||||
};
|
||||
@ -811,14 +811,15 @@ FilterOriginMiss.prototype = Object.create(FilterOrigin.prototype, {
|
||||
var needle = this.hostname, haystack = pageHostnameRegister;
|
||||
if ( haystack.endsWith(needle) === false ) { return true; }
|
||||
var offset = haystack.length - needle.length;
|
||||
return offset !== 0 && haystack.charCodeAt(offset - 1) !== 0x2E /* '.' */;
|
||||
return offset !== 0 &&
|
||||
haystack.charCodeAt(offset - 1) !== 0x2E /* '.' */;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
var FilterOriginHitSet = function(domainOpt) {
|
||||
const FilterOriginHitSet = function(domainOpt) {
|
||||
FilterOrigin.call(this);
|
||||
this.domainOpt = domainOpt.length < 128
|
||||
? domainOpt
|
||||
@ -840,17 +841,17 @@ FilterOriginHitSet.prototype = Object.create(FilterOrigin.prototype, {
|
||||
},
|
||||
matchOrigin: {
|
||||
value: function() {
|
||||
if ( this.oneOf === null ) {
|
||||
this.oneOf = HNTrieBuilder.fromDomainOpt(this.domainOpt);
|
||||
if ( hnTrieManager.isValidRef(this.oneOf) === false ) {
|
||||
this.oneOf = hnTrieManager.fromDomainOpt(this.domainOpt);
|
||||
}
|
||||
return this.oneOf.matches(pageHostnameRegister);
|
||||
return this.oneOf.matches(pageHostnameRegister) === 1;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
var FilterOriginMissSet = function(domainOpt) {
|
||||
const FilterOriginMissSet = function(domainOpt) {
|
||||
FilterOrigin.call(this);
|
||||
this.domainOpt = domainOpt.length < 128
|
||||
? domainOpt
|
||||
@ -872,17 +873,19 @@ FilterOriginMissSet.prototype = Object.create(FilterOrigin.prototype, {
|
||||
},
|
||||
matchOrigin: {
|
||||
value: function() {
|
||||
if ( this.noneOf === null ) {
|
||||
this.noneOf = HNTrieBuilder.fromDomainOpt(this.domainOpt.replace(/~/g, ''));
|
||||
if ( hnTrieManager.isValidRef(this.noneOf) === false ) {
|
||||
this.noneOf = hnTrieManager.fromDomainOpt(
|
||||
this.domainOpt.replace(/~/g, '')
|
||||
);
|
||||
}
|
||||
return this.noneOf.matches(pageHostnameRegister) === false;
|
||||
return this.noneOf.matches(pageHostnameRegister) === 0;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
var FilterOriginMixedSet = function(domainOpt) {
|
||||
const FilterOriginMixedSet = function(domainOpt) {
|
||||
FilterOrigin.call(this);
|
||||
this.domainOpt = domainOpt.length < 128
|
||||
? domainOpt
|
||||
@ -903,20 +906,16 @@ FilterOriginMixedSet.prototype = Object.create(FilterOrigin.prototype, {
|
||||
},
|
||||
init: {
|
||||
value: function() {
|
||||
var oneOf = [], noneOf = [],
|
||||
hostnames = this.domainOpt.split('|'),
|
||||
i = hostnames.length,
|
||||
hostname;
|
||||
while ( i-- ) {
|
||||
hostname = hostnames[i];
|
||||
let oneOf = [], noneOf = [];
|
||||
for ( let hostname of this.domainOpt.split('|') ) {
|
||||
if ( hostname.charCodeAt(0) === 0x7E /* '~' */ ) {
|
||||
noneOf.push(hostname.slice(1));
|
||||
} else {
|
||||
oneOf.push(hostname);
|
||||
}
|
||||
}
|
||||
this.oneOf = HNTrieBuilder.fromIterable(oneOf);
|
||||
this.noneOf = HNTrieBuilder.fromIterable(noneOf);
|
||||
this.oneOf = hnTrieManager.fromIterable(oneOf);
|
||||
this.noneOf = hnTrieManager.fromIterable(noneOf);
|
||||
}
|
||||
},
|
||||
toDomainOpt: {
|
||||
@ -926,10 +925,12 @@ FilterOriginMixedSet.prototype = Object.create(FilterOrigin.prototype, {
|
||||
},
|
||||
matchOrigin: {
|
||||
value: function() {
|
||||
if ( this.oneOf === null ) { this.init(); }
|
||||
var needle = pageHostnameRegister;
|
||||
return this.oneOf.matches(needle) &&
|
||||
this.noneOf.matches(needle) === false;
|
||||
if ( hnTrieManager.isValidRef(this.oneOf) === false ) {
|
||||
this.init();
|
||||
}
|
||||
let needle = pageHostnameRegister;
|
||||
return this.oneOf.matches(needle) === 1 &&
|
||||
this.noneOf.matches(needle) === 0;
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -981,7 +982,7 @@ registerFilterClass(FilterOrigin);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterDataHolder = function(dataType, dataStr) {
|
||||
const FilterDataHolder = function(dataType, dataStr) {
|
||||
this.dataType = dataType;
|
||||
this.dataStr = dataStr;
|
||||
this.wrapped = undefined;
|
||||
@ -1024,7 +1025,7 @@ registerFilterClass(FilterDataHolder);
|
||||
|
||||
// Helper class for storing instances of FilterDataHolder.
|
||||
|
||||
var FilterDataHolderEntry = function(categoryBits, tokenHash, fdata) {
|
||||
const FilterDataHolderEntry = function(categoryBits, tokenHash, fdata) {
|
||||
this.categoryBits = categoryBits;
|
||||
this.tokenHash = tokenHash;
|
||||
this.filter = filterFromCompiledData(fdata);
|
||||
@ -1047,7 +1048,7 @@ FilterDataHolderEntry.load = function(data) {
|
||||
|
||||
// Dictionary of hostnames
|
||||
//
|
||||
var FilterHostnameDict = function() {
|
||||
const FilterHostnameDict = function() {
|
||||
this.h = ''; // short-lived register
|
||||
this.dict = new Set();
|
||||
};
|
||||
@ -1138,7 +1139,7 @@ registerFilterClass(FilterHostnameDict);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterPair = function(a, b) {
|
||||
const FilterPair = function(a, b) {
|
||||
this.f1 = a;
|
||||
this.f2 = b;
|
||||
this.f = null;
|
||||
@ -1217,7 +1218,7 @@ registerFilterClass(FilterPair);
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterBucket = function(a, b, c) {
|
||||
const FilterBucket = function(a, b, c) {
|
||||
this.filters = [];
|
||||
this.f = null;
|
||||
if ( a !== undefined ) {
|
||||
@ -1315,7 +1316,7 @@ registerFilterClass(FilterBucket);
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterParser = function() {
|
||||
const FilterParser = function() {
|
||||
this.cantWebsocket = vAPI.cantWebsocket;
|
||||
this.reBadDomainOptChars = /[*+?^${}()[\]\\]/;
|
||||
this.reHostnameRule1 = /^[0-9a-z][0-9a-z.-]*[0-9a-z]$/i;
|
||||
@ -1933,7 +1934,7 @@ FilterParser.prototype.makeToken = function() {
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
|
||||
var FilterContainer = function() {
|
||||
const FilterContainer = function() {
|
||||
this.reIsGeneric = /[\^\*]/;
|
||||
this.filterParser = new FilterParser();
|
||||
this.urlTokenizer = µb.urlTokenizer;
|
||||
@ -1960,6 +1961,9 @@ FilterContainer.prototype.reset = function() {
|
||||
this.dataFilters = new Map();
|
||||
this.filterParser.reset();
|
||||
|
||||
// This will invalidate all hn tries throughout uBO:
|
||||
hnTrieManager.reset();
|
||||
|
||||
// Runtime registers
|
||||
this.cbRegister = undefined;
|
||||
this.thRegister = undefined;
|
||||
@ -2052,6 +2056,15 @@ FilterContainer.prototype.freeze = function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// This is necessary for when the filtering engine readiness will depend
|
||||
// on asynchronous operations (ex.: when loading a wasm module).
|
||||
|
||||
FilterContainer.prototype.readyToUse = function() {
|
||||
return hnTrieManager.readyToUse();
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.toSelfie = function() {
|
||||
let categoriesToSelfie = function(categoryMap) {
|
||||
let selfie = [];
|
||||
@ -2250,7 +2263,7 @@ FilterContainer.prototype.compileToAtomicFilter = function(
|
||||
|
||||
// Only static filter with an explicit type can be redirected. If we reach
|
||||
// this point, it's because there is one or more explicit type.
|
||||
if ( parsed.badFilter === false && parsed.redirect ) {
|
||||
if ( parsed.redirect ) {
|
||||
let redirects = µb.redirectEngine.compileRuleFromStaticFilter(parsed.raw);
|
||||
if ( Array.isArray(redirects) ) {
|
||||
for ( let redirect of redirects ) {
|
||||
@ -2292,26 +2305,24 @@ FilterContainer.prototype.fromCompiledContent = function(reader) {
|
||||
FilterContainer.prototype.matchAndFetchData = function(dataType, requestURL, out, outlog) {
|
||||
if ( this.dataFilters.length === 0 ) { return; }
|
||||
|
||||
var url = this.urlTokenizer.setURL(requestURL);
|
||||
let url = this.urlTokenizer.setURL(requestURL);
|
||||
|
||||
requestHostnameRegister = µb.URI.hostnameFromURI(url);
|
||||
pageHostnameRegister = requestHostnameRegister = µb.URI.hostnameFromURI(url);
|
||||
|
||||
// We need to visit ALL the matching filters.
|
||||
var toAddImportant = new Map(),
|
||||
let toAddImportant = new Map(),
|
||||
toAdd = new Map(),
|
||||
toRemove = new Map();
|
||||
|
||||
var entry, f,
|
||||
tokenHashes = this.urlTokenizer.getTokens(),
|
||||
tokenHash, tokenOffset,
|
||||
let tokenHashes = this.urlTokenizer.getTokens(),
|
||||
i = 0;
|
||||
while ( i < 32 ) {
|
||||
tokenHash = tokenHashes[i++];
|
||||
let tokenHash = tokenHashes[i++];
|
||||
if ( tokenHash === 0 ) { break; }
|
||||
tokenOffset = tokenHashes[i++];
|
||||
entry = this.dataFilters.get(tokenHash);
|
||||
let tokenOffset = tokenHashes[i++];
|
||||
let entry = this.dataFilters.get(tokenHash);
|
||||
while ( entry !== undefined ) {
|
||||
f = entry.filter;
|
||||
let f = entry.filter;
|
||||
if ( f.match(url, tokenOffset) === true ) {
|
||||
if ( entry.categoryBits & 0x001 ) {
|
||||
toRemove.set(f.dataStr, entry);
|
||||
@ -2324,9 +2335,9 @@ FilterContainer.prototype.matchAndFetchData = function(dataType, requestURL, out
|
||||
entry = entry.next;
|
||||
}
|
||||
}
|
||||
entry = this.dataFilters.get(this.noTokenHash);
|
||||
let entry = this.dataFilters.get(this.noTokenHash);
|
||||
while ( entry !== undefined ) {
|
||||
f = entry.filter;
|
||||
let f = entry.filter;
|
||||
if ( f.match(url) === true ) {
|
||||
if ( entry.categoryBits & 0x001 ) {
|
||||
toRemove.set(f.dataStr, entry);
|
||||
@ -2342,12 +2353,11 @@ FilterContainer.prototype.matchAndFetchData = function(dataType, requestURL, out
|
||||
if ( toAddImportant.size === 0 && toAdd.size === 0 ) { return; }
|
||||
|
||||
// Remove entries overriden by other filters.
|
||||
var key;
|
||||
for ( key of toAddImportant.keys() ) {
|
||||
for ( let key of toAddImportant.keys() ) {
|
||||
toAdd.delete(key);
|
||||
toRemove.delete(key);
|
||||
}
|
||||
for ( key of toRemove.keys() ) {
|
||||
for ( let key of toRemove.keys() ) {
|
||||
if ( key === '' ) {
|
||||
toAdd.clear();
|
||||
break;
|
||||
@ -2355,26 +2365,25 @@ FilterContainer.prototype.matchAndFetchData = function(dataType, requestURL, out
|
||||
toAdd.delete(key);
|
||||
}
|
||||
|
||||
var logData;
|
||||
for ( entry of toAddImportant ) {
|
||||
for ( let entry of toAddImportant ) {
|
||||
out.push(entry[0]);
|
||||
if ( outlog === undefined ) { continue; }
|
||||
logData = entry[1].logData();
|
||||
let logData = entry[1].logData();
|
||||
logData.source = 'static';
|
||||
logData.result = 1;
|
||||
outlog.push(logData);
|
||||
}
|
||||
for ( entry of toAdd ) {
|
||||
for ( let entry of toAdd ) {
|
||||
out.push(entry[0]);
|
||||
if ( outlog === undefined ) { continue; }
|
||||
logData = entry[1].logData();
|
||||
let logData = entry[1].logData();
|
||||
logData.source = 'static';
|
||||
logData.result = 1;
|
||||
outlog.push(logData);
|
||||
}
|
||||
if ( outlog !== undefined ) {
|
||||
for ( entry of toRemove.values()) {
|
||||
logData = entry.logData();
|
||||
for ( let entry of toRemove.values()) {
|
||||
let logData = entry.logData();
|
||||
logData.source = 'static';
|
||||
logData.result = 2;
|
||||
outlog.push(logData);
|
||||
@ -2389,20 +2398,19 @@ FilterContainer.prototype.matchAndFetchData = function(dataType, requestURL, out
|
||||
|
||||
FilterContainer.prototype.matchTokens = function(bucket, url) {
|
||||
// Hostname-only filters
|
||||
var f = bucket.get(this.dotTokenHash);
|
||||
let f = bucket.get(this.dotTokenHash);
|
||||
if ( f !== undefined && f.match() === true ) {
|
||||
this.thRegister = this.dotTokenHash;
|
||||
this.fRegister = f;
|
||||
return true;
|
||||
}
|
||||
|
||||
var tokenHashes = this.urlTokenizer.getTokens(),
|
||||
tokenHash, tokenOffset,
|
||||
let tokenHashes = this.urlTokenizer.getTokens(),
|
||||
i = 0;
|
||||
for (;;) {
|
||||
tokenHash = tokenHashes[i++];
|
||||
let tokenHash = tokenHashes[i++];
|
||||
if ( tokenHash === 0 ) { break; }
|
||||
tokenOffset = tokenHashes[i++];
|
||||
let tokenOffset = tokenHashes[i++];
|
||||
f = bucket.get(tokenHash);
|
||||
if ( f !== undefined && f.match(url, tokenOffset) === true ) {
|
||||
this.thRegister = tokenHash;
|
||||
@ -2437,8 +2445,10 @@ FilterContainer.prototype.matchStringGenericHide = function(requestURL) {
|
||||
let url = this.urlTokenizer.setURL(requestURL);
|
||||
|
||||
// https://github.com/gorhill/uBlock/issues/2225
|
||||
// Important: this is used by FilterHostnameDict.match().
|
||||
requestHostnameRegister = µb.URI.hostnameFromURI(url);
|
||||
// Important:
|
||||
// - `pageHostnameRegister` is used by FilterOrigin.matchOrigin().
|
||||
// - `requestHostnameRegister` is used by FilterHostnameDict.match().
|
||||
pageHostnameRegister = requestHostnameRegister = µb.URI.hostnameFromURI(url);
|
||||
|
||||
let bucket = this.categories.get(genericHideException);
|
||||
if ( !bucket || this.matchTokens(bucket, url) === false ) {
|
||||
@ -2548,7 +2558,7 @@ FilterContainer.prototype.matchString = function(context) {
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/519
|
||||
// Use exact type match for anything beyond `other`
|
||||
// Also, be prepared to support unknown types
|
||||
var type = typeNameToTypeValue[context.requestType];
|
||||
let type = typeNameToTypeValue[context.requestType];
|
||||
if ( type === undefined ) {
|
||||
type = otherTypeBitValue;
|
||||
} else if ( type === 0 || type > otherTypeBitValue ) {
|
||||
@ -2577,7 +2587,7 @@ FilterContainer.prototype.matchString = function(context) {
|
||||
// filter.
|
||||
|
||||
// Prime tokenizer: we get a normalized URL in return.
|
||||
var url = this.urlTokenizer.setURL(context.requestURL);
|
||||
let url = this.urlTokenizer.setURL(context.requestURL);
|
||||
|
||||
// These registers will be used by various filters
|
||||
pageHostnameRegister = context.pageHostname || '';
|
||||
@ -2585,10 +2595,10 @@ FilterContainer.prototype.matchString = function(context) {
|
||||
|
||||
this.fRegister = null;
|
||||
|
||||
var party = isFirstParty(context.pageDomain, context.requestHostname)
|
||||
let party = isFirstParty(context.pageDomain, context.requestHostname)
|
||||
? FirstParty
|
||||
: ThirdParty;
|
||||
var categories = this.categories,
|
||||
let categories = this.categories,
|
||||
catBits, bucket;
|
||||
|
||||
// https://github.com/chrisaljoudi/uBlock/issues/139
|
||||
|
@ -604,9 +604,7 @@
|
||||
|
||||
µBlock.loadFilterLists = function(callback) {
|
||||
// Callers are expected to check this first.
|
||||
if ( this.loadingFilterLists ) {
|
||||
return;
|
||||
}
|
||||
if ( this.loadingFilterLists ) { return; }
|
||||
this.loadingFilterLists = true;
|
||||
|
||||
var µb = this,
|
||||
@ -961,38 +959,31 @@
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.loadPublicSuffixList = function(callback) {
|
||||
var µb = this,
|
||||
assetKey = µb.pslAssetKey,
|
||||
compiledAssetKey = 'compiled/' + assetKey;
|
||||
|
||||
if ( typeof callback !== 'function' ) {
|
||||
callback = this.noopFunc;
|
||||
}
|
||||
var onRawListLoaded = function(details) {
|
||||
if ( details.content !== '' ) {
|
||||
µb.compilePublicSuffixList(details.content);
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
var onCompiledListLoaded = function(details) {
|
||||
var selfie;
|
||||
µBlock.loadPublicSuffixList = function() {
|
||||
return new Promise(resolve => {
|
||||
// start of executor
|
||||
this.assets.get('compiled/' + this.pslAssetKey, details => {
|
||||
let selfie;
|
||||
try {
|
||||
selfie = JSON.parse(details.content);
|
||||
} catch (ex) {
|
||||
}
|
||||
if (
|
||||
selfie === undefined ||
|
||||
publicSuffixList.fromSelfie(selfie) === false
|
||||
selfie instanceof Object &&
|
||||
publicSuffixList.fromSelfie(selfie)
|
||||
) {
|
||||
µb.assets.get(assetKey, onRawListLoaded);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
};
|
||||
|
||||
this.assets.get(compiledAssetKey, onCompiledListLoaded);
|
||||
this.assets.get(this.pslAssetKey, details => {
|
||||
if ( details.content !== '' ) {
|
||||
this.compilePublicSuffixList(details.content);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
// end of executor
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
24
src/js/wasm/README.md
Normal file
24
src/js/wasm/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
### For code reviewers
|
||||
|
||||
All `wasm` files in that directory where created by compiling the
|
||||
corresponding `wat` file using the command (using `hntrie.wat`/`hntrie.wasm`
|
||||
as example):
|
||||
|
||||
wat2wasm hntrie.wat -o hntrie.wasm
|
||||
|
||||
Assuming:
|
||||
|
||||
- The command is executed from within the present directory.
|
||||
|
||||
### `wat2wasm` tool
|
||||
|
||||
The `wat2wasm` tool can be downloaded from an official WebAssembly project:
|
||||
<https://github.com/WebAssembly/wabt/releases>.
|
||||
|
||||
### `wat2wasm` tool online
|
||||
|
||||
You can also use the following online `wat2wasm` tool:
|
||||
<https://webassembly.github.io/wabt/demo/wat2wasm/>.
|
||||
|
||||
Just paste the whole content of the `wat` file to compile into the WAT pane.
|
||||
Click "Download" button to retrieve the resulting `wasm` file.
|
BIN
src/js/wasm/hntrie.wasm
Normal file
BIN
src/js/wasm/hntrie.wasm
Normal file
Binary file not shown.
200
src/js/wasm/hntrie.wat
Normal file
200
src/js/wasm/hntrie.wat
Normal file
@ -0,0 +1,200 @@
|
||||
;;
|
||||
;; uBlock Origin - a browser extension to block requests.
|
||||
;; Copyright (C) 2018-present Raymond Hill
|
||||
;;
|
||||
;; This program is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see {http://www.gnu.org/licenses/}.
|
||||
;;
|
||||
;; Home: https://github.com/gorhill/uBlock
|
||||
;; File: hntrie.wat
|
||||
;; Description: WebAssembly code used by src/js/hntrie.js
|
||||
;; How to compile: See README.md in this directory.
|
||||
|
||||
(module
|
||||
;;
|
||||
;; module start
|
||||
;;
|
||||
|
||||
;; (func $log (import "imports" "log") (param i32 i32 i32))
|
||||
|
||||
(memory (import "imports" "memory") 1)
|
||||
|
||||
;;
|
||||
;; Public functions
|
||||
;;
|
||||
|
||||
;;
|
||||
;; unsigned int matches(offset)
|
||||
;;
|
||||
;; Test whether the currently set needle matches the trie at specified offset.
|
||||
;;
|
||||
;; Memory layout, byte offset:
|
||||
;; 0-254: encoded needle (ASCII)
|
||||
;; 255 : needle length
|
||||
;; 256- : tries
|
||||
;;
|
||||
(func (export "matches")
|
||||
(param $itrie i32)
|
||||
(result i32) ;; result: 0 = miss, 1 = hit
|
||||
(local $ineedle i32) ;; current needle offset
|
||||
(local $nchar i32) ;; needle char being processed
|
||||
(local $tchar i32) ;; trie char being processed
|
||||
(local $lxtra i32)
|
||||
(local $ixtra i32)
|
||||
i32.const 255
|
||||
i32.load8_u
|
||||
set_local $ineedle
|
||||
loop $nextNeedleChar
|
||||
;; ineedle -= 1;
|
||||
get_local $ineedle
|
||||
i32.const -1
|
||||
i32.add
|
||||
tee_local $ineedle
|
||||
;; let nchar = ineedle === -1 ? 0 : buf[ineedle];
|
||||
i32.const 0
|
||||
i32.lt_s
|
||||
if
|
||||
i32.const 0
|
||||
set_local $nchar
|
||||
else
|
||||
get_local $ineedle
|
||||
i32.load8_u
|
||||
set_local $nchar
|
||||
end
|
||||
block $trieCharEqNeedleChar loop $nextTrieChar
|
||||
;; let tchar = buf[itrie+8];
|
||||
get_local $itrie
|
||||
i32.load8_u offset=8
|
||||
tee_local $tchar
|
||||
;; if ( tchar === nchar ) { break; }
|
||||
get_local $nchar
|
||||
i32.eq
|
||||
br_if $trieCharEqNeedleChar
|
||||
;; if ( tchar === 0 && nchar === 0x2E ) { return 1; }
|
||||
get_local $tchar
|
||||
i32.eqz
|
||||
if
|
||||
get_local $nchar
|
||||
i32.const 0x2E
|
||||
i32.eq
|
||||
if
|
||||
i32.const 1
|
||||
return
|
||||
end
|
||||
end
|
||||
;; itrie = buf32[itrie >>> 2];
|
||||
get_local $itrie
|
||||
i32.load
|
||||
tee_local $itrie
|
||||
;; if ( itrie === 0 ) { return 0; }
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 0
|
||||
return
|
||||
end
|
||||
br $nextTrieChar
|
||||
end end
|
||||
;; if ( nchar === 0 ) { return 1; }
|
||||
get_local $nchar
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 1
|
||||
return
|
||||
end
|
||||
;; let lxtra = buf[itrie+9];
|
||||
get_local $itrie
|
||||
i32.load8_u offset=9
|
||||
tee_local $lxtra
|
||||
i32.eqz
|
||||
if else
|
||||
;; if ( lxtra > ineedle ) { return 0; }
|
||||
get_local $lxtra
|
||||
get_local $ineedle
|
||||
i32.gt_u
|
||||
if
|
||||
i32.const 0
|
||||
return
|
||||
end
|
||||
;; let ixtra = itrie + 10;
|
||||
get_local $itrie
|
||||
i32.const 10
|
||||
i32.add
|
||||
tee_local $ixtra
|
||||
;; lxtra += ixtra;
|
||||
get_local $lxtra
|
||||
i32.add
|
||||
set_local $lxtra
|
||||
;; do {
|
||||
block $noMoreExtraChars loop
|
||||
;; ineedle -= 1;
|
||||
get_local $ineedle
|
||||
i32.const -1
|
||||
i32.add
|
||||
tee_local $ineedle
|
||||
;; if ( buf[ineedle] !== buf[ixtra] ) { return 0; }
|
||||
i32.load8_u
|
||||
get_local $ixtra
|
||||
i32.load8_u
|
||||
i32.ne
|
||||
if
|
||||
i32.const 0
|
||||
return
|
||||
end
|
||||
;; ixtra += 1;
|
||||
get_local $ixtra
|
||||
i32.const 1
|
||||
i32.add
|
||||
tee_local $ixtra
|
||||
;; while ( ixtra !== lxtra ) {
|
||||
get_local $lxtra
|
||||
i32.eq
|
||||
br_if $noMoreExtraChars
|
||||
br 0
|
||||
end end
|
||||
end
|
||||
;; itrie = buf32[itrie + 4 >>> 2];
|
||||
get_local $itrie
|
||||
i32.load offset=4
|
||||
tee_local $itrie
|
||||
;; if ( itrie === 0 ) {
|
||||
i32.eqz
|
||||
if
|
||||
;; return ineedle === 0 || buf[ineedle-1] === 0x2E ? 1 : 0;
|
||||
get_local $ineedle
|
||||
i32.eqz
|
||||
if
|
||||
i32.const 1
|
||||
return
|
||||
end
|
||||
get_local $ineedle
|
||||
i32.const -1
|
||||
i32.add
|
||||
i32.load8_u
|
||||
i32.const 0x2E
|
||||
i32.eq
|
||||
if
|
||||
i32.const 1
|
||||
return
|
||||
end
|
||||
i32.const 0
|
||||
return
|
||||
end
|
||||
br 0
|
||||
end
|
||||
i32.const 0
|
||||
)
|
||||
|
||||
;;
|
||||
;; module end
|
||||
;;
|
||||
)
|
479
test/hnset-benchmark.html
Normal file
479
test/hnset-benchmark.html
Normal file
File diff suppressed because one or more lines are too long
45866
test/hntrie-test.html
Normal file
45866
test/hntrie-test.html
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user