atomics_test.js 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. // ESNext SharedArrayBuffer tests
  6. WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
  7. var atomicsFunctionsList = [
  8. {op : Atomics.add, fullname: "Atomics.add", length : 3},
  9. {op : Atomics.and, fullname: "Atomics.and", length : 3},
  10. {op : Atomics.compareExchange, fullname: "Atomics.compareExchange", length : 4},
  11. {op : Atomics.exchange, fullname: "Atomics.exchange", length : 3},
  12. {op : Atomics.load, fullname: "Atomics.load", length : 2},
  13. {op : Atomics.or, fullname: "Atomics.or", length : 3},
  14. {op : Atomics.store, fullname: "Atomics.store", length : 3},
  15. {op : Atomics.sub, fullname: "Atomics.sub", length : 3},
  16. {op : Atomics.xor, fullname: "Atomics.xor", length : 3},
  17. ];
  18. var atomicsFunctionsList2 = [
  19. {op : Atomics.wait, fullname: "Atomics.wait", onlyInt32:true, length : 4},
  20. {op : Atomics.wake, fullname: "Atomics.wake", onlyInt32:true, length : 3},
  21. ];
  22. var allAtomicsFunctionsList = [...atomicsFunctionsList, ...atomicsFunctionsList2, {op : Atomics.isLockFree, fullname: "Atomics.isLockFree", length : 1}];
  23. var IntViews = [
  24. {ctor : Int8Array},
  25. {ctor : Int16Array},
  26. {ctor : Int32Array},
  27. {ctor : Uint8Array},
  28. {ctor : Uint16Array},
  29. {ctor : Uint32Array},
  30. ];
  31. var tests = [{
  32. name : "Atomics's operation sanity validation",
  33. body : function () {
  34. assert.throws(() => Atomics(), TypeError, "Atomics cannot be called", "Function expected");
  35. assert.throws(() => new Atomics(), TypeError, "Atomics cannot be called with new", "Object doesn't support this action");
  36. for (var {op, length} of allAtomicsFunctionsList) {
  37. assert.areEqual(typeof op, "function", "Atomics has " + op.name + " as a function");
  38. assert.areEqual(op.length, length, "Validating " + op.name + ".length");
  39. assert.throws(() => new op(), TypeError, op.name +" cannot be called with new", "Function is not a constructor");
  40. }
  41. }
  42. }, {
  43. name : "Atomics's operation allowed on SharedArrayBuffer only",
  44. body : function () {
  45. var nonInt32Views = [new Int8Array(new SharedArrayBuffer(8)),
  46. new Uint8Array(new SharedArrayBuffer(8)),
  47. new Int16Array(new SharedArrayBuffer(8)),
  48. new Uint16Array(new SharedArrayBuffer(8)),
  49. new Uint32Array(new SharedArrayBuffer(8))];
  50. for (var {op, fullname} of allAtomicsFunctionsList) {
  51. assert.throws(() => op(), RangeError, op.name +" requires parameter", fullname+": function called with too few arguments");
  52. }
  53. for (var {op, fullname, onlyInt32} of [...atomicsFunctionsList, ...atomicsFunctionsList2]) {
  54. [undefined, null, 1, {}, [], new Array()].forEach(function(o) {
  55. assert.throws(() => op(o, 0, 0, 0), TypeError, op.name +" is not allowed on this object",
  56. "Atomics function called with invalid typed array object");
  57. });
  58. if (onlyInt32)
  59. {
  60. assert.throws(() => op(new Int8Array(1), 0, 0, 0), TypeError, op.name +" is not allowed on Int8Array of ArrayBuffer",
  61. "The operation is not supported on this typed array type");
  62. for (var j of nonInt32Views) {
  63. assert.throws(() => op(new Int8Array(1), 0, 0, 0), TypeError, op.name +" is not allowed",
  64. "The operation is not supported on this typed array type");
  65. }
  66. }
  67. else
  68. {
  69. assert.throws(() => op(new Int8Array(1), 0, 0, 0), TypeError, op.name +" is not allowed on Int8Array of ArrayBuffer",
  70. "SharedArrayBuffer object expected");
  71. }
  72. assert.throws(() => op(new Float32Array(1), 0, 0, 0), TypeError, op.name +" is not allowed on Float32Array of ArrayBuffer",
  73. "The operation is not supported on this typed array type");
  74. assert.throws(() => op(new Float32Array(new SharedArrayBuffer(8)), 0, 0, 0), TypeError, op.name +" is not allowed on Float32Array",
  75. "The operation is not supported on this typed array type");
  76. assert.throws(() => op(new Float64Array(new SharedArrayBuffer(8)), 0, 0, 0), TypeError, op.name +" is not allowed on Float64Array",
  77. "The operation is not supported on this typed array type");
  78. }
  79. }
  80. },
  81. {
  82. name : "Atomics.add/and/exchange/or/store/sub/xor negative scenario",
  83. body : function () {
  84. atomicsFunctionsList.forEach(function(atomicFunction) {
  85. if (atomicFunction.length != 3) {
  86. return;
  87. }
  88. IntViews.forEach(function(item) {
  89. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  90. var sab = new SharedArrayBuffer(item.ctor.BYTES_PER_ELEMENT * elements);
  91. var view = new item.ctor(sab, offset * item.ctor.BYTES_PER_ELEMENT, length);
  92. assert.throws(() => atomicFunction.op(view), RangeError, "Calling "+atomicFunction.fullname+" with 1 param only is not valid", atomicFunction.fullname+": function called with too few arguments");
  93. assert.throws(() => atomicFunction.op(view, 0), RangeError, "Calling "+atomicFunction.fullname+" with 2 params only is not valid", atomicFunction.fullname+": function called with too few arguments");
  94. [undefined, -1, 1.1, "hi", NaN, {}, Infinity, -Infinity].forEach(function (index) {
  95. assert.throws(() => atomicFunction.op(view, index, 1), RangeError, "Only positive interger allowed, not " + index, "Access index is out of range");
  96. });
  97. assert.throws(() => atomicFunction.op(view, elements, 1), RangeError, "index is out of bound " + elements, "Access index is out of range");
  98. assert.throws(() => atomicFunction.op(view, length, 1), RangeError, "index is out of bound " + length, "Access index is out of range");
  99. Object.defineProperty(view, 'length', {
  100. get : function () {
  101. return elements + 10;
  102. }
  103. });
  104. assert.throws(() => atomicFunction.op(view, elements + 1, 1), RangeError, "Changing 'length' property does not affect the index", "Access index is out of range");
  105. });
  106. });
  107. });
  108. }
  109. },
  110. {
  111. name : "Atomics.compareExchange negative scenario",
  112. body : function () {
  113. IntViews.forEach(function(item) {
  114. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  115. var sab = new SharedArrayBuffer(item.ctor.BYTES_PER_ELEMENT * elements);
  116. var view = new item.ctor(sab, offset * item.ctor.BYTES_PER_ELEMENT, length);
  117. assert.throws(() => Atomics.compareExchange(view), RangeError, "Calling Atomics.compareExchange with 1 param only is not valid", "Atomics.compareExchange: function called with too few arguments");
  118. assert.throws(() => Atomics.compareExchange(view, 0), RangeError, "Calling Atomics.compareExchange with 2 params only is not valid", "Atomics.compareExchange: function called with too few arguments");
  119. assert.throws(() => Atomics.compareExchange(view, 0, 0), RangeError, "Calling Atomics.compareExchange with 3 params only is not valid", "Atomics.compareExchange: function called with too few arguments");
  120. [undefined, -1, 1.1, "hi", NaN, {}, Infinity, -Infinity].forEach(function (index) {
  121. assert.throws(() => Atomics.compareExchange(view, index, 0, 0), RangeError, "Only positive interger allowed not, " + index, "Access index is out of range");
  122. });
  123. assert.throws(() => Atomics.compareExchange(view, elements, 0, 0), RangeError, "index is out of bound " + elements, "Access index is out of range");
  124. assert.throws(() => Atomics.compareExchange(view, length, 0, 0), RangeError, "index is out of bound " + length, "Access index is out of range");
  125. });
  126. });
  127. }
  128. },
  129. {
  130. name : "Atomics.load negative scenario",
  131. body : function () {
  132. IntViews.forEach(function(item) {
  133. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  134. var sab = new SharedArrayBuffer(item.ctor.BYTES_PER_ELEMENT * elements);
  135. var view = new item.ctor(sab, offset * item.ctor.BYTES_PER_ELEMENT, length);
  136. assert.throws(() => Atomics.load(view), RangeError, "Calling Atomics.load with 1 param only is not valid", "Atomics.load: function called with too few arguments");
  137. [undefined, -1, 1.1, "hi", NaN, {}, Infinity, -Infinity].forEach(function (index) {
  138. assert.throws(() => Atomics.load(view, index), RangeError, "Only positive interger allowed, not " + index, "Access index is out of range");
  139. });
  140. assert.throws(() => Atomics.load(view, elements), RangeError, "index is out of bound " + elements, "Access index is out of range");
  141. assert.throws(() => Atomics.load(view, length), RangeError, "index is out of bound " + length, "Access index is out of range");
  142. });
  143. });
  144. }
  145. },
  146. {
  147. name : "Atomics.wait negative scenario",
  148. body : function () {
  149. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  150. var sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * elements);
  151. var view = new Int32Array(sab, offset * Int32Array.BYTES_PER_ELEMENT, length);
  152. assert.throws(() => Atomics.wait(view), RangeError, "Calling Atomics.wait with 1 param only is not valid", "Atomics.wait: function called with too few arguments");
  153. assert.throws(() => Atomics.wait(view, 0), RangeError, "Calling Atomics.wait with 1 param only is not valid", "Atomics.wait: function called with too few arguments");
  154. [undefined, -1, 1.1, "hi", NaN, {}, Infinity, -Infinity].forEach(function (index) {
  155. assert.throws(() => Atomics.wait(view, index, 0), RangeError, "Only positive interger allowed, not " + index, "Access index is out of range");
  156. });
  157. assert.throws(() => Atomics.wait(view, elements, 0), RangeError, "index is out of bound " + elements, "Access index is out of range");
  158. assert.throws(() => Atomics.wait(view, length, 0), RangeError, "index is out of bound " + length, "Access index is out of range");
  159. });
  160. }
  161. },
  162. {
  163. name : "Atomics.wake negative scenario",
  164. body : function () {
  165. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  166. var sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * elements);
  167. var view = new Int32Array(sab, offset * Int32Array.BYTES_PER_ELEMENT, length);
  168. assert.throws(() => Atomics.wake(view), RangeError, "Calling Atomics.wake with 1 param only is not valid", "Atomics.wake: function called with too few arguments");
  169. [undefined, -1, 1.1, "hi", NaN, {}, Infinity, -Infinity].forEach(function (index) {
  170. assert.throws(() => Atomics.wake(view, index, 1), RangeError, "Only positive interger allowed, not " + index, "Access index is out of range");
  171. });
  172. assert.throws(() => Atomics.wake(view, elements, 1), RangeError, "index is out of bound " + elements, "Access index is out of range");
  173. assert.throws(() => Atomics.wake(view, length, 1), RangeError, "index is out of bound " + length, "Access index is out of range");
  174. });
  175. }
  176. },
  177. {
  178. name : "Atomics.add/and/exchange/or/store/sub/xor functionality",
  179. body : function () {
  180. function ValidateAtomicOpFunctionality(ctor, atomicsOp, data) {
  181. [[0, 8, 8], [6, 2, 8]].forEach(function([offset, length, elements]) {
  182. var sab = new SharedArrayBuffer(elements * ctor.BYTES_PER_ELEMENT);
  183. var view = new ctor(sab, offset * ctor.BYTES_PER_ELEMENT, length);
  184. for (var {initValue, opValue, expectedReturn, expectedValue} of data) {
  185. if (initValue !== undefined) {
  186. view[1] = initValue;
  187. }
  188. var ret = atomicsOp(view, 1, opValue);
  189. assert.areEqual(ret, expectedReturn, "return value validation " + ctor.name + " " + atomicsOp.name);
  190. assert.areEqual(view[1], expectedValue, "final value validation " + ctor.name + " " + atomicsOp.name);
  191. assert.areEqual(Atomics.load(view, 1), expectedValue, "final value validation " + ctor.name + " " + atomicsOp.name);
  192. assert.areEqual(view[0], 0, "view[0] should not be affected");
  193. }
  194. });
  195. }
  196. ValidateAtomicOpFunctionality(Int8Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  197. {initValue: undefined, opValue : 0x7B, expectedReturn : 6, expectedValue : -127},
  198. {initValue: undefined, opValue : 10, expectedReturn : -127, expectedValue : -117},
  199. {initValue: 0, opValue : 0x104, expectedReturn : 0, expectedValue : 4}] );
  200. ValidateAtomicOpFunctionality(Uint8Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  201. {initValue: undefined, opValue : 0xFB, expectedReturn : 6, expectedValue : 1},
  202. {initValue: undefined, opValue : 0x80, expectedReturn : 1, expectedValue : 0x81},
  203. {initValue: 0, opValue : 0x104, expectedReturn : 0, expectedValue : 4}] );
  204. ValidateAtomicOpFunctionality(Int16Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  205. {initValue: undefined, opValue : 0x7FFB, expectedReturn : 6, expectedValue : -32767},
  206. {initValue: undefined, opValue : 20, expectedReturn : -32767, expectedValue : -32747},
  207. {initValue: 0, opValue : 0x10004, expectedReturn : 0, expectedValue : 4}] );
  208. ValidateAtomicOpFunctionality(Uint16Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  209. {initValue: undefined, opValue : 0xFFFB, expectedReturn : 6, expectedValue : 1},
  210. {initValue: undefined, opValue : 0x8000, expectedReturn : 1, expectedValue : 0x8001},
  211. {initValue: 0, opValue : 0x10004, expectedReturn : 0, expectedValue : 4}] );
  212. ValidateAtomicOpFunctionality(Int32Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  213. {initValue: undefined, opValue : 0x7FFFFFFB, expectedReturn : 6, expectedValue : -0x7FFFFFFF},
  214. {initValue: undefined, opValue : 0x7FFFFFFF, expectedReturn : -0x7FFFFFFF, expectedValue : 0},
  215. {initValue: 0, opValue : 0x100000004, expectedReturn : 0, expectedValue : 4}] );
  216. ValidateAtomicOpFunctionality(Uint32Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  217. {initValue: undefined, opValue : 0xFFFFFFFB, expectedReturn : 6, expectedValue : 1},
  218. {initValue: undefined, opValue : 0x7FFFFFFF, expectedReturn : 1, expectedValue : 0x80000000},
  219. {initValue: 0, opValue : 0x100000004, expectedReturn : 0, expectedValue : 4}] );
  220. // Atomics.and tests
  221. ValidateAtomicOpFunctionality(Int8Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  222. {initValue: 0x5C, opValue : 0x1B, expectedReturn : 0x5C, expectedValue : 0x18},
  223. {initValue: undefined, opValue : 0x108, expectedReturn : 0x18, expectedValue : 8},
  224. {initValue: 0x7F, opValue : 0x80, expectedReturn : 0x7F, expectedValue : 0}] );
  225. ValidateAtomicOpFunctionality(Uint8Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  226. {initValue: 0x5C, opValue : 0x1B, expectedReturn : 0x5C, expectedValue : 0x18},
  227. {initValue: undefined, opValue : 0x108, expectedReturn : 0x18, expectedValue : 8},
  228. {initValue: 0xFF, opValue : 0x101, expectedReturn : 0xFF, expectedValue : 1}] );
  229. ValidateAtomicOpFunctionality(Int16Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  230. {initValue: 0x7FFB, opValue : 0x1006, expectedReturn : 0x7FFB, expectedValue : 0x1002},
  231. {initValue: undefined, opValue : 0x10008, expectedReturn : 0x1002, expectedValue : 0},
  232. {initValue: 0x7FFF, opValue : 0x8004, expectedReturn : 0x7FFF, expectedValue : 4}] );
  233. ValidateAtomicOpFunctionality(Uint16Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  234. {initValue: 0xBFFC, opValue : 0xA00B, expectedReturn : 0xBFFC, expectedValue : 0xA008},
  235. {initValue: undefined, opValue : 0x10009, expectedReturn : 0xA008, expectedValue : 8},
  236. {initValue: 0xFFFF, opValue : 0x10004, expectedReturn : 0xFFFF, expectedValue : 4}] );
  237. ValidateAtomicOpFunctionality(Int32Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  238. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0x1FFFFFF8},
  239. {initValue: undefined, opValue : 0x8, expectedReturn : 0x1FFFFFF8, expectedValue : 8},
  240. {initValue: 0x7FFFFFFF, opValue : 0x100000004, expectedReturn : 0x7FFFFFFF, expectedValue : 4}] );
  241. ValidateAtomicOpFunctionality(Uint32Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  242. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0x1FFFFFF8},
  243. {initValue: undefined, opValue : 0x8, expectedReturn : 0x1FFFFFF8, expectedValue : 8},
  244. {initValue: 0x9FFFFFFF, opValue : 0x100000004, expectedReturn : 0x9FFFFFFF, expectedValue : 4}] );
  245. // Atomics.exchange tests
  246. ValidateAtomicOpFunctionality(Int8Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  247. {initValue: 0x9C, opValue : 0x1B, expectedReturn : -100, expectedValue : 0x1B},
  248. {initValue: undefined, opValue : 0x108, expectedReturn : 0x1B, expectedValue : 8}]);
  249. ValidateAtomicOpFunctionality(Uint8Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  250. {initValue: 0x9C, opValue : 0x1B, expectedReturn : 0x9C, expectedValue : 0x1B},
  251. {initValue: undefined, opValue : 0x108, expectedReturn : 0x1B, expectedValue : 8}]);
  252. ValidateAtomicOpFunctionality(Int16Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  253. {initValue: 0x9FFB, opValue : 0x1006, expectedReturn : -24581, expectedValue : 0x1006},
  254. {initValue: undefined, opValue : 0x10008, expectedReturn : 0x1006, expectedValue : 8}]);
  255. ValidateAtomicOpFunctionality(Uint16Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  256. {initValue: 0x9FFB, opValue : 0x1006, expectedReturn : 0x9FFB, expectedValue : 0x1006},
  257. {initValue: undefined, opValue : 0x10008, expectedReturn : 0x1006, expectedValue : 8}]);
  258. ValidateAtomicOpFunctionality(Int32Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  259. {initValue: 0x9FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : -1610612740, expectedValue : -1073741829},
  260. {initValue: undefined, opValue : 8, expectedReturn : -1073741829, expectedValue : 8}] );
  261. ValidateAtomicOpFunctionality(Uint32Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  262. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0xBFFFFFFB},
  263. {initValue: undefined, opValue : 0x100000004, expectedReturn : 0xBFFFFFFB, expectedValue : 4}] );
  264. // Atomics.or tests
  265. ValidateAtomicOpFunctionality(Int8Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  266. {initValue: 0x5C, opValue : 0x1F, expectedReturn : 0x5C, expectedValue : 0x5F},
  267. {initValue: undefined, opValue : 0x120, expectedReturn : 0x5F, expectedValue : 0x7F}] );
  268. ValidateAtomicOpFunctionality(Uint8Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  269. {initValue: 0x5C, opValue : 0x8F, expectedReturn : 0x5C, expectedValue : 0xDF},
  270. {initValue: undefined, opValue : 0x120, expectedReturn : 0xDF, expectedValue : 0xFF}] );
  271. ValidateAtomicOpFunctionality(Int16Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  272. {initValue: 0x700B, opValue : 0x0F00, expectedReturn : 0x700B, expectedValue : 0x7F0B},
  273. {initValue: undefined, opValue : 0x100F6, expectedReturn : 0x7F0B, expectedValue : 0x7FFF}] );
  274. ValidateAtomicOpFunctionality(Uint16Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  275. {initValue: 0xBFFC, opValue : 0xA00B, expectedReturn : 0xBFFC, expectedValue : 0xBFFF},
  276. {initValue: 0x10, opValue : 0x10009, expectedReturn : 0x10, expectedValue : 0x19}] );
  277. ValidateAtomicOpFunctionality(Int32Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  278. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : -1},
  279. {initValue: 0x100000004, opValue : 0x80, expectedReturn : 0x4, expectedValue : 0x84}] );
  280. ValidateAtomicOpFunctionality(Uint32Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  281. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0xFFFFFFFF},
  282. {initValue: 0x100000004, opValue : 0x80, expectedReturn : 0x4, expectedValue : 0x84}] );
  283. // Atomics.store tests
  284. ValidateAtomicOpFunctionality(Int8Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  285. {initValue: undefined, opValue : 0xFF, expectedReturn : 0xFF, expectedValue : -1}] );
  286. ValidateAtomicOpFunctionality(Uint8Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  287. {initValue: undefined, opValue : 0x1FF, expectedReturn : 0x1FF, expectedValue : 0xFF}] );
  288. ValidateAtomicOpFunctionality(Int16Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  289. {initValue: undefined, opValue : 0xFFFF, expectedReturn : 0xFFFF, expectedValue : -1}] );
  290. ValidateAtomicOpFunctionality(Uint16Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  291. {initValue: undefined, opValue : 0x1FFFF, expectedReturn : 0x1FFFF, expectedValue : 0xFFFF}] );
  292. ValidateAtomicOpFunctionality(Int32Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  293. {initValue: undefined, opValue : 0xFFFFFFFF, expectedReturn : 0xFFFFFFFF, expectedValue : -1}] );
  294. ValidateAtomicOpFunctionality(Uint32Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  295. {initValue: undefined, opValue : 0x1FFFFFFFF, expectedReturn : 0x1FFFFFFFF, expectedValue : 0xFFFFFFFF}] );
  296. // Atomics.sub tests
  297. ValidateAtomicOpFunctionality(Int8Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  298. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : -25},
  299. {initValue: 0x9C, opValue : 0x1B, expectedReturn : -100, expectedValue : -127},
  300. {initValue: 0x7F, opValue : 0x80, expectedReturn : 0x7F, expectedValue : -1}] );
  301. ValidateAtomicOpFunctionality(Uint8Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  302. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : 231},
  303. {initValue: 0x9C, opValue : 0x1B, expectedReturn : 0x9C, expectedValue : 129},
  304. {initValue: 0x7F, opValue : 0x80, expectedReturn : 0x7F, expectedValue : 255}] );
  305. ValidateAtomicOpFunctionality(Int16Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  306. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : -25},
  307. {initValue: 0x7FFF, opValue : 0x8004, expectedReturn : 0x7FFF, expectedValue : -5}] );
  308. ValidateAtomicOpFunctionality(Uint16Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  309. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : 65511},
  310. {initValue: 0x7FFF, opValue : 0x8004, expectedReturn : 0x7FFF, expectedValue : 65531}] );
  311. ValidateAtomicOpFunctionality(Int32Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  312. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : -25},
  313. {initValue: 0x7FFFFFFF, opValue : 0x100000004, expectedReturn : 0x7FFFFFFF, expectedValue : 2147483643}] );
  314. ValidateAtomicOpFunctionality(Uint32Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  315. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : 0xFFFFFFE7},
  316. {initValue: 0x9FFFFFFF, opValue : 5, expectedReturn : 0x9FFFFFFF, expectedValue : 0x9FFFFFFA}] );
  317. // Atomics.xor tests
  318. ValidateAtomicOpFunctionality(Int8Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  319. {initValue: 0x5C, opValue : 0x8F, expectedReturn : 0x5C, expectedValue : -45}] );
  320. ValidateAtomicOpFunctionality(Uint8Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  321. {initValue: 0x5C, opValue : 0x8F, expectedReturn : 0x5C, expectedValue : 0xD3}] );
  322. ValidateAtomicOpFunctionality(Int16Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  323. {initValue: 0x700B, opValue : 0x8F00, expectedReturn : 0x700B, expectedValue : -245}] );
  324. ValidateAtomicOpFunctionality(Uint16Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  325. {initValue: 0x700B, opValue : 0x8F00, expectedReturn : 0x700B, expectedValue : 0xFF0B}] );
  326. ValidateAtomicOpFunctionality(Int32Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  327. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : -536870905}] );
  328. ValidateAtomicOpFunctionality(Uint32Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  329. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0xE0000007}] );
  330. }
  331. },
  332. {
  333. name : "Atomics.load functionality",
  334. body : function () {
  335. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  336. IntViews.forEach(function ({ctor}) {
  337. var sab = new SharedArrayBuffer(ctor.BYTES_PER_ELEMENT * elements);
  338. var view = new ctor(sab, offset * ctor.BYTES_PER_ELEMENT, length);
  339. view[1] = 20;
  340. var ret = Atomics.load(view, 1);
  341. assert.areEqual(ret, 20, "value validation " + ctor.name);
  342. assert.areEqual(view[0], 0, "view[0] should not be affected");
  343. });
  344. });
  345. }
  346. },
  347. {
  348. name : "Atomics.compareExchange functionality",
  349. body : function () {
  350. IntViews.forEach(function({ctor}) {
  351. [[0, 8, 8], [6, 2, 8]].forEach(function([offset, length, elements]) {
  352. var sab = new SharedArrayBuffer(elements * ctor.BYTES_PER_ELEMENT);
  353. var view = new ctor(sab, offset * ctor.BYTES_PER_ELEMENT, length);
  354. view[1] = 10;
  355. var ret = Atomics.compareExchange(view, 1, 10, 20);
  356. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  357. assert.areEqual(view[1], 20, "value validation " + ctor.name);
  358. var ret = Atomics.compareExchange(view, 1, 5, 30);
  359. assert.areEqual(ret, 20, "compared failed - return value validation " + ctor.name);
  360. assert.areEqual(view[1], 20, "compared failed - value validation " + ctor.name);
  361. });
  362. });
  363. }
  364. },
  365. {
  366. name : "Atomics operations ToInteger verification",
  367. body : function () {
  368. var valueOf = {
  369. valueOf : () => 1
  370. };
  371. var toString = {
  372. toString : () => 1
  373. };
  374. IntViews.forEach(function({ctor}) {
  375. [undefined, NaN, null, Number.POSITIVE_INFINITY, true, "1", "blah", 1.1, valueOf, toString].forEach(function(value) {
  376. var sab = new SharedArrayBuffer(2 * ctor.BYTES_PER_ELEMENT);
  377. var view = new ctor(sab);
  378. var num = value | 0;
  379. view[1] = 10;
  380. var ret = Atomics.add(view, 1, value);
  381. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  382. assert.areEqual(view[1], 10 + num, "final value validation " + ctor.name);
  383. view[1] = 10;
  384. var ret = Atomics.and(view, 1, value);
  385. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  386. assert.areEqual(view[1], 10 & num, "final value validation " + ctor.name);
  387. view[1] = 10;
  388. var ret = Atomics.compareExchange(view, 1, 10, value);
  389. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  390. assert.areEqual(view[1], num, "final value validation " + ctor.name);
  391. view[1] = 10;
  392. var ret = Atomics.exchange(view, 1, value);
  393. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  394. assert.areEqual(view[1], num, "final value validation " + ctor.name);
  395. view[1] = 10;
  396. var ret = Atomics.or(view, 1, value);
  397. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  398. assert.areEqual(view[1], 10 | num, "final value validation " + ctor.name);
  399. view[1] = 10;
  400. var ret = Atomics.sub(view, 1, value);
  401. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  402. assert.areEqual(view[1], 10 - num, "final value validation " + ctor.name);
  403. view[1] = 10;
  404. var ret = Atomics.store(view, 1, value);
  405. if (value !== Number.POSITIVE_INFINITY)
  406. {
  407. assert.areEqual(ret, num, "return value validation " + ctor.name);
  408. }
  409. assert.areEqual(view[1], num, "final value validation " + ctor.name);
  410. view[1] = 10;
  411. var ret = Atomics.xor(view, 1, value);
  412. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  413. assert.areEqual(view[1], 10 ^ num, "final value validation " + ctor.name);
  414. });
  415. });
  416. }
  417. },
  418. {
  419. name : "Atomics.add buffer/length invalidation",
  420. body : function () {
  421. var sab = new SharedArrayBuffer(16);
  422. var view = new Int8Array(sab, 0, 8);
  423. var lengthChange = {
  424. valueOf : function() {
  425. view.length = 0;
  426. return 2;
  427. }
  428. };
  429. var lengthChange1 = {
  430. valueOf : function() {
  431. Object.defineProperty(view, 'length', {
  432. get : function () {
  433. return 0;
  434. }
  435. });
  436. return 2;
  437. }
  438. }
  439. var bufferChange = {
  440. valueOf : function() {
  441. view.buffer = null;
  442. return 2;
  443. }
  444. }
  445. view[1] = 0;
  446. Atomics.add(view, 1, lengthChange);
  447. assert.areEqual(view[1], 2, "Changing view's length does not affect the 'add'");
  448. view[1] = 0;
  449. Atomics.add(view, 1, lengthChange1);
  450. assert.areEqual(view[1], 2, "Changing view's length by defineProperty does not affect the 'add'");
  451. view[1] = 0;
  452. Atomics.add(view, 1, bufferChange);
  453. assert.areEqual(view[1], 2, "Changing the buffer does not affect the 'add'");
  454. }
  455. },
  456. {
  457. name : "Atomics ops on subclassed shared array buffer",
  458. body : function () {
  459. class MySAB extends SharedArrayBuffer {
  460. }
  461. var sab = new MySAB(16);
  462. assert.isTrue(sab instanceof MySAB, "object is instance of subclass of SharedArrayBuffer");
  463. assert.isTrue(sab instanceof SharedArrayBuffer, "object is instance of SharedArrayBuffer");
  464. var view = new Int8Array(sab, 0, 8);
  465. view[1] = 10;
  466. var ret = Atomics.add(view, 1, 20);
  467. assert.areEqual(ret, 10, "return value validation ");
  468. assert.areEqual(Atomics.load(view, 1), 30, "final value validation");
  469. }
  470. },
  471. {
  472. name : "Atomics.wait index test",
  473. body : function () {
  474. var view = new Int32Array(new SharedArrayBuffer(8));
  475. assert.doesNotThrow(() => Atomics.wait(view, 0, 0, 0), "Atomics.wait is allowed on the index 0, where the view's length is 2");
  476. assert.doesNotThrow(() => Atomics.wait(view, "0", 0, 0), "ToNumber : Atomics.wait is allowed on the index 0, where the view's length is 2");
  477. assert.throws(() => Atomics.wait(view, 2, 0, 0), RangeError, "Index is greater than the view's length", "Access index is out of range");
  478. assert.throws(() => Atomics.wait(view, -1, 0, 0), RangeError, "Negative index is not allowed", "Access index is out of range");
  479. }
  480. },
  481. {
  482. name : "Atomics.wait value match",
  483. body : function () {
  484. var view = new Int32Array(new SharedArrayBuffer(8));
  485. [2, "2", {valueOf : () => 2}].forEach(function(value) {
  486. view[0] = 1;
  487. var ret = Atomics.wait(view, 0, value, 0);
  488. assert.areEqual(ret, "not-equal", "value is not matching with 1 and 'wait' will return as 'not-equal'");
  489. });
  490. [10, "10", {valueOf : () => 10}].forEach(function(value) {
  491. view[0] = 10;
  492. var ret = Atomics.wait(view, 0, value, 5);
  493. assert.areEqual(ret, "timed-out", "value should match with 10 and 'wait' will wait till time-out");
  494. });
  495. view[0] = 10;
  496. var ret = Atomics.wait(view, 0, 10, Number.NEGATIVE_INFINITY);
  497. assert.areEqual(ret, "timed-out", "Negative infinity will be treated as 0 and so this will time-out");
  498. }
  499. },
  500. ];
  501. testRunner.runTests(tests, {
  502. verbose : WScript.Arguments[0] != "summary"
  503. });