View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.classfile;
    18
    19  import java.io.DataInputStream;
    20  import java.io.DataOutputStream;
    21  import java.io.IOException;
    22  import org.apache.bcel.Constants;
    23
    24  /***
    25   * This class represents a table of line numbers for debugging
    26   * purposes. This attribute is used by the <em>Code</em> attribute. It
    27   * contains pairs of PCs and line numbers.
    28   *
    29   * @version $Id: LineNumberTable.java 386056 2006-03-15 11:31:56Z tcurdt $
    30   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
    31   * @see     Code
    32   * @see LineNumber
    33   */
    34  public final class LineNumberTable extends Attribute {
    35
    36      private int line_number_table_length;
    37      private LineNumber[] line_number_table; // Table of line/numbers pairs
    38
    39
    40      /*
    41       * Initialize from another object. Note that both objects use the same
    42       * references (shallow copy). Use copy() for a physical copy.
    43       */
    44      public LineNumberTable(LineNumberTable c) {
    45          this(c.getNameIndex(), c.getLength(), c.getLineNumberTable(), c.getConstantPool());
    46      }
    47
    48
    49      /*
    50       * @param name_index Index of name
    51       * @param length Content length in bytes
    52       * @param line_number_table Table of line/numbers pairs
    53       * @param constant_pool Array of constants
    54       */
    55      public LineNumberTable(int name_index, int length, LineNumber[] line_number_table,
    56              ConstantPool constant_pool) {
    57          super(Constants.ATTR_LINE_NUMBER_TABLE, name_index, length, constant_pool);
    58          setLineNumberTable(line_number_table);
    59      }
    60
    61
    62      /***
    63       * Construct object from file stream.
    64       * @param name_index Index of name
    65       * @param length Content length in bytes
    66       * @param file Input stream
    67       * @param constant_pool Array of constants
    68       * @throws IOException
    69       */
    70      LineNumberTable(int name_index, int length, DataInputStream file, ConstantPool constant_pool)
    71              throws IOException {
    72          this(name_index, length, (LineNumber[]) null, constant_pool);
    73          line_number_table_length = (file.readUnsignedShort());
    74          line_number_table = new LineNumber[line_number_table_length];
    75          for (int i = 0; i < line_number_table_length; i++) {
    76              line_number_table[i] = new LineNumber(file);
    77          }
    78      }
    79
    80
    81      /***
    82       * Called by objects that are traversing the nodes of the tree implicitely
    83       * defined by the contents of a Java class. I.e., the hierarchy of methods,
    84       * fields, attributes, etc. spawns a tree of objects.
    85       *
    86       * @param v Visitor object
    87       */
    88      public void accept( Visitor v ) {
    89          v.visitLineNumberTable(this);
    90      }
    91
    92
    93      /***
    94       * Dump line number table attribute to file stream in binary format.
    95       *
    96       * @param file Output file stream
    97       * @throws IOException
    98       */
    99      public final void dump( DataOutputStream file ) throws IOException {
    100         super.dump(file);
    101         file.writeShort(line_number_table_length);
    102         for (int i = 0; i < line_number_table_length; i++) {
    103             line_number_table[i].dump(file);
    104         }
    105     }
    106
    107
    108     /***
    109      * @return Array of (pc offset, line number) pairs.
    110      */
    111     public final LineNumber[] getLineNumberTable() {
    112         return line_number_table;
    113     }
    114
    115
    116     /***
    117      * @param line_number_table the line number entries for this table
    118      */
    119     public final void setLineNumberTable( LineNumber[] line_number_table ) {
    120         this.line_number_table = line_number_table;
    121         line_number_table_length = (line_number_table == null) ? 0 : line_number_table.length;
    122     }
    123
    124
    125     /***
    126      * @return String representation.
    127      */
    128     public final String toString() {
    129         StringBuffer buf = new StringBuffer();
    130         StringBuffer line = new StringBuffer();
    131         String newLine = System.getProperty("line.separator", "\n");
    132         for (int i = 0; i < line_number_table_length; i++) {
    133             line.append(line_number_table[i].toString());
    134             if (i < line_number_table_length - 1) {
    135                 line.append(", ");
    136             }
    137             if (line.length() > 72) {
    138                 line.append(newLine);
    139                 buf.append(line.toString());
    140                 line.setLength(0);
    141             }
    142         }
    143         buf.append(line);
    144         return buf.toString();
    145     }
    146
    147
    148     /***
    149      * Map byte code positions to source code lines.
    150      *
    151      * @param pos byte code offset
    152      * @return corresponding line in source code
    153      */
    154     public int getSourceLine( int pos ) {
    155         int l = 0, r = line_number_table_length - 1;
    156         if (r < 0) {
    157             return -1;
    158         }
    159         int min_index = -1, min = -1;
    160         /* Do a binary search since the array is ordered.
    161          */
    162         do {
    163             int i = (l + r) / 2;
    164             int j = line_number_table[i].getStartPC();
    165             if (j == pos) {
    166                 return line_number_table[i].getLineNumber();
    167             } else if (pos < j) {
    168                 r = i - 1;
    169             } else {
    170                 l = i + 1;
    171             }
    172             /* If exact match can't be found (which is the most common case)
    173              * return the line number that corresponds to the greatest index less
    174              * than pos.
    175              */
    176             if (j < pos && j > min) {
    177                 min = j;
    178                 min_index = i;
    179             }
    180         } while (l <= r);
    181         /* It's possible that we did not find any valid entry for the bytecode
    182          * offset we were looking for.
    183          */
    184         if (min_index < 0) {
    185             return -1;
    186         }
    187         return line_number_table[min_index].getLineNumber();
    188     }
    189
    190
    191     /***
    192      * @return deep copy of this attribute
    193      */
    194     public Attribute copy( ConstantPool _constant_pool ) {
    195         LineNumberTable c = (LineNumberTable) clone();
    196         c.line_number_table = new LineNumber[line_number_table_length];
    197         for (int i = 0; i < line_number_table_length; i++) {
    198             c.line_number_table[i] = line_number_table[i].copy();
    199         }
    200         c.constant_pool = _constant_pool;
    201         return c;
    202     }
    203
    204
    205     public final int getTableLength() {
    206         return line_number_table_length;
    207     }
    208 }