1
0
mirror of https://github.com/gorhill/uBlock.git synced 2024-09-02 00:59:38 +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:
gorhill 2016-06-28 22:01:15 -04:00
parent b65699aef2
commit e99d993a4c
4 changed files with 117 additions and 78 deletions

View File

@ -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: {

View File

@ -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);
}
});
})();

View File

@ -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
};
}

View File

@ -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|$)');