1 /* 2 * Copyright (c) 2009, 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 package com.sun.tools.javap; 27 28 import com.sun.tools.classfile.Attribute; 29 import com.sun.tools.classfile.Code_attribute; 30 import com.sun.tools.classfile.ConstantPool; 31 import com.sun.tools.classfile.ConstantPoolException; 32 import com.sun.tools.classfile.Descriptor; 33 import com.sun.tools.classfile.Descriptor.InvalidDescriptor; 34 import com.sun.tools.classfile.Instruction; 35 import com.sun.tools.classfile.LocalVariableTypeTable_attribute; 36 import com.sun.tools.classfile.Signature; 37 import java.util.ArrayList; 38 import java.util.HashMap; 39 import java.util.List; 40 import java.util.ListIterator; 41 import java.util.Map; 42 43 /** 44 * Annotate instructions with details about local variables. 45 * 46 * <p><b>This is NOT part of any supported API. 47 * If you write code that depends on this, you do so at your own risk. 48 * This code and its internal interfaces are subject to change or 49 * deletion without notice.</b> 50 */ 51 public class LocalVariableTypeTableWriter extends InstructionDetailWriter { 52 public enum NoteKind { 53 START("start") { 54 public boolean match(LocalVariableTypeTable_attribute.Entry entry, int pc) { 55 return (pc == entry.start_pc); 56 } 57 }, 58 END("end") { 59 public boolean match(LocalVariableTypeTable_attribute.Entry entry, int pc) { 60 return (pc == entry.start_pc + entry.length); 61 } 62 }; 63 NoteKind(String text) { 64 this.text = text; 65 } 66 public abstract boolean match(LocalVariableTypeTable_attribute.Entry entry, int pc); 67 public final String text; 68 } 69 70 static LocalVariableTypeTableWriter instance(Context context) { 71 LocalVariableTypeTableWriter instance = context.get(LocalVariableTypeTableWriter.class); 72 if (instance == null) 73 instance = new LocalVariableTypeTableWriter(context); 74 return instance; 75 } 76 77 protected LocalVariableTypeTableWriter(Context context) { 78 super(context); 79 context.put(LocalVariableTypeTableWriter.class, this); 80 classWriter = ClassWriter.instance(context); 81 } 82 83 public void reset(Code_attribute attr) { 84 codeAttr = attr; 85 pcMap = new HashMap<>(); 86 LocalVariableTypeTable_attribute lvt = 87 (LocalVariableTypeTable_attribute) (attr.attributes.get(Attribute.LocalVariableTypeTable)); 88 if (lvt == null) 89 return; 90 91 for (int i = 0; i < lvt.local_variable_table.length; i++) { 92 LocalVariableTypeTable_attribute.Entry entry = lvt.local_variable_table[i]; 93 put(entry.start_pc, entry); 94 put(entry.start_pc + entry.length, entry); 95 } 96 } 97 98 public void writeDetails(Instruction instr) { 99 int pc = instr.getPC(); 100 writeLocalVariables(pc, NoteKind.END); 101 writeLocalVariables(pc, NoteKind.START); 102 } 103 104 @Override 105 public void flush() { 106 int pc = codeAttr.code_length; 107 writeLocalVariables(pc, NoteKind.END); 108 } 109 110 public void writeLocalVariables(int pc, NoteKind kind) { 111 ConstantPool constant_pool = classWriter.getClassFile().constant_pool; 112 String indent = space(2); // get from Options? 113 List<LocalVariableTypeTable_attribute.Entry> entries = pcMap.get(pc); 114 if (entries != null) { 115 for (ListIterator<LocalVariableTypeTable_attribute.Entry> iter = 116 entries.listIterator(kind == NoteKind.END ? entries.size() : 0); 117 kind == NoteKind.END ? iter.hasPrevious() : iter.hasNext() ; ) { 118 LocalVariableTypeTable_attribute.Entry entry = 119 kind == NoteKind.END ? iter.previous() : iter.next(); 120 if (kind.match(entry, pc)) { 121 print(indent); 122 print(kind.text); 123 print(" generic local "); 124 print(entry.index); 125 print(" // "); 126 Descriptor d = new Signature(entry.signature_index); 127 try { 128 print(d.getFieldType(constant_pool).toString().replace("/", ".")); 129 } catch (InvalidDescriptor e) { 130 print(report(e)); 131 } catch (ConstantPoolException e) { 132 print(report(e)); 133 } 134 print(" "); 135 try { 136 print(constant_pool.getUTF8Value(entry.name_index)); 137 } catch (ConstantPoolException e) { 138 print(report(e)); 139 } 140 println(); 141 } 142 } 143 } 144 } 145 146 private void put(int pc, LocalVariableTypeTable_attribute.Entry entry) { 147 List<LocalVariableTypeTable_attribute.Entry> list = pcMap.get(pc); 148 if (list == null) { 149 list = new ArrayList<>(); 150 pcMap.put(pc, list); 151 } 152 if (!list.contains(entry)) 153 list.add(entry); 154 } 155 156 private ClassWriter classWriter; 157 private Code_attribute codeAttr; 158 private Map<Integer, List<LocalVariableTypeTable_attribute.Entry>> pcMap; 159 }