summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/ion/object-keys-04.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /js/src/jit-test/tests/ion/object-keys-04.js
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/tests/ion/object-keys-04.js')
-rw-r--r--js/src/jit-test/tests/ion/object-keys-04.js208
1 files changed, 208 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/ion/object-keys-04.js b/js/src/jit-test/tests/ion/object-keys-04.js
new file mode 100644
index 0000000000..0b147bada4
--- /dev/null
+++ b/js/src/jit-test/tests/ion/object-keys-04.js
@@ -0,0 +1,208 @@
+load(libdir + 'array-compare.js'); // arraysEqual
+
+// Ion eager fails the test below because we have not yet created any
+// Cache IR IC in baseline before running the content of the top-level
+// function.
+if (getJitCompilerOptions()["ion.warmup.trigger"] <= 100)
+ setJitCompilerOption("ion.warmup.trigger", 100);
+
+// This test case checks that we are capable of recovering the Object.keys array
+// even if we optimized it away. It also checks that we indeed optimize it away
+// as we would expect.
+
+// Prevent GC from cancelling/discarding Ion compilations.
+gczeal(0);
+
+function objKeysLength(obj, expected, i) {
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, true);
+ if (i >= 99) {
+ // bailout would hint Ion to remove everything after, making the keys
+ // array appear like being only used by resume points.
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ return len;
+}
+
+// This is the same test as above, except that the branch which is being removed
+// cause the introduction of a different resume point to be inserted in the
+// middle. At the moment we expect this circustances to to disable the
+// optimization.
+//
+// Removing this limitation would be useful but would require more verification
+// when applying the optimization.
+function objKeysLengthDiffBlock(obj, expected, i) {
+ var keys = Object.keys(obj);
+ if (i >= 99) {
+ // bailout would hint Ion to remove everything after, making the keys
+ // array appear like being only used by resume points.
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, false);
+ return len;
+}
+
+// Mutating the object in-between the call from Object.keys and the evaluation
+// of the length property should prevent the optimization from being reflected
+// as the mutation of the object would cause the a different result of
+// Object.keys evaluation.
+function objKeysLengthMutate0(obj, expected, i) {
+ var keys = Object.keys(obj);
+ obj.foo = 42;
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, false);
+ if (i >= 99) {
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ return len;
+}
+
+function objKeysLengthMutate1(obj, expected, i) {
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, false);
+ obj.foo = 42;
+ if (i >= 99) {
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ return len;
+}
+
+function objKeysLengthMutate2(obj, expected, i) {
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, false);
+ if (i >= 99) {
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ obj.foo = 42;
+ return len;
+}
+
+function objKeysLengthMutate3(obj, expected, i) {
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, true);
+ if (i >= 99) {
+ // When branches are pruned, Warp/Ion is not aware and would recover the
+ // keys on bailout, and this is fine.
+ obj.foo = 42;
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ return len;
+}
+
+function objKeysLengthMutate4(obj, expected, i) {
+ // Mutating the objects ahead of keying the keys does not prevent optimizing
+ // the keys length query, given that all side-effects are already acted by
+ // the time we query the keys.
+ obj.foo = 42;
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, true);
+ if (i >= 99) {
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ return len;
+}
+
+
+function doNotInlineSideEffect() {
+ eval("1");
+}
+
+function objKeysLengthSideEffect0(obj, expected, i) {
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, false);
+ doNotInlineSideEffect();
+ if (i >= 99) {
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ return len;
+}
+
+function objKeysLengthSideEffect1(obj, expected, i) {
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, false);
+ if (i >= 99) {
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ doNotInlineSideEffect();
+ return len;
+}
+
+function objKeysLengthSideEffect2(obj, expected, i) {
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, true);
+ if (i >= 99) {
+ // When branches are pruned, Warp/Ion is not aware and would recover the
+ // keys on bailout, and this is fine.
+ doNotInlineSideEffect();
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ return len;
+}
+
+function objKeysLengthSideEffect3(obj, expected, i) {
+ doNotInlineSideEffect();
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, true);
+ if (i >= 99) {
+ bailout();
+ assertEq(arraysEqual(keys, expected), true);
+ }
+ return len;
+}
+
+// Check what we are doing as optimizations when the object is fully known and
+// when it does not escape.
+//
+// Except that today, Object.keys(..) is still assumed to make side-effect
+// despite being removed later.
+function nonEscapedObjKeysLength(i) {
+ let obj = {a: i};
+ var keys = Object.keys(obj);
+ let len = keys.length;
+ assertRecoveredOnBailout(keys, true);
+ assertRecoveredOnBailout(obj, false);
+ if (i >= 99) {
+ bailout();
+ assertEq(arraysEqual(keys, ["a"]), true);
+ }
+ return len;
+}
+
+// Prevent compilation of the top-level.
+eval(`${arraysEqual}`);
+let obj = {a: 0, b: 1, c: 2, d: 3};
+
+for (let i = 0; i < 100; i++) {
+ objKeysLength({...obj}, ["a", "b", "c", "d"], i);
+ objKeysLengthDiffBlock({...obj}, ["a", "b", "c", "d"], i);
+ objKeysLengthMutate0({...obj}, ["a", "b", "c", "d"], i);
+ objKeysLengthMutate1({...obj}, ["a", "b", "c", "d"], i);
+ objKeysLengthMutate2({...obj}, ["a", "b", "c", "d"], i);
+ objKeysLengthMutate3({...obj}, ["a", "b", "c", "d"], i);
+ objKeysLengthMutate4({...obj}, ["a", "b", "c", "d", "foo"], i);
+ objKeysLengthSideEffect0({...obj}, ["a", "b", "c", "d"], i);
+ objKeysLengthSideEffect1({...obj}, ["a", "b", "c", "d"], i);
+ objKeysLengthSideEffect2({...obj}, ["a", "b", "c", "d"], i);
+ objKeysLengthSideEffect3({...obj}, ["a", "b", "c", "d"], i);
+ nonEscapedObjKeysLength(i);
+}