atomics_test.js 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  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, "hi", NaN, {}].forEach(function (index) {
  95. atomicFunction.op(view, index, 1);
  96. });
  97. [-1, Infinity, -Infinity].forEach(function (index) {
  98. assert.throws(() => atomicFunction.op(view, index, 1), RangeError, "Only positive interger allowed, not " + index, "Access index is out of range");
  99. });
  100. assert.throws(() => atomicFunction.op(view, elements, 1), RangeError, "index is out of bound " + elements, "Access index is out of range");
  101. assert.throws(() => atomicFunction.op(view, length, 1), RangeError, "index is out of bound " + length, "Access index is out of range");
  102. Object.defineProperty(view, 'length', {
  103. get : function () {
  104. return elements + 10;
  105. }
  106. });
  107. assert.throws(() => atomicFunction.op(view, elements + 1, 1), RangeError, "Changing 'length' property does not affect the index", "Access index is out of range");
  108. });
  109. });
  110. });
  111. }
  112. },
  113. {
  114. name : "Atomics.compareExchange negative scenario",
  115. body : function () {
  116. IntViews.forEach(function(item) {
  117. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  118. var sab = new SharedArrayBuffer(item.ctor.BYTES_PER_ELEMENT * elements);
  119. var view = new item.ctor(sab, offset * item.ctor.BYTES_PER_ELEMENT, length);
  120. assert.throws(() => Atomics.compareExchange(view), RangeError, "Calling Atomics.compareExchange with 1 param only is not valid", "Atomics.compareExchange: function called with too few arguments");
  121. 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");
  122. 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");
  123. [undefined, 1.1, "hi", NaN, {}].forEach(function (index) {
  124. Atomics.compareExchange(view, index, 0, 0);
  125. });
  126. [-1, Infinity, -Infinity].forEach(function (index) {
  127. assert.throws(() => Atomics.compareExchange(view, index, 0, 0), RangeError, "Only positive interger allowed not, " + index, "Access index is out of range");
  128. });
  129. assert.throws(() => Atomics.compareExchange(view, elements, 0, 0), RangeError, "index is out of bound " + elements, "Access index is out of range");
  130. assert.throws(() => Atomics.compareExchange(view, length, 0, 0), RangeError, "index is out of bound " + length, "Access index is out of range");
  131. });
  132. });
  133. }
  134. },
  135. {
  136. name : "Atomics.load negative scenario",
  137. body : function () {
  138. IntViews.forEach(function(item) {
  139. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  140. var sab = new SharedArrayBuffer(item.ctor.BYTES_PER_ELEMENT * elements);
  141. var view = new item.ctor(sab, offset * item.ctor.BYTES_PER_ELEMENT, length);
  142. assert.throws(() => Atomics.load(view), RangeError, "Calling Atomics.load with 1 param only is not valid", "Atomics.load: function called with too few arguments");
  143. [undefined, 1.1, "hi", NaN, {}].forEach(function (index) {
  144. Atomics.load(view, index);
  145. });
  146. [-1, Infinity, -Infinity].forEach(function (index) {
  147. assert.throws(() => Atomics.load(view, index), RangeError, "Only positive interger allowed, not " + index, "Access index is out of range");
  148. });
  149. assert.throws(() => Atomics.load(view, elements), RangeError, "index is out of bound " + elements, "Access index is out of range");
  150. assert.throws(() => Atomics.load(view, length), RangeError, "index is out of bound " + length, "Access index is out of range");
  151. });
  152. });
  153. }
  154. },
  155. {
  156. name : "Atomics.wait negative scenario",
  157. body : function () {
  158. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  159. var sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * elements);
  160. var view = new Int32Array(sab, offset * Int32Array.BYTES_PER_ELEMENT, length);
  161. assert.throws(() => Atomics.wait(view), RangeError, "Calling Atomics.wait with 1 param only is not valid", "Atomics.wait: function called with too few arguments");
  162. 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");
  163. [undefined, 1.1, "hi", NaN, {}].forEach(function (index) {
  164. Atomics.wait(view, index, 1);
  165. });
  166. [-1, Infinity, -Infinity].forEach(function (index) {
  167. assert.throws(() => Atomics.wait(view, index, 0), RangeError, "Only positive interger allowed, not " + index, "Access index is out of range");
  168. });
  169. assert.throws(() => Atomics.wait(view, elements, 0), RangeError, "index is out of bound " + elements, "Access index is out of range");
  170. assert.throws(() => Atomics.wait(view, length, 0), RangeError, "index is out of bound " + length, "Access index is out of range");
  171. });
  172. }
  173. },
  174. {
  175. name : "Atomics.wake negative scenario",
  176. body : function () {
  177. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  178. var sab = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT * elements);
  179. var view = new Int32Array(sab, offset * Int32Array.BYTES_PER_ELEMENT, length);
  180. assert.throws(() => Atomics.wake(view), RangeError, "Calling Atomics.wake with 1 param only is not valid", "Atomics.wake: function called with too few arguments");
  181. [undefined, 1.1, "hi", NaN, {}].forEach(function (index) {
  182. Atomics.wake(view, index, 1);
  183. });
  184. [-1, Infinity, -Infinity].forEach(function (index) {
  185. assert.throws(() => Atomics.wake(view, index, 1), RangeError, "Only positive interger allowed, not " + index, "Access index is out of range");
  186. });
  187. assert.throws(() => Atomics.wake(view, elements, 1), RangeError, "index is out of bound " + elements, "Access index is out of range");
  188. assert.throws(() => Atomics.wake(view, length, 1), RangeError, "index is out of bound " + length, "Access index is out of range");
  189. });
  190. }
  191. },
  192. {
  193. name : "Atomics.add/and/exchange/or/store/sub/xor functionality",
  194. body : function () {
  195. function ValidateAtomicOpFunctionality(ctor, atomicsOp, data) {
  196. [[0, 8, 8], [6, 2, 8]].forEach(function([offset, length, elements]) {
  197. var sab = new SharedArrayBuffer(elements * ctor.BYTES_PER_ELEMENT);
  198. var view = new ctor(sab, offset * ctor.BYTES_PER_ELEMENT, length);
  199. for (var {initValue, opValue, expectedReturn, expectedValue} of data) {
  200. if (initValue !== undefined) {
  201. view[1] = initValue;
  202. }
  203. var ret = atomicsOp(view, 1, opValue);
  204. assert.areEqual(ret, expectedReturn, "return value validation " + ctor.name + " " + atomicsOp.name);
  205. assert.areEqual(view[1], expectedValue, "final value validation " + ctor.name + " " + atomicsOp.name);
  206. assert.areEqual(Atomics.load(view, 1), expectedValue, "final value validation " + ctor.name + " " + atomicsOp.name);
  207. assert.areEqual(view[0], 0, "view[0] should not be affected");
  208. }
  209. });
  210. }
  211. ValidateAtomicOpFunctionality(Int8Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  212. {initValue: undefined, opValue : 0x7B, expectedReturn : 6, expectedValue : -127},
  213. {initValue: undefined, opValue : 10, expectedReturn : -127, expectedValue : -117},
  214. {initValue: 0, opValue : 0x104, expectedReturn : 0, expectedValue : 4}] );
  215. ValidateAtomicOpFunctionality(Uint8Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  216. {initValue: undefined, opValue : 0xFB, expectedReturn : 6, expectedValue : 1},
  217. {initValue: undefined, opValue : 0x80, expectedReturn : 1, expectedValue : 0x81},
  218. {initValue: 0, opValue : 0x104, expectedReturn : 0, expectedValue : 4}] );
  219. ValidateAtomicOpFunctionality(Int16Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  220. {initValue: undefined, opValue : 0x7FFB, expectedReturn : 6, expectedValue : -32767},
  221. {initValue: undefined, opValue : 20, expectedReturn : -32767, expectedValue : -32747},
  222. {initValue: 0, opValue : 0x10004, expectedReturn : 0, expectedValue : 4}] );
  223. ValidateAtomicOpFunctionality(Uint16Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  224. {initValue: undefined, opValue : 0xFFFB, expectedReturn : 6, expectedValue : 1},
  225. {initValue: undefined, opValue : 0x8000, expectedReturn : 1, expectedValue : 0x8001},
  226. {initValue: 0, opValue : 0x10004, expectedReturn : 0, expectedValue : 4}] );
  227. ValidateAtomicOpFunctionality(Int32Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  228. {initValue: undefined, opValue : 0x7FFFFFFB, expectedReturn : 6, expectedValue : -0x7FFFFFFF},
  229. {initValue: undefined, opValue : 0x7FFFFFFF, expectedReturn : -0x7FFFFFFF, expectedValue : 0},
  230. {initValue: 0, opValue : 0x100000004, expectedReturn : 0, expectedValue : 4}] );
  231. ValidateAtomicOpFunctionality(Uint32Array, Atomics.add, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  232. {initValue: undefined, opValue : 0xFFFFFFFB, expectedReturn : 6, expectedValue : 1},
  233. {initValue: undefined, opValue : 0x7FFFFFFF, expectedReturn : 1, expectedValue : 0x80000000},
  234. {initValue: 0, opValue : 0x100000004, expectedReturn : 0, expectedValue : 4}] );
  235. // Atomics.and tests
  236. ValidateAtomicOpFunctionality(Int8Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  237. {initValue: 0x5C, opValue : 0x1B, expectedReturn : 0x5C, expectedValue : 0x18},
  238. {initValue: undefined, opValue : 0x108, expectedReturn : 0x18, expectedValue : 8},
  239. {initValue: 0x7F, opValue : 0x80, expectedReturn : 0x7F, expectedValue : 0}] );
  240. ValidateAtomicOpFunctionality(Uint8Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  241. {initValue: 0x5C, opValue : 0x1B, expectedReturn : 0x5C, expectedValue : 0x18},
  242. {initValue: undefined, opValue : 0x108, expectedReturn : 0x18, expectedValue : 8},
  243. {initValue: 0xFF, opValue : 0x101, expectedReturn : 0xFF, expectedValue : 1}] );
  244. ValidateAtomicOpFunctionality(Int16Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  245. {initValue: 0x7FFB, opValue : 0x1006, expectedReturn : 0x7FFB, expectedValue : 0x1002},
  246. {initValue: undefined, opValue : 0x10008, expectedReturn : 0x1002, expectedValue : 0},
  247. {initValue: 0x7FFF, opValue : 0x8004, expectedReturn : 0x7FFF, expectedValue : 4}] );
  248. ValidateAtomicOpFunctionality(Uint16Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  249. {initValue: 0xBFFC, opValue : 0xA00B, expectedReturn : 0xBFFC, expectedValue : 0xA008},
  250. {initValue: undefined, opValue : 0x10009, expectedReturn : 0xA008, expectedValue : 8},
  251. {initValue: 0xFFFF, opValue : 0x10004, expectedReturn : 0xFFFF, expectedValue : 4}] );
  252. ValidateAtomicOpFunctionality(Int32Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  253. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0x1FFFFFF8},
  254. {initValue: undefined, opValue : 0x8, expectedReturn : 0x1FFFFFF8, expectedValue : 8},
  255. {initValue: 0x7FFFFFFF, opValue : 0x100000004, expectedReturn : 0x7FFFFFFF, expectedValue : 4}] );
  256. ValidateAtomicOpFunctionality(Uint32Array, Atomics.and, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 0},
  257. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0x1FFFFFF8},
  258. {initValue: undefined, opValue : 0x8, expectedReturn : 0x1FFFFFF8, expectedValue : 8},
  259. {initValue: 0x9FFFFFFF, opValue : 0x100000004, expectedReturn : 0x9FFFFFFF, expectedValue : 4}] );
  260. // Atomics.exchange tests
  261. ValidateAtomicOpFunctionality(Int8Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  262. {initValue: 0x9C, opValue : 0x1B, expectedReturn : -100, expectedValue : 0x1B},
  263. {initValue: undefined, opValue : 0x108, expectedReturn : 0x1B, expectedValue : 8}]);
  264. ValidateAtomicOpFunctionality(Uint8Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  265. {initValue: 0x9C, opValue : 0x1B, expectedReturn : 0x9C, expectedValue : 0x1B},
  266. {initValue: undefined, opValue : 0x108, expectedReturn : 0x1B, expectedValue : 8}]);
  267. ValidateAtomicOpFunctionality(Int16Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  268. {initValue: 0x9FFB, opValue : 0x1006, expectedReturn : -24581, expectedValue : 0x1006},
  269. {initValue: undefined, opValue : 0x10008, expectedReturn : 0x1006, expectedValue : 8}]);
  270. ValidateAtomicOpFunctionality(Uint16Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  271. {initValue: 0x9FFB, opValue : 0x1006, expectedReturn : 0x9FFB, expectedValue : 0x1006},
  272. {initValue: undefined, opValue : 0x10008, expectedReturn : 0x1006, expectedValue : 8}]);
  273. ValidateAtomicOpFunctionality(Int32Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  274. {initValue: 0x9FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : -1610612740, expectedValue : -1073741829},
  275. {initValue: undefined, opValue : 8, expectedReturn : -1073741829, expectedValue : 8}] );
  276. ValidateAtomicOpFunctionality(Uint32Array, Atomics.exchange, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 4},
  277. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0xBFFFFFFB},
  278. {initValue: undefined, opValue : 0x100000004, expectedReturn : 0xBFFFFFFB, expectedValue : 4}] );
  279. // Atomics.or tests
  280. ValidateAtomicOpFunctionality(Int8Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  281. {initValue: 0x5C, opValue : 0x1F, expectedReturn : 0x5C, expectedValue : 0x5F},
  282. {initValue: undefined, opValue : 0x120, expectedReturn : 0x5F, expectedValue : 0x7F}] );
  283. ValidateAtomicOpFunctionality(Uint8Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  284. {initValue: 0x5C, opValue : 0x8F, expectedReturn : 0x5C, expectedValue : 0xDF},
  285. {initValue: undefined, opValue : 0x120, expectedReturn : 0xDF, expectedValue : 0xFF}] );
  286. ValidateAtomicOpFunctionality(Int16Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  287. {initValue: 0x700B, opValue : 0x0F00, expectedReturn : 0x700B, expectedValue : 0x7F0B},
  288. {initValue: undefined, opValue : 0x100F6, expectedReturn : 0x7F0B, expectedValue : 0x7FFF}] );
  289. ValidateAtomicOpFunctionality(Uint16Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  290. {initValue: 0xBFFC, opValue : 0xA00B, expectedReturn : 0xBFFC, expectedValue : 0xBFFF},
  291. {initValue: 0x10, opValue : 0x10009, expectedReturn : 0x10, expectedValue : 0x19}] );
  292. ValidateAtomicOpFunctionality(Int32Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  293. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : -1},
  294. {initValue: 0x100000004, opValue : 0x80, expectedReturn : 0x4, expectedValue : 0x84}] );
  295. ValidateAtomicOpFunctionality(Uint32Array, Atomics.or, [{initValue: 2, opValue : 4, expectedReturn : 2, expectedValue : 6},
  296. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0xFFFFFFFF},
  297. {initValue: 0x100000004, opValue : 0x80, expectedReturn : 0x4, expectedValue : 0x84}] );
  298. // Atomics.store tests
  299. ValidateAtomicOpFunctionality(Int8Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  300. {initValue: undefined, opValue : 0xFF, expectedReturn : 0xFF, expectedValue : -1}] );
  301. ValidateAtomicOpFunctionality(Uint8Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  302. {initValue: undefined, opValue : 0x1FF, expectedReturn : 0x1FF, expectedValue : 0xFF}] );
  303. ValidateAtomicOpFunctionality(Int16Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  304. {initValue: undefined, opValue : 0xFFFF, expectedReturn : 0xFFFF, expectedValue : -1}] );
  305. ValidateAtomicOpFunctionality(Uint16Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  306. {initValue: undefined, opValue : 0x1FFFF, expectedReturn : 0x1FFFF, expectedValue : 0xFFFF}] );
  307. ValidateAtomicOpFunctionality(Int32Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  308. {initValue: undefined, opValue : 0xFFFFFFFF, expectedReturn : 0xFFFFFFFF, expectedValue : -1}] );
  309. ValidateAtomicOpFunctionality(Uint32Array, Atomics.store, [{initValue: 0, opValue : 30, expectedReturn : 30, expectedValue : 30},
  310. {initValue: undefined, opValue : 0x1FFFFFFFF, expectedReturn : 0x1FFFFFFFF, expectedValue : 0xFFFFFFFF}] );
  311. // Atomics.sub tests
  312. ValidateAtomicOpFunctionality(Int8Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  313. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : -25},
  314. {initValue: 0x9C, opValue : 0x1B, expectedReturn : -100, expectedValue : -127},
  315. {initValue: 0x7F, opValue : 0x80, expectedReturn : 0x7F, expectedValue : -1}] );
  316. ValidateAtomicOpFunctionality(Uint8Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  317. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : 231},
  318. {initValue: 0x9C, opValue : 0x1B, expectedReturn : 0x9C, expectedValue : 129},
  319. {initValue: 0x7F, opValue : 0x80, expectedReturn : 0x7F, expectedValue : 255}] );
  320. ValidateAtomicOpFunctionality(Int16Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  321. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : -25},
  322. {initValue: 0x7FFF, opValue : 0x8004, expectedReturn : 0x7FFF, expectedValue : -5}] );
  323. ValidateAtomicOpFunctionality(Uint16Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  324. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : 65511},
  325. {initValue: 0x7FFF, opValue : 0x8004, expectedReturn : 0x7FFF, expectedValue : 65531}] );
  326. ValidateAtomicOpFunctionality(Int32Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  327. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : -25},
  328. {initValue: 0x7FFFFFFF, opValue : 0x100000004, expectedReturn : 0x7FFFFFFF, expectedValue : 2147483643}] );
  329. ValidateAtomicOpFunctionality(Uint32Array, Atomics.sub, [{initValue: 12, opValue : 4, expectedReturn : 12, expectedValue : 8},
  330. {initValue: 50, opValue : 75, expectedReturn : 50, expectedValue : 0xFFFFFFE7},
  331. {initValue: 0x9FFFFFFF, opValue : 5, expectedReturn : 0x9FFFFFFF, expectedValue : 0x9FFFFFFA}] );
  332. // Atomics.xor tests
  333. ValidateAtomicOpFunctionality(Int8Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  334. {initValue: 0x5C, opValue : 0x8F, expectedReturn : 0x5C, expectedValue : -45}] );
  335. ValidateAtomicOpFunctionality(Uint8Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  336. {initValue: 0x5C, opValue : 0x8F, expectedReturn : 0x5C, expectedValue : 0xD3}] );
  337. ValidateAtomicOpFunctionality(Int16Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  338. {initValue: 0x700B, opValue : 0x8F00, expectedReturn : 0x700B, expectedValue : -245}] );
  339. ValidateAtomicOpFunctionality(Uint16Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  340. {initValue: 0x700B, opValue : 0x8F00, expectedReturn : 0x700B, expectedValue : 0xFF0B}] );
  341. ValidateAtomicOpFunctionality(Int32Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  342. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : -536870905}] );
  343. ValidateAtomicOpFunctionality(Uint32Array, Atomics.xor, [{initValue: 10, opValue : 20, expectedReturn : 10, expectedValue : 30},
  344. {initValue: 0x5FFFFFFC, opValue : 0xBFFFFFFB, expectedReturn : 0x5FFFFFFC, expectedValue : 0xE0000007}] );
  345. }
  346. },
  347. {
  348. name : "Atomics.load functionality",
  349. body : function () {
  350. [[0, 4, 4], [3, 2, 8]].forEach(function([offset, length, elements]) {
  351. IntViews.forEach(function ({ctor}) {
  352. var sab = new SharedArrayBuffer(ctor.BYTES_PER_ELEMENT * elements);
  353. var view = new ctor(sab, offset * ctor.BYTES_PER_ELEMENT, length);
  354. view[1] = 20;
  355. var ret = Atomics.load(view, 1);
  356. assert.areEqual(ret, 20, "value validation " + ctor.name);
  357. assert.areEqual(view[0], 0, "view[0] should not be affected");
  358. });
  359. });
  360. }
  361. },
  362. {
  363. name : "Atomics.compareExchange functionality",
  364. body : function () {
  365. IntViews.forEach(function({ctor}) {
  366. [[0, 8, 8], [6, 2, 8]].forEach(function([offset, length, elements]) {
  367. var sab = new SharedArrayBuffer(elements * ctor.BYTES_PER_ELEMENT);
  368. var view = new ctor(sab, offset * ctor.BYTES_PER_ELEMENT, length);
  369. view[1] = 10;
  370. var ret = Atomics.compareExchange(view, 1, 10, 20);
  371. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  372. assert.areEqual(view[1], 20, "value validation " + ctor.name);
  373. var ret = Atomics.compareExchange(view, 1, 5, 30);
  374. assert.areEqual(ret, 20, "compared failed - return value validation " + ctor.name);
  375. assert.areEqual(view[1], 20, "compared failed - value validation " + ctor.name);
  376. });
  377. });
  378. }
  379. },
  380. {
  381. name : "Atomics operations ToInteger verification",
  382. body : function () {
  383. var valueOf = {
  384. valueOf : () => 1
  385. };
  386. var toString = {
  387. toString : () => 1
  388. };
  389. IntViews.forEach(function({ctor}) {
  390. [undefined, NaN, null, Number.POSITIVE_INFINITY, true, "1", "blah", 1.1, valueOf, toString].forEach(function(value) {
  391. var sab = new SharedArrayBuffer(2 * ctor.BYTES_PER_ELEMENT);
  392. var view = new ctor(sab);
  393. var num = value | 0;
  394. view[1] = 10;
  395. var ret = Atomics.add(view, 1, value);
  396. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  397. assert.areEqual(view[1], 10 + num, "final value validation " + ctor.name);
  398. view[1] = 10;
  399. var ret = Atomics.and(view, 1, value);
  400. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  401. assert.areEqual(view[1], 10 & num, "final value validation " + ctor.name);
  402. view[1] = 10;
  403. var ret = Atomics.compareExchange(view, 1, 10, value);
  404. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  405. assert.areEqual(view[1], num, "final value validation " + ctor.name);
  406. view[1] = 10;
  407. var ret = Atomics.exchange(view, 1, value);
  408. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  409. assert.areEqual(view[1], num, "final value validation " + ctor.name);
  410. view[1] = 10;
  411. var ret = Atomics.or(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. view[1] = 10;
  415. var ret = Atomics.sub(view, 1, value);
  416. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  417. assert.areEqual(view[1], 10 - num, "final value validation " + ctor.name);
  418. view[1] = 10;
  419. var ret = Atomics.store(view, 1, value);
  420. if (value !== Number.POSITIVE_INFINITY)
  421. {
  422. assert.areEqual(ret, num, "return value validation " + ctor.name);
  423. }
  424. assert.areEqual(view[1], num, "final value validation " + ctor.name);
  425. view[1] = 10;
  426. var ret = Atomics.xor(view, 1, value);
  427. assert.areEqual(ret, 10, "return value validation " + ctor.name);
  428. assert.areEqual(view[1], 10 ^ num, "final value validation " + ctor.name);
  429. });
  430. });
  431. }
  432. },
  433. {
  434. name : "Atomics.add buffer/length invalidation",
  435. body : function () {
  436. var sab = new SharedArrayBuffer(16);
  437. var view = new Int8Array(sab, 0, 8);
  438. var lengthChange = {
  439. valueOf : function() {
  440. view.length = 0;
  441. return 2;
  442. }
  443. };
  444. var lengthChange1 = {
  445. valueOf : function() {
  446. Object.defineProperty(view, 'length', {
  447. get : function () {
  448. return 0;
  449. }
  450. });
  451. return 2;
  452. }
  453. }
  454. var bufferChange = {
  455. valueOf : function() {
  456. view.buffer = null;
  457. return 2;
  458. }
  459. }
  460. view[1] = 0;
  461. Atomics.add(view, 1, lengthChange);
  462. assert.areEqual(view[1], 2, "Changing view's length does not affect the 'add'");
  463. view[1] = 0;
  464. Atomics.add(view, 1, lengthChange1);
  465. assert.areEqual(view[1], 2, "Changing view's length by defineProperty does not affect the 'add'");
  466. view[1] = 0;
  467. Atomics.add(view, 1, bufferChange);
  468. assert.areEqual(view[1], 2, "Changing the buffer does not affect the 'add'");
  469. }
  470. },
  471. {
  472. name : "Atomics ops on subclassed shared array buffer",
  473. body : function () {
  474. class MySAB extends SharedArrayBuffer {
  475. }
  476. var sab = new MySAB(16);
  477. assert.isTrue(sab instanceof MySAB, "object is instance of subclass of SharedArrayBuffer");
  478. assert.isTrue(sab instanceof SharedArrayBuffer, "object is instance of SharedArrayBuffer");
  479. var view = new Int8Array(sab, 0, 8);
  480. view[1] = 10;
  481. var ret = Atomics.add(view, 1, 20);
  482. assert.areEqual(ret, 10, "return value validation ");
  483. assert.areEqual(Atomics.load(view, 1), 30, "final value validation");
  484. }
  485. },
  486. {
  487. name : "Atomics.wait index test",
  488. body : function () {
  489. var view = new Int32Array(new SharedArrayBuffer(8));
  490. assert.doesNotThrow(() => Atomics.wait(view, 0, 0, 0), "Atomics.wait is allowed on the index 0, where the view's length is 2");
  491. assert.doesNotThrow(() => Atomics.wait(view, "0", 0, 0), "ToNumber : Atomics.wait is allowed on the index 0, where the view's length is 2");
  492. assert.throws(() => Atomics.wait(view, 2, 0, 0), RangeError, "Index is greater than the view's length", "Access index is out of range");
  493. assert.throws(() => Atomics.wait(view, -1, 0, 0), RangeError, "Negative index is not allowed", "Access index is out of range");
  494. }
  495. },
  496. {
  497. name : "Atomics.wait value match",
  498. body : function () {
  499. var view = new Int32Array(new SharedArrayBuffer(8));
  500. [2, "2", {valueOf : () => 2}].forEach(function(value) {
  501. view[0] = 1;
  502. var ret = Atomics.wait(view, 0, value, 0);
  503. assert.areEqual(ret, "not-equal", "value is not matching with 1 and 'wait' will return as 'not-equal'");
  504. });
  505. [10, "10", {valueOf : () => 10}].forEach(function(value) {
  506. view[0] = 10;
  507. var ret = Atomics.wait(view, 0, value, 5);
  508. assert.areEqual(ret, "timed-out", "value should match with 10 and 'wait' will wait till time-out");
  509. });
  510. view[0] = 10;
  511. var ret = Atomics.wait(view, 0, 10, Number.NEGATIVE_INFINITY);
  512. assert.areEqual(ret, "timed-out", "Negative infinity will be treated as 0 and so this will time-out");
  513. }
  514. },
  515. {
  516. name : "Atomics on virtual typedarray",
  517. body : function () {
  518. [2**15, 2**20, 2**25].forEach(function(size) {
  519. IntViews.forEach(function(item) {
  520. var view = new item.ctor(new SharedArrayBuffer(size));
  521. Atomics.add(view, 0, 10);
  522. Atomics.store(view, 2**10, 20);
  523. assert.areEqual(Atomics.load(view, 0), 10);
  524. assert.areEqual(Atomics.load(view, 2**10), 20);
  525. });
  526. });
  527. }
  528. },
  529. ];
  530. testRunner.runTests(tests, {
  531. verbose : WScript.Arguments[0] != "summary"
  532. });