mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-07 03:12:33 +01:00
Add filter instance deduplicater in static net filtering engine
Provide a way to optionally deduplicate filter instances, useful for filter instances with: - high likelihood of duplication; and - non-trivial memory footprint per instance - For examples, filter instances to implement `domain=`, `denyallow=`, `csp=`. Cursory tests show this helps further reduce uBO's memory footprint.
This commit is contained in:
parent
8b69af0dda
commit
ab629b9e10
@ -287,10 +287,6 @@ const isSeparatorChar = c => (charClassMap[c] & CHAR_CLASS_SEPARATOR) !== 0;
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// TODO: Unify [ string instance, string usage instance ] pairs
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
let filterUnits = [ null ];
|
let filterUnits = [ null ];
|
||||||
|
|
||||||
let filterSequences = new Uint32Array(131072);
|
let filterSequences = new Uint32Array(131072);
|
||||||
@ -378,6 +374,29 @@ const filterFromSelfie = function(args) {
|
|||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
// Optional manager to be used to reuse filters instances. This is useful
|
||||||
|
// when deduplicating instances is worth it. For examples, filter instances
|
||||||
|
// which have a high likelihood of larger than average memory usage per
|
||||||
|
// instance.
|
||||||
|
|
||||||
|
const filterInstanceManager = {
|
||||||
|
unitFromArgs: function(args, createFn) {
|
||||||
|
const key = JSON.stringify(args);
|
||||||
|
let iunit = this.argsToUnit.get(key);
|
||||||
|
if ( iunit === undefined ) {
|
||||||
|
iunit = createFn(args);
|
||||||
|
this.argsToUnit.set(key, iunit);
|
||||||
|
}
|
||||||
|
return iunit;
|
||||||
|
},
|
||||||
|
reset: function() {
|
||||||
|
this.argsToUnit.clear();
|
||||||
|
},
|
||||||
|
argsToUnit: new Map(),
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
const filterPattern = {
|
const filterPattern = {
|
||||||
compile: function(parsed, units) {
|
compile: function(parsed, units) {
|
||||||
if ( parsed.isRegex ) {
|
if ( parsed.isRegex ) {
|
||||||
@ -838,8 +857,10 @@ const FilterPatternGeneric = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unitFromCompiled(args) {
|
static unitFromCompiled(args) {
|
||||||
|
return filterInstanceManager.unitFromArgs(args, args => {
|
||||||
const f = new FilterPatternGeneric(args[1], args[2]);
|
const f = new FilterPatternGeneric(args[1], args[2]);
|
||||||
return filterUnits.push(f) - 1;
|
return filterUnits.push(f) - 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSelfie(args) {
|
static fromSelfie(args) {
|
||||||
@ -1139,8 +1160,10 @@ const FilterRegex = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unitFromCompiled(args) {
|
static unitFromCompiled(args) {
|
||||||
|
return filterInstanceManager.unitFromArgs(args, args => {
|
||||||
const f = new FilterRegex(args[1]);
|
const f = new FilterRegex(args[1]);
|
||||||
return filterUnits.push(f) - 1;
|
return filterUnits.push(f) - 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSelfie(args) {
|
static fromSelfie(args) {
|
||||||
@ -1163,8 +1186,6 @@ registerFilterClass(FilterRegex);
|
|||||||
const filterOrigin = new (class {
|
const filterOrigin = new (class {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.trieContainer = new µb.HNTrieContainer();
|
this.trieContainer = new µb.HNTrieContainer();
|
||||||
this.strToUnitMap = new Map();
|
|
||||||
this.gcTimer = undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compile(details, prepend, units) {
|
compile(details, prepend, units) {
|
||||||
@ -1219,23 +1240,6 @@ const filterOrigin = new (class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unitFromCompiled(ctor, s) {
|
|
||||||
let iunit = this.strToUnitMap.get(s);
|
|
||||||
if ( iunit !== undefined ) { return iunit; }
|
|
||||||
const f = new ctor(s);
|
|
||||||
iunit = filterUnits.push(f) - 1;
|
|
||||||
this.strToUnitMap.set(s, iunit);
|
|
||||||
if ( this.gcTimer !== undefined ) { return iunit; }
|
|
||||||
this.gcTimer = self.setTimeout(
|
|
||||||
( ) => {
|
|
||||||
this.gcTimer = undefined;
|
|
||||||
this.strToUnitMap.clear();
|
|
||||||
},
|
|
||||||
5000
|
|
||||||
);
|
|
||||||
return iunit;
|
|
||||||
}
|
|
||||||
|
|
||||||
prime() {
|
prime() {
|
||||||
this.trieContainer.reset(
|
this.trieContainer.reset(
|
||||||
vAPI.localStorage.getItem('SNFE.filterOrigin.trieDetails')
|
vAPI.localStorage.getItem('SNFE.filterOrigin.trieDetails')
|
||||||
@ -1244,7 +1248,6 @@ const filterOrigin = new (class {
|
|||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.trieContainer.reset();
|
this.trieContainer.reset();
|
||||||
this.strToUnitMap.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
optimize() {
|
optimize() {
|
||||||
@ -1293,7 +1296,8 @@ const FilterOriginHit = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unitFromCompiled(args) {
|
static unitFromCompiled(args) {
|
||||||
return filterOrigin.unitFromCompiled(FilterOriginHit, args[1]);
|
const f = new FilterOriginHit(args[1]);
|
||||||
|
return filterUnits.push(f) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSelfie(args) {
|
static fromSelfie(args) {
|
||||||
@ -1337,7 +1341,8 @@ const FilterOriginMiss = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unitFromCompiled(args) {
|
static unitFromCompiled(args) {
|
||||||
return filterOrigin.unitFromCompiled(FilterOriginMiss, args[1]);
|
const f = new FilterOriginMiss(args[1]);
|
||||||
|
return filterUnits.push(f) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSelfie(args) {
|
static fromSelfie(args) {
|
||||||
@ -1385,7 +1390,10 @@ const FilterOriginHitSet = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unitFromCompiled(args) {
|
static unitFromCompiled(args) {
|
||||||
return filterOrigin.unitFromCompiled(FilterOriginHitSet, args[1]);
|
return filterInstanceManager.unitFromArgs(args, args => {
|
||||||
|
const f = new FilterOriginHitSet(args[1]);
|
||||||
|
return filterUnits.push(f) - 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSelfie(args) {
|
static fromSelfie(args) {
|
||||||
@ -1433,7 +1441,10 @@ const FilterOriginMissSet = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unitFromCompiled(args) {
|
static unitFromCompiled(args) {
|
||||||
return filterOrigin.unitFromCompiled(FilterOriginMissSet, args[1]);
|
return filterInstanceManager.unitFromArgs(args, args => {
|
||||||
|
const f = new FilterOriginMissSet(args[1]);
|
||||||
|
return filterUnits.push(f) - 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSelfie(args) {
|
static fromSelfie(args) {
|
||||||
@ -1483,8 +1494,10 @@ const FilterDataHolder = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unitFromCompiled(args) {
|
static unitFromCompiled(args) {
|
||||||
|
return filterInstanceManager.unitFromArgs(args, args => {
|
||||||
const f = new FilterDataHolder(args[1], args[2]);
|
const f = new FilterDataHolder(args[1], args[2]);
|
||||||
return filterUnits.push(f) - 1;
|
return filterUnits.push(f) - 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSelfie(args) {
|
static fromSelfie(args) {
|
||||||
@ -1742,12 +1755,14 @@ const FilterDenyAllow = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unitFromCompiled(args) {
|
static unitFromCompiled(args) {
|
||||||
|
return filterInstanceManager.unitFromArgs(args, args => {
|
||||||
const f = new FilterDenyAllow(args[1]);
|
const f = new FilterDenyAllow(args[1]);
|
||||||
for ( const hn of args[1].split('|') ) {
|
for ( const hn of args[1].split('|') ) {
|
||||||
if ( hn === '' ) { continue; }
|
if ( hn === '' ) { continue; }
|
||||||
f.hndict.add(hn);
|
f.hndict.add(hn);
|
||||||
}
|
}
|
||||||
return filterUnits.push(f) - 1;
|
return filterUnits.push(f) - 1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSelfie(args) {
|
static fromSelfie(args) {
|
||||||
@ -2739,6 +2754,7 @@ FilterContainer.prototype.reset = function() {
|
|||||||
FilterHostnameDict.reset();
|
FilterHostnameDict.reset();
|
||||||
filterOrigin.reset();
|
filterOrigin.reset();
|
||||||
bidiTrie.reset();
|
bidiTrie.reset();
|
||||||
|
filterInstanceManager.reset();
|
||||||
|
|
||||||
filterUnits = filterUnits.slice(0, FILTER_UNITS_MIN);
|
filterUnits = filterUnits.slice(0, FILTER_UNITS_MIN);
|
||||||
filterSequenceWritePtr = FILTER_SEQUENCES_MIN;
|
filterSequenceWritePtr = FILTER_SEQUENCES_MIN;
|
||||||
@ -2861,6 +2877,7 @@ FilterContainer.prototype.freeze = function() {
|
|||||||
|
|
||||||
FilterHostnameDict.optimize();
|
FilterHostnameDict.optimize();
|
||||||
bidiTrieOptimize();
|
bidiTrieOptimize();
|
||||||
|
filterInstanceManager.reset();
|
||||||
|
|
||||||
log.info(`staticNetFilteringEngine.freeze() took ${Date.now()-t0} ms`);
|
log.info(`staticNetFilteringEngine.freeze() took ${Date.now()-t0} ms`);
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user