summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/ion/recover-arrays.js
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/src/jit-test/tests/ion/recover-arrays.js336
1 files changed, 336 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/ion/recover-arrays.js b/js/src/jit-test/tests/ion/recover-arrays.js
new file mode 100644
index 0000000000..dd7c196edd
--- /dev/null
+++ b/js/src/jit-test/tests/ion/recover-arrays.js
@@ -0,0 +1,336 @@
+// |jit-test| --no-ion
+// Warp lacks Scalar Replacement support (bug 1650233). Re-evaluate after that
+// bug has been fixed.
+
+// Ion eager fails the test below because we have not yet created any
+// template object in baseline before running the content of the top-level
+// function.
+if (getJitCompilerOptions()["ion.warmup.trigger"] <= 100)
+ setJitCompilerOption("ion.warmup.trigger", 100);
+
+// This test checks that we are able to remove the getelem & setelem with scalar
+// replacement, so we should not force inline caches, as this would skip the
+// generation of getelem & setelem instructions.
+if (getJitCompilerOptions()["ion.forceinlineCaches"])
+ setJitCompilerOption("ion.forceinlineCaches", 0);
+
+// Prevent the GC from cancelling Ion compilations, when we expect them to succeed
+gczeal(0);
+
+// This function is used to force a bailout when it is inlined, and to recover
+// the frame which is inlining this function.
+var resumeHere = function (i) { if (i >= 99) bailout(); };
+
+// This function is used to cause an invalidation after having removed a branch
+// after DCE. This is made to check if we correctly recover an array
+// allocation.
+var uceFault = function (i) {
+ if (i > 98)
+ uceFault = function (i) { return true; };
+ return false;
+};
+
+// This function is used to ensure that we do escape the array, and thus prevent
+// any escape analysis.
+var global_arr;
+function escape(arr) { global_arr = arr; }
+
+// Check Array length defined by the literal.
+function array0Length(i) {
+ var a = [];
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function array0LengthBail(i) {
+ var a = [];
+ resumeHere(i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function array1Length(i) {
+ var a = [ i ];
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function array1LengthBail(i) {
+ var a = [ i ];
+ resumeHere(i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function array2Length(i) {
+ var a = [ i, i ];
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function array2LengthBail(i) {
+ var a = [ i, i ];
+ resumeHere(i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+// Check that we can correctly gc in the middle of an incomplete object
+// intialization.
+function arrayWithGCInit0(i) {
+ var a = [ (i == 99 ? (gc(), i) : i), i ];
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function arrayWithGCInit1(i) {
+ var a = [ i, (i == 99 ? (gc(), i) : i) ];
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function arrayWithGCInit2(i) {
+ var a = [ i, i ];
+ if (i == 99) gc();
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+// Check Array content
+function array1Content(i) {
+ var a = [ i ];
+ assertEq(a[0], i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+function array1ContentBail0(i) {
+ var a = [ i ];
+ resumeHere(i);
+ assertEq(a[0], i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+function array1ContentBail1(i) {
+ var a = [ i ];
+ assertEq(a[0], i);
+ resumeHere(i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function array2Content(i) {
+ var a = [ i, i ];
+ assertEq(a[0], i);
+ assertEq(a[1], i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function array2ContentBail0(i) {
+ var a = [ i, i ];
+ resumeHere(i);
+ assertEq(a[0], i);
+ assertEq(a[1], i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function array2ContentBail1(i) {
+ var a = [ i, i ];
+ assertEq(a[0], i);
+ resumeHere(i);
+ assertEq(a[1], i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function array2ContentBail2(i) {
+ var a = [ i, i ];
+ assertEq(a[0], i);
+ assertEq(a[1], i);
+ resumeHere(i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+// Check bailouts during the initialization.
+function arrayInitBail0(i) {
+ var a = [ resumeHere(i), i ];
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+function arrayInitBail1(i) {
+ var a = [ i, resumeHere(i) ];
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+// Check recovery of large arrays.
+function arrayLarge0(i) {
+ var a = new Array(10000000);
+ resumeHere(); bailout(); // always resume here.
+ // IsArrayEscaped prevent us from escaping Arrays with too many elements.
+ assertRecoveredOnBailout(a, false);
+ return a.length;
+}
+
+function arrayLarge1(i) {
+ var a = new Array(10000000);
+ a[0] = i;
+ assertEq(a[0], i);
+ // IsArrayEscaped prevent us from escaping Arrays with too many elements.
+ assertRecoveredOnBailout(a, false);
+ return a.length;
+}
+
+function arrayLarge2(i) {
+ var a = new Array(10000000);
+ a[0] = i;
+ a[100] = i;
+ assertEq(a[0], i);
+ assertEq(a[100], i);
+ // IsArrayEscaped prevent us from escaping Arrays with too many elements.
+ assertRecoveredOnBailout(a, false);
+ return a.length;
+}
+
+// Check escape analysis in case of branches.
+function arrayCond(i) {
+ var a = [i,0,i];
+ if (i % 2 == 1)
+ a[1] = i;
+ assertEq(a[0], i);
+ assertEq(a[1], (i % 2) * i);
+ assertEq(a[2], i);
+ assertRecoveredOnBailout(a, true);
+ return a.length;
+}
+
+// Check escape analysis in case of holes.
+function arrayHole0(i) {
+ var a = [i,,i];
+ if (i != 99)
+ a[1] = i;
+ assertEq(a[0], i);
+ assertEq(a[1], i != 99 ? i : undefined);
+ assertEq(a[2], i);
+ // need to check for holes.
+ assertRecoveredOnBailout(a, false);
+ return a.length;
+}
+
+// Same test as the previous one, but the Array.prototype is changed to reutn
+// "100" when we request for the element "1".
+function arrayHole1(i) {
+ var a = [i,,i];
+ if (i != 99)
+ a[1] = i;
+ assertEq(a[0], i);
+ assertEq(a[1], i != 99 ? i : 100);
+ assertEq(a[2], i);
+ // need to check for holes.
+ assertRecoveredOnBailout(a, false);
+ return a.length;
+}
+
+// Check that we correctly allocate the array after taking the recover path.
+var uceFault_arrayAlloc0 = eval(`(${uceFault})`.replace('uceFault', 'uceFault_arrayAlloc0'));
+function arrayAlloc0(i) {
+ var a = new Array(10);
+ if (uceFault_arrayAlloc0(i) || uceFault_arrayAlloc0(i)) {
+ return a.length;
+ }
+ assertRecoveredOnBailout(a, true);
+ return 0;
+}
+
+var uceFault_arrayAlloc1 = eval(`(${uceFault})`.replace('uceFault', 'uceFault_arrayAlloc1'));
+function arrayAlloc1(i) {
+ var a = new Array(10);
+ if (uceFault_arrayAlloc1(i) || uceFault_arrayAlloc1(i)) {
+ a[0] = i;
+ a[1] = i;
+ assertEq(a[0], i);
+ assertEq(a[1], i);
+ assertEq(a[2], undefined);
+ return a.length;
+ }
+ assertRecoveredOnBailout(a, true);
+ return 0;
+}
+
+var uceFault_arrayAlloc2 = eval(`(${uceFault})`.replace('uceFault', 'uceFault_arrayAlloc2'));
+function arrayAlloc2(i) {
+ var a = new Array(10);
+ if (uceFault_arrayAlloc2(i) || uceFault_arrayAlloc2(i)) {
+ a[4096] = i;
+ assertEq(a[0], undefined);
+ assertEq(a[4096], i);
+ return a.length;
+ }
+ assertRecoveredOnBailout(a, true);
+ return 0;
+}
+
+function build(l) { var arr = []; for (var i = 0; i < l; i++) arr.push(i); return arr }
+var uceFault_arrayAlloc3 = eval(`(${uceFault})`.replace('uceFault', 'uceFault_arrayAlloc3'));
+function arrayAlloc3(i) {
+ var a = [0,1,2,3,4,5,6,7,8];
+ if (uceFault_arrayAlloc3(i) || uceFault_arrayAlloc3(i)) {
+ assertEq(a[0], 0);
+ assertEq(a[3], 3);
+ return a.length;
+ }
+ assertRecoveredOnBailout(a, true);
+ return 0;
+};
+
+// Prevent compilation of the top-level
+eval(`(${resumeHere})`);
+
+for (var i = 0; i < 100; i++) {
+ array0Length(i);
+ array0LengthBail(i);
+ array1Length(i);
+ array1LengthBail(i);
+ array2Length(i);
+ array2LengthBail(i);
+ array1Content(i);
+ array1ContentBail0(i);
+ array1ContentBail1(i);
+ array2Content(i);
+ array2ContentBail0(i);
+ array2ContentBail1(i);
+ array2ContentBail2(i);
+ arrayInitBail0(i);
+ arrayInitBail1(i);
+ arrayLarge0(i);
+ arrayLarge1(i);
+ arrayLarge2(i);
+ arrayCond(i);
+ arrayHole0(i);
+ arrayAlloc0(i);
+ arrayAlloc1(i);
+ arrayAlloc2(i);
+ arrayAlloc3(i);
+}
+
+for (var i = 0; i < 100; i++) {
+ arrayWithGCInit0(i);
+ arrayWithGCInit1(i);
+ arrayWithGCInit2(i);
+}
+
+// If arr[1] is not defined, then we fallback on the prototype which instead of
+// returning undefined, returns "0".
+Object.defineProperty(Array.prototype, 1, {
+ value: 100,
+ configurable: true,
+ enumerable: true,
+ writable: true
+});
+
+for (var i = 0; i < 100; i++) {
+ arrayHole1(i);
+}