Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: Compil3r/Quad/ProgramLocation.java


1   // ProgramLocation.java, created Sun Sep  1 17:38:25 2002 by joewhaley
2   // Copyright (C) 2001-3 John Whaley <jwhaley@alum.mit.edu>
3   // Licensed under the terms of the GNU LGPL; see COPYING for details.
4   package Compil3r.Quad;
5   
6   import java.util.Iterator;
7   import java.util.Map;
8   import java.util.Set;
9   
10  import Clazz.jq_Class;
11  import Clazz.jq_ClassFileConstants;
12  import Clazz.jq_InstanceMethod;
13  import Clazz.jq_Method;
14  import Clazz.jq_Reference;
15  import Compil3r.BytecodeAnalysis.BytecodeVisitor;
16  import Compil3r.BytecodeAnalysis.CallTargets;
17  import Compil3r.Quad.AndersenInterface.AndersenMethod;
18  import Compil3r.Quad.AndersenInterface.AndersenReference;
19  import Compil3r.Quad.AndersenInterface.AndersenType;
20  import Compil3r.Quad.MethodSummary.ConcreteTypeNode;
21  import Compil3r.Quad.MethodSummary.Node;
22  import Compil3r.Quad.Operator.Invoke;
23  import Compil3r.Quad.SSAReader.SSAClass;
24  import Compil3r.Quad.SSAReader.SSAMethod;
25  import Compil3r.Quad.SSAReader.SSAType;
26  import UTF.Utf8;
27  import Util.Assert;
28  import Util.Collections.HashCodeComparator;
29  import Util.Collections.SortedArraySet;
30  
31  /**
32   * This class combines a jq_Method with a Quad to represent a location in the code.
33   * This is useful for interprocedural analysis.
34   *
35   * @author  John Whaley <jwhaley@alum.mit.edu>
36   * @version $Id: ProgramLocation.java,v 1.23 2003/08/03 12:32:34 joewhaley Exp $
37   */
38  public abstract class ProgramLocation {
39      protected final AndersenMethod m;
40      public ProgramLocation(AndersenMethod m) {
41          this.m = m;
42      }
43      public AndersenMethod getMethod() { return m; }
44      public abstract int getNumParams();
45      public abstract AndersenType getParamType(int i);
46      
47      public abstract Utf8 getSourceFile();
48      public abstract int getLineNumber();
49      
50      public abstract int getID();
51      public abstract int getBytecodeIndex();
52      
53      public abstract boolean isSingleTarget();
54      public abstract boolean isInterfaceCall();
55      
56      public abstract AndersenMethod getTargetMethod();
57      
58      public abstract CallTargets getCallTargets();
59  
60      public abstract CallTargets getCallTargets(AndersenReference klass, boolean exact);
61      public abstract CallTargets getCallTargets(java.util.Set receiverTypes, boolean exact);
62      
63      public CallTargets getCallTargets(AndersenMethod target, Node n) {
64          return getCallTargets((AndersenReference)n.getDeclaredType(), n instanceof ConcreteTypeNode);
65      }
66      
67      public CallTargets getCallTargets(java.util.Set nodes) {
68          Set exact_types = SortedArraySet.FACTORY.makeSet(HashCodeComparator.INSTANCE);
69          Set notexact_types = SortedArraySet.FACTORY.makeSet(HashCodeComparator.INSTANCE);
70  
71          for (Iterator i=nodes.iterator(); i.hasNext(); ) {
72              Node n = (Node)i.next();
73              Set s = (n instanceof ConcreteTypeNode)?exact_types:notexact_types;
74              if (n.getDeclaredType() != null)
75                  s.add(n.getDeclaredType());
76          }
77          if (notexact_types.isEmpty()) return getCallTargets(exact_types, true);
78          if (exact_types.isEmpty()) return getCallTargets(notexact_types, false);
79          CallTargets ct = getCallTargets(exact_types, true);
80          if (ct==null) return null;
81          // bugfix - added 'ct=' (Daniel Wright)
82          ct = ct.union(getCallTargets(notexact_types, false));
83          return ct;
84      }
85      
86      public static class QuadProgramLocation extends ProgramLocation {
87          private final Quad q;
88          public QuadProgramLocation(AndersenMethod m, Quad q) {
89              super(m);
90              this.q = q;
91          }
92          
93          public AndersenMethod getTargetMethod() {
94              if (!(q.getOperator() instanceof Invoke)) return null;
95              return Invoke.getMethod(q).getMethod();
96          }
97          
98          public int getID() { return q.getID(); }
99          public int getBytecodeIndex() {
100             Map map = CodeCache.getBCMap((jq_Method) super.m);
101             Integer i = (Integer) map.get(q);
102             return i.intValue();
103         }
104         
105         public Utf8 getSourceFile() {
106             jq_Method method = (jq_Method) m;
107             return method.getDeclaringClass().getSourceFile();
108         }
109         public int getLineNumber() {
110             jq_Method method = (jq_Method) m;
111             int bci = getBytecodeIndex();
112             return method.getLineNumber(bci);
113         }
114         
115         public int getNumParams() { return Invoke.getParamList(q).length(); }
116         public AndersenType getParamType(int i) { return Invoke.getParamList(q).get(i).getType(); }
117         
118         public int hashCode() {
119             return (q==null)?-1:q.hashCode();
120         }
121         public boolean equals(QuadProgramLocation that) { return this.q == that.q; }
122         public boolean equals(Object o) { if (o instanceof QuadProgramLocation) return equals((QuadProgramLocation)o); return false; }
123         
124         public String toString() {
125             StringBuffer sb = new StringBuffer();
126             sb.append(super.m.getName());
127             sb.append("() quad ");
128             sb.append((q==null)?-1:q.getID());
129             if (q.getOperator() instanceof Invoke) {
130                 sb.append(" => ");
131                 sb.append(Invoke.getMethod(q).getMethod().getName());
132                 sb.append("()");
133             }
134             return sb.toString();
135         }
136         
137         public boolean isSingleTarget() {
138             if (isInterfaceCall()) return false;
139             if (!((Invoke) q.getOperator()).isVirtual()) return true;
140             jq_InstanceMethod target = (jq_InstanceMethod) Invoke.getMethod(q).getMethod();
141             target.getDeclaringClass().load();
142             if (target.getDeclaringClass().isFinal()) return true;
143             target.getDeclaringClass().prepare();
144             if (!target.isLoaded()) {
145                 target = target.resolve1();
146                 if (!target.isLoaded()) {
147                     // bad target method!
148                     return false;
149                 }
150                 Invoke.getMethod(q).setMethod(target);
151             }
152             if (!target.isVirtual()) return true;
153             return false;
154         }
155         
156         public boolean isInterfaceCall() {
157             return q.getOperator() instanceof Invoke.InvokeInterface;
158         }
159         
160         private byte getInvocationType() {
161             if (q.getOperator() instanceof Invoke.InvokeVirtual) {
162                 return BytecodeVisitor.INVOKE_VIRTUAL;
163             } else if (q.getOperator() instanceof Invoke.InvokeStatic) {
164                 jq_Method target = Invoke.getMethod(q).getMethod();
165                 if (target instanceof jq_InstanceMethod)
166                     return BytecodeVisitor.INVOKE_SPECIAL;
167                 else
168                     return BytecodeVisitor.INVOKE_STATIC;
169             } else {
170                 Assert._assert(q.getOperator() instanceof Invoke.InvokeInterface);
171                 return BytecodeVisitor.INVOKE_INTERFACE;
172             }
173         }
174         
175         public CallTargets getCallTargets() {
176             if (!(q.getOperator() instanceof Invoke)) return null;
177             jq_Method target = Invoke.getMethod(q).getMethod();
178             byte type = getInvocationType();
179             return CallTargets.getTargets(target.getDeclaringClass(), target, type, true);
180         }
181         
182         public CallTargets getCallTargets(AndersenReference klass, boolean exact) {
183             if (!(q.getOperator() instanceof Invoke)) return null;
184             jq_Method target = Invoke.getMethod(q).getMethod();
185             byte type = getInvocationType();
186             return CallTargets.getTargets(target.getDeclaringClass(), target, type, (jq_Reference)klass, exact, true);
187         }
188         
189         public CallTargets getCallTargets(java.util.Set receiverTypes, boolean exact) {
190             if (!(q.getOperator() instanceof Invoke)) return null;
191             jq_Method target = Invoke.getMethod(q).getMethod();
192             byte type = getInvocationType();
193             return CallTargets.getTargets(target.getDeclaringClass(), target, type, receiverTypes, exact, true);
194         }
195         
196         public Quad getQuad() { return q; }
197     }
198     
199     public static class BCProgramLocation extends ProgramLocation {
200         final int bcIndex;
201         
202         public BCProgramLocation(jq_Method m, int bcIndex) {
203             super(m);
204             this.bcIndex = bcIndex;
205         }
206         
207         public int getID() { return bcIndex; }
208         public int getBytecodeIndex() { return bcIndex; }
209         
210         public Utf8 getSourceFile() {
211             jq_Method method = (jq_Method) m;
212             return method.getDeclaringClass().getSourceFile();
213         }
214         public int getLineNumber() {
215             jq_Method method = (jq_Method) m;
216             return method.getLineNumber(bcIndex);
217         }
218         
219         public AndersenMethod getTargetMethod() {
220             jq_Class clazz = ((jq_Method) super.m).getDeclaringClass();
221             byte[] bc = ((jq_Method) super.m).getBytecode();
222             if (bc == null || bcIndex < 0 || bcIndex+2 >= bc.length) return null;
223             char cpi = Util.Convert.twoBytesToChar(bc, bcIndex+1);
224             switch (bc[bcIndex]) {
225                 case (byte) jq_ClassFileConstants.jbc_INVOKEVIRTUAL:
226                 case (byte) jq_ClassFileConstants.jbc_INVOKESPECIAL:
227                 case (byte) jq_ClassFileConstants.jbc_INVOKEINTERFACE:
228                     return clazz.getCPasInstanceMethod(cpi);
229                 case (byte) jq_ClassFileConstants.jbc_INVOKESTATIC:
230                     return clazz.getCPasStaticMethod(cpi);
231                 case (byte) jq_ClassFileConstants.jbc_MULTIANEWARRAY:
232                     return Run_Time.Arrays._multinewarray;
233                 default:
234                     return null;
235             }
236         }
237         public int getNumParams() {
238             return ((jq_Method) getTargetMethod()).getParamTypes().length;
239         }
240         public AndersenType getParamType(int i) {
241             return ((jq_Method) getTargetMethod()).getParamTypes()[i];
242         }
243 
244         public boolean isSingleTarget() {
245             jq_Class clazz = ((jq_Method) super.m).getDeclaringClass();
246             byte[] bc = ((jq_Method) super.m).getBytecode();
247             if (bc == null || bcIndex < 0 || bcIndex+2 >= bc.length) return false;
248             switch (bc[bcIndex]) {
249                 case (byte) jq_ClassFileConstants.jbc_INVOKESPECIAL:
250                 case (byte) jq_ClassFileConstants.jbc_INVOKESTATIC:
251                 case (byte) jq_ClassFileConstants.jbc_MULTIANEWARRAY:
252                     return true;
253                 case (byte) jq_ClassFileConstants.jbc_INVOKEVIRTUAL:
254                 case (byte) jq_ClassFileConstants.jbc_INVOKEINTERFACE:
255                 default:
256                     return false;
257             }
258         }
259         public boolean isInterfaceCall() {
260             jq_Class clazz = ((jq_Method) super.m).getDeclaringClass();
261             byte[] bc = ((jq_Method) super.m).getBytecode();
262             if (bc == null || bcIndex < 0 || bcIndex+2 >= bc.length) return false;
263             return bc[bcIndex] == jq_ClassFileConstants.jbc_INVOKEINTERFACE;
264         }
265 
266         public int hashCode() {
267             return super.m.hashCode() ^ bcIndex;
268         }
269         public boolean equals(BCProgramLocation that) {
270             return this.bcIndex == that.bcIndex && super.m == that.m;
271         }
272         public boolean equals(Object o) {
273             if (o instanceof BCProgramLocation) return equals((BCProgramLocation) o);
274             return false;
275         }
276         public String toString() {
277             String s = super.m.getName()+"() @ "+bcIndex;
278             return s;
279         }
280         
281         public CallTargets getCallTargets() {
282             jq_Class clazz = ((jq_Method) super.m).getDeclaringClass();
283             byte[] bc = ((jq_Method) super.m).getBytecode();
284             if (bc == null || bcIndex < 0 || bcIndex+2 >= bc.length) return null;
285             char cpi = Util.Convert.twoBytesToChar(bc, bcIndex+1);
286             byte type;
287             jq_Method method;
288             switch (bc[bcIndex]) {
289                 case (byte) jq_ClassFileConstants.jbc_INVOKEVIRTUAL:
290                     type = BytecodeVisitor.INVOKE_VIRTUAL;
291                     // fallthrough
292                 case (byte) jq_ClassFileConstants.jbc_INVOKESPECIAL:
293                     type = BytecodeVisitor.INVOKE_SPECIAL;
294                     // fallthrough
295                 case (byte) jq_ClassFileConstants.jbc_INVOKEINTERFACE:
296                     method = clazz.getCPasInstanceMethod(cpi);
297                     type = BytecodeVisitor.INVOKE_INTERFACE;
298                     break;
299                 case (byte) jq_ClassFileConstants.jbc_INVOKESTATIC:
300                     method = clazz.getCPasStaticMethod(cpi);
301                     type = BytecodeVisitor.INVOKE_STATIC;
302                     break;
303                 case (byte) jq_ClassFileConstants.jbc_MULTIANEWARRAY:
304                     method = Run_Time.Arrays._multinewarray;
305                     type = BytecodeVisitor.INVOKE_STATIC;
306                     break;
307                 default:
308                     return null;
309             }
310             return CallTargets.getTargets(clazz, method, type, true);
311         }
312         public CallTargets getCallTargets(AndersenReference klass, boolean exact) {
313             jq_Class clazz = ((jq_Method) super.m).getDeclaringClass();
314             byte[] bc = ((jq_Method) super.m).getBytecode();
315             if (bc == null || bcIndex < 0 || bcIndex+2 >= bc.length) return null;
316             char cpi = Util.Convert.twoBytesToChar(bc, bcIndex+1);
317             byte type;
318             jq_Method method;
319             switch (bc[bcIndex]) {
320                 case (byte) jq_ClassFileConstants.jbc_INVOKEVIRTUAL:
321                     type = BytecodeVisitor.INVOKE_VIRTUAL;
322                     // fallthrough
323                 case (byte) jq_ClassFileConstants.jbc_INVOKESPECIAL:
324                     type = BytecodeVisitor.INVOKE_SPECIAL;
325                     // fallthrough
326                 case (byte) jq_ClassFileConstants.jbc_INVOKEINTERFACE:
327                     method = clazz.getCPasInstanceMethod(cpi);
328                     type = BytecodeVisitor.INVOKE_INTERFACE;
329                     break;
330                 case (byte) jq_ClassFileConstants.jbc_INVOKESTATIC:
331                     method = clazz.getCPasStaticMethod(cpi);
332                     type = BytecodeVisitor.INVOKE_STATIC;
333                     break;
334                 case (byte) jq_ClassFileConstants.jbc_MULTIANEWARRAY:
335                     method = Run_Time.Arrays._multinewarray;
336                     type = BytecodeVisitor.INVOKE_STATIC;
337                     break;
338                 default:
339                     return null;
340             }
341             return CallTargets.getTargets(clazz, method, type, (jq_Reference) klass, exact, true);
342         }
343         public CallTargets getCallTargets(java.util.Set receiverTypes, boolean exact) {
344             jq_Class clazz = ((jq_Method) super.m).getDeclaringClass();
345             byte[] bc = ((jq_Method) super.m).getBytecode();
346             if (bc == null || bcIndex < 0 || bcIndex+2 >= bc.length) return null;
347             char cpi = Util.Convert.twoBytesToChar(bc, bcIndex+1);
348             byte type;
349             jq_Method method;
350             switch (bc[bcIndex]) {
351                 case (byte) jq_ClassFileConstants.jbc_INVOKEVIRTUAL:
352                     type = BytecodeVisitor.INVOKE_VIRTUAL;
353                     // fallthrough
354                 case (byte) jq_ClassFileConstants.jbc_INVOKESPECIAL:
355                     type = BytecodeVisitor.INVOKE_SPECIAL;
356                     // fallthrough
357                 case (byte) jq_ClassFileConstants.jbc_INVOKEINTERFACE:
358                     method = clazz.getCPasInstanceMethod(cpi);
359                     type = BytecodeVisitor.INVOKE_INTERFACE;
360                     break;
361                 case (byte) jq_ClassFileConstants.jbc_INVOKESTATIC:
362                     method = clazz.getCPasStaticMethod(cpi);
363                     type = BytecodeVisitor.INVOKE_STATIC;
364                     break;
365                 case (byte) jq_ClassFileConstants.jbc_MULTIANEWARRAY:
366                     method = Run_Time.Arrays._multinewarray;
367                     type = BytecodeVisitor.INVOKE_STATIC;
368                     break;
369                 default:
370                     return null;
371             }
372             return CallTargets.getTargets(clazz, method, type, receiverTypes, exact, true);
373         }
374     }
375     
376     public static class SSAProgramLocation extends ProgramLocation {
377         final int identifier; // for .equals() comparison - should identify program location
378         SSAMethod targetMethod;
379         
380         public SSAProgramLocation(int identifier, AndersenMethod m, SSAMethod targetMethod) {
381             super(m);
382             this.identifier = identifier;
383             this.targetMethod = targetMethod;
384         }
385         
386         public int getID() { return identifier; }
387         public int getBytecodeIndex() {
388             Assert.UNREACHABLE();
389             return 0;
390         }
391         
392         public Utf8 getSourceFile() {
393             Assert.UNREACHABLE();
394             return null;
395         }
396         public int getLineNumber() {
397             Assert.UNREACHABLE();
398             return 0;
399         }
400         
401         public AndersenMethod getTargetMethod() { return targetMethod; }
402         public int getNumParams() { return targetMethod.getNumParams(); }
403         public AndersenType getParamType(int i) { return targetMethod.getParamType(i); }
404 
405         public boolean isSingleTarget() { return false; } // todo.
406         public boolean isInterfaceCall() { return false; }
407 
408         public int hashCode() { return identifier; }
409         public boolean equals(SSAProgramLocation that) { return this.identifier == that.identifier; }
410         public boolean equals(Object o) { if (o instanceof SSAProgramLocation) return equals((SSAProgramLocation)o); return false; }
411         public String toString() {
412             String s = super.m.getName()+"() invocation "+identifier;
413             if (targetMethod != null)
414                 s += " => "+targetMethod.getName()+"()";
415             return s;
416         }
417         
418         
419         public CallTargets getCallTargets() {
420             return targetMethod.getCallTargets(targetMethod.getDeclaringClass(), false);
421         }
422         public CallTargets getCallTargets(AndersenReference klass, boolean exact) {
423       
424             SSAType ssaType = (SSAType)klass;
425       SSAClass clazz = null;
426       if (ssaType.getTargetType()!=null)
427     clazz = ssaType.getTargetType().getSSAClass();
428       // else this is not a pointer to a class
429 
430             return targetMethod.getCallTargets(clazz, exact);
431         }
432         public CallTargets getCallTargets(java.util.Set receiverTypes, boolean exact) {
433             CallTargets ct = CallTargets.NoCallTarget.INSTANCE;
434             
435             for (Iterator i = receiverTypes.iterator(); i.hasNext(); ) {
436                 ct = ct.union(getCallTargets((AndersenReference)i.next(), exact));
437             }
438             
439             return ct;
440         }
441     }
442 
443 }