mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-05 18:32:30 +01:00
Ensure disableWebAssembly setting is loaded before use
Related issue: - https://github.com/uBlockOrigin/uBlock-issues/issues/899 WASM modules are now loaded on demand rather than at script evaluation time.
This commit is contained in:
parent
78dd56b7a9
commit
15470bcbdc
152
src/js/hntrie.js
152
src/js/hntrie.js
@ -139,9 +139,7 @@ const HNTrieContainer = class {
|
||||
this.buf32[TRIE1_SLOT] = this.buf32[TRIE0_SLOT];
|
||||
this.buf32[CHAR0_SLOT] = details.char0 || 65536;
|
||||
this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT];
|
||||
this.wasmInstancePromise = null;
|
||||
this.wasmMemory = null;
|
||||
this.readyToUse();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@ -153,15 +151,6 @@ const HNTrieContainer = class {
|
||||
this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT];
|
||||
}
|
||||
|
||||
readyToUse() {
|
||||
if ( HNTrieContainer.wasmModulePromise instanceof Promise === false ) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return HNTrieContainer.wasmModulePromise.then(
|
||||
module => this.initWASM(module)
|
||||
);
|
||||
}
|
||||
|
||||
setNeedle(needle) {
|
||||
if ( needle !== this.needle ) {
|
||||
const buf = this.buf;
|
||||
@ -407,6 +396,40 @@ const HNTrieContainer = class {
|
||||
return true;
|
||||
}
|
||||
|
||||
async enableWASM() {
|
||||
if ( typeof WebAssembly !== 'object' ) { return false; }
|
||||
if ( this.wasmMemory instanceof WebAssembly.Memory ) { return true; }
|
||||
const module = await getWasmModule();
|
||||
if ( module instanceof WebAssembly.Module === false ) {
|
||||
return false;
|
||||
}
|
||||
const memory = new WebAssembly.Memory({ initial: 2 });
|
||||
const instance = await WebAssembly.instantiate(
|
||||
module,
|
||||
{
|
||||
imports: {
|
||||
memory,
|
||||
growBuf: this.growBuf.bind(this, 24, 256)
|
||||
}
|
||||
}
|
||||
);
|
||||
if ( instance instanceof WebAssembly.Instance === false ) {
|
||||
return false;
|
||||
}
|
||||
this.wasmMemory = memory;
|
||||
const curPageCount = memory.buffer.byteLength >>> 16;
|
||||
const newPageCount = this.buf.byteLength + PAGE_SIZE-1 >>> 16;
|
||||
if ( newPageCount > curPageCount ) {
|
||||
memory.grow(newPageCount - curPageCount);
|
||||
}
|
||||
const buf = new Uint8Array(memory.buffer);
|
||||
buf.set(this.buf);
|
||||
this.buf = buf;
|
||||
this.buf32 = new Uint32Array(this.buf.buffer);
|
||||
this.matches = this.matchesWASM = instance.exports.matches;
|
||||
this.add = this.addWASM = instance.exports.add;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private methods
|
||||
//--------------------------------------------------------------------------
|
||||
@ -507,39 +530,6 @@ const HNTrieContainer = class {
|
||||
this.buf32[CHAR1_SLOT] = char0 + charDataLen;
|
||||
}
|
||||
}
|
||||
|
||||
initWASM(module) {
|
||||
if ( module instanceof WebAssembly.Module === false ) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if ( this.wasmInstancePromise === null ) {
|
||||
const memory = new WebAssembly.Memory({ initial: 2 });
|
||||
this.wasmInstancePromise = WebAssembly.instantiate(
|
||||
module,
|
||||
{
|
||||
imports: {
|
||||
memory,
|
||||
growBuf: this.growBuf.bind(this, 24, 256)
|
||||
}
|
||||
}
|
||||
);
|
||||
this.wasmInstancePromise.then(instance => {
|
||||
this.wasmMemory = memory;
|
||||
const curPageCount = memory.buffer.byteLength >>> 16;
|
||||
const newPageCount = this.buf.byteLength + PAGE_SIZE-1 >>> 16;
|
||||
if ( newPageCount > curPageCount ) {
|
||||
memory.grow(newPageCount - curPageCount);
|
||||
}
|
||||
const buf = new Uint8Array(memory.buffer);
|
||||
buf.set(this.buf);
|
||||
this.buf = buf;
|
||||
this.buf32 = new Uint32Array(this.buf.buffer);
|
||||
this.matches = this.matchesWASM = instance.exports.matches;
|
||||
this.add = this.addWASM = instance.exports.add;
|
||||
});
|
||||
}
|
||||
return this.wasmInstancePromise;
|
||||
}
|
||||
};
|
||||
|
||||
HNTrieContainer.prototype.matches = HNTrieContainer.prototype.matchesJS;
|
||||
@ -698,35 +688,8 @@ HNTrieContainer.prototype.HNTrieRef.prototype.needle = '';
|
||||
// The WASM module is entirely optional, the JS implementations will be
|
||||
// used should the WASM module be unavailable for whatever reason.
|
||||
|
||||
(( ) => {
|
||||
HNTrieContainer.wasmModulePromise = null;
|
||||
|
||||
if (
|
||||
typeof WebAssembly !== 'object' ||
|
||||
typeof WebAssembly.compileStreaming !== 'function'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Soft-dependency on vAPI so that the code here can be used outside of
|
||||
// uBO (i.e. tests, benchmarks)
|
||||
if ( typeof vAPI === 'object' && vAPI.canWASM !== true ) { return; }
|
||||
|
||||
// Soft-dependency on µBlock's advanced settings so that the code here can
|
||||
// be used outside of uBO (i.e. tests, benchmarks)
|
||||
if (
|
||||
typeof µBlock === 'object' &&
|
||||
µBlock.hiddenSettings.disableWebAssembly === true
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The wasm module will work only if CPU is natively little-endian,
|
||||
// as we use native uint32 array in our js code.
|
||||
const uint32s = new Uint32Array(1);
|
||||
const uint8s = new Uint8Array(uint32s.buffer);
|
||||
uint32s[0] = 1;
|
||||
if ( uint8s[0] !== 1 ) { return; }
|
||||
const getWasmModule = (( ) => {
|
||||
let wasmModulePromise;
|
||||
|
||||
// The directory from which the current script was fetched should also
|
||||
// contain the related WASM file. The script is fetched from a trusted
|
||||
@ -741,15 +704,40 @@ HNTrieContainer.prototype.HNTrieRef.prototype.needle = '';
|
||||
workingDir = url.href;
|
||||
}
|
||||
|
||||
HNTrieContainer.wasmModulePromise = fetch(
|
||||
workingDir + 'wasm/hntrie.wasm',
|
||||
{ mode: 'same-origin' }
|
||||
).then(
|
||||
WebAssembly.compileStreaming
|
||||
).catch(reason => {
|
||||
HNTrieContainer.wasmModulePromise = null;
|
||||
log.info(reason);
|
||||
});
|
||||
return async function() {
|
||||
if ( wasmModulePromise instanceof Promise ) {
|
||||
return wasmModulePromise;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof WebAssembly !== 'object' ||
|
||||
typeof WebAssembly.compileStreaming !== 'function'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Soft-dependency on vAPI so that the code here can be used outside of
|
||||
// uBO (i.e. tests, benchmarks)
|
||||
if ( typeof vAPI === 'object' && vAPI.canWASM !== true ) { return; }
|
||||
|
||||
// The wasm module will work only if CPU is natively little-endian,
|
||||
// as we use native uint32 array in our js code.
|
||||
const uint32s = new Uint32Array(1);
|
||||
const uint8s = new Uint8Array(uint32s.buffer);
|
||||
uint32s[0] = 1;
|
||||
if ( uint8s[0] !== 1 ) { return; }
|
||||
|
||||
wasmModulePromise = fetch(
|
||||
workingDir + 'wasm/hntrie.wasm',
|
||||
{ mode: 'same-origin' }
|
||||
).then(
|
||||
WebAssembly.compileStreaming
|
||||
).catch(reason => {
|
||||
log.info(reason);
|
||||
});
|
||||
|
||||
return wasmModulePromise;
|
||||
};
|
||||
})();
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -263,6 +263,12 @@ try {
|
||||
await µb.loadHiddenSettings();
|
||||
log.info(`Hidden settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
|
||||
if ( µb.hiddenSettings.disableWebAssembly !== true ) {
|
||||
µb.staticNetFilteringEngine.enableWASM().then(( ) => {
|
||||
log.info(`Static filtering engine WASM modules ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
});
|
||||
}
|
||||
|
||||
const cacheBackend = await µb.cacheStorage.select(
|
||||
µb.hiddenSettings.cacheStorageAPI
|
||||
);
|
||||
|
@ -311,26 +311,15 @@ const bidiTrieMatchExtra = function(l, r, ix) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
const bidiTrie = (( ) => {
|
||||
let trieDetails;
|
||||
try {
|
||||
trieDetails = JSON.parse(
|
||||
vAPI.localStorage.getItem('SNFE.bidiTrieDetails')
|
||||
);
|
||||
} catch(ex) {
|
||||
}
|
||||
const trie = new µb.BidiTrieContainer(trieDetails, bidiTrieMatchExtra);
|
||||
if ( µb.hiddenSettings.disableWebAssembly !== true ) {
|
||||
trie.enableWASM();
|
||||
}
|
||||
return trie;
|
||||
})();
|
||||
const bidiTrie = new µb.BidiTrieContainer(
|
||||
vAPI.localStorage.getItem('SNFE.bidiTrieDetails'),
|
||||
bidiTrieMatchExtra
|
||||
);
|
||||
|
||||
const bidiTrieOptimize = function(shrink = false) {
|
||||
const trieDetails = bidiTrie.optimize(shrink);
|
||||
vAPI.localStorage.setItem(
|
||||
'SNFE.bidiTrieDetails',
|
||||
JSON.stringify(trieDetails)
|
||||
bidiTrie.optimize(shrink)
|
||||
);
|
||||
};
|
||||
|
||||
@ -1157,14 +1146,9 @@ registerFilterClass(FilterRegex);
|
||||
|
||||
const filterOrigin = new (class {
|
||||
constructor() {
|
||||
let trieDetails;
|
||||
try {
|
||||
trieDetails = JSON.parse(
|
||||
vAPI.localStorage.getItem('FilterOrigin.trieDetails')
|
||||
);
|
||||
} catch(ex) {
|
||||
}
|
||||
this.trieContainer = new µb.HNTrieContainer(trieDetails);
|
||||
this.trieContainer = new µb.HNTrieContainer(
|
||||
vAPI.localStorage.getItem('FilterOrigin.trieDetails')
|
||||
);
|
||||
this.strToUnitMap = new Map();
|
||||
this.gcTimer = undefined;
|
||||
}
|
||||
@ -1244,10 +1228,9 @@ const filterOrigin = new (class {
|
||||
}
|
||||
|
||||
optimize() {
|
||||
const trieDetails = this.trieContainer.optimize();
|
||||
vAPI.localStorage.setItem(
|
||||
'FilterOrigin.trieDetails',
|
||||
JSON.stringify(trieDetails)
|
||||
this.trieContainer.optimize()
|
||||
);
|
||||
}
|
||||
|
||||
@ -1689,10 +1672,9 @@ const FilterHostnameDict = class {
|
||||
}
|
||||
|
||||
static optimize() {
|
||||
const trieDetails = FilterHostnameDict.trieContainer.optimize();
|
||||
vAPI.localStorage.setItem(
|
||||
'FilterHostnameDict.trieDetails',
|
||||
JSON.stringify(trieDetails)
|
||||
FilterHostnameDict.trieContainer.optimize()
|
||||
);
|
||||
}
|
||||
|
||||
@ -1701,16 +1683,9 @@ const FilterHostnameDict = class {
|
||||
}
|
||||
};
|
||||
|
||||
FilterHostnameDict.trieContainer = (( ) => {
|
||||
let trieDetails;
|
||||
try {
|
||||
trieDetails = JSON.parse(
|
||||
vAPI.localStorage.getItem('FilterHostnameDict.trieDetails')
|
||||
);
|
||||
} catch(ex) {
|
||||
}
|
||||
return new µb.HNTrieContainer(trieDetails);
|
||||
})();
|
||||
FilterHostnameDict.trieContainer = new µb.HNTrieContainer(
|
||||
vAPI.localStorage.getItem('FilterHostnameDict.trieDetails')
|
||||
);
|
||||
|
||||
registerFilterClass(FilterHostnameDict);
|
||||
|
||||
@ -3445,6 +3420,16 @@ FilterContainer.prototype.getFilterCount = function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.enableWASM = function() {
|
||||
return Promise.all([
|
||||
bidiTrie.enableWASM(),
|
||||
filterOrigin.trieContainer.enableWASM(),
|
||||
FilterHostnameDict.trieContainer.enableWASM(),
|
||||
]);
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
// action: 1=test, 2=record
|
||||
|
||||
FilterContainer.prototype.benchmark = async function(action, target) {
|
||||
|
@ -198,7 +198,6 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||
µBlock.saveImmediateHiddenSettings = function() {
|
||||
const props = [
|
||||
'consoleLogLevel',
|
||||
'disableWebAssembly',
|
||||
'suspendTabsUntilReady',
|
||||
];
|
||||
const toSave = {};
|
||||
@ -1011,7 +1010,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||
/******************************************************************************/
|
||||
|
||||
µBlock.loadPublicSuffixList = async function() {
|
||||
if ( this.hiddenSettings.disableWebAssembly === false ) {
|
||||
if ( this.hiddenSettings.disableWebAssembly !== true ) {
|
||||
publicSuffixList.enableWASM();
|
||||
}
|
||||
|
||||
|
@ -914,7 +914,20 @@ const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1);
|
||||
const getWasmModule = (( ) => {
|
||||
let wasmModulePromise;
|
||||
|
||||
return function() {
|
||||
// The directory from which the current script was fetched should also
|
||||
// contain the related WASM file. The script is fetched from a trusted
|
||||
// location, and consequently so will be the related WASM file.
|
||||
let workingDir;
|
||||
{
|
||||
const url = new URL(document.currentScript.src);
|
||||
const match = /[^\/]+$/.exec(url.pathname);
|
||||
if ( match !== null ) {
|
||||
url.pathname = url.pathname.slice(0, match.index);
|
||||
}
|
||||
workingDir = url.href;
|
||||
}
|
||||
|
||||
return async function() {
|
||||
if ( wasmModulePromise instanceof Promise ) {
|
||||
return wasmModulePromise;
|
||||
}
|
||||
@ -937,19 +950,6 @@ const getWasmModule = (( ) => {
|
||||
uint32s[0] = 1;
|
||||
if ( uint8s[0] !== 1 ) { return; }
|
||||
|
||||
// The directory from which the current script was fetched should also
|
||||
// contain the related WASM file. The script is fetched from a trusted
|
||||
// location, and consequently so will be the related WASM file.
|
||||
let workingDir;
|
||||
{
|
||||
const url = new URL(document.currentScript.src);
|
||||
const match = /[^\/]+$/.exec(url.pathname);
|
||||
if ( match !== null ) {
|
||||
url.pathname = url.pathname.slice(0, match.index);
|
||||
}
|
||||
workingDir = url.href;
|
||||
}
|
||||
|
||||
wasmModulePromise = fetch(
|
||||
workingDir + 'wasm/biditrie.wasm',
|
||||
{ mode: 'same-origin' }
|
||||
|
Loading…
Reference in New Issue
Block a user