JSMpeg.WASMModule = (function(){ "use strict"; var WASM = function() { this.stackSize = 5 * 1024 * 1024; // emscripten default this.pageSize = 64 * 1024; // wasm page size this.onInitCallback = null; this.ready = false; }; WASM.prototype.write = function(buffer) { this.loadFromBuffer(buffer, this.onInitCallback); }; WASM.prototype.loadFromFile = function(url, callback) { this.onInitCallback = callback; var ajax = new JSMpeg.Source.Ajax(url, {}); ajax.connect(this); ajax.start(); }; WASM.prototype.loadFromBuffer = function(buffer, callback) { this.moduleInfo = this.readDylinkSection(buffer); if (!this.moduleInfo) { this.callback && this.callback(null); return; } this.memory = new WebAssembly.Memory({initial: 256}); var env = { memory: this.memory, memoryBase: 0, __memory_base: 0, table: new WebAssembly.Table({initial: this.moduleInfo.tableSize, element: 'anyfunc'}), tableBase: 0, __table_base: 0, abort: this.c_abort.bind(this), ___assert_fail: this.c_assertFail.bind(this), _sbrk: this.c_sbrk.bind(this) }; this.brk = this.align(this.moduleInfo.memorySize + this.stackSize); WebAssembly.instantiate(buffer, {env: env}).then(function(results){ this.instance = results.instance; if (this.instance.exports.__post_instantiate) { this.instance.exports.__post_instantiate(); } this.createHeapViews(); this.ready = true; callback && callback(this); }.bind(this)) }; WASM.prototype.createHeapViews = function() { this.instance.heapU8 = new Uint8Array(this.memory.buffer); this.instance.heapU32 = new Uint32Array(this.memory.buffer); this.instance.heapF32 = new Float32Array(this.memory.buffer); }; WASM.prototype.align = function(addr) { var a = Math.pow(2, this.moduleInfo.memoryAlignment); return Math.ceil(addr / a) * a; }; WASM.prototype.c_sbrk = function(size) { var previousBrk = this.brk; this.brk += size; if (this.brk > this.memory.buffer.byteLength) { var bytesNeeded = this.brk - this.memory.buffer.byteLength; var pagesNeeded = Math.ceil(bytesNeeded / this.pageSize); this.memory.grow(pagesNeeded); this.createHeapViews(); } return previousBrk; }; WASM.prototype.c_abort = function(size) { console.warn('JSMPeg: WASM abort', arguments); }; WASM.prototype.c_assertFail = function(size) { console.warn('JSMPeg: WASM ___assert_fail', arguments); }; WASM.prototype.readDylinkSection = function(buffer) { // Read the WASM header and dylink section of the .wasm binary data // to get the needed table size and static data size. // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md // https://github.com/kripken/emscripten/blob/20602efb955a7c6c20865a495932427e205651d2/src/support.js var bytes = new Uint8Array(buffer); var next = 0; var readVarUint = function () { var ret = 0; var mul = 1; while (1) { var byte = bytes[next++]; ret += ((byte & 0x7f) * mul); mul *= 0x80; if (!(byte & 0x80)) { return ret } } } var matchNextBytes = function(expected) { for (var i = 0; i < expected.length; i++) { var b = typeof(expected[i]) === 'string' ? expected[i].charCodeAt(0) : expected[i]; if (bytes[next++] !== b) { return false; } } return true; }; // Make sure we have a wasm header if (!matchNextBytes([0, 'a', 's', 'm'])) { console.warn('JSMpeg: WASM header not found'); return null; } // Make sure we have a dylink section var next = 9; var sectionSize = readVarUint(); if (!matchNextBytes([6, 'd', 'y', 'l', 'i', 'n', 'k'])) { console.warn('JSMpeg: No dylink section found in WASM'); return null; } return { memorySize: readVarUint(), memoryAlignment: readVarUint(), tableSize: readVarUint(), tableAlignment: readVarUint() }; }; WASM.IsSupported = function() { return (!!window.WebAssembly); }; WASM.GetModule = function() { WASM.CACHED_MODULE = WASM.CACHED_MODULE || new WASM(); return WASM.CACHED_MODULE; }; return WASM; })();