Skip to content

Commit

Permalink
Store domain= option into trie container's character buffer
Browse files Browse the repository at this point in the history
As the trie is not immediately created, in order to speed up
launch time, the `domain=` option was stored in the filterRefs
array until it was moved to the trie.

This commit instead stores the `domain=` option into the trie
container's character buffer.
  • Loading branch information
gorhill committed Dec 18, 2021
1 parent 47680c7 commit e45d851
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 57 deletions.
2 changes: 1 addition & 1 deletion src/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ const µBlock = { // jshint ignore:line
// Read-only
systemSettings: {
compiledMagic: 44, // Increase when compiled format changes
selfieMagic: 44, // Increase when selfie format changes
selfieMagic: 45, // Increase when selfie format changes
},

// https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501
Expand Down
70 changes: 65 additions & 5 deletions src/js/hntrie.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ class HNTrieContainer {
return -1;
}

createTrie(hostnames = undefined) {
createTrie() {
// grow buffer if needed
if ( (this.buf32[CHAR0_SLOT] - this.buf32[TRIE1_SLOT]) < 12 ) {
this.growBuf(12, 0);
Expand All @@ -233,12 +233,41 @@ class HNTrieContainer {
this.buf32[iroot+0] = 0;
this.buf32[iroot+1] = 0;
this.buf32[iroot+2] = 0;
if ( hostnames !== undefined ) {
for ( const hn of hostnames ) {
this.setNeedle(hn).add(iroot);
return iroot;
}

createTrieFromIterable(hostnames) {
const itrie = this.createTrie();
for ( const hn of hostnames ) {
if ( hn === '' ) { continue; }
this.setNeedle(hn).add(itrie);
}
return itrie;
}

createTrieFromStoredDomainOpt(i, n) {
const itrie = this.createTrie();
const jend = i + n;
let j = i, offset = 0, k = 0, c = 0;
while ( j !== jend ) {
offset = this.buf32[CHAR0_SLOT]; // Important
k = 0;
for (;;) {
if ( j === jend ) { break; }
c = this.buf[offset+j];
j += 1;
if ( c === 0x7C /* '|' */ ) { break; }
if ( k === 255 ) { continue; }
this.buf[k] = c;
k += 1;
}
if ( k !== 0 ) {
this.buf[255] = k;
this.add(itrie);
}
}
return iroot;
this.needle = ''; // Important
return itrie;
}

dumpTrie(iroot) {
Expand Down Expand Up @@ -304,6 +333,12 @@ class HNTrieContainer {
};
}

// TODO:
// Rework code to add from a string already present in the character
// buffer, i.e. not having to go through setNeedle() when adding a new
// hostname to a trie. This will require much work though, and probably
// changing the order in which string segments are stored in the
// character buffer.
addJS(iroot) {
let lhnchar = this.buf[255];
if ( lhnchar === 0 ) { return 0; }
Expand Down Expand Up @@ -488,6 +523,31 @@ class HNTrieContainer {
return textDecoder.decode(this.buf.subarray(offset, offset + n));
}

storeDomainOpt(s) {
let n = s.length;
if ( n === this.lastStoredLen && s === this.lastStored ) {
return this.lastStoredIndex;
}
this.lastStored = s;
this.lastStoredLen = n;
if ( (this.buf.length - this.buf32[CHAR1_SLOT]) < n ) {
this.growBuf(0, n);
}
const offset = this.buf32[CHAR1_SLOT];
this.buf32[CHAR1_SLOT] = offset + n;
const buf8 = this.buf;
for ( let i = 0; i < n; i++ ) {
buf8[offset+i] = s.charCodeAt(i);
}
return (this.lastStoredIndex = offset - this.buf32[CHAR0_SLOT]);
}

extractDomainOpt(i, n) {
const textDecoder = new TextDecoder();
const offset = this.buf32[CHAR0_SLOT] + i;
return textDecoder.decode(this.buf.subarray(offset, offset + n));
}

matchesHostname(hn, i, n) {
this.setNeedle(hn);
const buf8 = this.buf;
Expand Down
92 changes: 41 additions & 51 deletions src/js/static-net-filtering.js
Original file line number Diff line number Diff line change
Expand Up @@ -1200,10 +1200,6 @@ class DomainOptIterator {
// A helper instance to reuse throughout
const domainOptIterator = new DomainOptIterator('');

const domainOptNormalizer = domainOpt => {
return domainOpt.split('|').sort().join('|');
};

/******************************************************************************/

// The optimal class is picked according to the content of the `domain=`
Expand Down Expand Up @@ -1367,15 +1363,10 @@ registerFilterClass(FilterOriginMiss);
/******************************************************************************/

const FilterOriginHitSet = class {
// The `domainOpt` value may be in either the allocated refs or the trie,
// never in both at the same time.
static getDomainOpt(idata) {
const itrie = filterData[idata+2];
if ( itrie === 0 ) {
return filterRefs[filterData[idata+4]].domainOpt;
}
return domainOptNormalizer(
Array.from(origHNTrieContainer.trieIterator(itrie)).join('|')
return origHNTrieContainer.extractDomainOpt(
filterData[idata+1],
filterData[idata+2]
);
}

Expand All @@ -1384,13 +1375,13 @@ const FilterOriginHitSet = class {
}

static match(idata) {
const refs = filterRefs[filterData[idata+4]];
const refs = filterRefs[filterData[idata+6]];
if ( $docHostname === refs.$last ) {
return filterData[idata+3] !== -1;
return filterData[idata+5] !== -1;
}
refs.$last = $docHostname;
const which = filterData[idata+1];
const itrie = filterData[idata+2] || this.toTrie(idata);
const which = filterData[idata+3];
const itrie = filterData[idata+4] || this.toTrie(idata);
let lastResult = -1;
if ( (which & 0b01) !== 0 ) {
lastResult = origHNTrieContainer
Expand All @@ -1402,16 +1393,19 @@ const FilterOriginHitSet = class {
.setNeedle($docEntity.compute())
.matches(itrie);
}
return (filterData[idata+3] = lastResult) !== -1;
return (filterData[idata+5] = lastResult) !== -1;
}

static create(domainOpt, which = 0b11) {
const idata = filterDataAllocLen(5);
const idata = filterDataAllocLen(7);
filterData[idata+0] = FilterOriginHitSet.fid;
filterData[idata+1] = which;
filterData[idata+2] = 0; // itrie
filterData[idata+3] = -1; // $lastResult
filterData[idata+4] = filterRefAdd({ domainOpt, $last: '' });
filterData[idata+1] = origHNTrieContainer.storeDomainOpt(domainOpt);
filterData[idata+2] = domainOpt.length;
filterData[idata+3] = which;
filterData[idata+4] = 0; // itrie
filterData[idata+5] = -1; // $lastResult
filterData[idata+6] = filterRefAdd({ $last: '' });
this.toTrie(idata);
return idata;
}

Expand All @@ -1424,28 +1418,26 @@ const FilterOriginHitSet = class {
}

static fromCompiled(args) {
const idata = filterDataAllocLen(5);
const idata = filterDataAllocLen(7);
filterData[idata+0] = args[0]; // fid
filterData[idata+1] = args[2]; // which
filterData[idata+2] = 0; // itrie
filterData[idata+3] = -1; // $lastResult
filterData[idata+4] = filterRefAdd({ domainOpt: args[1], $last: '' });
filterData[idata+1] = origHNTrieContainer.storeDomainOpt(args[1]);
filterData[idata+2] = args[1].length;
filterData[idata+3] = args[2]; // which
filterData[idata+4] = 0; // itrie
filterData[idata+5] = -1; // $lastResult
filterData[idata+6] = filterRefAdd({ $last: '' });
return idata;
}

static toTrie(idata) {
const refs = filterRefs[filterData[idata+4]];
const itrie = filterData[idata+2] = origHNTrieContainer.createTrie(
domainOptIterator.reset(refs.domainOpt)
);
refs.domainOpt = '';
const itrie = filterData[idata+4] =
origHNTrieContainer.createTrieFromStoredDomainOpt(
filterData[idata+1],
filterData[idata+2]
);
return itrie;
}

static getTrie(idata) {
return filterData[idata+2];
}

static keyFromArgs(args) {
return args[1];
}
Expand All @@ -1455,7 +1447,7 @@ const FilterOriginHitSet = class {
}

static dumpInfo(idata) {
return `0b${filterData[idata+1].toString(2)} ${this.getDomainOpt(idata)}`;
return `0b${filterData[idata+3].toString(2)} ${this.getDomainOpt(idata)}`;
}
};

Expand Down Expand Up @@ -1863,7 +1855,7 @@ const FilterHostnameDict = class {
const itrie = filterData[idata+1];
if ( itrie !== 0 ) { return itrie; }
const hostnames = filterRefs[filterData[idata+3]];
filterData[idata+1] = destHNTrieContainer.createTrie(hostnames);
filterData[idata+1] = destHNTrieContainer.createTrieFromIterable(hostnames);
filterRefs[filterData[idata+3]] = null;
return filterData[idata+1];
}
Expand Down Expand Up @@ -1908,11 +1900,9 @@ const FilterDenyAllow = class {
}

static fromCompiled(args) {
const itrie = destHNTrieContainer.createTrie();
for ( const hn of domainOptIterator.reset(args[1]) ) {
if ( hn === '' ) { continue; }
destHNTrieContainer.setNeedle(hn).add(itrie);
}
const itrie = destHNTrieContainer.createTrieFromIterable(
domainOptIterator.reset(args[1])
);
const idata = filterDataAllocLen(3);
filterData[idata+0] = args[0]; // fid
filterData[idata+1] = itrie; // itrie
Expand Down Expand Up @@ -3503,7 +3493,7 @@ FilterCompiler.prototype.FILTER_UNSUPPORTED = 2;

const FilterContainer = function() {
this.compilerVersion = '6';
this.selfieVersion = '6';
this.selfieVersion = '7';

this.MAX_TOKEN_LENGTH = MAX_TOKEN_LENGTH;
this.optimizeTaskId = undefined;
Expand Down Expand Up @@ -4579,7 +4569,7 @@ FilterContainer.prototype.dump = function() {

const out = [];

const toOutput = (depth, line) => {
const toOutput = (depth, line, out) => {
out.push(`${' '.repeat(depth*2)}${line}`);
};

Expand All @@ -4588,7 +4578,7 @@ FilterContainer.prototype.dump = function() {
const fc = filterGetClass(idata);
fcCounts.set(fc.name, (fcCounts.get(fc.name) || 0) + 1);
const info = filterDumpInfo(idata) || '';
toOutput(depth, info !== '' ? `${fc.name}: ${info}` : fc.name);
toOutput(depth, info !== '' ? `${fc.name}: ${info}` : fc.name, out);
switch ( fc ) {
case FilterBucket:
case FilterCompositeAll:
Expand Down Expand Up @@ -4618,7 +4608,7 @@ FilterContainer.prototype.dump = function() {
const realms = new Map([
[ BlockAction, 'block' ],
[ BlockImportant, 'block-important' ],
[ AllowAction, 'allow' ],
[ AllowAction, 'unblock' ],
[ ModifyAction, 'modify' ],
]);
const partyness = new Map([
Expand All @@ -4627,9 +4617,9 @@ FilterContainer.prototype.dump = function() {
[ ThirdParty, '3rd-party' ],
]);
for ( const [ realmBits, realmName ] of realms ) {
toOutput(1, `+ realm: ${realmName}`);
toOutput(1, `+ realm: ${realmName}`, out);
for ( const [ partyBits, partyName ] of partyness ) {
toOutput(2, `+ party: ${partyName}`);
toOutput(2, `+ party: ${partyName}`, out);
const processedTypeBits = new Set();
for ( const typeName in typeNameToTypeValue ) {
const typeBits = typeNameToTypeValue[typeName];
Expand All @@ -4639,13 +4629,13 @@ FilterContainer.prototype.dump = function() {
const ibucket = this.bitsToBucketIndices[bits];
if ( ibucket === 0 ) { continue; }
const thCount = this.buckets[ibucket].size;
toOutput(3, `+ type: ${typeName} (${thCount})`);
toOutput(3, `+ type: ${typeName} (${thCount})`, out);
for ( const [ th, iunit ] of this.buckets[ibucket] ) {
thCounts.add(th);
const ths = thConstants.has(th)
? thConstants.get(th)
: `0x${th.toString(16)}`;
toOutput(4, `+ th: ${ths}`);
toOutput(4, `+ th: ${ths}`, out);
dumpUnit(iunit, out, 5);
}
}
Expand Down

0 comments on commit e45d851

Please sign in to comment.