recover-rest.js (8124B)
1 // Prevent GC from cancelling/discarding Ion compilations. 2 gczeal(0); 3 4 // This function is used to force a bailout when it is inlined, and to recover 5 // the frame which is inlining this function. 6 var resumeHere = function (i) { if (i >= 99) bailout(); }; 7 8 // This function is used to cause an invalidation after having removed a branch 9 // after DCE. This is made to check if we correctly recover an array 10 // allocation. 11 var uceFault = function (i) { 12 if (i > 98) 13 uceFault = function (i) { return true; }; 14 return false; 15 }; 16 17 function empty() {} 18 19 var globalArgs; 20 function escape(args) { globalArgs = args; } 21 22 // Check rest array length. 23 function length(i, ...rest) { 24 assertRecoveredOnBailout(rest, true); 25 return rest.length; 26 } 27 28 function lengthBail(i, ...rest) { 29 resumeHere(i); 30 assertRecoveredOnBailout(rest, true); 31 return rest.length; 32 } 33 34 // Check rest array content. 35 function content(...rest) { 36 assertEq(rest[0], rest[1]); 37 assertRecoveredOnBailout(rest, true); 38 return rest.length; 39 } 40 41 function contentBail(...rest) { 42 resumeHere(rest[0]); 43 assertEq(rest[0], rest[1]); 44 assertRecoveredOnBailout(rest, true); 45 return rest.length; 46 } 47 48 function contentExtraFormals(i, ...rest) { 49 assertEq(rest[0], i); 50 assertRecoveredOnBailout(rest, true); 51 return rest.length; 52 } 53 function contentExtraFormalsBail(i, ...rest) { 54 resumeHere(i); 55 assertEq(rest[0], i); 56 assertRecoveredOnBailout(rest, true); 57 return rest.length; 58 } 59 60 // No scalar replacement when the rest array is modified. 61 function setLength(i, ...rest) { 62 rest.length = 0; 63 assertRecoveredOnBailout(rest, false); 64 return rest.length; 65 } 66 67 function setLengthBail(i, ...rest) { 68 resumeHere(i); 69 rest.length = 0; 70 assertRecoveredOnBailout(rest, false); 71 return rest.length; 72 } 73 74 function setContent(i, ...rest) { 75 rest[0] = "bad"; 76 assertRecoveredOnBailout(rest, false); 77 return rest.length; 78 } 79 80 function setContentBail(i, ...rest) { 81 resumeHere(i); 82 rest[0] = "bad"; 83 assertRecoveredOnBailout(rest, false); 84 return rest.length; 85 } 86 87 function deleteContent(i, ...rest) { 88 delete rest[0]; 89 assertRecoveredOnBailout(rest, false); 90 return rest.length; 91 } 92 93 function deleteContentBail(i, ...rest) { 94 resumeHere(i); 95 delete rest[0]; 96 assertRecoveredOnBailout(rest, false); 97 return rest.length; 98 } 99 100 // No scalar replacement when the rest array escapes. 101 function escapes(i, ...rest) { 102 escape(rest); 103 assertRecoveredOnBailout(rest, false); 104 return rest.length; 105 } 106 107 function escapesBail(i, ...rest) { 108 resumeHere(i); 109 escape(rest); 110 assertRecoveredOnBailout(rest, false); 111 return rest.length; 112 } 113 114 // Check rest array with Function.prototype.apply. 115 function apply(...rest) { 116 empty.apply(null, rest); 117 assertRecoveredOnBailout(rest, true); 118 return rest.length; 119 } 120 121 function applyBail(...rest) { 122 resumeHere(rest[0]); 123 empty.apply(null, rest); 124 assertRecoveredOnBailout(rest, true); 125 return rest.length; 126 } 127 128 function applyExtraFormals(i, ...rest) { 129 empty.apply(null, rest); 130 assertRecoveredOnBailout(rest, true); 131 return rest.length; 132 } 133 134 function applyExtraFormalsBail(i, ...rest) { 135 resumeHere(i); 136 empty.apply(null, rest); 137 assertRecoveredOnBailout(rest, true); 138 return rest.length; 139 } 140 141 // Check rest array with spread. 142 function spread(...rest) { 143 empty(...rest); 144 assertRecoveredOnBailout(rest, true); 145 return rest.length; 146 } 147 148 function spreadBail(...rest) { 149 resumeHere(rest[0]); 150 empty(...rest); 151 assertRecoveredOnBailout(rest, true); 152 return rest.length; 153 } 154 155 function spreadExtraFormals(i, ...rest) { 156 empty(...rest); 157 assertRecoveredOnBailout(rest, true); 158 return rest.length; 159 } 160 161 function spreadExtraFormalsBail(i, ...rest) { 162 resumeHere(i); 163 empty(...rest); 164 assertRecoveredOnBailout(rest, true); 165 return rest.length; 166 } 167 168 // Extra args currently not supported. 169 function spreadExtraArgs(...rest) { 170 empty(0, ...rest); 171 assertRecoveredOnBailout(rest, false); 172 return rest.length; 173 } 174 175 function spreadExtraArgsBail(...rest) { 176 resumeHere(rest[0]); 177 empty(0, ...rest); 178 assertRecoveredOnBailout(rest, false); 179 return rest.length; 180 } 181 182 // Check rest array with new spread. 183 function newSpread(...rest) { 184 new empty(...rest); 185 assertRecoveredOnBailout(rest, true); 186 return rest.length; 187 } 188 189 function newSpreadBail(...rest) { 190 resumeHere(rest[0]); 191 new empty(...rest); 192 assertRecoveredOnBailout(rest, true); 193 return rest.length; 194 } 195 196 function newSpreadExtraFormals(i, ...rest) { 197 new empty(...rest); 198 assertRecoveredOnBailout(rest, true); 199 return rest.length; 200 } 201 202 function newSpreadExtraFormalsBail(i, ...rest) { 203 resumeHere(i); 204 new empty(...rest); 205 assertRecoveredOnBailout(rest, true); 206 return rest.length; 207 } 208 209 // Extra args currently not supported. 210 function newSpreadExtraArgs(...rest) { 211 new empty(0, ...rest); 212 assertRecoveredOnBailout(rest, false); 213 return rest.length; 214 } 215 216 function newSpreadExtraArgsBail(...rest) { 217 resumeHere(rest[0]); 218 new empty(0, ...rest); 219 assertRecoveredOnBailout(rest, false); 220 return rest.length; 221 } 222 223 // The arguments object isn't mapped. 224 function setArgs(i, ...rest) { 225 arguments[1] = "fail"; 226 assertEq(rest[0], i); 227 assertRecoveredOnBailout(rest, true); 228 return rest.length; 229 } 230 231 function setArgsBail(i, ...rest) { 232 resumeHere(i); 233 arguments[1] = "fail"; 234 assertEq(rest[0], i); 235 assertRecoveredOnBailout(rest, true); 236 return rest.length; 237 } 238 239 // Check that we correctly allocate the array after taking the recover path. 240 var uceFault_recoverLength = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverLength')); 241 function recoverLength(i, ...rest) { 242 if (uceFault_recoverLength(i) || uceFault_recoverLength(i)) { 243 return rest.length; 244 } 245 assertRecoveredOnBailout(rest, true); 246 return 0; 247 } 248 249 var uceFault_recoverContent = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverContent')); 250 function recoverContent(i, ...rest) { 251 if (uceFault_recoverContent(i) || uceFault_recoverContent(i)) { 252 return rest[0]; 253 } 254 assertRecoveredOnBailout(rest, true); 255 return 0; 256 } 257 258 var uceFault_recoverApply = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverApply')); 259 function recoverApply(i, ...rest) { 260 if (uceFault_recoverApply(i) || uceFault_recoverApply(i)) { 261 return empty.apply(null, rest); 262 } 263 assertRecoveredOnBailout(rest, true); 264 return 0; 265 } 266 267 var uceFault_recoverSpread = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverSpread')); 268 function recoverSpread(i, ...rest) { 269 if (uceFault_recoverSpread(i) || uceFault_recoverSpread(i)) { 270 return empty(...rest); 271 } 272 assertRecoveredOnBailout(rest, true); 273 return 0; 274 } 275 276 var uceFault_recoverNewSpread = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverNewSpread')); 277 function recoverNewSpread(i, ...rest) { 278 if (uceFault_recoverNewSpread(i) || uceFault_recoverNewSpread(i)) { 279 return new empty(...rest); 280 } 281 assertRecoveredOnBailout(rest, true); 282 return 0; 283 } 284 285 var uceFault_recoverSetArgs = eval(`(${uceFault})`.replace('uceFault', 'uceFault_recoverSetArgs')); 286 function recoverSetArgs(i, ...rest) { 287 arguments[1] = "fail"; 288 if (uceFault_recoverSetArgs(i) || uceFault_recoverSetArgs(i)) { 289 // Ensure arguments[1] isn't mapped to rest[0]. 290 assertEq(rest[0], "ok"); 291 return 0; 292 } 293 assertRecoveredOnBailout(rest, true); 294 return 0; 295 } 296 297 // Prevent compilation of the top-level 298 eval(`(${resumeHere})`); 299 300 for (let i = 0; i < 100; i++) { 301 length(i); 302 lengthBail(i); 303 content(i, i); 304 contentBail(i, i); 305 contentExtraFormals(i, i); 306 contentExtraFormalsBail(i, i); 307 setLength(i); 308 setLengthBail(i); 309 setContent(i, i); 310 setContentBail(i, i); 311 deleteContent(i, i); 312 deleteContentBail(i, i); 313 escapes(i); 314 escapesBail(i); 315 apply(i); 316 applyBail(i); 317 applyExtraFormals(i); 318 applyExtraFormalsBail(i); 319 spread(i); 320 spreadBail(i); 321 spreadExtraFormals(i); 322 spreadExtraFormalsBail(i); 323 spreadExtraArgs(i); 324 spreadExtraArgsBail(i); 325 newSpread(i); 326 newSpreadBail(i); 327 newSpreadExtraFormals(i); 328 newSpreadExtraFormalsBail(i); 329 newSpreadExtraArgs(i); 330 newSpreadExtraArgsBail(i); 331 setArgs(i, i); 332 setArgsBail(i, i); 333 334 recoverLength(i); 335 recoverContent(i); 336 recoverApply(i); 337 recoverSpread(i); 338 recoverNewSpread(i); 339 recoverSetArgs(i, "ok"); 340 }