ArrayCheckHoist_Generate.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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. var echoFunctionString = echo.toString();
  6. echo("// The tests in this file are GENERATED. Don't add tests to this file manually; instead, modify");
  7. echo("// ArrayCheckHoist_Generate.js and regenerate this file, or use a different file for the new test.");
  8. echo();
  9. var ArrayType = {
  10. ObjectWithArray: 0,
  11. Array: 1,
  12. LastJsArray: 1,
  13. Int32Array: 2
  14. };
  15. var JsArrayElementType = {
  16. Object: 0,
  17. Int32: 1,
  18. Float64: 2
  19. };
  20. var ArrayAccessType = {
  21. Local: 0,
  22. Field: 1
  23. };
  24. var ElementAccessType = {
  25. Load: 0,
  26. Store: 1
  27. };
  28. var NonInvariantLoopType = {
  29. None: 0,
  30. Redefine: 1,
  31. Call: 2,
  32. ImplicitCall: 3
  33. };
  34. var Indexes = [
  35. "-1",
  36. "0",
  37. "i"
  38. ];
  39. var Bools = [
  40. false,
  41. true
  42. ];
  43. // Test helper constants and variables
  44. var LoopIterations = 2;
  45. function ChangeToEs5ArrayStatement(a, jsArrayElementType) {
  46. var v = "-" + a + "[0]";
  47. if(jsArrayElementType == JsArrayElementType.Object)
  48. v = "{ p: " + v + ".p - 1 }";
  49. else
  50. v += " - 1";
  51. return "Object.defineProperty(" + a + ", 0, { configurable: true, writable: false, enumerable: true, value: " + v + " });";
  52. }
  53. var indent = 0;
  54. var testIndex = 0;
  55. echo("var bailout = !this.WScript || this.WScript.Arguments[0] === \"bailout\";");
  56. echo();
  57. var indexIndex = 0;
  58. var inlineIndex = 0;
  59. var strictIndex = 0;
  60. var indexChanger = 0;
  61. for(var arrayTypeIndex in ArrayType) {
  62. if(arrayTypeIndex.substring(0, 4) === "Last")
  63. continue;
  64. var arrayType = ArrayType[arrayTypeIndex];
  65. for(var jsArrayElementTypeIndex in JsArrayElementType) {
  66. var jsArrayElementType = JsArrayElementType[jsArrayElementTypeIndex];
  67. if(arrayType === ArrayType.Int32Array && jsArrayElementType !== JsArrayElementType.Int32)
  68. continue;
  69. for(var arrayAccessTypeIndex in ArrayAccessType) {
  70. var arrayAccessType = ArrayAccessType[arrayAccessTypeIndex];
  71. for(var elementAccessTypeIndex in ElementAccessType) {
  72. var elementAccessType = ElementAccessType[elementAccessTypeIndex];
  73. for(var nonInvariantLoopTypeIndex in NonInvariantLoopType) {
  74. var nonInvariantLoopType = NonInvariantLoopType[nonInvariantLoopTypeIndex];
  75. for(var numLoops = 1; numLoops <= 4; numLoops *= 2) {
  76. for(var arrayAccessLoopIndex = 0;
  77. arrayAccessLoopIndex < numLoops;
  78. arrayAccessLoopIndex = (arrayAccessLoopIndex + 1) * 2 - 1) {
  79. var arrayAccess2LoopIndex = numLoops - 1 - arrayAccessLoopIndex;
  80. for(var nonInvariantLoopIndex = 0;
  81. nonInvariantLoopIndex < numLoops;
  82. nonInvariantLoopIndex = (nonInvariantLoopIndex + 1) * 2 - 1) {
  83. var index = Indexes[indexIndex % Indexes.length];
  84. var inline = Bools[inlineIndex % Bools.length];
  85. var strict = Bools[strictIndex % Bools.length];
  86. ++indexChanger;
  87. if(!(indexChanger & 0x1))++indexIndex;
  88. if(!(indexChanger & 0x3))++inlineIndex;
  89. if(!(indexChanger & 0xf))++strictIndex;
  90. generate(
  91. arrayType,
  92. jsArrayElementType,
  93. arrayAccessType,
  94. elementAccessType,
  95. nonInvariantLoopType,
  96. numLoops,
  97. arrayAccessLoopIndex,
  98. arrayAccess2LoopIndex,
  99. nonInvariantLoopIndex,
  100. index,
  101. inline,
  102. strict);
  103. }
  104. }
  105. }
  106. }
  107. }
  108. }
  109. }
  110. }
  111. echo("////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////");
  112. echo();
  113. var f = "";
  114. f += echos("function changeToEs5Array_object(a) {", 1);
  115. {
  116. f += preventInline(ChangeToEs5ArrayStatement("a", JsArrayElementType.Object));
  117. }
  118. f += echos("}", -1);
  119. echo(f);
  120. f = "";
  121. f += echos("function changeToEs5Array_int32(a) {", 1);
  122. {
  123. f += preventInline(ChangeToEs5ArrayStatement("a", JsArrayElementType.Int32));
  124. }
  125. f += echos("}", -1);
  126. echo(f);
  127. f = "";
  128. f += echos("function someCall(a) {", 1);
  129. {
  130. f += preventInline("a.someProperty = 0;");
  131. }
  132. f += echos("}", -1);
  133. echo(f);
  134. echo(toSafeInt.toString());
  135. echo();
  136. echo(echoFunctionString);
  137. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  138. // Test helpers
  139. function generate(
  140. arrayType,
  141. jsArrayElementType,
  142. arrayAccessType,
  143. elementAccessType,
  144. nonInvariantLoopType,
  145. numLoops,
  146. arrayAccessLoopIndex,
  147. arrayAccess2LoopIndex,
  148. nonInvariantLoopIndex,
  149. index,
  150. inline,
  151. strict) {
  152. if(numLoops === 0)
  153. throw new Error("Invalid numLoops");
  154. if(arrayAccessLoopIndex < 0 || arrayAccessLoopIndex >= numLoops)
  155. throw new Error("Invalid arrayAccessLoopIndex");
  156. if(arrayAccess2LoopIndex < 0 || arrayAccess2LoopIndex >= numLoops)
  157. throw new Error("Invalid arrayAccess2LoopIndex");
  158. if(nonInvariantLoopIndex < 0 || nonInvariantLoopIndex >= numLoops)
  159. throw new Error("Invalid nonInvariantLoopIndex");
  160. if(nonInvariantLoopType === NonInvariantLoopType.None && nonInvariantLoopIndex !== 0)
  161. return; // no non-invariant loops, only generate this test once
  162. if(arrayType >= ArrayType.LastJsArray && nonInvariantLoopType === NonInvariantLoopType.ImplicitCall)
  163. return; // typed arrays don't need implicit call checks, and their elements are not configurable
  164. if(strict && elementAccessType === ElementAccessType.Store && nonInvariantLoopType >= NonInvariantLoopType.Call)
  165. strict = false; // calls and implicit calls make elements read-only and those elements can't be set in strict mode thereafter
  166. var f = "";
  167. var testName = "test" + testIndex++;
  168. f += echos("function " + testName + "() {", 1);
  169. {
  170. if(strict) {
  171. f += echos('"use strict";');
  172. f += echos("");
  173. }
  174. f += createArray(arrayType, jsArrayElementType, nonInvariantLoopType === NonInvariantLoopType.ImplicitCall);
  175. f += echos("return toSafeInt(" + testName + "_run(o, a, a2));");
  176. f += echos("");
  177. f += echos("function " + testName + "_run(o, a, a2) {", 1);
  178. {
  179. f += echos("var sum = 0;");
  180. for(var i = 0; i < numLoops; ++i) {
  181. var si = "i" + i;
  182. var n = nonInvariantLoopType !== NonInvariantLoopType.None && i === nonInvariantLoopIndex ? LoopIterations : "a.length";
  183. f += echos("for(var " + si + " = 0; " + si + " < " + n + "; ++" + si + ") {", 1);
  184. {
  185. f += echos("sum += " + si + ";");
  186. }
  187. }
  188. for(var i = numLoops - 1; i >= 0; --i) {
  189. var si = "i" + i;
  190. if(nonInvariantLoopType !== NonInvariantLoopType.None && i === nonInvariantLoopIndex) {
  191. if(nonInvariantLoopType === NonInvariantLoopType.Redefine)
  192. f += echos("a = a2;");
  193. else if(nonInvariantLoopType === NonInvariantLoopType.Call) {
  194. if(arrayType <= ArrayType.LastJsArray)
  195. f += echos("changeToEs5Array_" + (jsArrayElementType === JsArrayElementType.Object ? "object" : "int32") + "(a);");
  196. else
  197. f += echos("someCall(a);");
  198. }
  199. else if(nonInvariantLoopType === NonInvariantLoopType.ImplicitCall) {
  200. var n = nonInvariantLoopType !== NonInvariantLoopType.None && i === nonInvariantLoopIndex ? LoopIterations : "a.length";
  201. f += echos("if(bailout && " + si + " === (" + n + " >> 1))", 1);
  202. {
  203. f += echos("o.changeToEs5Array = 0;");
  204. }
  205. f += echos(null, -1);
  206. }
  207. else
  208. throw new Error("Invalid nonInvariantLoopType");
  209. }
  210. if(i === arrayAccessLoopIndex || i === arrayAccess2LoopIndex) {
  211. if(inline)
  212. f += echos("sum += " + testName + "_access(o, a, " + si + ");");
  213. else
  214. f += access(arrayType, jsArrayElementType, arrayAccessType, elementAccessType, index === "i" ? si : index);
  215. }
  216. f += echos("}", -1);
  217. }
  218. if(inline) {
  219. f += echos("");
  220. f += echos("function " + testName + "_access(o, a, i) {", 1);
  221. {
  222. f += access(arrayType, jsArrayElementType, arrayAccessType, elementAccessType, index, true);
  223. }
  224. f += echos("}", -1);
  225. }
  226. f += echos("return sum;");
  227. }
  228. f += echos("}", -1);
  229. }
  230. f += echos("}", -1);
  231. f += echos("echo(\"" + testName + ": \" + " + testName + "());");
  232. echo(f);
  233. }
  234. function createArray(arrayType, jsArrayElementType, includeImplicitCall) {
  235. var f = "";
  236. if(arrayType === ArrayType.Int32Array) {
  237. f += echos("var o = { a: new Int32Array(" + LoopIterations + ") };");
  238. f += echos("for(var i = 0; i < " + LoopIterations + "; ++i)", 1);
  239. {
  240. f += echos("o.a[i] = i + 1;");
  241. }
  242. f += echos(null, -1);
  243. } else {
  244. if(arrayType > ArrayType.LastJsArray)
  245. throw new Error("Unknown ArrayType");
  246. f += echos("var o = {", 1);
  247. {
  248. var arrayBegin = arrayType === ArrayType.ObjectWithArray ? "{" : "[";
  249. var arrayEnd = arrayType === ArrayType.ObjectWithArray ? "}" : "]";
  250. function arrayElementBegin(i) {
  251. return arrayType === ArrayType.ObjectWithArray ? "\"" + i + "\": " : "";
  252. }
  253. var a = "a: " + arrayBegin + " ";
  254. for(var i = 1; i <= LoopIterations; ++i) {
  255. var end = i === LoopIterations ? "" : ", ";
  256. a += arrayElementBegin(i - 1);
  257. if(jsArrayElementType === JsArrayElementType.Object)
  258. a += "{ p: " + i + " }" + end;
  259. else if(jsArrayElementType === JsArrayElementType.Int32)
  260. a += i + end;
  261. else if(jsArrayElementType === JsArrayElementType.Float64)
  262. a += i + ".1" + end;
  263. else
  264. throw new Error("Unknown JsArrayElementType");
  265. }
  266. if(arrayType === ArrayType.ObjectWithArray)
  267. a += ", length: " + LoopIterations;
  268. if(includeImplicitCall) {
  269. f += echos(a + " " + arrayEnd + ",");
  270. f += echos("set changeToEs5Array(v) {", 1);
  271. {
  272. f += preventInline(ChangeToEs5ArrayStatement("this.a", jsArrayElementType));
  273. }
  274. f += echos("}", -1);
  275. }
  276. else
  277. f += echos(a + " " + arrayEnd);
  278. }
  279. f += echos("};", -1);
  280. }
  281. f += echos("var a = o.a;");
  282. f += echos("a[-1] = a[0];");
  283. if(arrayType === ArrayType.ObjectWithArray)
  284. f += echos("var a2 = [];");
  285. else
  286. f += echos("var a2 = { length: a.length };");
  287. f += echos("for(var i = -1; i < a.length; ++i)", 1);
  288. {
  289. if(arrayType <= ArrayType.LastJsArray && jsArrayElementType === JsArrayElementType.Object)
  290. f += echos("a2[i] = { p: -a[i].p };");
  291. else
  292. f += echos("a2[i] = -a[i];");
  293. }
  294. f += echos(null, -1);
  295. return f;
  296. }
  297. function access(arrayType, jsArrayElementType, arrayAccessType, elementAccessType, index, returnAccessed) {
  298. var f = "";
  299. var e = "[" + index + "]";
  300. if(arrayType <= ArrayType.LastJsArray && jsArrayElementType === JsArrayElementType.Object)
  301. e += ".p";
  302. if(arrayAccessType === ArrayAccessType.Local)
  303. e = "a" + e;
  304. else if(arrayAccessType === ArrayAccessType.Field)
  305. e = "o.a" + e;
  306. else
  307. throw new Error("Unknown ArrayAccessType");
  308. var beginning = returnAccessed ? "return " : "sum += ";
  309. if(elementAccessType === ElementAccessType.Load)
  310. f += echos(beginning + e + ";");
  311. else if(elementAccessType === ElementAccessType.Store)
  312. f += echos(beginning + "(" + e + " = -" + e + " - 1, " + e + ");");
  313. else
  314. throw new Error("Unknown ElementAccessType");
  315. return f;
  316. }
  317. function preventInline(functionBodyLine) {
  318. var f = "";
  319. f += echos("try {", 1);
  320. {
  321. f += echos(functionBodyLine);
  322. }
  323. f += echos("} catch(ex) {", -1);
  324. f += echos(null, 1);
  325. {
  326. f += echos('echo("Unexpected exception - " + ex.name + ": " + ex.message);');
  327. }
  328. f += echos("}", -1);
  329. return f;
  330. }
  331. function echos(s, changeIndent) {
  332. if(changeIndent && changeIndent < 0)
  333. indent += changeIndent * 4;
  334. if(s && s !== "") {
  335. var spaces = "";
  336. for(var i = 0; i < indent; ++i)
  337. spaces += " ";
  338. s = spaces + s + "\n";
  339. }
  340. else if(s === "")
  341. s = "\n";
  342. else
  343. s = "";
  344. if(changeIndent && changeIndent > 0)
  345. indent += changeIndent * 4;
  346. return s;
  347. }
  348. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  349. function toSafeInt(n) {
  350. return Math.round(Math.round(n * 10) / 10);
  351. }
  352. function echo() {
  353. var doEcho;
  354. if(this.WScript)
  355. doEcho = function(s) { this.WScript.Echo(s); };
  356. else if(this.document)
  357. doEcho = function(s) {
  358. var div = this.document.createElement("div");
  359. div.innerText = s;
  360. this.document.body.appendChild(div);
  361. };
  362. else
  363. doEcho = function(s) { this.print(s); };
  364. echo = function() {
  365. var s = "";
  366. for(var i = 0; i < arguments.length; ++i)
  367. s += arguments[i];
  368. doEcho(s);
  369. };
  370. echo.apply(this, arguments);
  371. }