Skip to content

Commit

Permalink
Refactoring work in static network filtering engine
Browse files Browse the repository at this point in the history
The original motivation is to further speed up launch time
for either non-selfie-based and selfie-based initialization
of the static network filtering engine (SNFE).

As a result of the refactoring:

Filters are no longer instance-based, they are sequence-of-
integer-based. This eliminates the need to create instances
of filters at launch, and consequently eliminates all the
calls to class constructors, the resulting churning of memory,
and so forth.

All the properties defining filter instances are now as much
as possible 32-bit integer-based, and these are allocated in a
single module-scoped typed array -- this eliminates the need
to allocate memory for every filter being instantiated.

Not all filter properties can be represented as a 32-bit
integer, and in this case a filter class can allocate slots
into another module-scoped array of references.

As a result, this eliminates a lot of memory allocations when
the SNFE is populated with filters, and this makes the saving
and loading of selfie more straightforward, as the operation
is reduced to saving/loading two arrays, one of 32-bit
integers, and the other, much smaller, an array JSON-able
values.

All filter classes now only contain static methods, and all
of these methods are called with an index to the specific
filter data in the module-scoped array of 32-bit integers.

The filter sequences (used to avoid the use of JS arrays) are
also allocated in the single module-scoped array of 32-bit
integers -- they used to be stored in their own dedicated
array.

Additionally, some filters are now loaded more in a deferred
way, so as reduce uBO's time-to-readiness -- the outcome of
this still needs to be evaluated, time-to-readiness is
especially a concern in Firefox for Android or less powerful
computers.
  • Loading branch information
