wasm-module.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. JSMpeg.WASMModule = (function(){ "use strict";
  2. var WASM = function() {
  3. this.stackSize = 5 * 1024 * 1024; // emscripten default
  4. this.pageSize = 64 * 1024; // wasm page size
  5. this.onInitCallback = null;
  6. this.ready = false;
  7. };
  8. WASM.prototype.write = function(buffer) {
  9. this.loadFromBuffer(buffer, this.onInitCallback);
  10. };
  11. WASM.prototype.loadFromFile = function(url, callback) {
  12. this.onInitCallback = callback;
  13. var ajax = new JSMpeg.Source.Ajax(url, {});
  14. ajax.connect(this);
  15. ajax.start();
  16. };
  17. WASM.prototype.loadFromBuffer = function(buffer, callback) {
  18. this.moduleInfo = this.readDylinkSection(buffer);
  19. if (!this.moduleInfo) {
  20. this.callback && this.callback(null);
  21. return;
  22. }
  23. this.memory = new WebAssembly.Memory({initial: 256});
  24. var env = {
  25. memory: this.memory,
  26. memoryBase: 0,
  27. __memory_base: 0,
  28. table: new WebAssembly.Table({initial: this.moduleInfo.tableSize, element: 'anyfunc'}),
  29. tableBase: 0,
  30. __table_base: 0,
  31. abort: this.c_abort.bind(this),
  32. ___assert_fail: this.c_assertFail.bind(this),
  33. _sbrk: this.c_sbrk.bind(this)
  34. };
  35. this.brk = this.align(this.moduleInfo.memorySize + this.stackSize);
  36. WebAssembly.instantiate(buffer, {env: env}).then(function(results){
  37. this.instance = results.instance;
  38. if (this.instance.exports.__post_instantiate) {
  39. this.instance.exports.__post_instantiate();
  40. }
  41. this.createHeapViews();
  42. this.ready = true;
  43. callback && callback(this);
  44. }.bind(this))
  45. };
  46. WASM.prototype.createHeapViews = function() {
  47. this.instance.heapU8 = new Uint8Array(this.memory.buffer);
  48. this.instance.heapU32 = new Uint32Array(this.memory.buffer);
  49. this.instance.heapF32 = new Float32Array(this.memory.buffer);
  50. };
  51. WASM.prototype.align = function(addr) {
  52. var a = Math.pow(2, this.moduleInfo.memoryAlignment);
  53. return Math.ceil(addr / a) * a;
  54. };
  55. WASM.prototype.c_sbrk = function(size) {
  56. var previousBrk = this.brk;
  57. this.brk += size;
  58. if (this.brk > this.memory.buffer.byteLength) {
  59. var bytesNeeded = this.brk - this.memory.buffer.byteLength;
  60. var pagesNeeded = Math.ceil(bytesNeeded / this.pageSize);
  61. this.memory.grow(pagesNeeded);
  62. this.createHeapViews();
  63. }
  64. return previousBrk;
  65. };
  66. WASM.prototype.c_abort = function(size) {
  67. console.warn('JSMPeg: WASM abort', arguments);
  68. };
  69. WASM.prototype.c_assertFail = function(size) {
  70. console.warn('JSMPeg: WASM ___assert_fail', arguments);
  71. };
  72. WASM.prototype.readDylinkSection = function(buffer) {
  73. // Read the WASM header and dylink section of the .wasm binary data
  74. // to get the needed table size and static data size.
  75. // https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
  76. // https://github.com/kripken/emscripten/blob/20602efb955a7c6c20865a495932427e205651d2/src/support.js
  77. var bytes = new Uint8Array(buffer);
  78. var next = 0;
  79. var readVarUint = function () {
  80. var ret = 0;
  81. var mul = 1;
  82. while (1) {
  83. var byte = bytes[next++];
  84. ret += ((byte & 0x7f) * mul);
  85. mul *= 0x80;
  86. if (!(byte & 0x80)) {
  87. return ret
  88. }
  89. }
  90. }
  91. var matchNextBytes = function(expected) {
  92. for (var i = 0; i < expected.length; i++) {
  93. var b = typeof(expected[i]) === 'string'
  94. ? expected[i].charCodeAt(0)
  95. : expected[i];
  96. if (bytes[next++] !== b) {
  97. return false;
  98. }
  99. }
  100. return true;
  101. };
  102. // Make sure we have a wasm header
  103. if (!matchNextBytes([0, 'a', 's', 'm'])) {
  104. console.warn('JSMpeg: WASM header not found');
  105. return null;
  106. }
  107. // Make sure we have a dylink section
  108. var next = 9;
  109. var sectionSize = readVarUint();
  110. if (!matchNextBytes([6, 'd', 'y', 'l', 'i', 'n', 'k'])) {
  111. console.warn('JSMpeg: No dylink section found in WASM');
  112. return null;
  113. }
  114. return {
  115. memorySize: readVarUint(),
  116. memoryAlignment: readVarUint(),
  117. tableSize: readVarUint(),
  118. tableAlignment: readVarUint()
  119. };
  120. };
  121. WASM.IsSupported = function() {
  122. return (!!window.WebAssembly);
  123. };
  124. WASM.GetModule = function() {
  125. WASM.CACHED_MODULE = WASM.CACHED_MODULE || new WASM();
  126. return WASM.CACHED_MODULE;
  127. };
  128. return WASM;
  129. })();