mirror of
https://github.com/gorhill/uBlock.git
synced 2024-10-06 09:37:12 +02:00
Add support for enabling WASM code paths in NodeJS package
See `test.js` for reference on how to enable WASM code paths (which are disabled by default).
This commit is contained in:
parent
b02970f5ee
commit
98fc66bb1b
@ -36,7 +36,7 @@ vAPI.cantWebsocket =
|
||||
vAPI.canWASM = vAPI.webextFlavor.soup.has('chromium') === false;
|
||||
if ( vAPI.canWASM === false ) {
|
||||
const csp = manifest.content_security_policy;
|
||||
vAPI.canWASM = csp !== undefined && csp.indexOf("'wasm-eval'") !== -1;
|
||||
vAPI.canWASM = csp !== undefined && csp.indexOf("'unsafe-eval'") !== -1;
|
||||
}
|
||||
|
||||
vAPI.supportsUserStylesheets = vAPI.webextFlavor.soup.has('user_stylesheet');
|
||||
|
@ -80,11 +80,35 @@ function applyList(name, raw) {
|
||||
snfe.fromCompiled(reader);
|
||||
}
|
||||
|
||||
function enableWASM(path) {
|
||||
return Promise.all([
|
||||
globals.publicSuffixList.enableWASM(`${path}/lib/publicsuffixlist`),
|
||||
snfe.enableWASM(`${path}/js`),
|
||||
async function enableWASM() {
|
||||
const wasmModuleFetcher = async function(path) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const require = createRequire(import.meta.url); // jshint ignore:line
|
||||
const fs = require('fs');
|
||||
fs.readFile(`${path}.wasm`, null, (err, data) => {
|
||||
if ( err ) { return reject(err); }
|
||||
return globals.WebAssembly.compile(data).then(module => {
|
||||
resolve(module);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
try {
|
||||
const results = await Promise.all([
|
||||
globals.publicSuffixList.enableWASM(
|
||||
wasmModuleFetcher,
|
||||
'./lib/publicsuffixlist/wasm/'
|
||||
),
|
||||
snfe.enableWASM(
|
||||
wasmModuleFetcher,
|
||||
'./js/wasm/'
|
||||
),
|
||||
]);
|
||||
return results.every(a => a === true);
|
||||
} catch(reason) {
|
||||
console.info(reason);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function pslInit(raw) {
|
||||
|
@ -28,6 +28,7 @@
|
||||
import { createRequire } from 'module';
|
||||
|
||||
import {
|
||||
enableWASM,
|
||||
FilteringContext,
|
||||
pslInit,
|
||||
restart,
|
||||
@ -43,13 +44,14 @@ function fetch(listName) {
|
||||
}
|
||||
|
||||
(async ( ) => {
|
||||
/*
|
||||
* WASM require fetch(), not present in Node
|
||||
try {
|
||||
await enableWASM('//ublock/dist/build/uBlock0.nodejs');
|
||||
} catch(ex) {
|
||||
const result = await enableWASM();
|
||||
if ( result !== true ) {
|
||||
console.log('Failed to enable all WASM code paths');
|
||||
}
|
||||
} catch(ex) {
|
||||
console.log(ex);
|
||||
}
|
||||
*/
|
||||
|
||||
await pslInit();
|
||||
|
||||
|
@ -692,10 +692,10 @@ const BidiTrieContainer = class {
|
||||
return -1;
|
||||
}
|
||||
|
||||
async enableWASM(modulePath) {
|
||||
async enableWASM(wasmModuleFetcher, path) {
|
||||
if ( typeof WebAssembly !== 'object' ) { return false; }
|
||||
if ( this.wasmMemory instanceof WebAssembly.Memory ) { return true; }
|
||||
const module = await getWasmModule(modulePath);
|
||||
const module = await getWasmModule(wasmModuleFetcher, path);
|
||||
if ( module instanceof WebAssembly.Module === false ) { return false; }
|
||||
const memory = new WebAssembly.Memory({
|
||||
initial: roundToPageSize(this.buf8.length) >>> 16
|
||||
@ -925,17 +925,12 @@ BidiTrieContainer.prototype.STrieRef = class {
|
||||
const getWasmModule = (( ) => {
|
||||
let wasmModulePromise;
|
||||
|
||||
return async function(modulePath) {
|
||||
return async function(wasmModuleFetcher, path) {
|
||||
if ( wasmModulePromise instanceof Promise ) {
|
||||
return wasmModulePromise;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof WebAssembly !== 'object' ||
|
||||
typeof WebAssembly.compileStreaming !== 'function'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if ( typeof WebAssembly !== 'object' ) { return; }
|
||||
|
||||
// Soft-dependency on vAPI so that the code here can be used outside of
|
||||
// uBO (i.e. tests, benchmarks)
|
||||
@ -948,12 +943,7 @@ const getWasmModule = (( ) => {
|
||||
uint32s[0] = 1;
|
||||
if ( uint8s[0] !== 1 ) { return; }
|
||||
|
||||
wasmModulePromise = fetch(
|
||||
`${modulePath}/wasm/biditrie.wasm`,
|
||||
{ mode: 'same-origin' }
|
||||
).then(
|
||||
WebAssembly.compileStreaming
|
||||
).catch(reason => {
|
||||
wasmModulePromise = wasmModuleFetcher(`${path}biditrie`).catch(reason => {
|
||||
console.info(reason);
|
||||
});
|
||||
|
||||
|
@ -456,10 +456,10 @@ const HNTrieContainer = class {
|
||||
return n === hr || hn.charCodeAt(hl-1) === 0x2E /* '.' */;
|
||||
}
|
||||
|
||||
async enableWASM(modulePath) {
|
||||
async enableWASM(wasmModuleFetcher, path) {
|
||||
if ( typeof WebAssembly !== 'object' ) { return false; }
|
||||
if ( this.wasmMemory instanceof WebAssembly.Memory ) { return true; }
|
||||
const module = await getWasmModule(modulePath);
|
||||
const module = await getWasmModule(wasmModuleFetcher, path);
|
||||
if ( module instanceof WebAssembly.Module === false ) { return false; }
|
||||
const memory = new WebAssembly.Memory({ initial: 2 });
|
||||
const instance = await WebAssembly.instantiate(module, {
|
||||
@ -483,6 +483,7 @@ const HNTrieContainer = class {
|
||||
this.buf32 = new Uint32Array(this.buf.buffer);
|
||||
this.matches = this.matchesWASM = instance.exports.matches;
|
||||
this.add = this.addWASM = instance.exports.add;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@ -767,17 +768,12 @@ HNTrieContainer.prototype.HNTrieRef.prototype.needle = '';
|
||||
const getWasmModule = (( ) => {
|
||||
let wasmModulePromise;
|
||||
|
||||
return async function(modulePath) {
|
||||
return async function(wasmModuleFetcher, path) {
|
||||
if ( wasmModulePromise instanceof Promise ) {
|
||||
return wasmModulePromise;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof WebAssembly !== 'object' ||
|
||||
typeof WebAssembly.compileStreaming !== 'function'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if ( typeof WebAssembly !== 'object' ) { return; }
|
||||
|
||||
// Soft-dependency on vAPI so that the code here can be used outside of
|
||||
// uBO (i.e. tests, benchmarks)
|
||||
@ -790,12 +786,7 @@ const getWasmModule = (( ) => {
|
||||
uint32s[0] = 1;
|
||||
if ( uint8s[0] !== 1 ) { return; }
|
||||
|
||||
wasmModulePromise = fetch(
|
||||
`${modulePath}/wasm/hntrie.wasm`,
|
||||
{ mode: 'same-origin' }
|
||||
).then(
|
||||
WebAssembly.compileStreaming
|
||||
).catch(reason => {
|
||||
wasmModulePromise = wasmModuleFetcher(`${path}hntrie`).catch(reason => {
|
||||
console.info(reason);
|
||||
});
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
import cacheStorage from './cachestorage.js';
|
||||
import contextMenu from './contextmenu.js';
|
||||
import globals from './globals.js';
|
||||
import io from './assets.js';
|
||||
import lz4Codec from './lz4.js';
|
||||
import staticExtFilteringEngine from './static-ext-filtering.js';
|
||||
@ -343,7 +344,15 @@ try {
|
||||
}
|
||||
|
||||
if ( µb.hiddenSettings.disableWebAssembly !== true ) {
|
||||
staticNetFilteringEngine.enableWASM('/js').then(( ) => {
|
||||
const wasmModuleFetcher = async function(path) {
|
||||
return fetch(`${path}.wasm`, { mode: 'same-origin' }).then(
|
||||
globals.WebAssembly.compileStreaming
|
||||
).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
};
|
||||
staticNetFilteringEngine.enableWASM(wasmModuleFetcher, './js/wasm/').then(result => {
|
||||
if ( result !== true ) { return; }
|
||||
ubolog(`WASM modules ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
});
|
||||
}
|
||||
|
@ -4448,12 +4448,14 @@ FilterContainer.prototype.getFilterCount = function() {
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
FilterContainer.prototype.enableWASM = function(modulePath) {
|
||||
FilterContainer.prototype.enableWASM = function(wasmModuleFetcher, path) {
|
||||
return Promise.all([
|
||||
bidiTrie.enableWASM(modulePath),
|
||||
filterOrigin.trieContainer.enableWASM(modulePath),
|
||||
FilterHostnameDict.trieContainer.enableWASM(modulePath),
|
||||
]);
|
||||
bidiTrie.enableWASM(wasmModuleFetcher, path),
|
||||
filterOrigin.trieContainer.enableWASM(wasmModuleFetcher, path),
|
||||
FilterHostnameDict.trieContainer.enableWASM(wasmModuleFetcher, path),
|
||||
]).then(results => {
|
||||
return results.every(a => a === true);
|
||||
});
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -1194,17 +1194,36 @@ self.addEventListener('hiddenSettingsChanged', ( ) => {
|
||||
|
||||
µb.loadPublicSuffixList = async function() {
|
||||
const psl = globals.publicSuffixList;
|
||||
|
||||
// WASM is nice but not critical
|
||||
if ( this.hiddenSettings.disableWebAssembly !== true ) {
|
||||
psl.enableWASM('/lib/publicsuffixlist');
|
||||
const wasmModuleFetcher = function(path) {
|
||||
return fetch( `${path}.wasm`, {
|
||||
mode: 'same-origin'
|
||||
}).then(
|
||||
globals.WebAssembly.compileStreaming
|
||||
).catch(reason => {
|
||||
ubolog(reason);
|
||||
});
|
||||
};
|
||||
let result = false;
|
||||
try {
|
||||
result = await psl.enableWASM(wasmModuleFetcher,
|
||||
'./lib/publicsuffixlist/wasm/'
|
||||
);
|
||||
} catch(reason) {
|
||||
ubolog(reason);
|
||||
}
|
||||
if ( result ) {
|
||||
ubolog(`WASM PSL ready ${Date.now()-vAPI.T0} ms after launch`);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await io.get(`compiled/${this.pslAssetKey}`);
|
||||
if ( psl.fromSelfie(result.content, sparseBase64) ) {
|
||||
return;
|
||||
}
|
||||
} catch (ex) {
|
||||
ubolog(ex);
|
||||
if ( psl.fromSelfie(result.content, sparseBase64) ) { return; }
|
||||
} catch (reason) {
|
||||
ubolog(reason);
|
||||
}
|
||||
|
||||
const result = await io.get(this.pslAssetKey);
|
||||
|
@ -13,8 +13,7 @@
|
||||
|
||||
/*! Home: https://github.com/gorhill/publicsuffixlist.js -- GPLv3 APLv2 */
|
||||
|
||||
/* jshint browser:true, esversion:6, laxbreak:true, undef:true, unused:true */
|
||||
/* globals WebAssembly, console, exports:true, module */
|
||||
/* globals WebAssembly, exports:true, module */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -528,43 +527,33 @@ const fromSelfie = function(selfie, decoder) {
|
||||
// The WASM module is entirely optional, the JS implementation will be
|
||||
// used should the WASM module be unavailable for whatever reason.
|
||||
|
||||
const enableWASM = (function() {
|
||||
let memory;
|
||||
|
||||
return function(modulePath) {
|
||||
if ( getPublicSuffixPosWASM instanceof Function ) {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
if (
|
||||
typeof WebAssembly !== 'object' ||
|
||||
typeof WebAssembly.instantiateStreaming !== 'function'
|
||||
) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
const enableWASM = (( ) => {
|
||||
let wasmPromise;
|
||||
|
||||
const getWasmInstance = async function(wasmModuleFetcher, path) {
|
||||
if ( typeof WebAssembly !== 'object' ) { return false; }
|
||||
// The wasm code 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 Promise.resolve(false);
|
||||
}
|
||||
if ( uint8s[0] !== 1 ) { return false; }
|
||||
|
||||
return fetch(
|
||||
`${modulePath}/wasm/publicsuffixlist.wasm`,
|
||||
{ mode: 'same-origin' }
|
||||
).then(response => {
|
||||
try {
|
||||
const module = await wasmModuleFetcher(`${path}publicsuffixlist`);
|
||||
if ( module instanceof WebAssembly.Module === false ) {
|
||||
return false;
|
||||
}
|
||||
const pageCount = pslBuffer8 !== undefined
|
||||
? pslBuffer8.byteLength + 0xFFFF >>> 16
|
||||
: 1;
|
||||
memory = new WebAssembly.Memory({ initial: pageCount });
|
||||
return WebAssembly.instantiateStreaming(
|
||||
response,
|
||||
{ imports: { memory: memory } }
|
||||
);
|
||||
}).then(({ instance }) => {
|
||||
const memory = new WebAssembly.Memory({ initial: pageCount });
|
||||
const instance = await WebAssembly.instantiate(module, {
|
||||
imports: { memory }
|
||||
});
|
||||
if ( instance instanceof WebAssembly.Instance === false ) {
|
||||
return false;
|
||||
}
|
||||
const curPageCount = memory.buffer.byteLength >>> 16;
|
||||
const newPageCount = pslBuffer8 !== undefined
|
||||
? pslBuffer8.byteLength + 0xFFFF >>> 16
|
||||
@ -582,12 +571,19 @@ const enableWASM = (function() {
|
||||
wasmMemory = memory;
|
||||
getPublicSuffixPosWASM = instance.exports.getPublicSuffixPos;
|
||||
getPublicSuffixPos = getPublicSuffixPosWASM;
|
||||
memory = undefined;
|
||||
return true;
|
||||
}).catch(reason => {
|
||||
} catch(reason) {
|
||||
console.info(reason);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
return async function(wasmModuleFetcher, path) {
|
||||
if ( getPublicSuffixPosWASM instanceof Function ) { return true; }
|
||||
if ( wasmPromise instanceof Promise === false ) {
|
||||
wasmPromise = getWasmInstance(wasmModuleFetcher, path);
|
||||
}
|
||||
return wasmPromise;
|
||||
};
|
||||
})();
|
||||
|
||||
|
@ -16,6 +16,9 @@ cp src/js/static-filtering-io.js $DES/js
|
||||
cp src/js/text-iterators.js $DES/js
|
||||
cp src/js/uri-utils.js $DES/js
|
||||
|
||||
mkdir -p $DES/js/wasm
|
||||
cp src/js/wasm/* $DES/js/wasm/
|
||||
|
||||
mkdir -p $DES/lib
|
||||
cp -R src/lib/punycode.js $DES/lib/
|
||||
cp -R src/lib/publicsuffixlist $DES/lib/
|
||||
|
Loading…
Reference in New Issue
Block a user