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