object-keys-04.js (7045B)
1 load(libdir + 'array-compare.js'); // arraysEqual 2 3 // Ion eager fails the test below because we have not yet created any 4 // Cache IR IC in baseline before running the content of the top-level 5 // function. 6 if (getJitCompilerOptions()["ion.warmup.trigger"] <= 100) 7 setJitCompilerOption("ion.warmup.trigger", 100); 8 9 // This test case checks that we are capable of recovering the Object.keys array 10 // even if we optimized it away. It also checks that we indeed optimize it away 11 // as we would expect. 12 13 // Prevent GC from cancelling/discarding Ion compilations. 14 gczeal(0); 15 16 function objKeysLength(obj, expected, i) { 17 var keys = Object.keys(obj); 18 let len = keys.length; 19 assertRecoveredOnBailout(keys, true); 20 if (i >= 99) { 21 // bailout would hint Ion to remove everything after, making the keys 22 // array appear like being only used by resume points. 23 bailout(); 24 assertEq(arraysEqual(keys, expected), true); 25 } 26 return len; 27 } 28 29 function objKeysLengthDiffBlock(obj, expected, i) { 30 var keys = Object.keys(obj); 31 if (i >= 99) { 32 // bailout would hint Ion to remove everything after, making the keys 33 // array appear like being only used by resume points. 34 bailout(); 35 assertEq(arraysEqual(keys, expected), true); 36 } 37 let len = keys.length; 38 assertRecoveredOnBailout(keys, true); 39 return len; 40 } 41 42 // Mutating the object in-between the call from Object.keys and the evaluation 43 // of the length property should still allow the optimization to take place 44 // since the iterator we held onto should be from the previous shape of the 45 // object. 46 function objKeysLengthMutate0(obj, expected, i) { 47 var keys = Object.keys(obj); 48 obj.foo = 42; 49 let len = keys.length; 50 assertRecoveredOnBailout(keys, true); 51 if (i >= 99) { 52 bailout(); 53 assertEq(arraysEqual(keys, expected), true); 54 } 55 return len; 56 } 57 58 function objKeysLengthMutate1(obj, expected, i) { 59 var keys = Object.keys(obj); 60 let len = keys.length; 61 assertRecoveredOnBailout(keys, true); 62 obj.foo = 42; 63 if (i >= 99) { 64 bailout(); 65 assertEq(arraysEqual(keys, expected), true); 66 } 67 return len; 68 } 69 70 function objKeysLengthMutate2(obj, expected, i) { 71 var keys = Object.keys(obj); 72 let len = keys.length; 73 assertRecoveredOnBailout(keys, true); 74 if (i >= 99) { 75 bailout(); 76 assertEq(arraysEqual(keys, expected), true); 77 } 78 obj.foo = 42; 79 return len; 80 } 81 82 function objKeysLengthMutate3(obj, expected, i) { 83 var keys = Object.keys(obj); 84 let len = keys.length; 85 assertRecoveredOnBailout(keys, true); 86 if (i >= 99) { 87 obj.foo = 42; 88 bailout(); 89 assertEq(arraysEqual(keys, expected), true); 90 } 91 return len; 92 } 93 94 function objKeysLengthMutate4(obj, expected, i) { 95 obj.foo = 42; 96 var keys = Object.keys(obj); 97 let len = keys.length; 98 assertRecoveredOnBailout(keys, true); 99 if (i >= 99) { 100 bailout(); 101 assertEq(arraysEqual(keys, expected), true); 102 } 103 return len; 104 } 105 106 107 function doNotInlineSideEffect() { 108 eval("1"); 109 } 110 111 function objKeysLengthSideEffect0(obj, expected, i) { 112 var keys = Object.keys(obj); 113 let len = keys.length; 114 assertRecoveredOnBailout(keys, true); 115 doNotInlineSideEffect(); 116 if (i >= 99) { 117 bailout(); 118 assertEq(arraysEqual(keys, expected), true); 119 } 120 return len; 121 } 122 123 function objKeysLengthSideEffect1(obj, expected, i) { 124 var keys = Object.keys(obj); 125 let len = keys.length; 126 assertRecoveredOnBailout(keys, true); 127 if (i >= 99) { 128 bailout(); 129 assertEq(arraysEqual(keys, expected), true); 130 } 131 doNotInlineSideEffect(); 132 return len; 133 } 134 135 function objKeysLengthSideEffect2(obj, expected, i) { 136 var keys = Object.keys(obj); 137 let len = keys.length; 138 assertRecoveredOnBailout(keys, true); 139 if (i >= 99) { 140 // When branches are pruned, Warp/Ion is not aware and would recover the 141 // keys on bailout, and this is fine. 142 doNotInlineSideEffect(); 143 bailout(); 144 assertEq(arraysEqual(keys, expected), true); 145 } 146 return len; 147 } 148 149 function objKeysLengthSideEffect3(obj, expected, i) { 150 doNotInlineSideEffect(); 151 var keys = Object.keys(obj); 152 let len = keys.length; 153 assertRecoveredOnBailout(keys, true); 154 if (i >= 99) { 155 bailout(); 156 assertEq(arraysEqual(keys, expected), true); 157 } 158 return len; 159 } 160 161 function objKeysLengthMutateElements0(obj, expected, i) { 162 var keys = Object.keys(obj); 163 obj[0] = 42; 164 obj[1] = 42; 165 obj[2] = 42; 166 let len = keys.length; 167 assertRecoveredOnBailout(keys, true); 168 if (i >= 99) { 169 bailout(); 170 assertEq(arraysEqual(keys, expected), true); 171 } 172 return len; 173 } 174 175 function objKeysLengthMutateElements1(obj, expected, i) { 176 obj[0] = 42; 177 var keys = Object.keys(obj); 178 obj[1] = 42; 179 obj[2] = 42; 180 let len = keys.length; 181 assertRecoveredOnBailout(keys, true); 182 if (i >= 99) { 183 bailout(); 184 assertEq(arraysEqual(keys, expected), true); 185 } 186 return len; 187 } 188 189 function objKeysLengthMutateElements2(obj, expected, i) { 190 obj[0] = 42; 191 obj[1] = 42; 192 var keys = Object.keys(obj); 193 obj[2] = 42; 194 let len = keys.length; 195 assertRecoveredOnBailout(keys, true); 196 if (i >= 99) { 197 bailout(); 198 assertEq(arraysEqual(keys, expected), true); 199 } 200 return len; 201 } 202 203 // Check what we are doing as optimizations when the object is fully known and 204 // when it does not escape. 205 // 206 // Except that today, Object.keys(..) is still assumed to make side-effect 207 // despite being removed later. 208 function nonEscapedObjKeysLength(i) { 209 let obj = {a: i}; 210 var keys = Object.keys(obj); 211 let len = keys.length; 212 assertRecoveredOnBailout(keys, true); 213 assertRecoveredOnBailout(obj, false); 214 if (i >= 99) { 215 bailout(); 216 assertEq(arraysEqual(keys, ["a"]), true); 217 } 218 return len; 219 } 220 221 // Prevent compilation of the top-level. 222 eval(`${arraysEqual}`); 223 let obj = {a: 0, b: 1, c: 2, d: 3}; 224 225 for (let i = 0; i < 100; i++) { 226 objKeysLength({...obj}, ["a", "b", "c", "d"], i); 227 objKeysLengthDiffBlock({...obj}, ["a", "b", "c", "d"], i); 228 objKeysLengthMutate0({...obj}, ["a", "b", "c", "d"], i); 229 objKeysLengthMutate1({...obj}, ["a", "b", "c", "d"], i); 230 objKeysLengthMutate2({...obj}, ["a", "b", "c", "d"], i); 231 objKeysLengthMutate3({...obj}, ["a", "b", "c", "d"], i); 232 objKeysLengthMutate4({...obj}, ["a", "b", "c", "d", "foo"], i); 233 objKeysLengthSideEffect0({...obj}, ["a", "b", "c", "d"], i); 234 objKeysLengthSideEffect1({...obj}, ["a", "b", "c", "d"], i); 235 objKeysLengthSideEffect2({...obj}, ["a", "b", "c", "d"], i); 236 objKeysLengthSideEffect3({...obj}, ["a", "b", "c", "d"], i); 237 objKeysLengthMutateElements0({...obj}, ["a", "b", "c", "d"], i); 238 objKeysLengthMutateElements1({...obj}, ["0", "a", "b", "c", "d"], i); 239 objKeysLengthMutateElements2({...obj}, ["0", "1", "a", "b", "c", "d"], i); 240 nonEscapedObjKeysLength(i); 241 }