gorhill committed Dec 4, 2021
1 parent 64f427d commit 725e693
Show file tree
Hide file tree
Showing 6 changed files with 1,466 additions and 1,752 deletions.
10 changes: 5 additions & 5 deletions src/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ const hiddenSettingsDefault = {
allowGenericProceduralFilters: false,
assetFetchTimeout: 30,
autoCommentFilterTemplate: '{{date}} {{origin}}',
autoUpdateAssetFetchPeriod: 120,
autoUpdateDelayAfterLaunch: 180,
autoUpdateAssetFetchPeriod: 60,
autoUpdateDelayAfterLaunch: 105,
autoUpdatePeriod: 4,
benchmarkDatasetURL: 'unset',
blockingProfiles: '11111/#F00 11010/#C0F 11001/#00F 00001',
Expand Down Expand Up @@ -78,7 +78,7 @@ const hiddenSettingsDefault = {
popupPanelLockedSections: 0,
popupPanelHeightMode: 0,
requestJournalProcessPeriod: 1000,
selfieAfter: 3,
selfieAfter: 2,
strictBlockingBypassDuration: 120,
suspendTabsUntilReady: 'unset',
uiPopupConfig: 'unset',
Expand Down Expand Up @@ -175,8 +175,8 @@ const µBlock = { // jshint ignore:line

// Read-only
systemSettings: {
compiledMagic: 39, // Increase when compiled format changes
selfieMagic: 39, // Increase when selfie format changes
compiledMagic: 40, // Increase when compiled format changes
selfieMagic: 40, // Increase when selfie format changes
},

// https://github.com/uBlockOrigin/uBlock-issues/issues/759#issuecomment-546654501
Expand Down
204 changes: 86 additions & 118 deletions src/js/biditrie.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ const toSegmentInfo = (aL, l, r) => ((r - l) << 24) | (aL + l);
const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1);


const BidiTrieContainer = class {
class BidiTrieContainer {

constructor(extraHandler) {
const len = PAGE_SIZE * 4;
Expand Down Expand Up @@ -177,6 +177,19 @@ const BidiTrieContainer = class {
this.lastStoredLen = this.lastStoredIndex = 0;
}

createTrie() {
// grow buffer if needed
if ( (this.buf32[CHAR0_SLOT] - this.buf32[TRIE1_SLOT]) < CELL_BYTE_LENGTH ) {
this.growBuf(CELL_BYTE_LENGTH, 0);
}
const iroot = this.buf32[TRIE1_SLOT] >>> 2;
this.buf32[TRIE1_SLOT] += CELL_BYTE_LENGTH;
this.buf32[iroot+CELL_OR] = 0;
this.buf32[iroot+CELL_AND] = 0;
this.buf32[iroot+SEGMENT_INFO] = 0;
return iroot;
}

matches(icell, ai) {
const buf32 = this.buf32;
const buf8 = this.buf8;
Expand Down Expand Up @@ -284,25 +297,9 @@ const BidiTrieContainer = class {
return 1;
}

createOne(args) {
if ( Array.isArray(args) ) {
return new this.STrieRef(this, args[0], args[1]);
}
// grow buffer if needed
if ( (this.buf32[CHAR0_SLOT] - this.buf32[TRIE1_SLOT]) < CELL_BYTE_LENGTH ) {
this.growBuf(CELL_BYTE_LENGTH, 0);
}
const iroot = this.buf32[TRIE1_SLOT] >>> 2;
this.buf32[TRIE1_SLOT] += CELL_BYTE_LENGTH;
this.buf32[iroot+CELL_OR] = 0;
this.buf32[iroot+CELL_AND] = 0;
this.buf32[iroot+SEGMENT_INFO] = 0;
return new this.STrieRef(this, iroot, 0);
}

compileOne(trieRef) {
return [ trieRef.iroot, trieRef.size ];
}
get $l() { return this.buf32[RESULT_L_SLOT] | 0; }
get $r() { return this.buf32[RESULT_R_SLOT] | 0; }
get $iu() { return this.buf32[RESULT_IU_SLOT] | 0; }

add(iroot, aL0, n, pivot = 0) {
const aR = n;
Expand Down Expand Up @@ -561,6 +558,14 @@ const BidiTrieContainer = class {
}
}

getExtra(iboundary) {
return this.buf32[iboundary+BCELL_EXTRA];
}

setExtra(iboundary, v) {
this.buf32[iboundary+BCELL_EXTRA] = v;
}

optimize(shrink = false) {
if ( shrink ) {
this.shrinkBuf();
Expand Down Expand Up @@ -693,6 +698,65 @@ const BidiTrieContainer = class {
return -1;
}

dumpTrie(iroot) {
for ( const s of this.trieIterator(iroot) ) {
console.log(s);
}
}

trieIterator(iroot) {
return {
value: undefined,
done: false,
next() {
if ( this.icell === 0 ) {
if ( this.forks.length === 0 ) {
this.value = undefined;
this.done = true;
return this;
}
this.charPtr = this.forks.pop();
this.icell = this.forks.pop();
}
for (;;) {
const idown = this.container.buf32[this.icell+CELL_OR];
if ( idown !== 0 ) {
this.forks.push(idown, this.charPtr);
}
const v = this.container.buf32[this.icell+SEGMENT_INFO];
let i0 = this.container.buf32[CHAR0_SLOT] + (v & 0x00FFFFFF);
const i1 = i0 + (v >>> 24);
while ( i0 < i1 ) {
this.charBuf[this.charPtr] = this.container.buf8[i0];
this.charPtr += 1;
i0 += 1;
}
this.icell = this.container.buf32[this.icell+CELL_AND];
if ( this.icell === 0 ) {
return this.toPattern();
}
if ( this.container.buf32[this.icell+SEGMENT_INFO] === 0 ) {
this.icell = this.container.buf32[this.icell+CELL_AND];
return this.toPattern();
}
}
},
toPattern() {
this.value = this.textDecoder.decode(
new Uint8Array(this.charBuf.buffer, 0, this.charPtr)
);
return this;
},
container: this,
icell: iroot,
charBuf: new Uint8Array(256),
charPtr: 0,
forks: [],
textDecoder: new TextDecoder(),
[Symbol.iterator]() { return this; },
};
}

async enableWASM(wasmModuleFetcher, path) {
if ( typeof WebAssembly !== 'object' ) { return false; }
if ( this.wasmMemory instanceof WebAssembly.Memory ) { return true; }
Expand Down Expand Up @@ -816,103 +880,7 @@ const BidiTrieContainer = class {
HAYSTACK_START + HAYSTACK_SIZE
);
}
};

/*******************************************************************************
Class to hold reference to a specific trie
*/

BidiTrieContainer.prototype.STrieRef = class {
constructor(container, iroot, size) {
this.container = container;
this.iroot = iroot;
this.size = size;
}

add(i, n, pivot = 0) {
const iboundary = this.container.add(this.iroot, i, n, pivot);
if ( iboundary !== 0 ) {
this.size += 1;
}
return iboundary;
}

getExtra(iboundary) {
return this.container.buf32[iboundary+BCELL_EXTRA];
}

setExtra(iboundary, v) {
this.container.buf32[iboundary+BCELL_EXTRA] = v;
}

matches(i) {
return this.container.matches(this.iroot, i);
}

dump() {
for ( const s of this ) {
console.log(s);
}
}

get $l() { return this.container.buf32[RESULT_L_SLOT] | 0; }
get $r() { return this.container.buf32[RESULT_R_SLOT] | 0; }
get $iu() { return this.container.buf32[RESULT_IU_SLOT] | 0; }

[Symbol.iterator]() {
return {
value: undefined,
done: false,
next: function() {
if ( this.icell === 0 ) {
if ( this.forks.length === 0 ) {
this.value = undefined;
this.done = true;
return this;
}
this.charPtr = this.forks.pop();
this.icell = this.forks.pop();
}
for (;;) {
const idown = this.container.buf32[this.icell+CELL_OR];
if ( idown !== 0 ) {
this.forks.push(idown, this.charPtr);
}
const v = this.container.buf32[this.icell+SEGMENT_INFO];
let i0 = this.container.buf32[CHAR0_SLOT] + (v & 0x00FFFFFF);
const i1 = i0 + (v >>> 24);
while ( i0 < i1 ) {
this.charBuf[this.charPtr] = this.container.buf8[i0];
this.charPtr += 1;
i0 += 1;
}
this.icell = this.container.buf32[this.icell+CELL_AND];
if ( this.icell === 0 ) {
return this.toPattern();
}
if ( this.container.buf32[this.icell+SEGMENT_INFO] === 0 ) {
this.icell = this.container.buf32[this.icell+CELL_AND];
return this.toPattern();
}
}
},
toPattern: function() {
this.value = this.textDecoder.decode(
new Uint8Array(this.charBuf.buffer, 0, this.charPtr)
);
return this;
},
container: this.container,
icell: this.iroot,
charBuf: new Uint8Array(256),
charPtr: 0,
forks: [],
textDecoder: new TextDecoder()
};
}
};
}

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

Expand Down Expand Up @@ -954,4 +922,4 @@ const getWasmModule = (( ) => {

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

export { BidiTrieContainer };
export default BidiTrieContainer;
Loading

0 comments on commit 725e693

Please sign in to comment.