1/* 2 * Copyright (c) 2009, 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 26package com.sun.tools.javap; 27 28import java.util.Arrays; 29import java.util.HashMap; 30import java.util.Map; 31 32import com.sun.tools.classfile.AccessFlags; 33import com.sun.tools.classfile.Attribute; 34import com.sun.tools.classfile.Code_attribute; 35import com.sun.tools.classfile.ConstantPool; 36import com.sun.tools.classfile.ConstantPoolException; 37import com.sun.tools.classfile.Descriptor; 38import com.sun.tools.classfile.Descriptor.InvalidDescriptor; 39import com.sun.tools.classfile.Instruction; 40import com.sun.tools.classfile.Method; 41import com.sun.tools.classfile.StackMapTable_attribute; 42import com.sun.tools.classfile.StackMapTable_attribute.*; 43 44import static com.sun.tools.classfile.StackMapTable_attribute.verification_type_info.*; 45 46/** 47 * Annotate instructions with stack map. 48 * 49 * <p><b>This is NOT part of any supported API. 50 * If you write code that depends on this, you do so at your own risk. 51 * This code and its internal interfaces are subject to change or 52 * deletion without notice.</b> 53 */ 54public class StackMapWriter extends InstructionDetailWriter { 55 static StackMapWriter instance(Context context) { 56 StackMapWriter instance = context.get(StackMapWriter.class); 57 if (instance == null) 58 instance = new StackMapWriter(context); 59 return instance; 60 } 61 62 protected StackMapWriter(Context context) { 63 super(context); 64 context.put(StackMapWriter.class, this); 65 classWriter = ClassWriter.instance(context); 66 } 67 68 public void reset(Code_attribute attr) { 69 setStackMap((StackMapTable_attribute) attr.attributes.get(Attribute.StackMapTable)); 70 } 71 72 void setStackMap(StackMapTable_attribute attr) { 73 if (attr == null) { 74 map = null; 75 return; 76 } 77 78 Method m = classWriter.getMethod(); 79 Descriptor d = m.descriptor; 80 String[] args; 81 try { 82 ConstantPool cp = classWriter.getClassFile().constant_pool; 83 String argString = d.getParameterTypes(cp); 84 args = argString.substring(1, argString.length() - 1).split("[, ]+"); 85 } catch (ConstantPoolException | InvalidDescriptor e) { 86 return; 87 } 88 boolean isStatic = m.access_flags.is(AccessFlags.ACC_STATIC); 89 90 verification_type_info[] initialLocals = new verification_type_info[(isStatic ? 0 : 1) + args.length]; 91 if (!isStatic) 92 initialLocals[0] = new CustomVerificationTypeInfo("this"); 93 for (int i = 0; i < args.length; i++) { 94 initialLocals[(isStatic ? 0 : 1) + i] = 95 new CustomVerificationTypeInfo(args[i].replace(".", "/")); 96 } 97 98 map = new HashMap<>(); 99 StackMapBuilder builder = new StackMapBuilder(); 100 101 // using -1 as the pc for the initial frame effectively compensates for 102 // the difference in behavior for the first stack map frame (where the 103 // pc offset is just offset_delta) compared to subsequent frames (where 104 // the pc offset is always offset_delta+1). 105 int pc = -1; 106 107 map.put(pc, new StackMap(initialLocals, empty)); 108 109 for (int i = 0; i < attr.entries.length; i++) 110 pc = attr.entries[i].accept(builder, pc); 111 } 112 113 public void writeInitialDetails() { 114 writeDetails(-1); 115 } 116 117 public void writeDetails(Instruction instr) { 118 writeDetails(instr.getPC()); 119 } 120 121 private void writeDetails(int pc) { 122 if (map == null) 123 return; 124 125 StackMap m = map.get(pc); 126 if (m != null) { 127 print("StackMap locals: ", m.locals); 128 print("StackMap stack: ", m.stack); 129 } 130 131 } 132 133 void print(String label, verification_type_info[] entries) { 134 print(label); 135 for (int i = 0; i < entries.length; i++) { 136 print(" "); 137 print(entries[i]); 138 } 139 println(); 140 } 141 142 void print(verification_type_info entry) { 143 if (entry == null) { 144 print("ERROR"); 145 return; 146 } 147 148 switch (entry.tag) { 149 case -1: 150 print(((CustomVerificationTypeInfo) entry).text); 151 break; 152 153 case ITEM_Top: 154 print("top"); 155 break; 156 157 case ITEM_Integer: 158 print("int"); 159 break; 160 161 case ITEM_Float: 162 print("float"); 163 break; 164 165 case ITEM_Long: 166 print("long"); 167 break; 168 169 case ITEM_Double: 170 print("double"); 171 break; 172 173 case ITEM_Null: 174 print("null"); 175 break; 176 177 case ITEM_UninitializedThis: 178 print("uninit_this"); 179 break; 180 181 case ITEM_Object: 182 try { 183 ConstantPool cp = classWriter.getClassFile().constant_pool; 184 ConstantPool.CONSTANT_Class_info class_info = cp.getClassInfo(((Object_variable_info) entry).cpool_index); 185 print(cp.getUTF8Value(class_info.name_index)); 186 } catch (ConstantPoolException e) { 187 print("??"); 188 } 189 break; 190 191 case ITEM_Uninitialized: 192 print(((Uninitialized_variable_info) entry).offset); 193 break; 194 } 195 196 } 197 198 private Map<Integer, StackMap> map; 199 private ClassWriter classWriter; 200 201 class StackMapBuilder 202 implements StackMapTable_attribute.stack_map_frame.Visitor<Integer, Integer> { 203 204 public Integer visit_same_frame(same_frame frame, Integer pc) { 205 int new_pc = pc + frame.getOffsetDelta() + 1; 206 StackMap m = map.get(pc); 207 assert (m != null); 208 map.put(new_pc, m); 209 return new_pc; 210 } 211 212 public Integer visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, Integer pc) { 213 int new_pc = pc + frame.getOffsetDelta() + 1; 214 StackMap prev = map.get(pc); 215 assert (prev != null); 216 StackMap m = new StackMap(prev.locals, frame.stack); 217 map.put(new_pc, m); 218 return new_pc; 219 } 220 221 public Integer visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, Integer pc) { 222 int new_pc = pc + frame.getOffsetDelta() + 1; 223 StackMap prev = map.get(pc); 224 assert (prev != null); 225 StackMap m = new StackMap(prev.locals, frame.stack); 226 map.put(new_pc, m); 227 return new_pc; 228 } 229 230 public Integer visit_chop_frame(chop_frame frame, Integer pc) { 231 int new_pc = pc + frame.getOffsetDelta() + 1; 232 StackMap prev = map.get(pc); 233 assert (prev != null); 234 int k = 251 - frame.frame_type; 235 verification_type_info[] new_locals = Arrays.copyOf(prev.locals, prev.locals.length - k); 236 StackMap m = new StackMap(new_locals, empty); 237 map.put(new_pc, m); 238 return new_pc; 239 } 240 241 public Integer visit_same_frame_extended(same_frame_extended frame, Integer pc) { 242 int new_pc = pc + frame.getOffsetDelta(); 243 StackMap m = map.get(pc); 244 assert (m != null); 245 map.put(new_pc, m); 246 return new_pc; 247 } 248 249 public Integer visit_append_frame(append_frame frame, Integer pc) { 250 int new_pc = pc + frame.getOffsetDelta() + 1; 251 StackMap prev = map.get(pc); 252 assert (prev != null); 253 verification_type_info[] new_locals = new verification_type_info[prev.locals.length + frame.locals.length]; 254 System.arraycopy(prev.locals, 0, new_locals, 0, prev.locals.length); 255 System.arraycopy(frame.locals, 0, new_locals, prev.locals.length, frame.locals.length); 256 StackMap m = new StackMap(new_locals, empty); 257 map.put(new_pc, m); 258 return new_pc; 259 } 260 261 public Integer visit_full_frame(full_frame frame, Integer pc) { 262 int new_pc = pc + frame.getOffsetDelta() + 1; 263 StackMap m = new StackMap(frame.locals, frame.stack); 264 map.put(new_pc, m); 265 return new_pc; 266 } 267 268 } 269 270 static class StackMap { 271 StackMap(verification_type_info[] locals, verification_type_info[] stack) { 272 this.locals = locals; 273 this.stack = stack; 274 } 275 276 private final verification_type_info[] locals; 277 private final verification_type_info[] stack; 278 } 279 280 static class CustomVerificationTypeInfo extends verification_type_info { 281 public CustomVerificationTypeInfo(String text) { 282 super(-1); 283 this.text = text; 284 } 285 private String text; 286 } 287 288 private final verification_type_info[] empty = { }; 289} 290