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