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