Fix Promise chain of WASM module load operations

The Promise chain was not properly designed for WASM module
loading. This became apparent when removing WASM modules
from Opera build[1].

The problem was that errors thrown by fetch() -- used to
load WASM modules -- were not properly handled.

[1] Opera refuses updating uBO if there are unrecognized file
types in the package, and `.wasm`/`.wat` files are not
recognized by Opera uploader.
This commit is contained in:
Raymond Hill 2019-02-01 08:20:43 -05:00
parent 4f3aed6fe6
commit 69c87c5117
No known key found for this signature in database
GPG key ID: 25E1490B761470C2
6 changed files with 70 additions and 77 deletions

View file

@ -154,9 +154,9 @@ HNTrieContainer.prototype = {
if ( HNTrieContainer.wasmModulePromise instanceof Promise === false ) {
return Promise.resolve();
}
return HNTrieContainer.wasmModulePromise.then(module => {
return this.initWASM(module);
});
return HNTrieContainer.wasmModulePromise.then(
module => this.initWASM(module)
);
},
setNeedle: function(needle) {
@ -674,10 +674,13 @@ HNTrieContainer.prototype.HNTrieRef.prototype = {
workingDir = url.href;
}
HNTrieContainer.wasmModulePromise = WebAssembly.compileStreaming(
fetch(workingDir + 'wasm/hntrie.wasm')
HNTrieContainer.wasmModulePromise = fetch(
workingDir + 'wasm/hntrie.wasm',
{ mode: 'same-origin' }
).then(
WebAssembly.compileStreaming
).catch(reason => {
HNTrieContainer.wasmModulePromise = null;
console.error(reason);
console.info(reason);
});
})();

View file

