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 }