From 3621792f1635e933667b12cc7c830020fb1c81c0 Mon Sep 17 00:00:00 2001 From: Raymond Hill Date: Sun, 23 Feb 2020 12:18:45 -0500 Subject: [PATCH] Rework/remove remnant of code dependent on localStorage Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/899 --- src/js/background.js | 23 +-------------- src/js/hntrie.js | 52 +++++++++++++++++++++++++++------- src/js/messaging.js | 3 -- src/js/start.js | 16 ++++++++++- src/js/static-net-filtering.js | 52 +++++++++++++++++++++------------- src/js/storage.js | 31 ++------------------ src/js/strie.js | 23 +++++++++------ src/js/traffic.js | 10 +------ 8 files changed, 109 insertions(+), 101 deletions(-) diff --git a/src/js/background.js b/src/js/background.js index 91134e7c2..46b1d523e 100644 --- a/src/js/background.js +++ b/src/js/background.js @@ -98,28 +98,7 @@ const µBlock = (( ) => { // jshint ignore:line }, hiddenSettingsDefault: hiddenSettingsDefault, - hiddenSettings: (( ) => { - const out = Object.assign({}, hiddenSettingsDefault); - const json = vAPI.localStorage.getItem('immediateHiddenSettings'); - if ( typeof json !== 'string' ) { return out; } - try { - const o = JSON.parse(json); - if ( o instanceof Object ) { - for ( const k in o ) { - if ( out.hasOwnProperty(k) ) { out[k] = o[k]; } - } - self.log.verbosity = out.consoleLogLevel; - if ( typeof out.suspendTabsUntilReady === 'boolean' ) { - out.suspendTabsUntilReady = out.suspendTabsUntilReady - ? 'yes' - : 'unset'; - } - } - } - catch(ex) { - } - return out; - })(), + hiddenSettings: Object.assign({}, hiddenSettingsDefault), // Features detection. privacySettingsSupported: vAPI.browserSettings instanceof Object, diff --git a/src/js/hntrie.js b/src/js/hntrie.js index ba5d280cb..62a24e74b 100644 --- a/src/js/hntrie.js +++ b/src/js/hntrie.js @@ -127,17 +127,18 @@ const CHAR0_SLOT = TRIE0_SLOT + 2; // 66 / 264 const CHAR1_SLOT = TRIE0_SLOT + 3; // 67 / 268 const TRIE0_START = TRIE0_SLOT + 4 << 2; // 272 +const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1); + const HNTrieContainer = class { - constructor(details) { - if ( details instanceof Object === false ) { details = {}; } - let len = (details.byteLength || 0) + PAGE_SIZE-1 & ~(PAGE_SIZE-1); - this.buf = new Uint8Array(Math.max(len, 131072)); + constructor() { + const len = PAGE_SIZE * 2; + this.buf = new Uint8Array(len); this.buf32 = new Uint32Array(this.buf.buffer); this.needle = ''; this.buf32[TRIE0_SLOT] = TRIE0_START; this.buf32[TRIE1_SLOT] = this.buf32[TRIE0_SLOT]; - this.buf32[CHAR0_SLOT] = details.char0 || 65536; + this.buf32[CHAR0_SLOT] = len >>> 1; this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT]; this.wasmMemory = null; } @@ -146,7 +147,17 @@ const HNTrieContainer = class { // Public methods //-------------------------------------------------------------------------- - reset() { + reset(details) { + if ( + details instanceof Object && + typeof details.byteLength === 'number' && + typeof details.char0 === 'number' + ) { + if ( details.byteLength > this.buf.byteLength ) { + this.reallocateBuf(details.byteLength); + } + this.buf32[CHAR0_SLOT] = details.char0; + } this.buf32[TRIE1_SLOT] = this.buf32[TRIE0_SLOT]; this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT]; } @@ -375,7 +386,7 @@ const HNTrieContainer = class { ? decoder.decodeSize(selfie) : selfie.length << 2; if ( byteLength === 0 ) { return false; } - byteLength = byteLength + PAGE_SIZE-1 & ~(PAGE_SIZE-1); + byteLength = roundToPageSize(byteLength); if ( this.wasmMemory !== null ) { const pageCountBefore = this.buf.length >>> 16; const pageCountAfter = byteLength >>> 16; @@ -458,12 +469,12 @@ const HNTrieContainer = class { growBuf(trieGrow, charGrow) { const char0 = Math.max( - (this.buf32[TRIE1_SLOT] + trieGrow + PAGE_SIZE-1) & ~(PAGE_SIZE-1), + roundToPageSize(this.buf32[TRIE1_SLOT] + trieGrow), this.buf32[CHAR0_SLOT] ); const char1 = char0 + this.buf32[CHAR1_SLOT] - this.buf32[CHAR0_SLOT]; const bufLen = Math.max( - (char1 + charGrow + PAGE_SIZE-1) & ~(PAGE_SIZE-1), + roundToPageSize(char1 + charGrow), this.buf.length ); this.resizeBuf(bufLen, char0); @@ -479,7 +490,7 @@ const HNTrieContainer = class { } resizeBuf(bufLen, char0) { - bufLen = bufLen + PAGE_SIZE-1 & ~(PAGE_SIZE-1); + bufLen = roundToPageSize(bufLen); if ( bufLen === this.buf.length && char0 === this.buf32[CHAR0_SLOT] @@ -530,6 +541,27 @@ const HNTrieContainer = class { this.buf32[CHAR1_SLOT] = char0 + charDataLen; } } + + reallocateBuf(newSize) { + newSize = roundToPageSize(newSize); + if ( newSize === this.buf.length ) { return; } + if ( this.wasmMemory === null ) { + const newBuf = new Uint8Array(newSize); + newBuf.set( + newBuf.length < this.buf.length + ? this.buf.subarray(0, newBuf.length) + : this.buf + ); + this.buf = newBuf; + } else { + const growBy = + ((newSize + 0xFFFF) >>> 16) - (this.buf.length >>> 16); + if ( growBy <= 0 ) { return; } + this.wasmMemory.grow(growBy); + this.buf = new Uint8Array(this.wasmMemory.buffer); + } + this.buf32 = new Uint32Array(this.buf.buffer); + } }; HNTrieContainer.prototype.matches = HNTrieContainer.prototype.matchesJS; diff --git a/src/js/messaging.js b/src/js/messaging.js index c496d6f8a..b3004aa38 100644 --- a/src/js/messaging.js +++ b/src/js/messaging.js @@ -896,7 +896,6 @@ const restoreUserData = async function(request) { // If we are going to restore all, might as well wipe out clean local // storages - vAPI.localStorage.removeItem('immediateHiddenSettings'); await Promise.all([ µb.cacheStorage.clear(), vAPI.storage.clear(), @@ -945,8 +944,6 @@ const restoreUserData = async function(request) { // Remove all stored data but keep global counts, people can become // quite attached to numbers const resetUserData = async function() { - vAPI.localStorage.removeItem('immediateHiddenSettings'); - await Promise.all([ µb.cacheStorage.clear(), vAPI.storage.clear(), diff --git a/src/js/start.js b/src/js/start.js index 4aa61de28..826b74338 100644 --- a/src/js/start.js +++ b/src/js/start.js @@ -263,9 +263,20 @@ try { await µb.loadHiddenSettings(); log.info(`Hidden settings ready ${Date.now()-vAPI.T0} ms after launch`); + // By default network requests are always suspended, so we must + // unsuspend immediately if commanded by platform + advanced settings. + if ( + vAPI.net.canSuspend() && + µb.hiddenSettings.suspendTabsUntilReady === 'no' || + vAPI.net.canSuspend() !== true && + µb.hiddenSettings.suspendTabsUntilReady !== 'yes' + ) { + vAPI.net.unsuspend(true); + } + if ( µb.hiddenSettings.disableWebAssembly !== true ) { µb.staticNetFilteringEngine.enableWASM().then(( ) => { - log.info(`Static filtering engine WASM modules ready ${Date.now()-vAPI.T0} ms after launch`); + log.info(`WASM modules ready ${Date.now()-vAPI.T0} ms after launch`); }); } @@ -296,6 +307,9 @@ try { console.trace(ex); } +// Prime the filtering engines before first use. +µb.staticNetFilteringEngine.prime(); + // https://github.com/uBlockOrigin/uBlock-issues/issues/817#issuecomment-565730122 // Still try to load filter lists regardless of whether a serious error // occurred in the previous initialization steps. diff --git a/src/js/static-net-filtering.js b/src/js/static-net-filtering.js index c0b3ae346..d475cc618 100644 --- a/src/js/static-net-filtering.js +++ b/src/js/static-net-filtering.js @@ -311,16 +311,14 @@ const bidiTrieMatchExtra = function(l, r, ix) { return 0; }; -const bidiTrie = new µb.BidiTrieContainer( - vAPI.localStorage.getItem('SNFE.bidiTrieDetails'), - bidiTrieMatchExtra -); +const bidiTrie = new µb.BidiTrieContainer(bidiTrieMatchExtra); + +const bidiTriePrime = function() { + bidiTrie.reset(vAPI.localStorage.getItem('SNFE.bidiTrie')); +}; const bidiTrieOptimize = function(shrink = false) { - vAPI.localStorage.setItem( - 'SNFE.bidiTrieDetails', - bidiTrie.optimize(shrink) - ); + vAPI.localStorage.setItem('SNFE.bidiTrie', bidiTrie.optimize(shrink)); }; /******************************************************************************* @@ -1146,9 +1144,7 @@ registerFilterClass(FilterRegex); const filterOrigin = new (class { constructor() { - this.trieContainer = new µb.HNTrieContainer( - vAPI.localStorage.getItem('FilterOrigin.trieDetails') - ); + this.trieContainer = new µb.HNTrieContainer(); this.strToUnitMap = new Map(); this.gcTimer = undefined; } @@ -1222,6 +1218,12 @@ const filterOrigin = new (class { return iunit; } + prime() { + this.trieContainer.reset( + vAPI.localStorage.getItem('SNFE.filterOrigin.trieDetails') + ); + } + reset() { this.trieContainer.reset(); this.strToUnitMap.clear(); @@ -1229,7 +1231,7 @@ const filterOrigin = new (class { optimize() { vAPI.localStorage.setItem( - 'FilterOrigin.trieDetails', + 'SNFE.filterOrigin.trieDetails', this.trieContainer.optimize() ); } @@ -1667,13 +1669,19 @@ const FilterHostnameDict = class { ]; } + static prime() { + return FilterHostnameDict.trieContainer.reset( + vAPI.localStorage.getItem('SNFE.FilterHostnameDict.trieDetails') + ); + } + static reset() { return FilterHostnameDict.trieContainer.reset(); } static optimize() { vAPI.localStorage.setItem( - 'FilterHostnameDict.trieDetails', + 'SNFE.FilterHostnameDict.trieDetails', FilterHostnameDict.trieContainer.optimize() ); } @@ -1683,9 +1691,7 @@ const FilterHostnameDict = class { } }; -FilterHostnameDict.trieContainer = new µb.HNTrieContainer( - vAPI.localStorage.getItem('FilterHostnameDict.trieDetails') -); +FilterHostnameDict.trieContainer = new µb.HNTrieContainer(); registerFilterClass(FilterHostnameDict); @@ -2637,8 +2643,15 @@ const FilterContainer = function() { /******************************************************************************/ +FilterContainer.prototype.prime = function() { + FilterHostnameDict.prime(); + filterOrigin.prime(); + bidiTriePrime(); +}; + +/******************************************************************************/ + FilterContainer.prototype.reset = function() { - this.frozen = false; this.processedFilterCount = 0; this.acceptedCount = 0; this.rejectedCount = 0; @@ -2777,7 +2790,6 @@ FilterContainer.prototype.freeze = function() { FilterHostnameDict.optimize(); bidiTrieOptimize(); - this.frozen = true; log.info(`staticNetFilteringEngine.freeze() took ${Date.now()-t0} ms`); }; @@ -2875,7 +2887,6 @@ FilterContainer.prototype.fromSelfie = function(path) { } catch (ex) { } if ( selfie instanceof Object === false ) { return false; } - this.frozen = true; this.processedFilterCount = selfie.processedFilterCount; this.acceptedCount = selfie.acceptedCount; this.rejectedCount = selfie.rejectedCount; @@ -3453,6 +3464,9 @@ FilterContainer.prototype.benchmark = async function(action, target) { console.log(`\ttype=${fctxt.type}`); console.log(`\turl=${fctxt.url}`); console.log(`\tdocOrigin=${fctxt.getDocOrigin()}`); + if ( r !== 0 ) { + console.log(this.toLogData()); + } return; } diff --git a/src/js/storage.js b/src/js/storage.js index f38958c2a..3ebd3da2e 100644 --- a/src/js/storage.js +++ b/src/js/storage.js @@ -130,7 +130,6 @@ } } vAPI.storage.set(bin); - this.saveImmediateHiddenSettings(); }; self.addEventListener('hiddenSettingsChanged', ( ) => { @@ -192,32 +191,6 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { /******************************************************************************/ -// These settings must be available immediately on startup, without delay -// through the vAPI.localStorage. Add/remove settings as needed. - -µBlock.saveImmediateHiddenSettings = function() { - const props = [ - 'consoleLogLevel', - 'suspendTabsUntilReady', - ]; - const toSave = {}; - for ( const prop of props ) { - if ( this.hiddenSettings[prop] !== this.hiddenSettingsDefault[prop] ) { - toSave[prop] = this.hiddenSettings[prop]; - } - } - if ( Object.keys(toSave).length !== 0 ) { - vAPI.localStorage.setItem( - 'immediateHiddenSettings', - JSON.stringify(toSave) - ); - } else { - vAPI.localStorage.removeItem('immediateHiddenSettings'); - } -}; - -/******************************************************************************/ - µBlock.savePermanentFirewallRules = function() { vAPI.storage.set({ dynamicFilteringString: this.permanentFirewall.toString() @@ -630,8 +603,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { µBlock.loadFilterLists = (( ) => { const loadedListKeys = []; let loadingPromise; - - const t0 = Date.now(); + let t0 = 0; const onDone = function() { log.info(`loadFilterLists() took ${Date.now()-t0} ms`); @@ -708,6 +680,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => { return function() { if ( loadingPromise instanceof Promise === false ) { + t0 = Date.now(); loadedListKeys.length = 0; loadingPromise = Promise.all([ this.getAvailableLists().then(lists => diff --git a/src/js/strie.js b/src/js/strie.js index fa109854c..b7c62f27e 100644 --- a/src/js/strie.js +++ b/src/js/strie.js @@ -114,7 +114,6 @@ const RESULT_L_SLOT = HAYSTACK_SIZE_SLOT + 5; // 517 / 2068 const RESULT_R_SLOT = HAYSTACK_SIZE_SLOT + 6; // 518 / 2072 const RESULT_IU_SLOT = HAYSTACK_SIZE_SLOT + 7; // 519 / 2076 const TRIE0_START = HAYSTACK_SIZE_SLOT + 8 << 2; // 2080 -// TODO: need a few slots for result values if WASM-ing const CELL_BYTE_LENGTH = 12; const MIN_FREE_CELL_BYTE_LENGTH = CELL_BYTE_LENGTH * 8; @@ -133,15 +132,13 @@ const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1); µBlock.BidiTrieContainer = class { - constructor(details, extraHandler) { - if ( details instanceof Object === false ) { details = {}; } - const len = roundToPageSize(details.byteLength || 0); - const minInitialSize = PAGE_SIZE * 4; - this.buf8 = new Uint8Array(Math.max(len, minInitialSize)); + constructor(extraHandler) { + const len = PAGE_SIZE * 4; + this.buf8 = new Uint8Array(len); this.buf32 = new Uint32Array(this.buf8.buffer); this.buf32[TRIE0_SLOT] = TRIE0_START; this.buf32[TRIE1_SLOT] = this.buf32[TRIE0_SLOT]; - this.buf32[CHAR0_SLOT] = details.char0 || (minInitialSize >>> 1); + this.buf32[CHAR0_SLOT] = len >>> 1; this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT]; this.haystack = this.buf8.subarray( HAYSTACK_START, @@ -164,7 +161,17 @@ const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1); this.buf32[HAYSTACK_SIZE_SLOT] = v; } - reset() { + reset(details) { + if ( + details instanceof Object && + typeof details.byteLength === 'number' && + typeof details.char0 === 'number' + ) { + if ( details.byteLength > this.buf8.byteLength ) { + this.reallocateBuf(details.byteLength); + } + this.buf32[CHAR0_SLOT] = details.char0; + } this.buf32[TRIE1_SLOT] = this.buf32[TRIE0_SLOT]; this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT]; } diff --git a/src/js/traffic.js b/src/js/traffic.js index f2710ced8..089fb168a 100644 --- a/src/js/traffic.js +++ b/src/js/traffic.js @@ -1039,15 +1039,7 @@ const strictBlockBypasser = { return { start: (( ) => { vAPI.net = new vAPI.Net(); - - if ( - vAPI.net.canSuspend() && - µBlock.hiddenSettings.suspendTabsUntilReady !== 'no' || - vAPI.net.canSuspend() !== true && - µBlock.hiddenSettings.suspendTabsUntilReady === 'yes' - ) { - vAPI.net.suspend(true); - } + vAPI.net.suspend(true); return function() { vAPI.net.setSuspendableListener(onBeforeRequest);