@ -43,7 +43,7 @@ let ttlCount = 0;
let ttlTimer;
let ttlDelay = 60000;
let init = function() {
const init = function() {
ttlDelay = µBlock.hiddenSettings.autoUpdateAssetFetchPeriod * 1000 + 15000;
if ( lz4CodecInstance === null ) {
return Promise.resolve(null);
@ -72,7 +72,7 @@ let init = function() {
// which will cause the wasm instance to be forgotten after enough
// time elapse without the instance being used.
let destroy = function() {
const destroy = function() {
//if ( lz4CodecInstance !== undefined ) {
// console.info(
// 'uBO: freeing lz4-block-codec instance (%s KB)',
@ -85,7 +85,7 @@ let destroy = function() {
ttlTimer = undefined;
};
let ttlManage = function(count) {
const ttlManage = function(count) {
if ( ttlTimer !== undefined ) {
clearTimeout(ttlTimer);
ttlTimer = undefined;
@ -96,7 +96,7 @@ let ttlManage = function(count) {
ttlTimer = vAPI.setTimeout(destroy, ttlDelay);
};
let uint8ArrayFromBlob = function(key, data) {
const uint8ArrayFromBlob = function(key, data) {
if ( data instanceof Blob === false ) {
return Promise.resolve({ key, data });
}
@ -109,7 +109,7 @@ let uint8ArrayFromBlob = function(key, data) {
});
};
let encodeValue = function(key, value) {
const encodeValue = function(key, value) {
if ( !lz4CodecInstance ) { return; }
//let t0 = window.performance.now();
if ( textEncoder === undefined ) {
@ -138,7 +138,7 @@ let encodeValue = function(key, value) {
return outputArray;
};
let decodeValue = function(key, inputArray) {
const decodeValue = function(key, inputArray) {
if ( !lz4CodecInstance ) { return; }
//let t0 = window.performance.now();
if (

View file

@ -46,7 +46,7 @@
/******************************************************************************/
let wd = (function() {
const wd = (function() {
let url = document.currentScript.src;
let match = /[^\/]+$/.exec(url);
return match !== null ?
@ -54,38 +54,31 @@ let wd = (function() {
'';
})();
let removeScript = function(script) {
const removeScript = function(script) {
if ( !script ) { return; }
if ( script.parentNode === null ) { return; }
script.parentNode.removeChild(script);
};
let createInstanceWASM = function() {
const createInstanceWASM = function() {
if ( context.LZ4BlockWASM instanceof Function ) {
let instance = new context.LZ4BlockWASM();
return instance.init().then(( ) => { return instance; });
const instance = new context.LZ4BlockWASM();
return instance.init().then(ok => ok ? instance : null);
}
if ( context.LZ4BlockWASM === null ) {
return Promise.resolve(null);
}
return new Promise((resolve, reject) => {
let script = document.createElement('script');
return new Promise(resolve => {
const script = document.createElement('script');
script.src = wd + 'lz4-block-codec-wasm.js';
script.addEventListener('load', ( ) => {
if ( context.LZ4BlockWASM instanceof Function === false ) {
context.LZ4BlockWASM = null;
context.LZ4BlockWASM = undefined;
resolve(null);
} else {
let instance = new context.LZ4BlockWASM();
instance.init()
.then(( ) => {
resolve(instance);
})
.catch(error => {
reject(error);
});
return;
}
const instance = new context.LZ4BlockWASM();
instance.init().then(ok => { resolve(ok ? instance : null); });
});
script.addEventListener('error', ( ) => {
context.LZ4BlockWASM = null;
@ -96,31 +89,25 @@ let createInstanceWASM = function() {
});
};
let createInstanceJS = function() {
const createInstanceJS = function() {
if ( context.LZ4BlockJS instanceof Function ) {
let instance = new context.LZ4BlockJS();
return instance.init().then(( ) => { return instance; });
const instance = new context.LZ4BlockJS();
return instance.init().then(ok => ok ? instance : null);
}
if ( context.LZ4BlockJS === null ) {
return Promise.resolve(null);
}
return new Promise((resolve, reject) => {
let script = document.createElement('script');
return new Promise(resolve => {
const script = document.createElement('script');
script.src = wd + 'lz4-block-codec-js.js';
script.addEventListener('load', ( ) => {
if ( context.LZ4BlockJS instanceof Function === false ) {
context.LZ4BlockJS = null;
resolve(null);
} else {
let instance = new context.LZ4BlockJS();
instance.init()
.then(( ) => {
resolve(instance);
})
.catch(error => {
reject(error);
});
return;
}
const instance = new context.LZ4BlockJS();
instance.init().then(ok => { resolve(ok ? instance : null); });
});
script.addEventListener('error', ( ) => {
context.LZ4BlockJS = null;
@ -143,20 +130,13 @@ context.lz4BlockCodec = {
} else {
instantiator = createInstanceWASM || createInstanceJS;
}
return (instantiator)()
.then(instance => {
if ( instance ) { return instance; }
if ( flavor === undefined ) {
return createInstanceJS();
}
return null;
})
.catch(( ) => {
if ( flavor === undefined ) {
return createInstanceJS();
}
return null;
});
return (instantiator)().then(instance => {
if ( instance ) { return instance; }
if ( flavor === undefined ) {
return createInstanceJS();
}
return null;
});
},
reset: function() {
context.LZ4BlockWASM = undefined;

View file

@ -46,7 +46,7 @@
/******************************************************************************/
let growOutputBuffer = function(instance, size) {
const growOutputBuffer = function(instance, size) {
if (
instance.outputBuffer === undefined ||
instance.outputBuffer.byteLength < size
@ -56,13 +56,13 @@ let growOutputBuffer = function(instance, size) {
return instance.outputBuffer;
};
let encodeBound = function(size) {
const encodeBound = function(size) {
return size > 0x7E000000 ?
0 :
size + (size / 255 | 0) + 16;
};
let encodeBlock = function(instance, iBuf, oOffset) {
const encodeBlock = function(instance, iBuf, oOffset) {
let iLen = iBuf.byteLength;
if ( iLen >= 0x7E000000 ) { throw new RangeError(); }
@ -183,7 +183,7 @@ let encodeBlock = function(instance, iBuf, oOffset) {
return new Uint8Array(oBuf.buffer, 0, oPos);
};
let decodeBlock = function(instance, iBuf, iOffset, oLen) {
const decodeBlock = function(instance, iBuf, iOffset, oLen) {
let iLen = iBuf.byteLength;
let oBuf = new Uint8Array(growOutputBuffer(instance, oLen), 0, oLen);
let iPos = iOffset, oPos = 0;
@ -252,7 +252,7 @@ context.LZ4BlockJS = function() {
context.LZ4BlockJS.prototype = {
flavor: 'js',
init: function() {
return Promise.resolve();
return Promise.resolve(true);
},
reset: function() {

View file

@ -48,7 +48,7 @@
/******************************************************************************/
let wd = (function() {
const wd = (function() {
let url = document.currentScript.src;
let match = /[^\/]+$/.exec(url);
return match !== null ?
@ -56,7 +56,7 @@ let wd = (function() {
'';
})();
let growMemoryTo = function(wasmInstance, byteLength) {
const growMemoryTo = function(wasmInstance, byteLength) {
let lz4api = wasmInstance.exports;
let neededByteLength = lz4api.getLinearMemoryOffset() + byteLength;
let pageCountBefore = lz4api.memory.buffer.byteLength >>> 16;
@ -67,7 +67,7 @@ let growMemoryTo = function(wasmInstance, byteLength) {
return lz4api.memory.buffer;
};
let encodeBlock = function(wasmInstance, inputArray, outputOffset) {
const encodeBlock = function(wasmInstance, inputArray, outputOffset) {
let lz4api = wasmInstance.exports;
let mem0 = lz4api.getLinearMemoryOffset();
let hashTableSize = 65536 * 4;
@ -96,7 +96,7 @@ let encodeBlock = function(wasmInstance, inputArray, outputOffset) {
return outputArray;
};
let decodeBlock = function(wasmInstance, inputArray, inputOffset, outputSize) {
const decodeBlock = function(wasmInstance, inputArray, inputOffset, outputSize) {
let inputSize = inputArray.byteLength;
let lz4api = wasmInstance.exports;
let mem0 = lz4api.getLinearMemoryOffset();
@ -130,24 +130,25 @@ context.LZ4BlockWASM.prototype = {
this.lz4wasmInstance = null;
}
if ( this.lz4wasmInstance === null ) {
return Promise.reject();
return Promise.resolve(false);
}
if ( this.lz4wasmInstance instanceof WebAssembly.Instance ) {
return Promise.resolve(this.lz4wasmInstance);
return Promise.resolve(true);
}
if ( this.lz4wasmInstance === undefined ) {
this.lz4wasmInstance = WebAssembly.instantiateStreaming(
fetch(wd + 'lz4-block-codec.wasm', { mode: 'same-origin' })
this.lz4wasmInstance = fetch(
wd + 'lz4-block-codec.wasm',
{ mode: 'same-origin' }
).then(
WebAssembly.instantiateStreaming
).then(result => {
this.lz4wasmInstance = undefined;
this.lz4wasmInstance = result && result.instance || null;
if ( this.lz4wasmInstance !== null ) { return this; }
return null;
});
this.lz4wasmInstance.catch(( ) => {
}).catch(reason => {
this.lz4wasmInstance = null;
return null;
});
console.info(reason);
}).then(( ) =>
this.lz4wasmInstance !== null
);
}
return this.lz4wasmInstance;
},

View file

@ -46,6 +46,15 @@ rm -r $DES/_locales/mr
rm -r $DES/_locales/ta
rm -r $DES/_locales/th
# Removing WASM modules until I receive an answer from Opera people: Opera's
# uploader issue an error for hntrie.wasm and this prevents me from
# updating uBO in the Opera store. The modules are unused anyway for
# Chromium- based browsers.
rm $DES/js/wasm/*.wasm
rm $DES/js/wasm/*.wat
rm $DES/lib/lz4/*.wasm
rm $DES/lib/lz4/*.wat
echo "*** uBlock0.opera: Generating web accessible resources..."
cp -R src/web_accessible_resources $DES/
python3 tools/import-war.py $DES/