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