memory.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft Corporation and contributors. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. const cliArgs = WScript.Arguments || [];
  6. if (cliArgs.indexOf("--help") !== -1) {
  7. print("usage: ch memory.js -args [-verbose] -endargs");
  8. WScript.quit(0);
  9. }
  10. // Parse arguments
  11. let verbose = 0;
  12. while (true) {
  13. const iVerbose = cliArgs.indexOf("-verbose");
  14. if (iVerbose === -1) {
  15. break;
  16. }
  17. cliArgs.splice(iVerbose, 1);
  18. ++verbose;
  19. }
  20. function testTransfer(buffer) {
  21. if (ArrayBuffer.transfer) {
  22. try {
  23. ArrayBuffer.transfer(buffer);
  24. print("Failed. Expected an error when trying to transfer ");
  25. } catch (e) {
  26. if (verbose > 1) {
  27. print(`Passed. Expected error: ${e.message}`);
  28. }
  29. }
  30. } else {
  31. print("ArrayBuffer.tranfer is missing");
  32. }
  33. }
  34. function test({init, max, checkOOM} = {}) {
  35. if (verbose) {
  36. print(`Testing memory {init: ${init|0}, max: ${max}}`);
  37. }
  38. const moduleTxt = `
  39. (module
  40. (memory (export "mem") ${init|0} ${max !== undefined ? max|0 : ""})
  41. (func (export "grow") (param i32) (result i32) (grow_memory (get_local 0)))
  42. (func (export "current") (result i32) (current_memory))
  43. (func (export "load") (param i32) (result i32) (i32.load (get_local 0)))
  44. (func (export "store") (param i32 i32) (i32.store (get_local 0) (get_local 1)))
  45. )`;
  46. if (verbose > 1) {
  47. print(moduleTxt);
  48. }
  49. const module = new WebAssembly.Module(WebAssembly.wabt.convertWast2Wasm(moduleTxt));
  50. let instance;
  51. try {
  52. instance = new WebAssembly.Instance(module);
  53. } catch (e) {
  54. if (!checkOOM || !e.message.includes("Failed to create WebAssembly.Memory")) {
  55. print(`FAILED. failed to instanciate module with error: ${e}`);
  56. } else if (verbose) {
  57. print(e.message);
  58. }
  59. return;
  60. }
  61. const {exports: {grow, current, load, store, mem}} = instance;
  62. function testReadWrite(index, value, currentSize) {
  63. const shouldTrap = index < 0 || (index + 4) > currentSize;
  64. const commonMsg = op => `trap on ${op}(${index}, ${value})`;
  65. try {
  66. store(index, value);
  67. if (shouldTrap) {
  68. print(`Failed. Expected ${commonMsg("store")}`);
  69. return;
  70. }
  71. } catch (e) {
  72. if (shouldTrap) {
  73. if (verbose) {
  74. print(`Passed. Expected ${commonMsg("store")}`);
  75. }
  76. } else {
  77. print(`Failed. Unexpected ${commonMsg("store")}`);
  78. }
  79. }
  80. try {
  81. const loadedValue = load(index);
  82. if (shouldTrap) {
  83. print(`Failed. Expected ${commonMsg("load")}`);
  84. return;
  85. }
  86. if ((loadedValue|0) !== (value|0)) {
  87. print(`Failed. Expected value ${value|0} after load. Got ${loadedValue|0}`);
  88. }
  89. } catch (e) {
  90. if (shouldTrap) {
  91. if (verbose) {
  92. print(`Passed. Expected ${commonMsg("load")}`);
  93. }
  94. } else {
  95. print(`Failed. Unexpected ${commonMsg("load")}`);
  96. }
  97. }
  98. }
  99. function run(delta) {
  100. testTransfer(mem.buffer);
  101. const beforePages = current();
  102. const growRes = grow(delta);
  103. if (growRes !== -1 && growRes !== beforePages) {
  104. print(`FAILED. Expected grow(${delta}) to return ${beforePages}`);
  105. }
  106. const afterPages = current();
  107. if (growRes !== -1 && beforePages + delta !== afterPages) {
  108. print(`FAILED. Expected to have ${beforePages + delta} pages. Got ${afterPages} pages`);
  109. }
  110. if (verbose) {
  111. print(`current: ${beforePages}, grow(${delta}): ${growRes}, after: ${afterPages}`);
  112. }
  113. const currentSize = afterPages * 0x10000;
  114. testReadWrite(-4, -4, currentSize);
  115. testReadWrite(-3, -3, currentSize);
  116. testReadWrite(-2, -2, currentSize);
  117. testReadWrite(-1, -1, currentSize);
  118. testReadWrite(0, 6, currentSize);
  119. testTransfer(mem.buffer);
  120. testReadWrite(1, 7, currentSize);
  121. testTransfer(mem.buffer);
  122. testReadWrite(1, 7, currentSize);
  123. testReadWrite(currentSize - 4, 457, currentSize);
  124. testReadWrite(currentSize - 3, -98745, currentSize);
  125. testReadWrite(currentSize - 2, 786452, currentSize);
  126. testReadWrite(currentSize - 1, -1324, currentSize);
  127. testReadWrite(currentSize, 123, currentSize);
  128. testTransfer(mem.buffer);
  129. }
  130. run(0);
  131. run(3);
  132. run(5);
  133. run(1 << 13);
  134. }
  135. test({init: 0});
  136. test({init: 0, max: 5});
  137. test({init: 0, max: 10});
  138. test({init: 5});
  139. test({init: 5, max: 10});
  140. // test({init: 1 << 14, checkOOM: true}); // ArrayBuffer will throw OOM instead of returning a null buffer
  141. try {
  142. test({init: 1 << 15});
  143. print("Failed. Expected an error when allocating WebAssembly.Memory too big");
  144. } catch (e) {
  145. if (verbose) {
  146. print(`Passed. Expected error: ${e.message}`);
  147. }
  148. }
  149. print("PASSED");