atomics_test.js 38 KB

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