mirror of
https://github.com/gorhill/uBlock.git
synced 2024-11-11 17:41:03 +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
5 changed files with 114 additions and 136 deletions
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[TRIE1_SLOT] = this.buf32[TRIE0_SLOT];
|
||||||
this.buf32[CHAR0_SLOT] = details.char0 || 65536;
|
this.buf32[CHAR0_SLOT] = details.char0 || 65536;
|
||||||
this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT];
|
this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT];
|
||||||
this.wasmInstancePromise = null;
|
|
||||||
this.wasmMemory = null;
|
this.wasmMemory = null;
|
||||||
this.readyToUse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
@ -153,15 +151,6 @@ const HNTrieContainer = class {
|
||||||
this.buf32[CHAR1_SLOT] = this.buf32[CHAR0_SLOT];
|
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) {
|
setNeedle(needle) {
|
||||||
if ( needle !== this.needle ) {
|
if ( needle !== this.needle ) {
|
||||||
const buf = this.buf;
|
const buf = this.buf;
|
||||||
|
@ -407,6 +396,40 @@ const HNTrieContainer = class {
|
||||||
return true;
|
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
|
// Private methods
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
@ -507,39 +530,6 @@ const HNTrieContainer = class {
|
||||||
this.buf32[CHAR1_SLOT] = char0 + charDataLen;
|
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;
|
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
|
// The WASM module is entirely optional, the JS implementations will be
|
||||||
// used should the WASM module be unavailable for whatever reason.
|
// used should the WASM module be unavailable for whatever reason.
|
||||||
|
|
||||||
(( ) => {
|
const getWasmModule = (( ) => {
|
||||||
HNTrieContainer.wasmModulePromise = null;
|
let 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; }
|
|
||||||
|
|
||||||
// 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; }
|
|
||||||
|
|
||||||
// The directory from which the current script was fetched should also
|
// The directory from which the current script was fetched should also
|
||||||
// contain the related WASM file. The script is fetched from a trusted
|
// contain the related WASM file. The script is fetched from a trusted
|
||||||
|
@ -741,15 +704,40 @@ HNTrieContainer.prototype.HNTrieRef.prototype.needle = '';
|
||||||
workingDir = url.href;
|
workingDir = url.href;
|
||||||
}
|
}
|
||||||
|
|
||||||
HNTrieContainer.wasmModulePromise = fetch(
|
return async function() {
|
||||||
workingDir + 'wasm/hntrie.wasm',
|
if ( wasmModulePromise instanceof Promise ) {
|
||||||
{ mode: 'same-origin' }
|
return wasmModulePromise;
|
||||||
).then(
|
}
|
||||||
WebAssembly.compileStreaming
|
|
||||||
).catch(reason => {
|
if (
|
||||||
HNTrieContainer.wasmModulePromise = null;
|
typeof WebAssembly !== 'object' ||
|
||||||
log.info(reason);
|
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();
|
await µb.loadHiddenSettings();
|
||||||
log.info(`Hidden settings ready ${Date.now()-vAPI.T0} ms after launch`);
|
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(
|
const cacheBackend = await µb.cacheStorage.select(
|
||||||
µb.hiddenSettings.cacheStorageAPI
|
µb.hiddenSettings.cacheStorageAPI
|
||||||
);
|
);
|
||||||
|
|
|
@ -311,26 +311,15 @@ const bidiTrieMatchExtra = function(l, r, ix) {
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const bidiTrie = (( ) => {
|
const bidiTrie = new µb.BidiTrieContainer(
|
||||||
let trieDetails;
|
vAPI.localStorage.getItem('SNFE.bidiTrieDetails'),
|
||||||
try {
|
bidiTrieMatchExtra
|
||||||
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 bidiTrieOptimize = function(shrink = false) {
|
const bidiTrieOptimize = function(shrink = false) {
|
||||||
const trieDetails = bidiTrie.optimize(shrink);
|
|
||||||
vAPI.localStorage.setItem(
|
vAPI.localStorage.setItem(
|
||||||
'SNFE.bidiTrieDetails',
|
'SNFE.bidiTrieDetails',
|
||||||
JSON.stringify(trieDetails)
|
bidiTrie.optimize(shrink)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1157,14 +1146,9 @@ registerFilterClass(FilterRegex);
|
||||||
|
|
||||||
const filterOrigin = new (class {
|
const filterOrigin = new (class {
|
||||||
constructor() {
|
constructor() {
|
||||||
let trieDetails;
|
this.trieContainer = new µb.HNTrieContainer(
|
||||||
try {
|
vAPI.localStorage.getItem('FilterOrigin.trieDetails')
|
||||||
trieDetails = JSON.parse(
|
);
|
||||||
vAPI.localStorage.getItem('FilterOrigin.trieDetails')
|
|
||||||
);
|
|
||||||
} catch(ex) {
|
|
||||||
}
|
|
||||||
this.trieContainer = new µb.HNTrieContainer(trieDetails);
|
|
||||||
this.strToUnitMap = new Map();
|
this.strToUnitMap = new Map();
|
||||||
this.gcTimer = undefined;
|
this.gcTimer = undefined;
|
||||||
}
|
}
|
||||||
|
@ -1244,10 +1228,9 @@ const filterOrigin = new (class {
|
||||||
}
|
}
|
||||||
|
|
||||||
optimize() {
|
optimize() {
|
||||||
const trieDetails = this.trieContainer.optimize();
|
|
||||||
vAPI.localStorage.setItem(
|
vAPI.localStorage.setItem(
|
||||||
'FilterOrigin.trieDetails',
|
'FilterOrigin.trieDetails',
|
||||||
JSON.stringify(trieDetails)
|
this.trieContainer.optimize()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1689,10 +1672,9 @@ const FilterHostnameDict = class {
|
||||||
}
|
}
|
||||||
|
|
||||||
static optimize() {
|
static optimize() {
|
||||||
const trieDetails = FilterHostnameDict.trieContainer.optimize();
|
|
||||||
vAPI.localStorage.setItem(
|
vAPI.localStorage.setItem(
|
||||||
'FilterHostnameDict.trieDetails',
|
'FilterHostnameDict.trieDetails',
|
||||||
JSON.stringify(trieDetails)
|
FilterHostnameDict.trieContainer.optimize()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1701,16 +1683,9 @@ const FilterHostnameDict = class {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FilterHostnameDict.trieContainer = (( ) => {
|
FilterHostnameDict.trieContainer = new µb.HNTrieContainer(
|
||||||
let trieDetails;
|
vAPI.localStorage.getItem('FilterHostnameDict.trieDetails')
|
||||||
try {
|
);
|
||||||
trieDetails = JSON.parse(
|
|
||||||
vAPI.localStorage.getItem('FilterHostnameDict.trieDetails')
|
|
||||||
);
|
|
||||||
} catch(ex) {
|
|
||||||
}
|
|
||||||
return new µb.HNTrieContainer(trieDetails);
|
|
||||||
})();
|
|
||||||
|
|
||||||
registerFilterClass(FilterHostnameDict);
|
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
|
// action: 1=test, 2=record
|
||||||
|
|
||||||
FilterContainer.prototype.benchmark = async function(action, target) {
|
FilterContainer.prototype.benchmark = async function(action, target) {
|
||||||
|
|
|
@ -198,7 +198,6 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
µBlock.saveImmediateHiddenSettings = function() {
|
µBlock.saveImmediateHiddenSettings = function() {
|
||||||
const props = [
|
const props = [
|
||||||
'consoleLogLevel',
|
'consoleLogLevel',
|
||||||
'disableWebAssembly',
|
|
||||||
'suspendTabsUntilReady',
|
'suspendTabsUntilReady',
|
||||||
];
|
];
|
||||||
const toSave = {};
|
const toSave = {};
|
||||||
|
@ -1011,7 +1010,7 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
µBlock.loadPublicSuffixList = async function() {
|
µBlock.loadPublicSuffixList = async function() {
|
||||||
if ( this.hiddenSettings.disableWebAssembly === false ) {
|
if ( this.hiddenSettings.disableWebAssembly !== true ) {
|
||||||
publicSuffixList.enableWASM();
|
publicSuffixList.enableWASM();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -914,7 +914,20 @@ const roundToPageSize = v => (v + PAGE_SIZE-1) & ~(PAGE_SIZE-1);
|
||||||
const getWasmModule = (( ) => {
|
const getWasmModule = (( ) => {
|
||||||
let wasmModulePromise;
|
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 ) {
|
if ( wasmModulePromise instanceof Promise ) {
|
||||||
return wasmModulePromise;
|
return wasmModulePromise;
|
||||||
}
|
}
|
||||||
|
@ -937,19 +950,6 @@ const getWasmModule = (( ) => {
|
||||||
uint32s[0] = 1;
|
uint32s[0] = 1;
|
||||||
if ( uint8s[0] !== 1 ) { return; }
|
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(
|
wasmModulePromise = fetch(
|
||||||
workingDir + 'wasm/biditrie.wasm',
|
workingDir + 'wasm/biditrie.wasm',
|
||||||
{ mode: 'same-origin' }
|
{ mode: 'same-origin' }
|
||||||
|
|
Loading…
Reference in a new issue