mirror of
https://github.com/gorhill/uBlock.git
synced 2024-09-15 07:22:28 +02:00
new content script code: perf work re. high-high generics
Now splitting high-high generics in two subgroups: one group for simple selectors, another group for complex selectors. Turns out the great majority of high-high generics are simple selectors, and simple selectors can be applied incrementally with DOM changes, as opposed to complex selectors. This brings in a significant perf. improvement in the processing of high-high generics (previously, all high-high generic selectors were processed as one big complex selector).
This commit is contained in:
parent
b65699aef2
commit
e99d993a4c
@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
|
||||
uBlock - a browser extension to block requests.
|
||||
Copyright (C) 2014-2015 Raymond Hill
|
||||
uBlock Origin - a browser extension to block requests.
|
||||
Copyright (C) 2014-2016 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
|
||||
@ -19,7 +19,6 @@
|
||||
Home: https://github.com/gorhill/uBlock
|
||||
*/
|
||||
|
||||
/* global vAPI */
|
||||
/* exported µBlock */
|
||||
|
||||
'use strict';
|
||||
@ -92,8 +91,8 @@ return {
|
||||
|
||||
// read-only
|
||||
systemSettings: {
|
||||
compiledMagic: 'nytangedtvcz',
|
||||
selfieMagic: 'emzolxctioww'
|
||||
compiledMagic: 'splsmclwnvoj',
|
||||
selfieMagic: 'splsmclwnvoj'
|
||||
},
|
||||
|
||||
restoreBackupSettings: {
|
||||
|
@ -38,6 +38,18 @@ if ( typeof vAPI !== 'object' || vAPI.contentscriptInjected ) {
|
||||
|
||||
vAPI.contentscriptInjected = true;
|
||||
|
||||
vAPI.matchesProp = (function() {
|
||||
var docElem = document.documentElement;
|
||||
if ( typeof docElem.matches !== 'function' ) {
|
||||
if ( typeof docElem.mozMatchesSelector === 'function' ) {
|
||||
return 'mozMatchesSelector';
|
||||
} else if ( typeof docElem.webkitMatchesSelector === 'function' ) {
|
||||
return 'webkitMatchesSelector';
|
||||
}
|
||||
}
|
||||
return 'matches';
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
/******************************************************************************/
|
||||
@ -53,7 +65,7 @@ vAPI.domFilterer = {
|
||||
enabled: true,
|
||||
hiddenId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
||||
hiddenNodeCount: 0,
|
||||
matchesProp: 'matches',
|
||||
matchesProp: vAPI.matchesProp,
|
||||
newDeclarativeSelectors: [],
|
||||
shadowId: String.fromCharCode(Date.now() % 26 + 97) + Math.floor(Math.random() * 982451653 + 982451653).toString(36),
|
||||
styleTags: [],
|
||||
@ -410,14 +422,6 @@ vAPI.domFilterer = {
|
||||
var df = vAPI.domFilterer;
|
||||
df.cssNotHiddenId = ':not([' + df.hiddenId + '])';
|
||||
df.xpathNotHiddenId = '[not(@' + df.hiddenId + ')]';
|
||||
var docElem = document.documentElement;
|
||||
if ( typeof docElem.matches !== 'function' ) {
|
||||
if ( typeof docElem.mozMatchesSelector === 'function' ) {
|
||||
df.matchesProp = 'mozMatchesSelector';
|
||||
} else if ( typeof docElem.webkitMatchesSelector === 'function' ) {
|
||||
df.matchesProp = 'webkitMatchesSelector';
|
||||
}
|
||||
}
|
||||
|
||||
// Complex selectors, due to their nature may need to be "de-committed". A
|
||||
// Set() is used to implement this functionality. For browser with no
|
||||
@ -835,12 +839,11 @@ if ( !vAPI.contentscriptInjected ) {
|
||||
domFilterer.checkStyleTags(false);
|
||||
domFilterer.commit();
|
||||
|
||||
var contextNodes = [ document.documentElement ];
|
||||
var messaging = vAPI.messaging;
|
||||
var highGenerics = null;
|
||||
var highHighGenericsInjected = false;
|
||||
var lowGenericSelectors = [];
|
||||
var queriedSelectors = Object.create(null);
|
||||
var contextNodes = [ document.documentElement ],
|
||||
messaging = vAPI.messaging,
|
||||
highGenerics = null,
|
||||
lowGenericSelectors = [],
|
||||
queriedSelectors = Object.create(null);
|
||||
|
||||
var responseHandler = function(response) {
|
||||
// https://github.com/gorhill/uMatrix/issues/144
|
||||
@ -859,6 +862,7 @@ if ( !vAPI.contentscriptInjected ) {
|
||||
highGenerics = result.highGenerics;
|
||||
}
|
||||
}
|
||||
|
||||
if ( highGenerics ) {
|
||||
if ( highGenerics.hideLowCount ) {
|
||||
processHighLowGenerics(highGenerics.hideLow);
|
||||
@ -866,10 +870,11 @@ if ( !vAPI.contentscriptInjected ) {
|
||||
if ( highGenerics.hideMediumCount ) {
|
||||
processHighMediumGenerics(highGenerics.hideMedium);
|
||||
}
|
||||
if ( highGenerics.hideHighCount ) {
|
||||
processHighHighGenericsAsync();
|
||||
if ( highGenerics.hideHighSimpleCount || highGenerics.hideHighComplexCount ) {
|
||||
processHighHighGenerics();
|
||||
}
|
||||
}
|
||||
|
||||
domFilterer.commit(contextNodes);
|
||||
contextNodes = [];
|
||||
};
|
||||
@ -886,10 +891,10 @@ if ( !vAPI.contentscriptInjected ) {
|
||||
},
|
||||
responseHandler
|
||||
);
|
||||
lowGenericSelectors = [];
|
||||
} else {
|
||||
responseHandler(null);
|
||||
}
|
||||
lowGenericSelectors = [];
|
||||
};
|
||||
|
||||
// Extract and return the staged nodes which (may) match the selectors.
|
||||
@ -1009,42 +1014,50 @@ if ( !vAPI.contentscriptInjected ) {
|
||||
}
|
||||
};
|
||||
|
||||
// High-high generics are very costly to process, so we will coalesce
|
||||
// requests to process high-high generics into as few requests as possible.
|
||||
// The gain is significant on bloated pages.
|
||||
|
||||
var processHighHighGenericsMisses = 8;
|
||||
var processHighHighGenericsTimer = null;
|
||||
var highHighSimpleGenericsCost = 0,
|
||||
highHighSimpleGenericsInjected = false,
|
||||
highHighComplexGenericsCost = 0,
|
||||
highHighComplexGenericsInjected = false;
|
||||
|
||||
var processHighHighGenerics = function() {
|
||||
processHighHighGenericsTimer = null;
|
||||
if ( highGenerics.hideHigh === '' ) {
|
||||
return;
|
||||
}
|
||||
if ( highHighGenericsInjected ) {
|
||||
return;
|
||||
}
|
||||
// When there are too many misses for these highly generic CSS rules,
|
||||
// we will just give up on looking whether they need to be injected.
|
||||
if ( document.querySelector(highGenerics.hideHigh) === null ) {
|
||||
processHighHighGenericsMisses -= 1;
|
||||
if ( processHighHighGenericsMisses === 0 ) {
|
||||
highHighGenericsInjected = true;
|
||||
var tstart;
|
||||
// Simple selectors.
|
||||
if (
|
||||
highHighSimpleGenericsInjected === false &&
|
||||
highHighSimpleGenericsCost < 50 &&
|
||||
highGenerics.hideHighSimpleCount !== 0
|
||||
) {
|
||||
tstart = window.performance.now();
|
||||
var matchesProp = vAPI.matchesProp,
|
||||
nodes = contextNodes,
|
||||
i = nodes.length, node;
|
||||
while ( i-- ) {
|
||||
node = nodes[i];
|
||||
if (
|
||||
node[matchesProp](highGenerics.hideHighSimple) ||
|
||||
node.querySelector(highGenerics.hideHighSimple) !== null
|
||||
) {
|
||||
highHighSimpleGenericsInjected = true;
|
||||
domFilterer.addSelectors(highGenerics.hideHighSimple.split(',\n'));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
highHighSimpleGenericsCost += window.performance.now() - tstart;
|
||||
}
|
||||
highHighGenericsInjected = true;
|
||||
// We need to filter out possible exception cosmetic filters from
|
||||
// high-high generics selectors.
|
||||
domFilterer.addSelectors(highGenerics.hideHigh.split(',\n'));
|
||||
domFilterer.commit();
|
||||
};
|
||||
|
||||
var processHighHighGenericsAsync = function() {
|
||||
if ( processHighHighGenericsTimer !== null ) {
|
||||
clearTimeout(processHighHighGenericsTimer);
|
||||
// Complex selectors.
|
||||
if (
|
||||
highHighComplexGenericsInjected === false &&
|
||||
highHighComplexGenericsCost < 50 &&
|
||||
highGenerics.hideHighComplexCount !== 0
|
||||
) {
|
||||
tstart = window.performance.now();
|
||||
if ( document.querySelector(highGenerics.hideHighComplex) !== null ) {
|
||||
highHighComplexGenericsInjected = true;
|
||||
domFilterer.addSelectors(highGenerics.hideHighComplex.split(',\n'));
|
||||
domFilterer.commit();
|
||||
}
|
||||
highHighComplexGenericsCost += window.performance.now() - tstart;
|
||||
}
|
||||
processHighHighGenericsTimer = vAPI.setTimeout(processHighHighGenerics, 300);
|
||||
};
|
||||
|
||||
// Extract all classes/ids: these will be passed to the cosmetic filtering
|
||||
@ -1225,9 +1238,6 @@ if ( !vAPI.contentscriptInjected ) {
|
||||
if ( removedNodeListsTimer !== null ) {
|
||||
clearTimeout(removedNodeListsTimer);
|
||||
}
|
||||
if ( processHighHighGenericsTimer !== null ) {
|
||||
clearTimeout(processHighHighGenericsTimer);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
||||
|
@ -672,10 +672,15 @@ FilterContainer.prototype.reset = function() {
|
||||
this.highMediumGenericHide = {};
|
||||
this.highMediumGenericHideCount = 0;
|
||||
|
||||
// everything else
|
||||
this.highHighGenericHideArray = [];
|
||||
this.highHighGenericHide = '';
|
||||
this.highHighGenericHideCount = 0;
|
||||
// high-high-simple selectors
|
||||
this.highHighSimpleGenericHideArray = [];
|
||||
this.highHighSimpleGenericHide = '';
|
||||
this.highHighSimpleGenericHideCount = 0;
|
||||
|
||||
// high-high-complex selectors
|
||||
this.highHighComplexGenericHideArray = [];
|
||||
this.highHighComplexGenericHide = '';
|
||||
this.highHighComplexGenericHideCount = 0;
|
||||
|
||||
// generic exception filters
|
||||
this.genericDonthide = [];
|
||||
@ -888,8 +893,13 @@ FilterContainer.prototype.compileGenericSelector = function(parsed, out) {
|
||||
return;
|
||||
}
|
||||
|
||||
// All else
|
||||
out.push('c\vhhg0\v' + selector);
|
||||
// All else: high-high generics.
|
||||
// Distinguish simple vs complex selectors.
|
||||
if ( selector.indexOf(' ') === -1 ) {
|
||||
out.push('c\vhhsg0\v' + selector);
|
||||
} else {
|
||||
out.push('c\vhhcg0\v' + selector);
|
||||
}
|
||||
};
|
||||
|
||||
FilterContainer.prototype.reClassOrIdSelector = /^[#.][\w-]+$/;
|
||||
@ -1048,9 +1058,15 @@ FilterContainer.prototype.fromCompiledContent = function(text, lineBeg, skip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( fields[0] === 'hhg0' ) {
|
||||
this.highHighGenericHideArray.push(fields[1]);
|
||||
this.highHighGenericHideCount += 1;
|
||||
if ( fields[0] === 'hhsg0' ) {
|
||||
this.highHighSimpleGenericHideArray.push(fields[1]);
|
||||
this.highHighSimpleGenericHideCount += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( fields[0] === 'hhcg0' ) {
|
||||
this.highHighComplexGenericHideArray.push(fields[1]);
|
||||
this.highHighComplexGenericHideCount += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1197,11 +1213,17 @@ FilterContainer.prototype.retrieveScriptTags = function(domain, hostname) {
|
||||
FilterContainer.prototype.freeze = function() {
|
||||
this.duplicateBuster = {};
|
||||
|
||||
if ( this.highHighGenericHide !== '' ) {
|
||||
this.highHighGenericHideArray.unshift(this.highHighGenericHide);
|
||||
if ( this.highHighSimpleGenericHide !== '' ) {
|
||||
this.highHighSimpleGenericHideArray.unshift(this.highHighSimpleGenericHide);
|
||||
}
|
||||
this.highHighGenericHide = this.highHighGenericHideArray.join(',\n');
|
||||
this.highHighGenericHideArray = [];
|
||||
this.highHighSimpleGenericHide = this.highHighSimpleGenericHideArray.join(',\n');
|
||||
this.highHighSimpleGenericHideArray = [];
|
||||
|
||||
if ( this.highHighComplexGenericHide !== '' ) {
|
||||
this.highHighComplexGenericHideArray.unshift(this.highHighComplexGenericHide);
|
||||
}
|
||||
this.highHighComplexGenericHide = this.highHighComplexGenericHideArray.join(',\n');
|
||||
this.highHighComplexGenericHideArray = [];
|
||||
|
||||
this.parser.reset();
|
||||
this.frozen = true;
|
||||
@ -1245,8 +1267,10 @@ FilterContainer.prototype.toSelfie = function() {
|
||||
highLowGenericHideCount: this.highLowGenericHideCount,
|
||||
highMediumGenericHide: this.highMediumGenericHide,
|
||||
highMediumGenericHideCount: this.highMediumGenericHideCount,
|
||||
highHighGenericHide: this.highHighGenericHide,
|
||||
highHighGenericHideCount: this.highHighGenericHideCount,
|
||||
highHighSimpleGenericHide: this.highHighSimpleGenericHide,
|
||||
highHighSimpleGenericHideCount: this.highHighSimpleGenericHideCount,
|
||||
highHighComplexGenericHide: this.highHighComplexGenericHide,
|
||||
highHighComplexGenericHideCount: this.highHighComplexGenericHideCount,
|
||||
genericDonthide: this.genericDonthide,
|
||||
scriptTagFilters: this.scriptTagFilters,
|
||||
scriptTagFilterCount: this.scriptTagFilterCount,
|
||||
@ -1309,8 +1333,10 @@ FilterContainer.prototype.fromSelfie = function(selfie) {
|
||||
this.highLowGenericHideCount = selfie.highLowGenericHideCount;
|
||||
this.highMediumGenericHide = selfie.highMediumGenericHide;
|
||||
this.highMediumGenericHideCount = selfie.highMediumGenericHideCount;
|
||||
this.highHighGenericHide = selfie.highHighGenericHide;
|
||||
this.highHighGenericHideCount = selfie.highHighGenericHideCount;
|
||||
this.highHighSimpleGenericHide = selfie.highHighSimpleGenericHide;
|
||||
this.highHighSimpleGenericHideCount = selfie.highHighSimpleGenericHideCount;
|
||||
this.highHighComplexGenericHide = selfie.highHighComplexGenericHide;
|
||||
this.highHighComplexGenericHideCount = selfie.highHighComplexGenericHideCount;
|
||||
this.genericDonthide = selfie.genericDonthide;
|
||||
this.scriptTagFilters = selfie.scriptTagFilters;
|
||||
this.scriptTagFilterCount = selfie.scriptTagFilterCount;
|
||||
@ -1441,8 +1467,10 @@ FilterContainer.prototype.retrieveGenericSelectors = function(request) {
|
||||
hideLowCount: this.highLowGenericHideCount,
|
||||
hideMedium: this.highMediumGenericHide,
|
||||
hideMediumCount: this.highMediumGenericHideCount,
|
||||
hideHigh: this.highHighGenericHide,
|
||||
hideHighCount: this.highHighGenericHideCount
|
||||
hideHighSimple: this.highHighSimpleGenericHide,
|
||||
hideHighSimpleCount: this.highHighSimpleGenericHideCount,
|
||||
hideHighComplex: this.highHighComplexGenericHide,
|
||||
hideHighComplexCount: this.highHighComplexGenericHideCount
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -125,8 +125,10 @@ var fromCosmeticFilter = function(details) {
|
||||
reStr.push('c', 'hlg0', reEscape(filter));
|
||||
} else if ( reHighMedium.test(filter) ) { // [href^="..."]
|
||||
reStr.push('c', 'hmg0', '[^"]{8}', '[a-z]*' + reEscape(filter));
|
||||
} else { // all else
|
||||
reStr.push('c', 'hhg0', reEscape(filter));
|
||||
} else if ( filter.indexOf(' ') === -1 ) { // high-high-simple selector
|
||||
reStr.push('c', 'hhsg0', reEscape(filter));
|
||||
} else { // high-high-complex selector
|
||||
reStr.push('c', 'hhcg0', reEscape(filter));
|
||||
}
|
||||
candidates[details.rawFilter] = new RegExp(reStr.join('\\v') + '(?:\\n|$)');
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user