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