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 }