Debugger-findScripts-delazify.js (13567B)
1 // |jit-test| skip-if: isLcovEnabled() 2 3 // findScript should try to avoid delazifying unnecessarily. 4 5 function newTestcase(code) { 6 var g = newGlobal({newCompartment: true}); 7 var dbg = new Debugger(); 8 var gw = dbg.addDebuggee(g); 9 10 var lines = code.split('\n'); 11 // Returns the line number of the line with "<= line". 12 // + 1 for 1-origin. 13 var line = lines.findIndex(x => x.includes("<= line")) + 1; 14 15 g.eval(code); 16 17 // Functions are relazified, and the top-level script is dropped. 18 relazifyFunctions(); 19 20 return [dbg, g, line]; 21 } 22 23 var url = thisFilename(); 24 var dbg, g, line, scripts; 25 26 // If the specified line is inside the function body, only the function should 27 // be delazified. 28 [dbg, g, line] = newTestcase(` 29 function f1() { 30 } 31 function f2() { 32 // <= line 33 } 34 function f3() { 35 } 36 `); 37 38 assertEq(g.eval(`isLazyFunction(f1)`), true); 39 assertEq(g.eval(`isLazyFunction(f2)`), true); 40 assertEq(g.eval(`isLazyFunction(f3)`), true); 41 42 scripts = dbg.findScripts({url, line}); 43 assertEq(scripts.length, 1); 44 assertEq(scripts.map(s => s.displayName).sort().join(","), "f2"); 45 46 assertEq(g.eval(`isLazyFunction(f1)`), true); 47 assertEq(g.eval(`isLazyFunction(f2)`), false); 48 assertEq(g.eval(`isLazyFunction(f3)`), true); 49 50 // If the functions starts at the specified line, the function shouldn't be 51 // the first function to delazify. 52 [dbg, g, line] = newTestcase(` 53 function f1() { 54 } 55 function f2() { 56 } 57 function f3() { // <= line 58 } 59 function f4() { 60 } 61 `); 62 63 assertEq(g.eval(`isLazyFunction(f1)`), true); 64 assertEq(g.eval(`isLazyFunction(f2)`), true); 65 assertEq(g.eval(`isLazyFunction(f3)`), true); 66 assertEq(g.eval(`isLazyFunction(f4)`), true); 67 68 scripts = dbg.findScripts({url, line}); 69 assertEq(scripts.length, 1); 70 assertEq(scripts.map(s => s.displayName).sort().join(","), "f3"); 71 72 assertEq(g.eval(`isLazyFunction(f1)`), true); 73 // f2 is delazified because f3 cannot be the first function to delazify. 74 assertEq(g.eval(`isLazyFunction(f2)`), false); 75 assertEq(g.eval(`isLazyFunction(f3)`), false); 76 assertEq(g.eval(`isLazyFunction(f4)`), true); 77 78 // Multiple functions in the specified line, and one of them starts before 79 // the specified line. 80 // All functions should be returned, and others shouldn't be delazified. 81 [dbg, g, line] = newTestcase(` 82 function f1() {} 83 function f2() { 84 } function f3() {} function f4() {} function f5() { // <= line 85 } 86 function f6() {} 87 `); 88 89 assertEq(g.eval(`isLazyFunction(f1)`), true); 90 assertEq(g.eval(`isLazyFunction(f2)`), true); 91 assertEq(g.eval(`isLazyFunction(f3)`), true); 92 assertEq(g.eval(`isLazyFunction(f4)`), true); 93 assertEq(g.eval(`isLazyFunction(f5)`), true); 94 assertEq(g.eval(`isLazyFunction(f6)`), true); 95 96 scripts = dbg.findScripts({url, line}); 97 assertEq(scripts.length, 4); 98 assertEq(scripts.map(s => s.displayName).sort().join(","), "f2,f3,f4,f5"); 99 100 assertEq(g.eval(`isLazyFunction(f1)`), true); 101 assertEq(g.eval(`isLazyFunction(f2)`), false); 102 assertEq(g.eval(`isLazyFunction(f3)`), false); 103 assertEq(g.eval(`isLazyFunction(f4)`), false); 104 assertEq(g.eval(`isLazyFunction(f5)`), false); 105 assertEq(g.eval(`isLazyFunction(f6)`), true); 106 107 // The same rule should apply to inner functions. 108 [dbg, g, line] = newTestcase(` 109 function f1() {} 110 function f2() { 111 function g1() { 112 } 113 function g2() { 114 function h1() {} 115 function h2() { 116 } function h3() {} function h4() {} function h5() { // <= line 117 } 118 function h6() {} 119 120 return [h1, h2, h3, h4, h5, h6]; 121 } 122 function g3() { 123 } 124 125 return [g1, g2, g3]; 126 } 127 function f3() {} 128 `); 129 130 assertEq(g.eval(`isLazyFunction(f1)`), true); 131 assertEq(g.eval(`isLazyFunction(f2)`), true); 132 assertEq(g.eval(`isLazyFunction(f3)`), true); 133 134 scripts = dbg.findScripts({url, line}); 135 assertEq(scripts.length, 6); 136 assertEq(scripts.map(s => s.displayName).sort().join(","), "f2,g2,h2,h3,h4,h5"); 137 138 assertEq(g.eval(`isLazyFunction(f1)`), true); 139 assertEq(g.eval(`isLazyFunction(f2)`), false); 140 assertEq(g.eval(`isLazyFunction(f3)`), true); 141 g.eval(`var [g1, g2, g3] = f2();`); 142 assertEq(g.eval(`isLazyFunction(g1)`), true); 143 assertEq(g.eval(`isLazyFunction(g2)`), false); 144 assertEq(g.eval(`isLazyFunction(g3)`), true); 145 g.eval(`var [h1, h2, h3, h4, h5, h6] = g2();`); 146 assertEq(g.eval(`isLazyFunction(h1)`), true); 147 assertEq(g.eval(`isLazyFunction(h2)`), false); 148 assertEq(g.eval(`isLazyFunction(h3)`), false); 149 assertEq(g.eval(`isLazyFunction(h4)`), false); 150 assertEq(g.eval(`isLazyFunction(h5)`), false); 151 assertEq(g.eval(`isLazyFunction(h6)`), true); 152 153 // The same rule should apply to functions inside parameter expression. 154 [dbg, g, line] = newTestcase(` 155 function f1( 156 a = function g1() {}, 157 b = function g2() { 158 }, c = function g3() {}, d = function g4() { // <= line 159 }, 160 e = function g5() {}, 161 ) { 162 return [a, b, c, d, e]; 163 } 164 `); 165 166 assertEq(g.eval(`isLazyFunction(f1)`), true); 167 168 scripts = dbg.findScripts({url, line}); 169 assertEq(scripts.length, 4); 170 assertEq(scripts.map(s => s.displayName).sort().join(","), "f1,g2,g3,g4"); 171 172 assertEq(g.eval(`isLazyFunction(f1)`), false); 173 174 g.eval(`var [g1, g2, g3, g4, g5] = f1();`); 175 176 assertEq(g.eval(`isLazyFunction(g1)`), true); 177 assertEq(g.eval(`isLazyFunction(g2)`), false); 178 assertEq(g.eval(`isLazyFunction(g3)`), false); 179 assertEq(g.eval(`isLazyFunction(g4)`), false); 180 assertEq(g.eval(`isLazyFunction(g5)`), true); 181 182 // The same should apply to function inside method with computed property. 183 [dbg, g, line] = newTestcase(` 184 var f1, f2, f3; 185 var O = { 186 [(f1 = () => 0, "m1")]() { 187 }, 188 [(f2 = () => 0, "m2")](p2) { // <= line 189 }, 190 [(f3 = () => 0, "m3")]() { 191 }, 192 } 193 `); 194 195 assertEq(g.eval(`isLazyFunction(f1)`), true); 196 assertEq(g.eval(`isLazyFunction(O.m2)`), true); 197 assertEq(g.eval(`isLazyFunction(f2)`), true); 198 assertEq(g.eval(`isLazyFunction(O.m1)`), true); 199 assertEq(g.eval(`isLazyFunction(f3)`), true); 200 assertEq(g.eval(`isLazyFunction(O.m3)`), true); 201 202 scripts = dbg.findScripts({url, line}); 203 assertEq(scripts.length, 2); 204 assertEq(scripts.map(s => s.displayName).sort().join(","), "f2,"); 205 // Use parameterNames because displayName isn't set for computed property. 206 assertEq(scripts.map(s => `${s.displayName}(${s.parameterNames.join(",")})`) 207 .sort().join(","), "f2(),undefined(p2)"); 208 209 assertEq(g.eval(`isLazyFunction(f1)`), true); 210 // m1 is delazified because f2 cannot be the first function to delazify. 211 assertEq(g.eval(`isLazyFunction(O.m1)`), false); 212 assertEq(g.eval(`isLazyFunction(f2)`), false); 213 assertEq(g.eval(`isLazyFunction(O.m2)`), false); 214 assertEq(g.eval(`isLazyFunction(f3)`), true); 215 assertEq(g.eval(`isLazyFunction(O.m3)`), true); 216 217 [dbg, g, line] = newTestcase(` 218 var f1, f2, f3; 219 var O = { 220 [(f1 = () => 0, "m1")]() { 221 }, 222 [(f2 = () => 0 + 223 1, "m2")](p2) { // <= line 224 }, 225 [(f3 = () => 0, "m3")]() { 226 }, 227 } 228 `); 229 230 assertEq(g.eval(`isLazyFunction(f1)`), true); 231 assertEq(g.eval(`isLazyFunction(O.m1)`), true); 232 assertEq(g.eval(`isLazyFunction(f2)`), true); 233 assertEq(g.eval(`isLazyFunction(O.m2)`), true); 234 assertEq(g.eval(`isLazyFunction(f3)`), true); 235 assertEq(g.eval(`isLazyFunction(O.m3)`), true); 236 237 scripts = dbg.findScripts({url, line}); 238 assertEq(scripts.length, 2); 239 assertEq(scripts.map(s => `${s.displayName}(${s.parameterNames.join(",")})`) 240 .sort().join(","), "f2(),undefined(p2)"); 241 242 assertEq(g.eval(`isLazyFunction(f1)`), true); 243 assertEq(g.eval(`isLazyFunction(O.m1)`), true); 244 assertEq(g.eval(`isLazyFunction(f2)`), false); 245 assertEq(g.eval(`isLazyFunction(O.m2)`), false); 246 assertEq(g.eval(`isLazyFunction(f3)`), true); 247 assertEq(g.eval(`isLazyFunction(O.m3)`), true); 248 249 // Class constructor shouldn't be delazified even if methods match. 250 [dbg, g, line] = newTestcase(` 251 // Use variable to access across eval. 252 var C = class { 253 constructor() { 254 } 255 m1() {} 256 m2() { 257 } m3() {} m4() { // <= line 258 } 259 m5() {} 260 } 261 `); 262 263 assertEq(g.eval(`isLazyFunction(C)`), true); 264 assertEq(g.eval(`isLazyFunction(C.prototype.m1)`), true); 265 assertEq(g.eval(`isLazyFunction(C.prototype.m2)`), true); 266 assertEq(g.eval(`isLazyFunction(C.prototype.m3)`), true); 267 assertEq(g.eval(`isLazyFunction(C.prototype.m4)`), true); 268 assertEq(g.eval(`isLazyFunction(C.prototype.m5)`), true); 269 270 scripts = dbg.findScripts({url, line}); 271 assertEq(scripts.length, 3); 272 assertEq(scripts.map(s => s.displayName).sort().join(","), "m2,m3,m4"); 273 274 assertEq(g.eval(`isLazyFunction(C)`), true); 275 assertEq(g.eval(`isLazyFunction(C.prototype.m1)`), true); 276 assertEq(g.eval(`isLazyFunction(C.prototype.m2)`), false); 277 assertEq(g.eval(`isLazyFunction(C.prototype.m3)`), false); 278 assertEq(g.eval(`isLazyFunction(C.prototype.m4)`), false); 279 assertEq(g.eval(`isLazyFunction(C.prototype.m5)`), true); 280 281 // If the line is placed before sourceStart, the function shouldn't match, 282 // and the function shouldn't be delazified. 283 [dbg, g, line] = newTestcase(` 284 function f1() { 285 } 286 function f2() { 287 } 288 function 289 // <= line 290 f3() { 291 } 292 function f4() { 293 } 294 `); 295 296 assertEq(g.eval(`isLazyFunction(f1)`), true); 297 assertEq(g.eval(`isLazyFunction(f2)`), true); 298 assertEq(g.eval(`isLazyFunction(f3)`), true); 299 assertEq(g.eval(`isLazyFunction(f4)`), true); 300 301 scripts = dbg.findScripts({url, line}); 302 assertEq(scripts.length, 0); 303 304 assertEq(g.eval(`isLazyFunction(f1)`), true); 305 // f2 is delazified because it's the first function before the specified line. 306 assertEq(g.eval(`isLazyFunction(f2)`), false); 307 assertEq(g.eval(`isLazyFunction(f3)`), true); 308 assertEq(g.eval(`isLazyFunction(f4)`), true); 309 310 [dbg, g, line] = newTestcase(` 311 function f1() { 312 } 313 function f2() { 314 } 315 function f3 316 // <= line 317 () { 318 } 319 function f4() { 320 } 321 `); 322 323 assertEq(g.eval(`isLazyFunction(f1)`), true); 324 assertEq(g.eval(`isLazyFunction(f2)`), true); 325 assertEq(g.eval(`isLazyFunction(f3)`), true); 326 assertEq(g.eval(`isLazyFunction(f4)`), true); 327 328 scripts = dbg.findScripts({url, line}); 329 assertEq(scripts.length, 0); 330 331 assertEq(g.eval(`isLazyFunction(f1)`), true); 332 // f2 is delazified because it's the first function before the specified line. 333 assertEq(g.eval(`isLazyFunction(f2)`), false); 334 assertEq(g.eval(`isLazyFunction(f3)`), true); 335 assertEq(g.eval(`isLazyFunction(f4)`), true); 336 337 [dbg, g, line] = newTestcase(` 338 function f1() { 339 } 340 function f2() { 341 } 342 function f3 343 ( // <= line 344 ) { 345 } 346 function f4() { 347 } 348 `); 349 350 assertEq(g.eval(`isLazyFunction(f1)`), true); 351 assertEq(g.eval(`isLazyFunction(f2)`), true); 352 assertEq(g.eval(`isLazyFunction(f3)`), true); 353 assertEq(g.eval(`isLazyFunction(f4)`), true); 354 355 scripts = dbg.findScripts({url, line}); 356 assertEq(scripts.length, 1); 357 assertEq(scripts.map(s => s.displayName).sort().join(","), "f3"); 358 359 assertEq(g.eval(`isLazyFunction(f1)`), true); 360 // f2 is delazified because it's the first function _before_ the specified line. 361 assertEq(g.eval(`isLazyFunction(f2)`), false); 362 assertEq(g.eval(`isLazyFunction(f3)`), false); 363 assertEq(g.eval(`isLazyFunction(f4)`), true); 364 365 [dbg, g, line] = newTestcase(` 366 function f1() { 367 } 368 function f2() { 369 } 370 function f3 371 ( 372 // <= line 373 ) { 374 } 375 function f4() { 376 } 377 `); 378 379 assertEq(g.eval(`isLazyFunction(f1)`), true); 380 assertEq(g.eval(`isLazyFunction(f2)`), true); 381 assertEq(g.eval(`isLazyFunction(f3)`), true); 382 assertEq(g.eval(`isLazyFunction(f4)`), true); 383 384 scripts = dbg.findScripts({url, line}); 385 assertEq(scripts.length, 1); 386 assertEq(scripts.map(s => s.displayName).sort().join(","), "f3"); 387 388 assertEq(g.eval(`isLazyFunction(f1)`), true); 389 assertEq(g.eval(`isLazyFunction(f2)`), true); 390 assertEq(g.eval(`isLazyFunction(f3)`), false); 391 assertEq(g.eval(`isLazyFunction(f4)`), true); 392 393 // If the specified line is the next line after the function ends, 394 // nothing should match, but the function should be delazified. 395 [dbg, g, line] = newTestcase(` 396 function f1() { 397 } 398 function f2() { 399 } 400 // <= line 401 function f3() { 402 } 403 `); 404 405 assertEq(g.eval(`isLazyFunction(f1)`), true); 406 assertEq(g.eval(`isLazyFunction(f2)`), true); 407 assertEq(g.eval(`isLazyFunction(f3)`), true); 408 409 scripts = dbg.findScripts({url, line}); 410 assertEq(scripts.length, 0); 411 412 assertEq(g.eval(`isLazyFunction(f1)`), true); 413 assertEq(g.eval(`isLazyFunction(f2)`), false); 414 assertEq(g.eval(`isLazyFunction(f3)`), true); 415 416 // The matching non-lazy script should prevent the previous function's 417 // delazification. 418 [dbg, g, line] = newTestcase(` 419 function f1() { 420 } 421 function f2() { 422 } 423 function f3() { 424 // <= line 425 } 426 function f4() { 427 } 428 `); 429 430 assertEq(g.eval(`isLazyFunction(f1)`), true); 431 assertEq(g.eval(`isLazyFunction(f2)`), true); 432 assertEq(g.eval(`isLazyFunction(f3)`), true); 433 assertEq(g.eval(`isLazyFunction(f4)`), true); 434 435 // Delazify f3. 436 g.eval(`f3()`); 437 438 assertEq(g.eval(`isLazyFunction(f1)`), true); 439 assertEq(g.eval(`isLazyFunction(f2)`), true); 440 assertEq(g.eval(`isLazyFunction(f3)`), false); 441 assertEq(g.eval(`isLazyFunction(f4)`), true); 442 443 scripts = dbg.findScripts({url, line}); 444 assertEq(scripts.length, 1); 445 assertEq(scripts.map(s => s.displayName).sort().join(","), "f3"); 446 447 assertEq(g.eval(`isLazyFunction(f1)`), true); 448 assertEq(g.eval(`isLazyFunction(f2)`), true); 449 assertEq(g.eval(`isLazyFunction(f3)`), false); 450 assertEq(g.eval(`isLazyFunction(f4)`), true); 451 452 // The non-matching non-lazy script should prevent the previous function's 453 // delazification. 454 [dbg, g, line] = newTestcase(` 455 function f1() { 456 } 457 function f2() { 458 } 459 function f3() { 460 } 461 // <= line 462 function f4() { 463 } 464 `); 465 466 assertEq(g.eval(`isLazyFunction(f1)`), true); 467 assertEq(g.eval(`isLazyFunction(f2)`), true); 468 assertEq(g.eval(`isLazyFunction(f3)`), true); 469 assertEq(g.eval(`isLazyFunction(f4)`), true); 470 471 // Delazify f3. 472 g.eval(`f3()`); 473 474 assertEq(g.eval(`isLazyFunction(f1)`), true); 475 assertEq(g.eval(`isLazyFunction(f2)`), true); 476 assertEq(g.eval(`isLazyFunction(f3)`), false); 477 assertEq(g.eval(`isLazyFunction(f4)`), true); 478 479 scripts = dbg.findScripts({url, line}); 480 assertEq(scripts.length, 0); 481 482 assertEq(g.eval(`isLazyFunction(f1)`), true); 483 assertEq(g.eval(`isLazyFunction(f2)`), true); 484 assertEq(g.eval(`isLazyFunction(f3)`), false); 485 assertEq(g.eval(`isLazyFunction(f4)`), true);