1 /*
   2  * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <setjmp.h>
  27 
  28 #include "util.h"
  29 #include "SDE.h"
  30 
  31 #ifdef __APPLE__
  32 /* use setjmp/longjmp versions that do not save/restore the signal mask */
  33 #define setjmp _setjmp
  34 #define longjmp _longjmp
  35 #endif
  36 
  37 /**
  38  * This SourceDebugExtension code does not
  39  * allow concurrent translation - due to caching method.
  40  * A separate thread setting the default stratum ID
  41  * is, however, fine.
  42  */
  43 
  44 #define INIT_SIZE_FILE 10
  45 #define INIT_SIZE_LINE 100
  46 #define INIT_SIZE_STRATUM 3
  47 
  48 #define BASE_STRATUM_NAME "Java"
  49 
  50 #define null NULL
  51 #define true JNI_TRUE
  52 #define false JNI_FALSE
  53 #define String char *
  54 #define private static
  55 
  56 typedef struct {
  57   int fileId;
  58   String sourceName;
  59   String sourcePath; // do not read - use accessor
  60   int isConverted;
  61 } FileTableRecord;
  62 
  63 typedef struct {
  64     int jplsStart;
  65     int jplsEnd;
  66     int jplsLineInc;
  67     int njplsStart;
  68     int njplsEnd;
  69     int fileId;
  70 } LineTableRecord;
  71 
  72 typedef struct {
  73     String id;
  74     int fileIndex;
  75     int lineIndex;
  76 } StratumTableRecord;
  77 
  78 /* back-end wide value for default stratum */
  79 private String globalDefaultStratumId = null;
  80 
  81 /* reference type default */
  82 private String defaultStratumId = null;
  83 
  84 private jclass cachedClass = NULL;
  85 
  86 private FileTableRecord* fileTable;
  87 private LineTableRecord* lineTable;
  88 private StratumTableRecord* stratumTable;
  89 
  90 private int fileTableSize;
  91 private int lineTableSize;
  92 private int stratumTableSize;
  93 
  94 private int fileIndex;
  95 private int lineIndex;
  96 private int stratumIndex = 0;
  97 private int currentFileId;
  98 
  99 private int defaultStratumIndex;
 100 private int baseStratumIndex;
 101 private char* sdePos;
 102 
 103 private char* jplsFilename = null;
 104 private char* NullString = null;
 105 
 106 /* mangled in parse, cannot be parsed.  Must be kept. */
 107 private String sourceDebugExtension;
 108 
 109 private jboolean sourceMapIsValid;
 110 
 111 private jmp_buf jmp_buf_env;
 112 
 113 private int stratumTableIndex(String stratumId);
 114 private int stiLineTableIndex(int sti, int jplsLine);
 115 private int stiLineNumber(int sti, int lti, int jplsLine);
 116 private void decode(void);
 117 private void ignoreWhite(void);
 118 private jboolean isValid(void);
 119 
 120     private void
 121     loadDebugInfo(JNIEnv *env, jclass clazz) {
 122 
 123         if (!isSameObject(env, clazz, cachedClass)) {
 124             /* Not the same - swap out the info */
 125 
 126             /* Delete existing info */
 127             if ( cachedClass != null ) {
 128                 tossGlobalRef(env, &cachedClass);
 129                 cachedClass = null;
 130             }
 131             if ( sourceDebugExtension!=null ) {
 132                 jvmtiDeallocate(sourceDebugExtension);
 133             }
 134             sourceDebugExtension = null;
 135 
 136             /* Init info */
 137             lineTable = null;
 138             fileTable = null;
 139             stratumTable = null;
 140             lineTableSize = 0;
 141             fileTableSize = 0;
 142             stratumTableSize = 0;
 143             fileIndex = 0;
 144             lineIndex = 0;
 145             stratumIndex = 0;
 146             currentFileId = 0;
 147             defaultStratumId = null;
 148             defaultStratumIndex = -1;
 149             baseStratumIndex = -2; /* so as not to match -1 above */
 150             sourceMapIsValid = false;
 151 
 152             if (getSourceDebugExtension(clazz, &sourceDebugExtension) ==
 153                 JVMTI_ERROR_NONE) {
 154                 sdePos = sourceDebugExtension;
 155                 if (setjmp(jmp_buf_env) == 0) {
 156                     /* this is the initial (non-error) case, do parse */
 157                     decode();
 158                 }
 159             }
 160 
 161             cachedClass = null;
 162             saveGlobalRef(env, clazz, &cachedClass);
 163         }
 164     }
 165 
 166     /* Return 1 if match, 0 if no match */
 167     private int
 168     patternMatch(char *classname, const char *pattern) {
 169         int pattLen;
 170         int compLen;
 171         char *start;
 172         int offset;
 173 
 174         if (pattern == NULL || classname == NULL) {
 175             return 0;
 176         }
 177         pattLen = (int)strlen(pattern);
 178 
 179         if ((pattern[0] != '*') && (pattern[pattLen-1] != '*')) {
 180             return strcmp(pattern, classname) == 0;
 181         }
 182 
 183         compLen = pattLen - 1;
 184         offset = (int)strlen(classname) - compLen;
 185         if (offset < 0) {
 186             return 0;
 187         }
 188         if (pattern[0] == '*') {
 189             pattern++;
 190             start = classname + offset;
 191         }  else {
 192             start = classname;
 193         }
 194         return strncmp(pattern, start, compLen) == 0;
 195     }
 196 
 197     /**
 198      * Return 1 if p1 is a SourceName for stratum sti,
 199      * else, return 0.
 200      */
 201     private int
 202     searchOneSourceName(int sti, char *p1) {
 203         int fileIndexStart = stratumTable[sti].fileIndex;
 204         /* one past end */
 205         int fileIndexEnd = stratumTable[sti+1].fileIndex;
 206         int ii;
 207         for (ii = fileIndexStart; ii < fileIndexEnd; ++ii) {
 208             if (patternMatch(fileTable[ii].sourceName, p1)) {
 209               return 1;
 210             }
 211         }
 212         return 0;
 213     }
 214 
 215     /**
 216      * Return 1 if p1 is a SourceName for any stratum
 217      * else, return 0.
 218      */
 219     int searchAllSourceNames(JNIEnv *env,
 220                              jclass clazz,
 221                              char *p1) {
 222         int ii;
 223         loadDebugInfo(env, clazz);
 224         if (!isValid()) {
 225           return 0; /* no SDE or not SourceMap */
 226         }
 227 
 228         for (ii = 0; ii < stratumIndex - 1; ++ii) {
 229             if (searchOneSourceName(ii, p1) == 1) {
 230                 return 1;
 231             }
 232         }
 233         return 0;
 234     }
 235 
 236     /**
 237      * Convert a line number table, as returned by the JVMTI
 238      * function GetLineNumberTable, to one for another stratum.
 239      * Conversion is by overwrite.
 240      * Actual line numbers are not returned - just a unique
 241      * number (file ID in top 16 bits, line number in
 242      * bottom 16 bits) - this is all stepping needs.
 243      */
 244     void
 245     convertLineNumberTable(JNIEnv *env, jclass clazz,
 246                            jint *entryCountPtr,
 247                            jvmtiLineNumberEntry **tablePtr) {
 248         jvmtiLineNumberEntry *fromEntry = *tablePtr;
 249         jvmtiLineNumberEntry *toEntry = *tablePtr;
 250         int cnt = *entryCountPtr;
 251         int lastLn = 0;
 252         int sti;
 253 
 254         loadDebugInfo(env, clazz);
 255         if (!isValid()) {
 256             return; /* no SDE or not SourceMap - return unchanged */
 257         }
 258         sti = stratumTableIndex(globalDefaultStratumId);
 259         if (sti == baseStratumIndex) {
 260             return; /* Java stratum - return unchanged */
 261         }
 262         LOG_MISC(("SDE is re-ordering the line table"));
 263         for (; cnt-->0; ++fromEntry) {
 264             int jplsLine = fromEntry->line_number;
 265             int lti = stiLineTableIndex(sti, jplsLine);
 266             if (lti >= 0) {
 267                 int fileId = lineTable[lti].fileId;
 268                 int ln = stiLineNumber(sti, lti, jplsLine);
 269                 ln += (fileId << 16); /* create line hash */
 270                 if (ln != lastLn) {
 271                     lastLn = ln;
 272                     toEntry->start_location = fromEntry->start_location;
 273                     toEntry->line_number = ln;
 274                     ++toEntry;
 275                 }
 276             }
 277         }
 278         /*LINTED*/
 279         *entryCountPtr = (int)(toEntry - *tablePtr);
 280     }
 281 
 282     /**
 283      * Set back-end wide default stratum ID .
 284      */
 285     void
 286     setGlobalStratumId(char *id) {
 287         globalDefaultStratumId = id;
 288     }
 289 
 290 
 291     private void syntax(String msg) {
 292         char buf[200];
 293         (void)snprintf(buf, sizeof(buf),
 294                 "bad SourceDebugExtension syntax - position %d - %s\n",
 295                 /*LINTED*/
 296                 (int)(sdePos-sourceDebugExtension),
 297                 msg);
 298         JDI_ASSERT_FAILED(buf);
 299 
 300         longjmp(jmp_buf_env, 1);  /* abort parse */
 301     }
 302 
 303     private char sdePeek(void) {
 304         if (*sdePos == 0) {
 305             syntax("unexpected EOF");
 306         }
 307         return *sdePos;
 308     }
 309 
 310     private char sdeRead(void) {
 311         if (*sdePos == 0) {
 312             syntax("unexpected EOF");
 313         }
 314         return *sdePos++;
 315     }
 316 
 317     private void sdeAdvance(void) {
 318         sdePos++;
 319     }
 320 
 321     private void assureLineTableSize(void) {
 322         if (lineIndex >= lineTableSize) {
 323             size_t allocSize;
 324             LineTableRecord* new_lineTable;
 325             int new_lineTableSize;
 326 
 327             new_lineTableSize = lineTableSize == 0?
 328                                   INIT_SIZE_LINE :
 329                                   lineTableSize * 2;
 330             allocSize = new_lineTableSize * (int)sizeof(LineTableRecord);
 331             new_lineTable = jvmtiAllocate((jint)allocSize);
 332             if ( new_lineTable == NULL ) {
 333                 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY, "SDE line table");
 334             }
 335             if ( lineTable!=NULL ) {
 336                 (void)memcpy(new_lineTable, lineTable,
 337                         lineTableSize * (int)sizeof(LineTableRecord));
 338                 jvmtiDeallocate(lineTable);
 339             }
 340             lineTable     = new_lineTable;
 341             lineTableSize = new_lineTableSize;
 342         }
 343     }
 344 
 345     private void assureFileTableSize(void) {
 346         if (fileIndex >= fileTableSize) {
 347             size_t allocSize;
 348             FileTableRecord* new_fileTable;
 349             int new_fileTableSize;
 350 
 351             new_fileTableSize = fileTableSize == 0?
 352                                   INIT_SIZE_FILE :
 353                                   fileTableSize * 2;
 354             allocSize = new_fileTableSize * (int)sizeof(FileTableRecord);
 355             new_fileTable = jvmtiAllocate((jint)allocSize);
 356             if ( new_fileTable == NULL ) {
 357                 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY, "SDE file table");
 358             }
 359             if ( fileTable!=NULL ) {
 360                 (void)memcpy(new_fileTable, fileTable,
 361                         fileTableSize * (int)sizeof(FileTableRecord));
 362                 jvmtiDeallocate(fileTable);
 363             }
 364             fileTable     = new_fileTable;
 365             fileTableSize = new_fileTableSize;
 366         }
 367     }
 368 
 369     private void assureStratumTableSize(void) {
 370         if (stratumIndex >= stratumTableSize) {
 371             size_t allocSize;
 372             StratumTableRecord* new_stratumTable;
 373             int new_stratumTableSize;
 374 
 375             new_stratumTableSize = stratumTableSize == 0?
 376                                   INIT_SIZE_STRATUM :
 377                                   stratumTableSize * 2;
 378             allocSize = new_stratumTableSize * (int)sizeof(StratumTableRecord);
 379             new_stratumTable = jvmtiAllocate((jint)allocSize);
 380             if ( new_stratumTable == NULL ) {
 381                 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY, "SDE stratum table");
 382             }
 383             if ( stratumTable!=NULL ) {
 384                 (void)memcpy(new_stratumTable, stratumTable,
 385                         stratumTableSize * (int)sizeof(StratumTableRecord));
 386                 jvmtiDeallocate(stratumTable);
 387             }
 388             stratumTable     = new_stratumTable;
 389             stratumTableSize = new_stratumTableSize;
 390         }
 391     }
 392 
 393     private String readLine(void) {
 394         char *initialPos;
 395         char ch;
 396 
 397         ignoreWhite();
 398         initialPos = sdePos;
 399         while (((ch = *sdePos) != '\n') && (ch != '\r')) {
 400             if (ch == 0) {
 401                 syntax("unexpected EOF");
 402             }
 403             ++sdePos;
 404         }
 405         *sdePos++ = 0; /* null terminate string - mangles SDE */
 406 
 407         /* check for CR LF */
 408         if ((ch == '\r') && (*sdePos == '\n')) {
 409             ++sdePos;
 410         }
 411         ignoreWhite(); /* leading white */
 412         return initialPos;
 413     }
 414 
 415     private int defaultStratumTableIndex(void) {
 416         if ((defaultStratumIndex == -1) && (defaultStratumId != null)) {
 417             defaultStratumIndex =
 418                 stratumTableIndex(defaultStratumId);
 419         }
 420         return defaultStratumIndex;
 421     }
 422 
 423     private int stratumTableIndex(String stratumId) {
 424         int i;
 425 
 426         if (stratumId == null) {
 427             return defaultStratumTableIndex();
 428         }
 429         for (i = 0; i < (stratumIndex-1); ++i) {
 430             if (strcmp(stratumTable[i].id, stratumId) == 0) {
 431                 return i;
 432             }
 433         }
 434         return defaultStratumTableIndex();
 435     }
 436 
 437 
 438 /*****************************
 439  * below functions/methods are written to compile under either Java or C
 440  *
 441  * Needed support functions:
 442  *   sdePeek()
 443  *   sdeRead()
 444  *   sdeAdvance()
 445  *   readLine()
 446  *   assureLineTableSize()
 447  *   assureFileTableSize()
 448  *   assureStratumTableSize()
 449  *   syntax(String)
 450  *
 451  *   stratumTableIndex(String)
 452  *
 453  * Needed support variables:
 454  *   lineTable
 455  *   lineIndex
 456  *   fileTable
 457  *   fileIndex
 458  *   currentFileId
 459  *
 460  * Needed types:
 461  *   String
 462  *
 463  * Needed constants:
 464  *   NullString
 465  */
 466 
 467     private void ignoreWhite(void) {
 468         char ch;
 469 
 470         while (((ch = sdePeek()) == ' ') || (ch == '\t')) {
 471             sdeAdvance();
 472         }
 473     }
 474 
 475     private void ignoreLine(void) {
 476         char ch;
 477 
 478         do {
 479            ch = sdeRead();
 480         } while ((ch != '\n') && (ch != '\r'));
 481 
 482         /* check for CR LF */
 483         if ((ch == '\r') && (sdePeek() == '\n')) {
 484             sdeAdvance();
 485         }
 486         ignoreWhite(); /* leading white */
 487     }
 488 
 489     private int readNumber(void) {
 490         int value = 0;
 491         char ch;
 492 
 493         ignoreWhite();
 494         while (((ch = sdePeek()) >= '0') && (ch <= '9')) {
 495             sdeAdvance();
 496             value = (value * 10) + ch - '0';
 497         }
 498         ignoreWhite();
 499         return value;
 500     }
 501 
 502     private void storeFile(int fileId, String sourceName, String sourcePath) {
 503         assureFileTableSize();
 504         fileTable[fileIndex].fileId = fileId;
 505         fileTable[fileIndex].sourceName = sourceName;
 506         fileTable[fileIndex].sourcePath = sourcePath;
 507         ++fileIndex;
 508     }
 509 
 510     private void fileLine(void) {
 511         int hasAbsolute = 0; /* acts as boolean */
 512         int fileId;
 513         String sourceName;
 514         String sourcePath = null;
 515 
 516         /* is there an absolute filename? */
 517         if (sdePeek() == '+') {
 518             sdeAdvance();
 519             hasAbsolute = 1;
 520         }
 521         fileId = readNumber();
 522         sourceName = readLine();
 523         if (hasAbsolute == 1) {
 524             sourcePath = readLine();
 525         }
 526         storeFile(fileId, sourceName, sourcePath);
 527     }
 528 
 529     private void storeLine(int jplsStart, int jplsEnd, int jplsLineInc,
 530                   int njplsStart, int njplsEnd, int fileId) {
 531         assureLineTableSize();
 532         lineTable[lineIndex].jplsStart = jplsStart;
 533         lineTable[lineIndex].jplsEnd = jplsEnd;
 534         lineTable[lineIndex].jplsLineInc = jplsLineInc;
 535         lineTable[lineIndex].njplsStart = njplsStart;
 536         lineTable[lineIndex].njplsEnd = njplsEnd;
 537         lineTable[lineIndex].fileId = fileId;
 538         ++lineIndex;
 539     }
 540 
 541     /**
 542      * Parse line translation info.  Syntax is
 543      *     <NJ-start-line> [ # <file-id> ] [ , <line-count> ] :
 544      *                 <J-start-line> [ , <line-increment> ] CR
 545      */
 546     private void lineLine(void) {
 547         int lineCount = 1;
 548         int lineIncrement = 1;
 549         int njplsStart;
 550         int jplsStart;
 551 
 552         njplsStart = readNumber();
 553 
 554         /* is there a fileID? */
 555         if (sdePeek() == '#') {
 556             sdeAdvance();
 557             currentFileId = readNumber();
 558         }
 559 
 560         /* is there a line count? */
 561         if (sdePeek() == ',') {
 562             sdeAdvance();
 563             lineCount = readNumber();
 564         }
 565 
 566         if (sdeRead() != ':') {
 567             syntax("expected ':'");
 568         }
 569         jplsStart = readNumber();
 570         if (sdePeek() == ',') {
 571             sdeAdvance();
 572             lineIncrement = readNumber();
 573         }
 574         ignoreLine(); /* flush the rest */
 575 
 576         storeLine(jplsStart,
 577                   jplsStart + (lineCount * lineIncrement) -1,
 578                   lineIncrement,
 579                   njplsStart,
 580                   njplsStart + lineCount -1,
 581                   currentFileId);
 582     }
 583 
 584     /**
 585      * Until the next stratum section, everything after this
 586      * is in stratumId - so, store the current indicies.
 587      */
 588     private void storeStratum(String stratumId) {
 589         /* remove redundant strata */
 590         if (stratumIndex > 0) {
 591             if ((stratumTable[stratumIndex-1].fileIndex
 592                                             == fileIndex) &&
 593                 (stratumTable[stratumIndex-1].lineIndex
 594                                             == lineIndex)) {
 595                 /* nothing changed overwrite it */
 596                 --stratumIndex;
 597             }
 598         }
 599         /* store the results */
 600         assureStratumTableSize();
 601         stratumTable[stratumIndex].id = stratumId;
 602         stratumTable[stratumIndex].fileIndex = fileIndex;
 603         stratumTable[stratumIndex].lineIndex = lineIndex;
 604         ++stratumIndex;
 605         currentFileId = 0;
 606     }
 607 
 608     /**
 609      * The beginning of a stratum's info
 610      */
 611     private void stratumSection(void) {
 612         storeStratum(readLine());
 613     }
 614 
 615     private void fileSection(void) {
 616         ignoreLine();
 617         while (sdePeek() != '*') {
 618             fileLine();
 619         }
 620     }
 621 
 622     private void lineSection(void) {
 623         ignoreLine();
 624         while (sdePeek() != '*') {
 625             lineLine();
 626         }
 627     }
 628 
 629     /**
 630      * Ignore a section we don't know about.
 631      */
 632     private void ignoreSection(void) {
 633         ignoreLine();
 634         while (sdePeek() != '*') {
 635             ignoreLine();
 636         }
 637     }
 638 
 639     /**
 640      * A base "Java" stratum is always available, though
 641      * it is not in the SourceDebugExtension.
 642      * Create the base stratum.
 643      */
 644     private void createJavaStratum(void) {
 645         baseStratumIndex = stratumIndex;
 646         storeStratum(BASE_STRATUM_NAME);
 647         storeFile(1, jplsFilename, NullString);
 648         /* JPL line numbers cannot exceed 65535 */
 649         storeLine(1, 65536, 1, 1, 65536, 1);
 650         storeStratum("Aux"); /* in case they don't declare */
 651     }
 652 
 653     /**
 654      * Decode a SourceDebugExtension which is in SourceMap format.
 655      * This is the entry point into the recursive descent parser.
 656      */
 657     private void decode(void) {
 658         /* check for "SMAP" - allow EOF if not ours */
 659         if (strlen(sourceDebugExtension) <= 4 ||
 660             (sdeRead() != 'S') ||
 661             (sdeRead() != 'M') ||
 662             (sdeRead() != 'A') ||
 663             (sdeRead() != 'P')) {
 664             return; /* not our info */
 665         }
 666         ignoreLine(); /* flush the rest */
 667         jplsFilename = readLine();
 668         defaultStratumId = readLine();
 669         createJavaStratum();
 670         while (true) {
 671             if (sdeRead() != '*') {
 672                 syntax("expected '*'");
 673             }
 674             switch (sdeRead()) {
 675                 case 'S':
 676                     stratumSection();
 677                     break;
 678                 case 'F':
 679                     fileSection();
 680                     break;
 681                 case 'L':
 682                     lineSection();
 683                     break;
 684                 case 'E':
 685                     /* set end points */
 686                     storeStratum("*terminator*");
 687                     sourceMapIsValid = true;
 688                     return;
 689                 default:
 690                     ignoreSection();
 691             }
 692         }
 693     }
 694 
 695     /***************** query functions ***********************/
 696 
 697     private int stiLineTableIndex(int sti, int jplsLine) {
 698         int i;
 699         int lineIndexStart;
 700         int lineIndexEnd;
 701 
 702         lineIndexStart = stratumTable[sti].lineIndex;
 703         /* one past end */
 704         lineIndexEnd = stratumTable[sti+1].lineIndex;
 705         for (i = lineIndexStart; i < lineIndexEnd; ++i) {
 706             if ((jplsLine >= lineTable[i].jplsStart) &&
 707                             (jplsLine <= lineTable[i].jplsEnd)) {
 708                 return i;
 709             }
 710         }
 711         return -1;
 712     }
 713 
 714     private int stiLineNumber(int sti, int lti, int jplsLine) {
 715         return lineTable[lti].njplsStart +
 716                 (((jplsLine - lineTable[lti].jplsStart) /
 717                                    lineTable[lti].jplsLineInc));
 718     }
 719 
 720     private int fileTableIndex(int sti, int fileId) {
 721         int i;
 722         int fileIndexStart = stratumTable[sti].fileIndex;
 723         /* one past end */
 724         int fileIndexEnd = stratumTable[sti+1].fileIndex;
 725         for (i = fileIndexStart; i < fileIndexEnd; ++i) {
 726             if (fileTable[i].fileId == fileId) {
 727                 return i;
 728             }
 729         }
 730         return -1;
 731     }
 732 
 733     private int stiFileTableIndex(int sti, int lti) {
 734         return fileTableIndex(sti, lineTable[lti].fileId);
 735     }
 736 
 737     private jboolean isValid(void) {
 738         return sourceMapIsValid;
 739     }