1 /* 2 * Copyright (c) 2009, 2025, 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 java.lang.classfile.constantpool.NameAndTypeEntry; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 import java.lang.classfile.Attributes; 33 import java.lang.classfile.ClassFile; 34 35 import java.lang.classfile.Instruction; 36 import java.lang.classfile.attribute.CodeAttribute; 37 import java.lang.classfile.attribute.StackMapFrameInfo; 38 import java.lang.classfile.attribute.StackMapTableAttribute; 39 40 /** 41 * Annotate instructions with stack map. 42 * 43 * <p><b>This is NOT part of any supported API. 44 * If you write code that depends on this, you do so at your own risk. 45 * This code and its internal interfaces are subject to change or 46 * deletion without notice.</b> 47 */ 48 public class StackMapWriter extends InstructionDetailWriter { 49 static StackMapWriter instance(Context context) { 50 StackMapWriter instance = context.get(StackMapWriter.class); 51 if (instance == null) 52 instance = new StackMapWriter(context); 53 return instance; 54 } 55 56 protected StackMapWriter(Context context) { 57 super(context); 58 context.put(StackMapWriter.class, this); 59 } 60 61 public void reset(CodeAttribute code) { 62 setStackMap(code); 63 } 64 65 void setStackMap(CodeAttribute code) { 66 StackMapTableAttribute attr = code.findAttribute(Attributes.stackMapTable()) 67 .orElse(null); 68 if (attr == null) { 69 map = null; 70 return; 71 } 72 var m = code.parent().get(); 73 if ((m.flags().flagsMask() & ClassFile.ACC_STATIC) == 0) { 74 thisClassName = m.parent().get().thisClass().asInternalName(); 75 } else { 76 thisClassName = null; 77 } 78 79 map = new HashMap<>(); 80 this.code = code; 81 for (var fr : attr.entries()) 82 map.put(code.labelToBci(fr.target()), fr); 83 } 84 85 public void writeInitialDetails() { 86 writeDetails(-1); 87 } 88 89 @Override 90 public void writeDetails(int pc, Instruction instr) { 91 writeDetails(pc); 92 } 93 94 private void writeDetails(int pc) { 95 if (map == null) 96 return; 97 98 var m = map.get(pc); 99 if (m != null) { 100 print("StackMap locals: ", m.locals(), true); 101 print("StackMap stack: ", m.stack(), false); 102 if (!m.unsetFields().isEmpty()) { 103 printFields("StackMap unset fields: ", m.unsetFields()); 104 } 105 } 106 107 } 108 109 void printFields(String label, List<NameAndTypeEntry> entries) { 110 print(label); 111 boolean first = true; 112 for (var e : entries) { 113 if (!first) { 114 print(", "); 115 } else { 116 first = false; 117 } 118 print(e::name); 119 print(":"); 120 print(e::type); 121 } 122 println(); 123 } 124 125 void print(String label, List<StackMapFrameInfo.VerificationTypeInfo> entries, 126 boolean firstThis) { 127 print(label); 128 for (var e : entries) { 129 print(" "); 130 print(e, firstThis); 131 firstThis = false; 132 } 133 println(); 134 } 135 136 void print(StackMapFrameInfo.VerificationTypeInfo entry, boolean firstThis) { 137 if (entry == null) { 138 print("ERROR"); 139 return; 140 } 141 142 switch (entry) { 143 case StackMapFrameInfo.SimpleVerificationTypeInfo s -> { 144 switch (s) { 145 case TOP -> 146 print("top"); 147 148 case INTEGER -> 149 print("int"); 150 151 case FLOAT -> 152 print("float"); 153 154 case LONG -> 155 print("long"); 156 157 case DOUBLE -> 158 print("double"); 159 160 case NULL -> 161 print("null"); 162 163 case UNINITIALIZED_THIS -> 164 print("uninit_this"); 165 } 166 } 167 168 case StackMapFrameInfo.ObjectVerificationTypeInfo o -> { 169 String cln = o.className().asInternalName(); 170 print(firstThis && cln.equals(thisClassName) ? "this" : cln); 171 } 172 173 case StackMapFrameInfo.UninitializedVerificationTypeInfo u -> 174 print(code.labelToBci(u.newTarget())); 175 } 176 177 } 178 179 private Map<Integer, StackMapFrameInfo> map; 180 private String thisClassName; 181 private CodeAttribute code; 182 }