1 /* See license.txt for terms of usage */ 2 3 FBL.ns(function() { with (FBL) 4 { 5 const Cc = Components.classes; 6 const Ci = Components.interfaces; 7 8 const PCMAP_SOURCETEXT = Ci.jsdIScript.PCMAP_SOURCETEXT; 9 const PCMAP_PRETTYPRINT = Ci.jsdIScript.PCMAP_PRETTYPRINT; 10 11 12 //* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 13 /* 14 * SourceFile one for every compilation unit. 15 * Unique URL for each. (href) 16 * Unique outerScript, the statements outside of any function defintion 17 * sourceCache keyed by href has source for this compilation unit 18 * Stored by href in context. 19 * Contains array of jsdIScript for functions (scripts) defined in this unit 20 * May contain line table (for sources viewed) 21 */ 22 23 Firebug.SourceFile = function (compilation_unit_type) 24 { 25 this.compilation_unit_type = compilation_unit_type; /*@explore*/ 26 } 27 28 Firebug.SourceFile.prototype = 29 { 30 getBaseLineOffset: function() 31 { 32 return 0; 33 }, 34 35 toString: function() 36 { 37 var str = (this.compilation_unit_type?this.compilation_unit_type+" ":"")+this.href+" script.tags( "; 38 if (this.outerScript) 39 str += (this.outerScript.isValid?this.outerScript.tag:"X") +"| "; 40 if (this.innerScripts) 41 { 42 var numberInvalid = 0; 43 for (var p in this.innerScripts) 44 { 45 var script = this.innerScripts[p]; 46 if (script.isValid) 47 str += p+" "; 48 else 49 numberInvalid++; 50 } 51 } 52 str += ")"+(numberInvalid ? "("+numberInvalid+" invalid)" : ""); 53 return str; 54 }, 55 56 forEachScript: function(callback) 57 { 58 if (this.outerScript) 59 callback(this.outerScript); 60 if (this.innerScripts) 61 { 62 for (var p in this.innerScripts) 63 { 64 var script = this.innerScripts[p]; 65 var rc = callback(script); 66 if (rc) 67 return rc; 68 } 69 } 70 }, 71 72 getLineRanges: function() 73 { 74 var str = ""; 75 this.forEachScript(function appendARange(script) 76 { 77 var endLineNumber = script.baseLineNumber + script.lineExtent; 78 str += " "+script.baseLineNumber +"-("+script.tag+")-"+endLineNumber; 79 }); 80 return str; 81 }, 82 83 getSourceLength: function() 84 { 85 return this.sourceLength; 86 }, 87 88 getLine: function(context, lineNo) 89 { 90 return context.sourceCache.getLine(this.href, lineNo); 91 }, 92 93 addToLineTable: function(script) 94 { 95 if (!script || !script.isValid) 96 { 97 if (FBTrace.DBG_ERRORS) 98 FBTrace.sysout("addToLineTable got invalid script "+(script?script.tag:"null")+"\n"); 99 return; 100 } 101 102 // For outer scripts, a better algorithm would loop over PC, use pcToLine to mark the lines. 103 // This assumes there are fewer PCs in an outer script than lines, probably true for large systems. 104 // And now addToLineTable is only used for outerScripts (eval and top-level). 105 // But since we can't know the range of PC values we cannot use that approach. 106 107 if (!this.outerScriptLineMap) 108 this.outerScriptLineMap = []; 109 110 var lineCount = script.lineExtent + 1; 111 var offset = this.getBaseLineOffset(); 112 if (FBTrace.DBG_LINETABLE) 113 { 114 FBTrace.sysout("lib.SourceFile.addToLineTable script.tag:"+script.tag+" lineExtent="+lineCount+" baseLineNumber="+script.baseLineNumber+" offset="+offset+" for "+this.compilation_unit_type+"\n"); 115 var startTime = new Date().getTime(); 116 } 117 if (lineCount > 100) 118 lineCount = 100; // isLineExecutable requires about 1ms per line, so it can only be called for toy programs 119 120 for (var i = 0; i <= lineCount; i++) 121 { 122 var scriptLineNo = i + script.baseLineNumber; // the max is (i + script.baseLineNumber + script.lineExtent) 123 var mapLineNo = scriptLineNo - offset; 124 try 125 { 126 if (script.isLineExecutable(scriptLineNo, this.pcmap_type)) 127 this.outerScriptLineMap.push(mapLineNo); 128 } 129 catch (e) 130 { 131 // I guess not... 132 } 133 134 if (FBTrace.DBG_LINETABLE) 135 { 136 var pcFromLine = script.lineToPc(scriptLineNo, this.pcmap_type); 137 var lineFromPC = script.pcToLine(pcFromLine, this.pcmap_type); 138 if (this.outerScriptLineMap.indexOf(mapLineNo) != -1) 139 FBTrace.sysout("lib.SourceFile.addToLineTable ["+mapLineNo+"]="+script.tag+" for scriptLineNo="+scriptLineNo+" vs "+lineFromPC+"=lineFromPC; lineToPc="+pcFromLine+" with map="+(this.pcmap_type==PCMAP_PRETTYPRINT?"PP":"SOURCE")+"\n"); 140 else 141 FBTrace.sysout("lib.SourceFile.addToLineTable not executable scriptLineNo="+scriptLineNo+" vs "+lineFromPC+"=lineFromPC; lineToPc="+pcFromLine+"\n"); 142 } 143 } 144 if (FBTrace.DBG_LINETABLE) 145 { 146 var endTime = new Date().getTime(); 147 var delta = endTime - startTime ; 148 if (delta > 0) FBTrace.sysout("SourceFile.addToLineTable processed "+lineCount+" lines in "+delta+" millisecs "+Math.round(lineCount/delta)+" lines per millisecond\n"); 149 FBTrace.sysout("SourceFile.addToLineTable: "+this.toString()+"\n"); 150 } 151 }, 152 153 addToLineTableByPCLoop: function(script) 154 { 155 // This code is not called; it crashes FF3pre https://bugzilla.mozilla.org/show_bug.cgi?id=430205 156 if (!this.outerScriptLineMap) 157 this.outerScriptLineMap = {}; 158 159 var lineCount = script.lineExtent; 160 var offset = this.getBaseLineOffset(); 161 if (FBTrace.DBG_LINETABLE) 162 { 163 FBTrace.sysout("lib.SourceFile.addToLineTableByPCLoop script.tag:"+script.tag+" lineCount="+lineCount+" offset="+offset+" for "+this.compilation_unit_type+"\n"); 164 var startTime = new Date().getTime(); 165 } 166 167 for (var i = 0; i <= 10*lineCount; i++) 168 { 169 var lineFromPC = script.pcToLine(i, this.pcmap_type); 170 //FBTrace.sysout("lib.SourceFile.addToLineTableByPCLoop pc="+i+" line: "+lineFromPC+"\n"); 171 this.outerScriptLineMap[lineFromPC] = script; 172 if (lineFromPC >= lineCount) break; 173 } 174 175 if (FBTrace.DBG_LINETABLE) 176 { 177 FBTrace.sysout("SourceFile.addToLineTableByPCLoop: "+this.toString()+"\n"); 178 var endTime = new Date().getTime(); 179 var delta = endTime - startTime ; 180 if (delta > 0) FBTrace.sysout("SourceFileaddToLineTableByPCLoop processed "+lineCount+" lines in "+delta+" millisecs "+Math.round(lineCount/delta)+" lines per millisecond\n"); 181 } 182 }, 183 184 getScriptsAtLineNumber: function(lineNo, mustBeExecutableLine) 185 { 186 var offset = this.getBaseLineOffset(); 187 188 if (!this.innerScripts) 189 return; // eg URLOnly 190 191 var targetLineNo = lineNo + offset; // lineNo is user-viewed number, targetLineNo is jsd number 192 193 var scripts = []; 194 for (var p in this.innerScripts) 195 { 196 var script = this.innerScripts[p]; 197 if (mustBeExecutableLine && !script.isValid) continue; 198 this.addScriptAtLineNumber(scripts, script, targetLineNo, mustBeExecutableLine, offset); 199 } 200 201 if (this.outerScript && !(mustBeExecutableLine && !this.outerScript.isValid) ) 202 this.addScriptAtLineNumber(scripts, this.outerScript, targetLineNo, mustBeExecutableLine, offset); 203 204 if (FBTrace.DBG_LINETABLE) 205 { 206 if (scripts.length < 1) 207 { 208 FBTrace.sysout("lib.getScriptsAtLineNumber no targetScript at "+lineNo," for sourceFile:"+this.toString()); 209 return false; 210 } 211 else 212 { 213 FBTrace.sysout("getScriptsAtLineNumber offset "+offset+" for sourcefile: "+this.toString()+"\n"); 214 } 215 } 216 217 return (scripts.length > 0) ? scripts : false; 218 }, 219 220 addScriptAtLineNumber: function(scripts, script, targetLineNo, mustBeExecutableLine, offset) 221 { 222 // script.isValid will be true. 223 if (FBTrace.DBG_LINETABLE) 224 FBTrace.sysout("addScriptAtLineNumber trying "+script.tag+", is "+script.baseLineNumber+" <= "+targetLineNo +" <= "+ (script.baseLineNumber + script.lineExtent)+"? using offset = "+offset+"\n"); 225 226 if (targetLineNo >= script.baseLineNumber) 227 { 228 if ( (script.baseLineNumber + script.lineExtent) >= targetLineNo) 229 { 230 if (mustBeExecutableLine) 231 { 232 try 233 { 234 if (!script.isLineExecutable(targetLineNo, this.pcmap_type) ) 235 { 236 if (FBTrace.DBG_LINETABLE) 237 FBTrace.sysout("getScriptsAtLineNumber tried "+script.tag+", not executable at targetLineNo:"+targetLineNo+" pcmap:"+this.pcmap_type+"\n"); 238 return; 239 } 240 } 241 catch (e) 242 { 243 // Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [jsdIScript.isLineExecutable] 244 return; 245 } 246 } 247 scripts.push(script); 248 if (FBTrace.DBG_LINETABLE) 249 { 250 var checkExecutable = ""; 251 if (mustBeExecutableLine) 252 var checkExecutable = " isLineExecutable: "+script.isLineExecutable(targetLineNo, this.pcmap_type)+"@pc:"+script.lineToPc(targetLineNo, this.pcmap_type); 253 FBTrace.sysout("getScriptsAtLineNumber found "+script.tag+", isValid: "+script.isValid+" targetLineNo:"+targetLineNo+checkExecutable+"\n"); 254 } 255 } 256 } 257 }, 258 259 scriptsIfLineCouldBeExecutable: function(lineNo) // script may not be valid 260 { 261 var scripts = this.getScriptsAtLineNumber(lineNo, true); 262 if (FBTrace.DBG_LINETABLE && !scripts) FBTrace.sysout("lib.scriptsIfLineCouldBeExecutable this.outerScriptLineMap", this.outerScriptLineMap); 263 if (!scripts && this.outerScriptLineMap && (this.outerScriptLineMap.indexOf(lineNo) != -1) ) 264 return [this.outerScript]; 265 return scripts; 266 }, 267 268 hasScript: function(script) 269 { 270 if (this.outerScript && (this.outerScript.tag == script.tag) ) 271 return true; 272 // XXXjjb Don't use indexOf or similar tests that rely on ===, since we are really working with 273 // wrappers around jsdIScript, not script themselves. I guess. 274 275 return ( this.innerScripts && this.innerScripts.hasOwnProperty(script.tag) ); 276 }, 277 278 // these objects map JSD's values to correct values 279 getScriptAnalyzer: function(script) 280 { 281 if (this.outerScript && (script.tag == this.outerScript.tag) ) 282 return this.getOuterScriptAnalyzer(); 283 return new Firebug.SourceFile.NestedScriptAnalyzer(this); 284 }, 285 286 // return.path: group/category label, return.name: item label 287 getObjectDescription: function() 288 { 289 return FBL.splitURLBase(this.href); 290 }, 291 292 isEval: function() 293 { 294 return (this.compilation_unit_type == "eval-level") || (this.compilation_unit_type == "newFunction"); 295 }, 296 297 isEvent: function() 298 { 299 return (this.compilation_unit_type == "event"); 300 }, 301 302 loadScriptLines: function(context) // array of lines 303 { 304 if (this.source) 305 return this.source; 306 else 307 return context.sourceCache.load(this.href); 308 }, 309 310 getOuterScriptAnalyzer: function() 311 { 312 FBTrace.sysout("getOuterScriptAnalyzer not overridden for "+sourceFile, this); 313 }, 314 315 } 316 317 Firebug.SourceFile.summarizeSourceLineArray = function(sourceLines, size) 318 { 319 var buf = ""; 320 for (var i = 0; i < sourceLines.length; i++) 321 { 322 var aLine = sourceLines[i].substr(0,240); // avoid huge lines 323 buf += aLine.replace(/\s/, " ", "g"); 324 if (buf.length > size || aLine.length > 240) 325 break; 326 } 327 return buf.substr(0, size); 328 }; 329 330 331 Firebug.SourceFile.NestedScriptAnalyzer = function(sourceFile) 332 { 333 this.sourceFile = sourceFile; 334 } 335 336 Firebug.SourceFile.NestedScriptAnalyzer.prototype = 337 { 338 // Adjust JSD line numbers based on origin of script 339 getSourceLineFromFrame: function(context, frame) 340 { 341 if (FBTrace.DBG_SOURCEFILES) FBTrace.sysout("NestedScriptAnalyzer in "+this.sourceFile.compilation_unit_type+": frame.line - this.sourceFile.getBaseLineOffset()", 342 frame.line +" - "+this.sourceFile.getBaseLineOffset()); 343 344 return frame.line - (this.sourceFile.getBaseLineOffset()); 345 }, 346 // Interpret frame to give fn(args) 347 getFunctionDescription: function(script, context, frame) 348 { 349 if (frame) 350 { 351 var name = frame.name; 352 var args = FBL.getFunctionArgValues(frame); 353 } 354 else 355 { 356 var name = script.functionName; 357 var args = []; 358 } 359 360 if (name == "anonymous") 361 { 362 name = FBL.guessFunctionName(this.sourceFile.href, this.getBaseLineNumberByScript(script), context); 363 } 364 365 return {name: name, args: args}; 366 }, 367 368 // link to source for this script. 369 getSourceLinkForScript: function (script) 370 { 371 var line = this.getBaseLineNumberByScript(script); 372 return new FBL.SourceLink(this.sourceFile.href, line, "js"); 373 }, 374 375 getBaseLineNumberByScript: function(script) 376 { 377 return script.baseLineNumber - (this.sourceFile.getBaseLineOffset() - 1); 378 } 379 } 380 381 Firebug.SourceFile.addScriptsToSourceFile = function(sourceFile, outerScript, innerScripts) 382 { 383 // Attach the innerScripts for use later 384 if (!sourceFile.innerScripts) 385 sourceFile.innerScripts = {}; 386 387 var total = 0; 388 while (innerScripts.hasMoreElements()) 389 { 390 var script = innerScripts.getNext(); 391 if (!script || ( (script instanceof Ci.jsdIScript) && !script.tag) ) 392 { 393 if (FBTrace.DBG_SOURCEFILES) 394 FBTrace.sysout("addScriptsToSourceFile innerScripts.getNext FAILS "+sourceFile, script); 395 continue; 396 } 397 sourceFile.innerScripts[script.tag] = script; 398 if (FBTrace.DBG_SOURCEFILES) 399 total++; 400 } 401 if (FBTrace.DBG_SOURCEFILES) 402 FBTrace.sysout("addScriptsToSourceFile "+ total +" scripts, sourcefile="+sourceFile.toString(), sourceFile); 403 } 404 405 //------------ 406 Firebug.EvalLevelSourceFile = function(url, script, eval_expr, source, mapType, innerScriptEnumerator) // ctor 407 { 408 this.href = url.href; 409 this.hrefKind = url.kind; 410 this.outerScript = script; 411 this.containingURL = script.fileName; 412 this.evalExpression = eval_expr; 413 this.sourceLength = source.length; 414 this.source = source; 415 this.pcmap_type = mapType; 416 Firebug.SourceFile.addScriptsToSourceFile(this, script, innerScriptEnumerator); 417 }; 418 419 Firebug.EvalLevelSourceFile.prototype = 420 descend(new Firebug.SourceFile("eval-level"), // shared prototype 421 { 422 getLine: function(context, lineNo) 423 { 424 return this.source[lineNo - 1]; 425 }, 426 427 getBaseLineOffset: function() 428 { 429 return this.outerScript.baseLineNumber - 1; // baseLineNumber always valid even after jsdIscript isValid false 430 }, 431 432 getObjectDescription: function() 433 { 434 if (this.hrefKind == "source" || this.hrefKind == "data") 435 return FBL.splitURLBase(this.href); 436 437 if (!this.summary) 438 { 439 if (this.evalExpression) 440 this.summary = Firebug.SourceFile.summarizeSourceLineArray(this.evalExpression.substr(0, 240), 120); 441 if (!this.summary) 442 this.summary = ""; 443 if (this.summary.length < 120) 444 this.summary = "eval("+this.summary + "...)=" + Firebug.SourceFile.summarizeSourceLineArray(this.source, 120 - this.summary.length); 445 } 446 var containingFileDescription = FBL.splitURLBase(this.containingURL); 447 if (FBTrace.DBG_SOURCEFILES) 448 FBTrace.sysout("EvalLevelSourceFile this.evalExpression.substr(0, 240):"+(this.evalExpression?this.evalExpression.substr(0, 240):"null")+" summary", this.summary); 449 return {path: containingFileDescription.path, name: containingFileDescription.name+"/eval: "+this.summary }; 450 }, 451 452 getOuterScriptAnalyzer: function() 453 { 454 return new Firebug.EvalLevelSourceFile.OuterScriptAnalyzer(this); 455 }, 456 457 }); 458 459 Firebug.EvalLevelSourceFile.OuterScriptAnalyzer = function(sourceFile) 460 { 461 this.sourceFile = sourceFile; 462 } 463 464 Firebug.EvalLevelSourceFile.OuterScriptAnalyzer.prototype = 465 { 466 // Adjust JSD line numbers based on origin of script 467 getSourceLineFromFrame: function(context, frame) 468 { 469 return frame.line - this.sourceFile.getBaseLineOffset(); 470 }, 471 // Interpret frame to give fn(args) 472 getFunctionDescription: function(script, context, frame) 473 { 474 return {name: "eval", args: [this.evalExpression] }; 475 }, 476 getSourceLinkForScript: function (script) 477 { 478 return new FBL.SourceLink(this.sourceFile.href, 1, "js"); 479 } 480 } 481 482 //------------ 483 Firebug.EventSourceFile = function(url, script, title, source, innerScriptEnumerator) 484 { 485 this.href = url; 486 this.outerScript = script; 487 this.containingURL = script.fileName; 488 this.title = title; 489 this.sourceLines = source; // points to the sourceCache lines 490 this.sourceLength = source.length; 491 this.pcmap_type = PCMAP_PRETTYPRINT; 492 493 Firebug.SourceFile.addScriptsToSourceFile(this, script, innerScriptEnumerator); 494 }; 495 496 Firebug.EventSourceFile.prototype = descend(new Firebug.SourceFile("event"), // prototypical inheritance 497 { 498 getLine: function(context, lineNo) 499 { 500 return this.sourceLines[lineNo - 1]; 501 }, 502 503 getBaseLineOffset: function() 504 { 505 return 1; 506 }, 507 508 getObjectDescription: function() 509 { 510 if (!this.summary) 511 this.summary = Firebug.SourceFile.summarizeSourceLineArray(this.sourceLines, 120); 512 513 var containingFileDescription = FBL.splitURLBase(this.containingURL); 514 515 return {path: containingFileDescription.path, name: containingFileDescription.name+"/event: "+this.summary }; 516 }, 517 518 getOuterScriptAnalyzer: function() 519 { 520 return new Firebug.EventSourceFile.OuterScriptAnalyzer(this); 521 }, 522 523 }); 524 525 Firebug.EventSourceFile.OuterScriptAnalyzer = function(sourceFile) 526 { 527 this.sourceFile = sourceFile; 528 } 529 530 Firebug.EventSourceFile.OuterScriptAnalyzer.prototype = 531 { 532 // Adjust JSD line numbers based on origin of script 533 getSourceLineFromFrame: function(context, frame) 534 { 535 var script = frame.script; 536 var line = script.pcToLine(frame.pc, PCMAP_PRETTYPRINT); 537 return line - 1; 538 }, 539 // Interpret frame to give fn(args) 540 getFunctionDescription: function(script, context, frame) 541 { 542 var fn = unwrapIValue(script.functionObject); //?? should be name of? 543 if (frame) 544 var args = FBL.getFunctionArgValues(frame); 545 else 546 var args = []; 547 return {name: fn, args: args}; 548 }, 549 getSourceLinkForScript: function (script) 550 { 551 return new FBL.SourceLink(this.sourceFile.href, 1, "js"); // XXXjjb why do we need FBL.?? 552 } 553 } 554 555 //------------ 556 Firebug.SourceFile.CommonBase = 557 { 558 getSourceLength: function() 559 { 560 if (!this.sourceLength) 561 this.sourceLength = this.context.sourceCache.load(this.href).length; 562 return this.sourceLength; 563 }, 564 565 getOuterScriptAnalyzer: function() 566 { 567 return Firebug.TopLevelSourceFile.OuterScriptAnalyzer; 568 }, 569 570 } 571 //----------- 572 Firebug.TopLevelSourceFile = function(url, outerScript, sourceLength, innerScriptEnumerator) 573 { 574 this.href = url; 575 this.outerScript = outerScript; // Beware may not be valid after we return!! 576 this.sourceLength = sourceLength; 577 this.pcmap_type = PCMAP_SOURCETEXT; 578 579 Firebug.SourceFile.addScriptsToSourceFile(this, outerScript, innerScriptEnumerator); 580 } 581 582 Firebug.TopLevelSourceFile.prototype = descend(new Firebug.SourceFile("top-level"), Firebug.SourceFile.CommonBase); 583 584 585 Firebug.TopLevelSourceFile.OuterScriptAnalyzer = { 586 // Adjust JSD line numbers based on origin of script 587 getSourceLineFromFrame: function(context, frame) 588 { 589 return frame.line; 590 }, 591 // Interpret frame to give fn(args) 592 getFunctionDescription: function(script, context, frame) 593 { 594 var file_name = FBL.getFileName(FBL.normalizeURL(script.fileName)); // this is more useful that just "top_level" 595 file_name = file_name ? file_name: "__top_level__"; 596 return {name: file_name, args: []}; 597 }, 598 getSourceLinkForScript: function (script) 599 { 600 return FBL.SourceLink(FBL.normalizeURL(script.fileName), script.baseLineNumber, "js") 601 } 602 } 603 604 //------- 605 606 Firebug.EnumeratedSourceFile = function(url) // we don't have the outer script and we delay source load. 607 { 608 this.href = new String(url); // may not be outerScript file name, eg this could be an enumerated eval 609 this.innerScripts = {}; 610 this.pcmap_type = PCMAP_SOURCETEXT; 611 } 612 613 Firebug.EnumeratedSourceFile.prototype = descend( 614 new Firebug.SourceFile("enumerated"), 615 Firebug.SourceFile.CommonBase); 616 617 //--------- 618 Firebug.NoScriptSourceFile = function(context, url) // Somehow we got the URL, but not the script 619 { 620 this.href = url; // we know this much 621 this.innerScripts = {}; 622 } 623 624 Firebug.NoScriptSourceFile.prototype = descend( 625 new Firebug.SourceFile("URLOnly"), 626 Firebug.SourceFile.CommonBase); 627 628 //---------// javascript in a .xul or .xml file, no outerScript 629 Firebug.XULSourceFile = function(url, innerScriptEnumerator) 630 { 631 this.href = url; 632 this.pcmap_type = PCMAP_SOURCETEXT; 633 634 Firebug.SourceFile.addScriptsToSourceFile(this, null, innerScriptEnumerator); 635 } 636 637 Firebug.XULSourceFile.prototype = descend( 638 new Firebug.SourceFile("xul"), 639 Firebug.SourceFile.CommonBase); 640 641 //--------- 642 Firebug.ScriptTagSourceFile = function(context, url, scriptTagNumber) // we don't have the outer script and we delay source load 643 { 644 this.context = context; 645 this.href = url; // we know this is not an eval 646 this.scriptTagNumber = scriptTagNumber; 647 this.innerScripts = {}; 648 this.pcmap_type = PCMAP_SOURCETEXT; 649 } 650 651 Firebug.ScriptTagSourceFile.prototype = descend( 652 new Firebug.SourceFile("scriptTag"), 653 Firebug.SourceFile.CommonBase); 654 655 //------------------- 656 Firebug.SourceFile.getSourceFileByScript = function(context, script) 657 { 658 if (!context.sourceFileMap) 659 return null; 660 661 // Other algorithms are possible: 662 // We could store an index, context.sourceFileByTag 663 // Or we could build a tree keyed by url, with SpiderMonkey script.fileNames at the top and our urls below 664 var lucky = context.sourceFileMap[script.fileName]; // we won't be lucky for file:/ urls, no normalizeURL applied 665 if (FBTrace.DBG_SOURCEFILES && lucky) 666 FBTrace.sysout("getSourceFileByScript trying to be lucky for "+ 667 script.tag + " in "+lucky, script); 668 669 if (lucky && lucky.hasScript(script)) 670 return lucky; 671 672 if (FBTrace.DBG_SOURCEFILES) 673 FBTrace.sysout("getSourceFileByScript looking for "+script.tag+"@"+script.fileName+" in "+ 674 context.getName()+": ", context.sourceFileMap); 675 676 for (var url in context.sourceFileMap) 677 { 678 var sourceFile = context.sourceFileMap[url]; 679 if (sourceFile.hasScript(script)) 680 return sourceFile; 681 } 682 }; 683 684 Firebug.SourceFile.getScriptAnalyzer = function(context, script) 685 { 686 var sourceFile = Firebug.SourceFile.getSourceFileByScript(context, script); 687 if (FBTrace.DBG_STACK) 688 FBTrace.sysout("getScriptAnalyzer "+ (sourceFile?"finds sourceFile: ":"FAILS to find sourceFile"), sourceFile); 689 if (sourceFile) 690 { 691 var analyzer = sourceFile.getScriptAnalyzer(script); 692 if (FBTrace.DBG_STACK) 693 FBTrace.sysout("getScriptAnalyzer finds analyzer: ", analyzer); 694 695 return analyzer; 696 } 697 return undefined; 698 }; 699 700 Firebug.SourceFile.getSourceFileAndLineByScript= function(context, script, frame) 701 { 702 var sourceFile = Firebug.SourceFile.getSourceFileByScript(context, script); 703 if (sourceFile) 704 { 705 var analyzer = sourceFile.getScriptAnalyzer(script); 706 if (analyzer) 707 var line = frame ? analyzer.getSourceLineFromFrame(context, frame) : analyzer.getBaseLineNumberByScript(script); 708 else 709 var line = 0; 710 711 return { sourceFile: sourceFile, lineNo: line }; 712 } 713 }; 714 715 Firebug.SourceFile.guessEnclosingFunctionName = function(url, line, context) 716 { 717 var sourceFile = context.sourceFileMap[url]; 718 if (sourceFile) 719 { 720 var scripts = sourceFile.getScriptsAtLineNumber(line); 721 if (scripts) 722 { 723 var script = scripts[0]; // TODO try others? 724 var analyzer = sourceFile.getScriptAnalyzer(script); 725 line = analyzer.getBaseLineNumberByScript(script); 726 } 727 } 728 return FBL.guessFunctionName(url, line-1, context); 729 }; 730 731 }}); 732