Source Code Cross Referenced for CallGraph.java in  » Database-DBMS » db4o-6.4 » EDU » purdue » cs » bloat » inline » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db4o 6.4 » EDU.purdue.cs.bloat.inline 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /* Copyright (C) 2004 - 2007  db4objects Inc.  http://www.db4o.com
002:
003:        This file is part of the db4o open source object database.
004:
005:        db4o is free software; you can redistribute it and/or modify it under
006:        the terms of version 2 of the GNU General Public License as published
007:        by the Free Software Foundation and as clarified by db4objects' GPL 
008:        interpretation policy, available at
009:        http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010:        Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011:        Suite 350, San Mateo, CA 94403, USA.
012:
013:        db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014:        WARRANTY; without even the implied warranty of MERCHANTABILITY or
015:        FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
016:        for more details.
017:
018:        You should have received a copy of the GNU General Public License along
019:        with this program; if not, write to the Free Software Foundation, Inc.,
020:        59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */
021:        package EDU.purdue.cs.bloat.inline;
022:
023:        import java.io.*;
024:        import java.util.*;
025:
026:        import EDU.purdue.cs.bloat.editor.*;
027:        import EDU.purdue.cs.bloat.reflect.*;
028:        import EDU.purdue.cs.bloat.util.*;
029:
030:        /**
031:         * Grants access to certain information about a Java program. At least one root
032:         * method must be specified. From these root methods, the call graph and
033:         * information such as the classes that are instantiated during the Java program
034:         * is computed.
035:         * 
036:         * <p>
037:         * 
038:         * The construction of the call graph is in the spirit of the "Program
039:         * Virtual-call Graph" presented in [Bacon97]. However, certain changes have
040:         * been made to tailor it to BLOAT and Java and to make the overall
041:         * representation smaller.
042:         * 
043:         * <p>
044:         * 
045:         * Rapid type analysis is integrated into the construction of the call graph. A
046:         * virtual method is not examined until we know that its declaring class has
047:         * been instantiated.
048:         * 
049:         * <p>
050:         * 
051:         * Some classes are created internally by the VM and are missed by our analysis.
052:         * So, we maintain a set of "pre-live" classes. We consider all of their
053:         * constructors to be live.
054:         */
055:        public class CallGraph {
056:            public static boolean DEBUG = false;
057:
058:            private static Set preLive; // "Pre-live" classes
059:
060:            public static boolean USEPRELIVE = true;
061:
062:            public static boolean USE1_2 = true;
063:
064:            private Set roots; // Root methods (MethodRefs)
065:
066:            private Map calls; // Maps methods to the methods they
067:
068:            // call (virtual calls are not resolved)
069:            private Set liveClasses; // Classes (Types) that have been instantiated
070:
071:            private Map resolvesTo; // Maps methods to the methods they resolve to
072:
073:            private Map blocked; // Maps types to methods blocked on those types
074:
075:            List worklist; // Methods to process
076:
077:            Set liveMethods; // Methods that may be executed
078:
079:            InlineContext context;
080:
081:            private ClassHierarchy hier;
082:
083:            static void db(final String s) {
084:                if (CallGraph.DEBUG) {
085:                    System.out.println(s);
086:                }
087:            }
088:
089:            /**
090:             * Initialize the set of classes that are "pre-live"
091:             */
092:            private static void init() {
093:                // We can't do this in the static initializer because USE1_2 might
094:                // not have the desired value.
095:
096:                CallGraph.preLive = new HashSet();
097:
098:                CallGraph.preLive.add("java.lang.Boolean");
099:                CallGraph.preLive.add("java.lang.Class");
100:                CallGraph.preLive.add("java.lang.ClassLoader");
101:                CallGraph.preLive.add("java.lang.Compiler");
102:                CallGraph.preLive.add("java.lang.Integer");
103:                CallGraph.preLive.add("java.lang.SecurityManager");
104:                CallGraph.preLive.add("java.lang.String");
105:                CallGraph.preLive.add("java.lang.StringBuffer");
106:                CallGraph.preLive.add("java.lang.System");
107:                CallGraph.preLive.add("java.lang.StackOverflowError");
108:                CallGraph.preLive.add("java.lang.Thread");
109:                CallGraph.preLive.add("java.lang.ThreadGroup");
110:
111:                CallGraph.preLive.add("java.io.BufferedInputStream");
112:                CallGraph.preLive.add("java.io.BufferedReader");
113:                CallGraph.preLive.add("java.io.BufferedOutputStream");
114:                CallGraph.preLive.add("java.io.BufferedWriter");
115:                CallGraph.preLive.add("java.io.File");
116:                CallGraph.preLive.add("java.io.FileDescriptor");
117:                CallGraph.preLive.add("java.io.InputStreamReader");
118:                CallGraph.preLive.add("java.io.ObjectStreamClass");
119:                CallGraph.preLive.add("java.io.OutputStreamWriter");
120:                CallGraph.preLive.add("java.io.PrintStream");
121:                CallGraph.preLive.add("java.io.PrintWriter");
122:
123:                CallGraph.preLive.add("java.net.URL");
124:
125:                CallGraph.preLive.add("java.security.Provider");
126:                CallGraph.preLive.add("java.security.Security");
127:
128:                CallGraph.preLive.add("java.util.Hashtable");
129:                CallGraph.preLive.add("java.util.ListResourceBundle");
130:                CallGraph.preLive.add("java.util.Locale");
131:                CallGraph.preLive.add("java.util.Properties");
132:                CallGraph.preLive.add("java.util.Stack");
133:                CallGraph.preLive.add("java.util.Vector");
134:
135:                CallGraph.preLive.add("java.util.zip.ZipFile");
136:
137:                // Some pre-live classes are only available on JDK1.2.
138:                if (CallGraph.USE1_2) {
139:                    CallGraph.preLive.add("java.lang.Package");
140:
141:                    CallGraph.preLive.add("java.lang.ref.Finalizer");
142:                    CallGraph.preLive.add("java.lang.ref.ReferenceQueue");
143:
144:                    CallGraph.preLive.add("java.io.FilePermission");
145:                    CallGraph.preLive.add("java.io.UnixFileSystem");
146:
147:                    CallGraph.preLive.add("java.net.URLClassLoader");
148:
149:                    CallGraph.preLive.add("java.security.SecureClassLoader");
150:                    CallGraph.preLive.add("java.security.AccessController");
151:
152:                    CallGraph.preLive.add("java.text.resources.LocaleElements");
153:                    CallGraph.preLive
154:                            .add("java.text.resources.LocaleElements_en");
155:
156:                    CallGraph.preLive.add("java.util.HashMap");
157:
158:                    CallGraph.preLive.add("java.util.jar.JarFile");
159:                }
160:            }
161:
162:            /**
163:             * Adds (the name of) a class to the set of classes that are considered to
164:             * be "pre-live"
165:             */
166:            public static void addPreLive(final String name) {
167:                if (CallGraph.preLive == null) {
168:                    CallGraph.init();
169:                }
170:                CallGraph.preLive.add(name);
171:            }
172:
173:            /**
174:             * Removes a class from the set of "pre-live" classes
175:             * 
176:             * @return <tt>true</tt> if the class was "pre-live"
177:             */
178:            public static boolean removePreLive(final String name) {
179:                if (CallGraph.preLive == null) {
180:                    CallGraph.init();
181:                }
182:                return (CallGraph.preLive.remove(name));
183:            }
184:
185:            /**
186:             * Constructor.
187:             * 
188:             * @param context
189:             *            <Tt>InlineContext</tt> used to examine classes and methods.
190:             * 
191:             * @param roots
192:             *            The methods (represented as <tt>MemberRef</tt>s) considered
193:             *            to the roots (that is, the "main" methods) of the call graph.
194:             *            Presumably, only static methods or constructors can be root
195:             *            methods.
196:             */
197:            public CallGraph(final InlineContext context, final Set roots) {
198:                Assert.isTrue(roots != null, "A call graph must have roots");
199:                Assert.isTrue(roots.size() > 0, "A call graph must have roots");
200:
201:                if (CallGraph.preLive == null) {
202:                    CallGraph.init();
203:                }
204:
205:                this .context = context;
206:                this .hier = context.getHierarchy();
207:                this .roots = roots;
208:
209:                this .liveClasses = new HashSet();
210:                this .resolvesTo = new HashMap();
211:                this .calls = new HashMap();
212:                this .blocked = new HashMap();
213:                this .worklist = new LinkedList(this .roots);
214:                this .liveMethods = new HashSet();
215:
216:                // To save space, make one InstructionVisitor and use it on every
217:                // Instruction.
218:                final CallVisitor visitor = new CallVisitor(this );
219:
220:                CallGraph.db("Adding pre-live classes");
221:                doPreLive();
222:
223:                CallGraph.db("Constructing call graph");
224:
225:                // Examine each method in the worklist. At each constructor
226:                // invocation make note of the type that was created. At each
227:                // method call determine all possible methods that it can resolve
228:                // to. Add the methods of classes that have been instantiated to
229:                // the worklist.
230:                while (!worklist.isEmpty()) {
231:                    final MemberRef caller = (MemberRef) worklist.remove(0);
232:
233:                    if (liveMethods.contains(caller)) {
234:                        // We've already handled this method
235:                        continue;
236:                    }
237:
238:                    MethodEditor callerMethod = null;
239:                    try {
240:                        callerMethod = context.editMethod(caller);
241:
242:                    } catch (final NoSuchMethodException ex1) {
243:                        System.err.println("** Could not find method: "
244:                                + caller);
245:                        ex1.printStackTrace(System.err);
246:                        System.exit(1);
247:                    }
248:
249:                    // If the method is abstract or native, we can't do anything
250:                    // with it.
251:                    if (callerMethod.isAbstract()) {
252:                        continue;
253:                    }
254:
255:                    liveMethods.add(caller);
256:
257:                    if (callerMethod.isNative()) {
258:                        // We still want native methods to be live
259:                        continue;
260:                    }
261:
262:                    CallGraph.db("\n  Examining method " + caller);
263:
264:                    final Set callees = new HashSet(); // Methods called by caller
265:                    calls.put(caller, callees);
266:
267:                    // If the method is static or is a constructor, the classes
268:                    // static initializer method must have been called. Make note
269:                    // of this.
270:                    if (callerMethod.isStatic() || callerMethod.isConstructor()) {
271:                        addClinit(callerMethod.declaringClass().type());
272:                    }
273:
274:                    // Examine the instructions in the caller method.
275:                    final Iterator code = callerMethod.code().iterator();
276:                    visitor.setCaller(callerMethod);
277:                    while (code.hasNext()) {
278:                        final Object o = code.next();
279:                        if (o instanceof  Instruction) {
280:                            final Instruction inst = (Instruction) o;
281:                            inst.visit(visitor);
282:                        }
283:                    }
284:                }
285:
286:                // We're done constructing the call graph. Try to free up some
287:                // memory.
288:                blocked = null;
289:            }
290:
291:            /**
292:             * Helper method to add the static initializers and all constructors of the
293:             * pre-live classes to the worklist, etc.
294:             */
295:            private void doPreLive() {
296:                if (!CallGraph.USEPRELIVE) {
297:                    return;
298:                }
299:
300:                CallGraph.db("Making constructors of pre-live classes live");
301:
302:                final Iterator iter = CallGraph.preLive.iterator();
303:                while (iter.hasNext()) {
304:                    String name = (String) iter.next();
305:                    CallGraph.db("  " + name + " is pre-live");
306:                    name = name.replace('.', '/');
307:
308:                    ClassEditor ce = null;
309:                    try {
310:                        ce = context.editClass(name);
311:
312:                    } catch (final ClassNotFoundException ex1) {
313:                        System.err.println("** Cannot find pre-live class: "
314:                                + name);
315:                        ex1.printStackTrace(System.err);
316:                        System.exit(1);
317:                    }
318:
319:                    // Make class and static initializer live
320:                    liveClasses.add(ce.type());
321:                    addClinit(ce.type());
322:
323:                    // Make all constructors live
324:                    final MethodInfo[] methods = ce.methods();
325:                    for (int i = 0; i < methods.length; i++) {
326:                        final MethodEditor method = context
327:                                .editMethod(methods[i]);
328:                        if (method.name().equals("<init>")) {
329:                            CallGraph.db("  " + method);
330:                            worklist.add(method.memberRef());
331:                        }
332:                    }
333:                }
334:            }
335:
336:            /**
337:             * Adds the static initializer for a given <tt>Type</tt> to the worklist.
338:             */
339:            void addClinit(final Type type) {
340:                try {
341:                    final ClassEditor ce = context.editClass(type);
342:
343:                    final MethodInfo[] methods = ce.methods();
344:                    for (int i = 0; i < methods.length; i++) {
345:                        final MethodEditor clinit = context
346:                                .editMethod(methods[i]);
347:                        if (clinit.name().equals("<clinit>")) {
348:                            worklist.add(clinit.memberRef());
349:                            context.release(clinit.methodInfo());
350:                            break;
351:                        }
352:                        context.release(clinit.methodInfo());
353:                    }
354:                    context.release(ce.classInfo());
355:
356:                } catch (final ClassNotFoundException ex1) {
357:                    System.err.println("** Could not find class for " + type);
358:                    ex1.printStackTrace(System.err);
359:                    System.exit(1);
360:                }
361:            }
362:
363:            /**
364:             * Handles a virtual call. Determines all possible methods the call could
365:             * resolve to. Adds the method whose declaring classes are live to the
366:             * worklist. Blocks the rest on their declaring types.
367:             */
368:            void doVirtual(final MethodEditor caller, final MemberRef callee) {
369:                // Figure out which methods the callee can resolve to.
370:                final Iterator resolvesToWith = hier.resolvesToWith(callee)
371:                        .iterator();
372:
373:                while (resolvesToWith.hasNext()) {
374:                    final ClassHierarchy.ResolvesToWith rtw = (ClassHierarchy.ResolvesToWith) resolvesToWith
375:                            .next();
376:                    CallGraph.db("      resolves to " + rtw.method);
377:
378:                    // Add all possible non-abstract methods to the call graph.
379:                    // This way, when a blocked method becomes unblocked, it will
380:                    // still be in the call graph.
381:                    addCall(caller, rtw.method);
382:
383:                    Iterator rTypes = rtw.rTypes.iterator();
384:                    boolean isLive = false; // Is one of the rTypes live?
385:                    while (rTypes.hasNext()) {
386:                        final Type rType = (Type) rTypes.next();
387:                        if (liveClasses.contains(rType)) {
388:                            isLive = true;
389:                            CallGraph.db("      Method " + rtw.method
390:                                    + " is live");
391:                            worklist.add(rtw.method);
392:                            break;
393:                        }
394:                    }
395:
396:                    if (!isLive) {
397:                        // If none of the receiver types is live, then the method is
398:                        // blocked on all possible receiver types.
399:                        rTypes = rtw.rTypes.iterator();
400:                        final StringBuffer sb = new StringBuffer();
401:                        while (rTypes.hasNext()) {
402:                            final Type rType = (Type) rTypes.next();
403:                            Set blockedMethods = (Set) blocked.get(rType);
404:                            if (blockedMethods == null) {
405:                                blockedMethods = new HashSet();
406:                                blocked.put(rType, blockedMethods);
407:                            }
408:                            blockedMethods.add(rtw.method);
409:                            sb.append(rType.toString());
410:                            if (rTypes.hasNext()) {
411:                                sb.append(',');
412:                            }
413:                        }
414:                        CallGraph.db("      Blocked " + rtw.method + " on "
415:                                + sb);
416:                    }
417:                }
418:            }
419:
420:            /**
421:             * Makes note of one method calling another. This does not make the method
422:             * live.
423:             */
424:            void addCall(final MethodEditor callerMethod, final MemberRef callee) {
425:                // Just maintain the calls mapping
426:                final MemberRef caller = callerMethod.memberRef();
427:                Set callees = (Set) this .calls.get(caller);
428:                if (callees == null) {
429:                    callees = new HashSet();
430:                    this .calls.put(caller, callees);
431:                }
432:                callees.add(callee);
433:            }
434:
435:            /**
436:             * Marks a <tt>Type</tt> as being lives. It also unblocks any methods that
437:             * were blocked on the type.
438:             */
439:            void makeLive(final Type type) {
440:                if (this .liveClasses.contains(type)) {
441:                    return;
442:                }
443:
444:                // Make type live and unblock all methods blocked on it
445:                CallGraph.db("    Making " + type + " live");
446:                liveClasses.add(type);
447:                final Set blockedMethods = (Set) blocked.remove(type);
448:                if (blockedMethods != null) {
449:                    final Iterator iter = blockedMethods.iterator();
450:                    while (iter.hasNext()) {
451:                        final MemberRef method = (MemberRef) iter.next();
452:                        CallGraph.db("      Unblocking " + method);
453:                        worklist.add(method);
454:                    }
455:                }
456:            }
457:
458:            /**
459:             * Returns the methods (<tt>MemberRef</tt>s) to which a given method
460:             * could resolve. Only live methods are taken into account. The methods are
461:             * sorted such that overriding methods appear before overriden methods.
462:             */
463:            public Set resolvesTo(final MemberRef method) {
464:                TreeSet resolvesTo = (TreeSet) this .resolvesTo.get(method);
465:
466:                if (resolvesTo == null) {
467:                    resolvesTo = new TreeSet(new MemberRefComparator(context));
468:                    this .resolvesTo.put(method, resolvesTo);
469:
470:                    final Set liveMethods = this .liveMethods();
471:                    final Iterator rtws = hier.resolvesToWith(method)
472:                            .iterator();
473:                    while (rtws.hasNext()) {
474:                        final ClassHierarchy.ResolvesToWith rtw = (ClassHierarchy.ResolvesToWith) rtws
475:                                .next();
476:                        if (liveMethods.contains(rtw.method)) {
477:                            resolvesTo.add(rtw.method);
478:                        }
479:                    }
480:                }
481:
482:                // Return a clone so that the set may safely be modified
483:                return ((Set) resolvesTo.clone());
484:            }
485:
486:            /**
487:             * Returns the methods (<tt>MemberRef</tt>s) to which a given method
488:             * could resolve given that the receiver is in a certain set of types. Only
489:             * live methods are taken into account. The methods are sorted such that
490:             * overriding methods appear before overriden methods.
491:             */
492:            public Set resolvesTo(final MemberRef method, final Set rTypes) {
493:                if (rTypes.isEmpty()) {
494:                    return (resolvesTo(method));
495:                }
496:
497:                // Since we're only dealing with a subset of types, don't bother
498:                // with the caching stuff.
499:                final TreeSet resolvesTo = new TreeSet(new MemberRefComparator(
500:                        context));
501:
502:                final Set liveMethods = this .liveMethods();
503:                final Iterator rtws = hier.resolvesToWith(method).iterator();
504:                while (rtws.hasNext()) {
505:                    final ClassHierarchy.ResolvesToWith rtw = (ClassHierarchy.ResolvesToWith) rtws
506:                            .next();
507:                    if (liveMethods.contains(rtw.method)) {
508:                        final HashSet clone = (HashSet) rtw.rTypes.clone();
509:
510:                        clone.retainAll(rTypes);
511:                        if (!clone.isEmpty()) {
512:                            // Only keep method that have at least one possible
513:                            // receiver type in rTypes
514:                            resolvesTo.add(rtw.method);
515:                        }
516:                    }
517:                }
518:
519:                // Return a clone so that the set may safely be modified
520:                return ((Set) resolvesTo.clone());
521:            }
522:
523:            /**
524:             * Returns the set of methods (<tt>MemberRef</tt>s) that the
525:             * construction algorithm has deemed to be live.
526:             */
527:            public Set liveMethods() {
528:                // Not all of the methods in the calls mapping are necessarily
529:                // live. So, we have to maintain a separate set.
530:                return (this .liveMethods);
531:            }
532:
533:            /**
534:             * Returns the root methods (<tt>MemberRef</tt>s) of the call graph.
535:             */
536:            public Set roots() {
537:                return (this .roots);
538:            }
539:
540:            /**
541:             * Returns the set of classes (<tt>Type</tt>s) that are instantiated in
542:             * the program.
543:             */
544:            public Set liveClasses() {
545:                return (this .liveClasses);
546:            }
547:
548:            /**
549:             * Prints a textual prepresentation of the <tt>CallGraph</tt> to a
550:             * <tt>PrintWriter</tt>.
551:             * 
552:             * @param out
553:             *            To where we print
554:             * @param printLeaves
555:             *            If <tt>true</tt>, leaf methods (methods that do not call
556:             *            any other methods) are printed
557:             */
558:            public void print(final PrintWriter out, boolean printLeaves) {
559:
560:                final Iterator callers = calls.keySet().iterator();
561:                while (callers.hasNext()) {
562:                    final MemberRef caller = (MemberRef) callers.next();
563:
564:                    final Iterator callees = ((Set) calls.get(caller))
565:                            .iterator();
566:
567:                    if (!printLeaves && !callees.hasNext()) {
568:                        continue;
569:                    }
570:
571:                    out.print(caller.declaringClass() + "." + caller.name()
572:                            + caller.type());
573:                    if (roots.contains(caller)) {
574:                        out.print(" (root)");
575:                    }
576:                    out.println("");
577:
578:                    while (callees.hasNext()) {
579:                        final MemberRef callee = (MemberRef) callees.next();
580:
581:                        // Only print live methods
582:                        if (!calls.containsKey(callee)) {
583:                            continue;
584:                        }
585:
586:                        out.println("  " + callee.declaringClass() + "."
587:                                + callee.name() + callee.type());
588:                    }
589:
590:                    out.println("");
591:                }
592:            }
593:
594:            /**
595:             * Prints a summary of the call graph. Including the classes that are live
596:             * and which methods are blocked.
597:             */
598:            public void printSummary(final PrintWriter out) {
599:                out.println("Instantiated classes:");
600:                final Iterator instantiated = this .liveClasses.iterator();
601:                while (instantiated.hasNext()) {
602:                    final Type type = (Type) instantiated.next();
603:                    out.println("  " + type.toString());
604:                }
605:
606:                out.println("\nBlocked methods:");
607:                if (blocked != null) {
608:                    final Iterator types = blocked.keySet().iterator();
609:                    while (types.hasNext()) {
610:                        final Type type = (Type) types.next();
611:                        out.println("  " + type);
612:
613:                        final Set set = (Set) blocked.get(type);
614:                        if (set != null) {
615:                            final Iterator methods = set.iterator();
616:                            while (methods.hasNext()) {
617:                                final MemberRef method = (MemberRef) methods
618:                                        .next();
619:                                out.println("    " + method);
620:                            }
621:                        }
622:                    }
623:                }
624:
625:                out.println("\nCall graph:");
626:                this .print(out, false);
627:            }
628:
629:        }
630:
631:        /**
632:         * <tt>CallVisitor</tt> examines the instructions in a method and notices what
633:         * methods are called and which classes are created.
634:         */
635:        class CallVisitor extends InstructionAdapter {
636:            MethodEditor caller;
637:
638:            CallGraph cg;
639:
640:            boolean firstSpecial; // Are we dealing with the first invokespecial?
641:
642:            private static void db(final String s) {
643:                CallGraph.db(s);
644:            }
645:
646:            public CallVisitor(final CallGraph cg) {
647:                this .cg = cg;
648:            }
649:
650:            public void setCaller(final MethodEditor caller) {
651:                this .caller = caller;
652:                if (caller.isConstructor()) {
653:                    this .firstSpecial = true;
654:                } else {
655:                    this .firstSpecial = false;
656:                }
657:            }
658:
659:            public void visit_invokevirtual(final Instruction inst) {
660:                CallVisitor.db("\n    Visiting Call: " + inst);
661:
662:                this .firstSpecial = false;
663:
664:                // Call doVirtual to determine which methods this call may resolve
665:                // to are live.
666:                final MemberRef callee = (MemberRef) inst.operand();
667:                cg.doVirtual(caller, callee);
668:            }
669:
670:            public void visit_invokeinterface(final Instruction inst) {
671:                CallVisitor.db("\n    Visiting Call: " + inst);
672:
673:                this .firstSpecial = false;
674:
675:                // Pretty much the same as invokevirtual
676:                final MemberRef callee = (MemberRef) inst.operand();
677:                cg.doVirtual(caller, callee);
678:            }
679:
680:            public void visit_invokestatic(final Instruction inst) {
681:                CallVisitor.db("\n    Visiting call: " + inst);
682:
683:                this .firstSpecial = false;
684:
685:                // There's not a lot to do with static methods since there is no
686:                // dynamic dispatch.
687:                final MemberRef callee = (MemberRef) inst.operand();
688:                cg.addCall(caller, callee);
689:                cg.worklist.add(callee);
690:            }
691:
692:            public void visit_invokespecial(final Instruction inst) {
693:                CallVisitor.db("\n    Visiting call: " + inst);
694:
695:                // Recall that invokespecial is used to call constructors, private
696:                // methods, and "super" methods. There is no dynamic dispatch for
697:                // special methods.
698:                final MemberRef callee = (MemberRef) inst.operand();
699:
700:                MethodEditor calleeMethod = null;
701:
702:                try {
703:                    calleeMethod = cg.context.editMethod(callee);
704:
705:                } catch (final NoSuchMethodException ex1) {
706:                    System.err.println("** Couldn't find method: " + callee);
707:                    System.exit(1);
708:                }
709:
710:                if (calleeMethod.isSynchronized() || calleeMethod.isNative()) {
711:                    // Calls to synchronized and native methods are virtual
712:                    cg.doVirtual(caller, callee);
713:
714:                } else {
715:                    // Calls to everything else (superclass methods, private
716:                    // methods, etc.) do not involve a dynamic dispatch and can be
717:                    // treated like a static method.
718:                    cg.addCall(caller, callee);
719:                    cg.worklist.add(callee);
720:                }
721:
722:                cg.context.release(calleeMethod.methodInfo());
723:            }
724:
725:            public void visit_getstatic(final Instruction inst) {
726:                // Referencing a static fields implies that its class's static
727:                // initializer has been invoked.
728:                CallVisitor.db("\n    Referencing static field " + inst);
729:                final MemberRef field = (MemberRef) inst.operand();
730:                cg.addClinit(field.declaringClass());
731:            }
732:
733:            public void visit_putstatic(final Instruction inst) {
734:                // Referencing a static field implies that its class's static
735:                // initializer has been invoked.
736:                CallVisitor.db("\n    Referencing static field " + inst);
737:                final MemberRef field = (MemberRef) inst.operand();
738:                cg.addClinit(field.declaringClass());
739:            }
740:
741:            public void visit_new(final Instruction inst) {
742:                // The new instruction instantiates a type and thus makes it live.
743:                final Type type = (Type) inst.operand();
744:                cg.makeLive(type);
745:            }
746:        }
747:
748:        /**
749:         * Compares <tt>MemberRef</tt>s such that overriding methods are less than
750:         * overridden methods.
751:         */
752:        class MemberRefComparator implements  Comparator {
753:            TypeComparator c;
754:
755:            public MemberRefComparator(final InlineContext context) {
756:                c = new TypeComparator(context);
757:            }
758:
759:            public int compare(final Object o1, final Object o2) {
760:                Assert.isTrue(o1 instanceof  MemberRef, o1
761:                        + " is not a MemberRef");
762:                Assert.isTrue(o2 instanceof  MemberRef, o2
763:                        + " is not a MemberRef");
764:
765:                final MemberRef ref1 = (MemberRef) o1;
766:                final MemberRef ref2 = (MemberRef) o2;
767:
768:                final Type type1 = ref1.declaringClass();
769:                final Type type2 = ref2.declaringClass();
770:
771:                return (c.compare(type1, type2));
772:            }
773:
774:            public boolean compareTo(final Object other) {
775:                return (other instanceof  MemberRefComparator);
776:            }
777:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.