• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9  * or the Apache License Version 2.0.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  */
16 
17 package javassist.bytecode.stackmap;
18 
19 import javassist.bytecode.AccessFlag;
20 import javassist.bytecode.BadBytecode;
21 import javassist.bytecode.CodeAttribute;
22 import javassist.bytecode.ConstPool;
23 import javassist.bytecode.MethodInfo;
24 
25 public class TypedBlock extends BasicBlock {
26     public int stackTop, numLocals;
27     // localsTypes is set to non-null when this block is first visited by a MapMaker.
28     // see alreadySet().
29     public TypeData[] localsTypes;
30     public TypeData[] stackTypes;
31 
32     /**
33      * Divides the method body into basic blocks.
34      * The type information of the first block is initialized.
35      *
36      * @param optimize       if it is true and the method does not include
37      *                      branches, this method returns null.
38      */
makeBlocks(MethodInfo minfo, CodeAttribute ca, boolean optimize)39     public static TypedBlock[] makeBlocks(MethodInfo minfo, CodeAttribute ca,
40                                           boolean optimize)
41         throws BadBytecode
42     {
43         TypedBlock[] blocks = (TypedBlock[])new Maker().make(minfo);
44         if (optimize && blocks.length < 2)
45             if (blocks.length == 0 || blocks[0].incoming == 0)
46                 return null;
47 
48         ConstPool pool = minfo.getConstPool();
49         boolean isStatic = (minfo.getAccessFlags() & AccessFlag.STATIC) != 0;
50         blocks[0].initFirstBlock(ca.getMaxStack(), ca.getMaxLocals(),
51                                  pool.getClassName(), minfo.getDescriptor(),
52                                  isStatic, minfo.isConstructor());
53         return blocks;
54     }
55 
TypedBlock(int pos)56     protected TypedBlock(int pos) {
57         super(pos);
58         localsTypes = null;
59     }
60 
61     @Override
toString2(StringBuffer sbuf)62     protected void toString2(StringBuffer sbuf) {
63         super.toString2(sbuf);
64         sbuf.append(",\n stack={");
65         printTypes(sbuf, stackTop, stackTypes);
66         sbuf.append("}, locals={");
67         printTypes(sbuf, numLocals, localsTypes);
68         sbuf.append('}');
69     }
70 
printTypes(StringBuffer sbuf, int size, TypeData[] types)71     private void printTypes(StringBuffer sbuf, int size,
72                             TypeData[] types) {
73         if (types == null)
74             return;
75 
76         for (int i = 0; i < size; i++) {
77             if (i > 0)
78                 sbuf.append(", ");
79 
80             TypeData td = types[i];
81             sbuf.append(td == null ? "<>" : td.toString());
82         }
83     }
84 
alreadySet()85     public boolean alreadySet() {
86         return localsTypes != null;
87     }
88 
setStackMap(int st, TypeData[] stack, int nl, TypeData[] locals)89     public void setStackMap(int st, TypeData[] stack, int nl, TypeData[] locals)
90         throws BadBytecode
91     {
92         stackTop = st;
93         stackTypes = stack;
94         numLocals = nl;
95         localsTypes = locals;
96     }
97 
98     /*
99      * Computes the correct value of numLocals.
100      */
resetNumLocals()101     public void resetNumLocals() {
102         if (localsTypes != null) {
103             int nl = localsTypes.length;
104             while (nl > 0 && localsTypes[nl - 1].isBasicType() == TypeTag.TOP) {
105                 if (nl > 1) {
106                     if (localsTypes[nl - 2].is2WordType())
107                         break;
108                 }
109 
110                 --nl;
111             }
112 
113             numLocals = nl;
114         }
115     }
116 
117     public static class Maker extends BasicBlock.Maker {
118         @Override
makeBlock(int pos)119         protected BasicBlock makeBlock(int pos) {
120             return new TypedBlock(pos);
121         }
122 
123         @Override
makeArray(int size)124         protected BasicBlock[] makeArray(int size) {
125             return new TypedBlock[size];
126         }
127     }
128 
129     /**
130      * Initializes the first block by the given method descriptor.
131      *
132      * @param block             the first basic block that this method initializes.
133      * @param className         a dot-separated fully qualified class name.
134      *                          For example, <code>javassist.bytecode.stackmap.BasicBlock</code>.
135      * @param methodDesc        method descriptor.
136      * @param isStatic          true if the method is a static method.
137      * @param isConstructor     true if the method is a constructor.
138      */
initFirstBlock(int maxStack, int maxLocals, String className, String methodDesc, boolean isStatic, boolean isConstructor)139     void initFirstBlock(int maxStack, int maxLocals, String className,
140                         String methodDesc, boolean isStatic, boolean isConstructor)
141         throws BadBytecode
142     {
143         if (methodDesc.charAt(0) != '(')
144             throw new BadBytecode("no method descriptor: " + methodDesc);
145 
146         stackTop = 0;
147         stackTypes = TypeData.make(maxStack);
148         TypeData[] locals = TypeData.make(maxLocals);
149         if (isConstructor)
150             locals[0] = new TypeData.UninitThis(className);
151         else if (!isStatic)
152             locals[0] = new TypeData.ClassName(className);
153 
154         int n = isStatic ? -1 : 0;
155         int i = 1;
156         try {
157             while ((i = descToTag(methodDesc, i, ++n, locals)) > 0)
158                 if (locals[n].is2WordType())
159                     locals[++n] = TypeTag.TOP;
160         }
161         catch (StringIndexOutOfBoundsException e) {
162             throw new BadBytecode("bad method descriptor: "
163                                   + methodDesc);
164         }
165 
166         numLocals = n;
167         localsTypes = locals;
168     }
169 
descToTag(String desc, int i, int n, TypeData[] types)170     private static int descToTag(String desc, int i,
171                                  int n, TypeData[] types)
172         throws BadBytecode
173     {
174         int i0 = i;
175         int arrayDim = 0;
176         char c = desc.charAt(i);
177         if (c == ')')
178             return 0;
179 
180         while (c == '[') {
181             ++arrayDim;
182             c = desc.charAt(++i);
183         }
184 
185         if (c == 'L') {
186             int i2 = desc.indexOf(';', ++i);
187             if (arrayDim > 0)
188                 types[n] = new TypeData.ClassName(desc.substring(i0, ++i2));
189             else
190                 types[n] = new TypeData.ClassName(desc.substring(i0 + 1, ++i2 - 1)
191                                                       .replace('/', '.'));
192             return i2;
193         }
194         else if (arrayDim > 0) {
195             types[n] = new TypeData.ClassName(desc.substring(i0, ++i));
196             return i;
197         }
198         else {
199             TypeData t = toPrimitiveTag(c);
200             if (t == null)
201                 throw new BadBytecode("bad method descriptor: " + desc);
202 
203             types[n] = t;
204             return i + 1;
205         }
206     }
207 
toPrimitiveTag(char c)208     private static TypeData toPrimitiveTag(char c) {
209         switch (c) {
210         case 'Z' :
211         case 'C' :
212         case 'B' :
213         case 'S' :
214         case 'I' :
215             return TypeTag.INTEGER;
216         case 'J' :
217             return TypeTag.LONG;
218         case 'F' :
219             return TypeTag.FLOAT;
220         case 'D' :
221             return TypeTag.DOUBLE;
222         case 'V' :
223         default :
224             return null;
225         }
226     }
227 
getRetType(String desc)228     public static String getRetType(String desc) {
229         int i = desc.indexOf(')');
230         if (i < 0)
231             return "java.lang.Object";
232 
233         char c = desc.charAt(i + 1);
234         if (c == '[')
235             return desc.substring(i + 1);
236         else if (c == 'L')
237             return desc.substring(i + 2, desc.length() - 1).replace('/', '.');
238         else
239             return "java.lang.Object";
240     }
241 }
242