Source Code Cross Referenced for Inline.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.util.*;
024:
025:        import EDU.purdue.cs.bloat.editor.*;
026:        import EDU.purdue.cs.bloat.util.*;
027:
028:        /**
029:         * Inlines the code of non-virtual method call sites. These sites include calls
030:         * to static methods and certain uses of the <tt>invokespecial</tt> method.
031:         * There are certain metrics that can be set to effect where and how inlining is
032:         * performed.
033:         */
034:        public class Inline {
035:            public static boolean DEBUG = false;
036:
037:            private int maxCodeSize; // Max number of instructions in method
038:
039:            private int maxCallDepth; // Max of height of call stack
040:
041:            private boolean inlineExceptions; // Inline methods that throw exceptions
042:
043:            private InlineContext context;
044:
045:            private Map editors; // Maps MemberRefs to their MethodEditors
046:
047:            /**
048:             * Size of the largest method that can be inlined
049:             */
050:            public static int CALLEE_SIZE = 100000;
051:
052:            private static void db(final String s) {
053:                if (Inline.DEBUG) {
054:                    System.out.println(s);
055:                }
056:            }
057:
058:            /**
059:             * Constructor. By default the first-level calls are only inlined one level
060:             * deep, there is no max size on methods to inline, and methods that may
061:             * throw exceptions are inlined.
062:             * 
063:             * @param maxCodeSize
064:             *            The maximum number of instructions a method can grow to.
065:             */
066:            public Inline(final InlineContext context, final int maxCodeSize) {
067:                this .context = context;
068:                this .maxCodeSize = maxCodeSize;
069:                this .maxCallDepth = 1;
070:                this .inlineExceptions = true;
071:
072:                editors = new HashMap();
073:            }
074:
075:            /**
076:             * Sets the maximum of size of a method that will be inlined. No method
077:             * larger than this will be inlined.
078:             */
079:            public void setMaxInlineSize(final int maxInlineSize) {
080:            }
081:
082:            /**
083:             * Sets the maximum number of nested calls we inline.
084:             */
085:            public void setMaxCallDepth(final int maxCallDepth) {
086:                this .maxCallDepth = maxCallDepth;
087:            }
088:
089:            /**
090:             * Sets whether or not methods that may throw exceptions (that is, have a
091:             * non-empty "throws" declaration) are inlined.
092:             */
093:            public void setInlineExceptions(final boolean inlineExceptions) {
094:                this .inlineExceptions = inlineExceptions;
095:            }
096:
097:            /**
098:             * Scans a method and inlines non-virtual method calls according to this
099:             * <tt>Inline</tt>'s metrics.
100:             */
101:            public void inline(final MethodEditor method) {
102:                // Go through the method and look for calls to inline
103:                StackHeightCounter stackHeight = new StackHeightCounter(method);
104:                List code = method.code();
105:                boolean firstCall = true;
106:                for (int i = 0; i < code.size(); i++) {
107:                    final Object o = code.get(i);
108:                    if (o instanceof  Instruction) {
109:                        final Instruction inst = (Instruction) o;
110:                        if ((inst.opcodeClass() == Opcode.opcx_invokestatic)
111:                                || (inst.opcodeClass() == Opcode.opcx_invokespecial)) {
112:                            final MemberRef callee = (MemberRef) inst.operand();
113:                            final Stack callStack = new Stack();
114:                            callStack.add(method.memberRef());
115:
116:                            Inline.db("  Call: " + inst);
117:
118:                            stackHeight.handle(inst);
119:                            final int expectedHeight = stackHeight.height();
120:                            stackHeight.unhandle(inst);
121:
122:                            final int j = i;
123:                            i = inline(method, callee, i, callStack,
124:                                    stackHeight, firstCall);
125:
126:                            if (j == i) {
127:                                // Call was not inlined, add it to the stack
128:                                stackHeight.handle(inst);
129:                                Inline.db("  " + i + "." + stackHeight.height()
130:                                        + ") " + inst);
131:                            }
132:
133:                            final int newHeight = stackHeight.height();
134:                            // If an exception is thrown as the last thing in a method
135:                            // newHeight will equal 0. Let's let this one slide.
136:                            Assert.isTrue((newHeight == 0)
137:                                    || (newHeight == expectedHeight),
138:                                    "Inlining did not get the stack heights right: "
139:                                            + "Expected " + expectedHeight
140:                                            + ", got " + newHeight);
141:
142:                        } else {
143:                            stackHeight.handle(inst);
144:                            Inline.db("  " + i + "." + stackHeight.height()
145:                                    + ") " + inst);
146:                        }
147:
148:                        if (inst.isInvoke()) {
149:                            firstCall = false;
150:                        }
151:
152:                    } else if (o instanceof  Label) {
153:                        final Label label = (Label) o;
154:                        stackHeight.handle(label);
155:                        Inline
156:                                .db("  "
157:                                        + i
158:                                        + "."
159:                                        + stackHeight.height()
160:                                        + ") "
161:                                        + label
162:                                        + (label.startsBlock() ? " (starts block)"
163:                                                : ""));
164:                    }
165:
166:                }
167:
168:                method.setCode(code);
169:
170:                if (Inline.DEBUG) {
171:                    stackHeight = new StackHeightCounter(method);
172:                    Inline.db("\nNew Code for "
173:                            + method.declaringClass().name() + "."
174:                            + method.name() + method.type());
175:                    code = method.code();
176:                    for (int j = 0; j < code.size(); j++) {
177:                        if (code.get(j) instanceof  Label) {
178:                            final Label label = (Label) code.get(j);
179:
180:                            stackHeight.handle(label);
181:
182:                            final Iterator tryCatches = method.tryCatches()
183:                                    .iterator();
184:                            while (tryCatches.hasNext()) {
185:                                final TryCatch tryCatch = (TryCatch) tryCatches
186:                                        .next();
187:                                if (tryCatch.start().equals(label)) {
188:                                    System.out
189:                                            .println(" Begin protected region");
190:
191:                                }
192:
193:                                if (tryCatch.end().equals(label)) {
194:                                    System.out.println(" End protected region");
195:
196:                                }
197:
198:                                // A Label can both end a protected region and begin
199:                                // catch
200:                                // block
201:
202:                                if (tryCatch.handler().equals(label)) {
203:                                    System.out.println(" Catch "
204:                                            + tryCatch.type());
205:                                }
206:
207:                            }
208:
209:                            System.out.println("  "
210:                                    + j
211:                                    + "."
212:                                    + stackHeight.height()
213:                                    + ") "
214:                                    + label
215:                                    + (label.startsBlock() ? " (starts block)"
216:                                            : ""));
217:                        } else {
218:                            final Instruction inst = (Instruction) code.get(j);
219:                            stackHeight.handle(inst);
220:                            System.out
221:                                    .println("  " + j + "."
222:                                            + stackHeight.height() + ") "
223:                                            + code.get(j));
224:                        }
225:                    }
226:
227:                    // Print try-catch information
228:                    final Iterator tryCatches = method.tryCatches().iterator();
229:                    System.out.println("Exception information:");
230:                    while (tryCatches.hasNext()) {
231:                        final TryCatch tryCatch = (TryCatch) tryCatches.next();
232:                        System.out.println("  " + tryCatch);
233:                    }
234:                    System.out.println("");
235:                }
236:
237:            }
238:
239:            /**
240:             * Helper method that does most of the work. By calling this method
241:             * recursively, we can inline more than one call deep.
242:             * 
243:             * @param caller
244:             *            The original caller that got all of this started. Into this
245:             *            method we insert the code.
246:             * @param callee
247:             *            The method to be inlined
248:             * @param index
249:             *            Where in caller we insert inlined code
250:             * @param callStack
251:             *            A stack of <tt>MemberRef</tt>s that represent the inlined
252:             *            methods that call other methods. It is used to detect
253:             *            recursion.
254:             * 
255:             * @return The index into the caller's code array of the instruction
256:             *         following the last inlinined instruction. Start looking here
257:             *         after inline returns.
258:             */
259:            private int inline(final MethodEditor caller,
260:                    final MemberRef callee, int index, final Stack callStack,
261:                    final StackHeightCounter stackHeight, boolean firstCall) {
262:
263:                Instruction newInst = null;
264:
265:                // Do we ignore the method being inlined?
266:                if (context.ignoreMethod(callee)) {
267:                    Inline.db("  Can't inline " + callee + ": it's ignored");
268:                    return (index++);
269:                }
270:
271:                // Can we inline this method
272:                if (callStack.size() > maxCallDepth) {
273:                    Inline.db("  Can't inline " + callee + ": max call depth ("
274:                            + maxCallDepth + ") reached");
275:                    return (index++);
276:
277:                } else if (callStack.contains(callee)) {
278:                    Inline.db("  Can't inline recursive call to " + callee);
279:                    return (index++);
280:                }
281:
282:                // Make sure we're not inlining the static-ized version of a
283:                // method in the call stack.
284:                String name = callee.name();
285:                final int b = name.indexOf("$$BLOAT");
286:                if (b != -1) {
287:                    name = name.substring(0, b);
288:
289:                    // Get rid of first parameter
290:                    final Type[] oldParams = callee.type().paramTypes();
291:                    final StringBuffer sb = new StringBuffer("(");
292:                    for (int p = 1; p < oldParams.length; p++) {
293:                        sb.append(oldParams[p].descriptor());
294:                    }
295:                    sb.append(")" + callee.type().returnType());
296:                    final Type newType = Type.getType(sb.toString());
297:
298:                    final MemberRef unBloated = new MemberRef(callee
299:                            .declaringClass(), new NameAndType(name, newType));
300:
301:                    if (callStack.contains(unBloated)) {
302:                        Inline.db("  Can't inline recursive call to " + callee);
303:                        return (index++);
304:                    }
305:                }
306:
307:                final List code = caller.code();
308:                if (code.size() > maxCodeSize) {
309:                    Inline.db("  Can't inline " + callee + ": max code size ("
310:                            + maxCodeSize + ") reached");
311:                    return (index++);
312:                }
313:
314:                MethodEditor calleeMethod = null;
315:                try {
316:                    calleeMethod = context.editMethod(callee);
317:
318:                } catch (final NoSuchMethodException ex) {
319:                    System.err.println("Couldn't find method " + callee);
320:                    ex.printStackTrace(System.err);
321:                    System.exit(1);
322:                }
323:
324:                if (calleeMethod.isNative()) {
325:                    Inline.db("  Can't inline " + callee
326:                            + ": it's a native method");
327:                    return (index++);
328:                }
329:
330:                if (calleeMethod.isSynchronized()) {
331:                    Inline.db("  Can't inline " + callee
332:                            + ": it's synchronized");
333:                    return (index++);
334:                }
335:
336:                if (!inlineExceptions
337:                        && (calleeMethod.methodInfo().exceptionTypes().length > 0)) {
338:                    Inline.db("  Can't inline " + callee
339:                            + ": it may throw an exception");
340:                    return (index++);
341:                }
342:
343:                if (calleeMethod.code().size() > Inline.CALLEE_SIZE) {
344:                    Inline.db("  Can't inline " + callee + ": it's too big");
345:                    return (index++);
346:                }
347:
348:                // Methods that catch exceptions are problematic. When an
349:                // exception is thrown, it clears the stack. Ordinarily this
350:                // isn't a problem. However, now the stack of the caller is
351:                // cleared in addition to the stack of the callee. This is bad.
352:                // The callee might catch the exception and deal with it.
353:                // However, the stack has still been cleared. This really messes
354:                // things up for the code that appears after the inlined method.
355:                // So, if a method catches an exception, we can only inline it if
356:                // the stack contains nothing but the parameters to the call.
357:                if (calleeMethod.tryCatches().size() > 0) {
358:                    if (stackHeight.height() > callee.type().stackHeight()) {
359:                        Inline
360:                                .db("  Can't inline "
361:                                        + callee
362:                                        + ": It catches an exception and there's stuff on the "
363:                                        + "stack");
364:                        return (index++);
365:                    }
366:                }
367:
368:                // If the callee method catches any of the same exceptions as the
369:                // protected region that we are currently in, then we can't inline
370:                // the method.
371:                final Iterator tryCatches0 = calleeMethod.tryCatches()
372:                        .iterator();
373:                while (tryCatches0.hasNext()) {
374:                    final TryCatch tc1 = (TryCatch) tryCatches0.next();
375:                    final Iterator iter = stackHeight.tryCatches().iterator();
376:                    while (iter.hasNext()) {
377:                        final TryCatch tc2 = (TryCatch) iter.next();
378:                        final Type t1 = tc1.type();
379:                        final Type t2 = tc2.type();
380:                        if ((t1 != null) && (t2 != null) && t1.equals(t2)) {
381:                            Inline.db("  Can't inline " + callee
382:                                    + ": It catches the same type "
383:                                    + tc1.type().className()
384:                                    + " as the current protected region");
385:                            return (index++);
386:                        }
387:                    }
388:                }
389:
390:                // If the caller is a constructor and this is the first
391:                // invokespecial we've seen in this callee method, we can inline
392:                // calls to the constructors of superclasses and other
393:                // constructors in this method. So, if this IS the first call in
394:                // a method which IS a constructor, we can inline it.
395:                if (calleeMethod.isConstructor()
396:                        && (!firstCall || !caller.isConstructor())) {
397:
398:                    Inline.db("  Can't inline " + callee
399:                            + ": It calls a normal constructor");
400:                    return (index++);
401:                }
402:
403:                // Local variables are problematic. We cannot simply map the
404:                // callee's variables to new variables in the caller because we
405:                // cannot precisely determine the width of the variable the first
406:                // time we see it. (For instance, Nate's generated code might use
407:                // a local variable as a non-wide initially and then use it as a
408:                // wide later.)
409:
410:                // Okay, we going to inline. Remove the calling instruction.
411:                final Instruction call = (Instruction) code.remove(index--);
412:                Inline.db("  Removing call: " + call);
413:                Assert.isTrue((call.opcodeClass() == Opcode.opcx_invokestatic)
414:                        || (call.opcodeClass() == Opcode.opcx_invokespecial),
415:                        "Removing the wrong call instruction:" + call);
416:                callStack.push(callee);
417:
418:                Inline.db("  Inlining call (" + callStack.size() + ") to "
419:                        + callee.declaringClass() + "." + callee.name()
420:                        + callee.type());
421:                context.getInlineStats().noteInlined();
422:
423:                // First we have to pop the arguments off the stack and store them
424:                // into the local variables. Remember that wide types occupy two
425:                // local variables.
426:                final Mapper mapper = new Mapper(caller);
427:                Type[] paramTypes = callee.type().indexedParamTypes();
428:                if (!calleeMethod.isStatic()) {
429:                    // Constructors (and any other special methods we're inlining)
430:                    // have a "this" pointer where static methods do not.
431:                    final Type[] newParams = new Type[paramTypes.length + 1];
432:                    newParams[0] = callee.declaringClass();
433:
434:                    for (int i = 0; i < paramTypes.length; i++) {
435:                        newParams[i + 1] = paramTypes[i];
436:                    }
437:                    paramTypes = newParams;
438:                }
439:
440:                final LocalVariable[] params = new LocalVariable[paramTypes.length];
441:
442:                Inline.db("  Indexed params:");
443:                for (int i = 0; i < params.length; i++) {
444:                    params[i] = calleeMethod.paramAt(i);
445:                    Inline.db("    "
446:                            + i
447:                            + ": "
448:                            + params[i]
449:                            + (params[i] != null ? " " + params[i].type() + " "
450:                                    : ""));
451:                }
452:
453:                for (int i = params.length - 1; i >= 0; i--) {
454:                    // Map the local variables containing the arguments to new
455:                    // local variables.
456:                    final LocalVariable param = params[i];
457:                    final Type paramType = params[i].type();
458:
459:                    if (param.type() == null) {
460:                        continue;
461:                    }
462:
463:                    Inline.db("  Param " + i + ": " + param + " of type "
464:                            + paramType);
465:
466:                    final LocalVariable newVar = mapper.map(param, paramType);
467:
468:                    int opcode;
469:
470:                    if (paramType.isReference()) {
471:                        opcode = Opcode.opcx_astore;
472:
473:                    } else {
474:                        switch (paramType.typeCode()) {
475:                        case Type.BOOLEAN_CODE:
476:                        case Type.BYTE_CODE:
477:                        case Type.CHARACTER_CODE:
478:                        case Type.SHORT_CODE:
479:                            opcode = Opcode.opcx_istore;
480:                            break;
481:
482:                        case Type.DOUBLE_CODE:
483:                            opcode = Opcode.opcx_dstore;
484:                            break;
485:
486:                        case Type.LONG_CODE:
487:                            opcode = Opcode.opcx_lstore;
488:                            break;
489:
490:                        case Type.FLOAT_CODE:
491:                            opcode = Opcode.opcx_fstore;
492:                            break;
493:
494:                        case Type.INTEGER_CODE:
495:                            opcode = Opcode.opcx_istore;
496:                            break;
497:
498:                        default:
499:                            throw new IllegalArgumentException("What's a "
500:                                    + paramType + "doing as a method "
501:                                    + "parameter");
502:                        }
503:                    }
504:
505:                    newInst = new Instruction(opcode, newVar);
506:                    code.add(++index, newInst);
507:                    stackHeight.handle(newInst);
508:                    Inline.db("  " + index + "." + stackHeight.height() + "> "
509:                            + newInst);
510:                }
511:
512:                // Before we mess with the code, we have to patch up the try-catch
513:                // information from the inlined method to the caller method.
514:                final Iterator tryCatches = calleeMethod.tryCatches()
515:                        .iterator();
516:                while (tryCatches.hasNext()) {
517:                    final TryCatch tryCatch = (TryCatch) tryCatches.next();
518:
519:                    final Label start = mapper.map(tryCatch.start());
520:                    final Label end = mapper.map(tryCatch.end());
521:                    final Label handler = mapper.map(tryCatch.handler());
522:
523:                    final TryCatch newTryCatch = new TryCatch(start, end,
524:                            handler, tryCatch.type());
525:                    caller.addTryCatch(newTryCatch);
526:
527:                    // db("Try-catch");
528:                    // db(" Before: " + tryCatch.start() + "\t" + tryCatch.end() +
529:                    // "\t" + tryCatch.handler());
530:                    // db(" After: " + newTryCatch.start() + "\t" + newTryCatch.end()
531:                    // + "\t" + newTryCatch.handler());
532:                }
533:
534:                // Go through the code in the callee method and inline it. Handle
535:                // any calls by making a recursive call to this method. Copy each
536:                // instruction to the method in which it is being inlined. Along
537:                // the way convert references to local variables to their mapped
538:                // values. Also remove return instructions. Replace them with
539:                // loads as necessary.
540:
541:                final List inlineCode = calleeMethod.code();
542:
543:                // We don't want to introduce a new end label because it confuses
544:                // BLOAT during CFG construction. We designate the end label as
545:                // starting a new block in hopes that it will solve problems with
546:                // CFG construction.
547:                final Object last = inlineCode.get(inlineCode.size() - 1);
548:                boolean addEndLabel;
549:                Label endLabel;
550:                if (last instanceof  Label) {
551:                    endLabel = mapper.map((Label) last);
552:                    addEndLabel = false;
553:
554:                } else {
555:                    endLabel = caller.newLabel();
556:                    addEndLabel = true;
557:                }
558:                endLabel.setStartsBlock(true);
559:
560:                firstCall = true;
561:
562:                for (int j = 0; j < inlineCode.size(); j++) {
563:                    final Object o = inlineCode.get(j);
564:
565:                    if (o instanceof  Label) {
566:                        final Label label = (Label) o;
567:                        final Label newLabel = mapper.map(label);
568:
569:                        code.add(++index, newLabel);
570:                        stackHeight.handle(newLabel);
571:                        Inline.db("  "
572:                                + index
573:                                + "."
574:                                + stackHeight.height()
575:                                + "> "
576:                                + newLabel
577:                                + (newLabel.startsBlock() ? " (starts block)"
578:                                        : ""));
579:                        continue;
580:                    }
581:
582:                    Assert.isTrue(o instanceof  Instruction, "What is a " + o
583:                            + " doing in the instruction stream?");
584:
585:                    final Instruction inst = (Instruction) inlineCode.get(j);
586:                    Object operand = inst.operand();
587:                    final int opcode = inst.opcodeClass();
588:
589:                    if (operand instanceof  LocalVariable) {
590:                        // Map local variable in the callee method to local
591:                        // variables in the caller method.
592:                        final LocalVariable local = mapper.map(
593:                                (LocalVariable) operand,
594:                                (inst.category() == 2 ? true : false));
595:                        operand = local;
596:
597:                    } else if (operand instanceof  Label) {
598:                        // Map labels in the callee method to labels in the caller
599:                        // method.
600:                        final Label label = mapper.map((Label) operand);
601:                        operand = label;
602:
603:                    } else if (operand instanceof  IncOperand) {
604:                        // Map the local being incremented
605:                        final IncOperand inc = (IncOperand) operand;
606:                        final LocalVariable newLocal = mapper.map(inc.var(),
607:                                Type.INTEGER);
608:                        operand = new IncOperand(newLocal, inc.incr());
609:
610:                    } else if (operand instanceof  Switch) {
611:                        // We have to patch up the Labels involved with the Switch
612:                        final Switch oldSwitch = (Switch) operand;
613:
614:                        final Label newDefault = mapper.map(oldSwitch
615:                                .defaultTarget());
616:
617:                        final Label[] oldTargets = oldSwitch.targets();
618:                        final Label[] newTargets = new Label[oldTargets.length];
619:                        for (int i = 0; i < newTargets.length; i++) {
620:                            final Label newTarget = mapper.map(oldTargets[i]);
621:                            newTargets[i] = newTarget;
622:                        }
623:
624:                        operand = new Switch(newDefault, newTargets, oldSwitch
625:                                .values());
626:                    }
627:
628:                    if (inst.isReturn()) {
629:                        // Insert a jump to the end of the inlined method. Any
630:                        // return value will be on top of the stack. This is where
631:                        // we want it.
632:                        newInst = new Instruction(Opcode.opcx_goto, endLabel);
633:                        code.add(++index, newInst);
634:                        stackHeight.handle(newInst);
635:                        Inline.db("  " + index + "." + stackHeight.height()
636:                                + "> " + newInst);
637:
638:                    } else if ((inst.opcodeClass() == Opcode.opcx_invokestatic)
639:                            || (inst.opcodeClass() == Opcode.opcx_invokespecial)) {
640:                        // Make a recursive call. Note that this must be done after
641:                        // we add the call instruction above. But we only want to
642:                        // visit the instruction with the stackHeight if the call was
643:                        // not inlined.
644:                        newInst = new Instruction(opcode, operand);
645:                        code.add(++index, newInst);
646:
647:                        stackHeight.handle(newInst);
648:                        final int expectedHeight = stackHeight.height();
649:                        stackHeight.unhandle(newInst);
650:
651:                        final MemberRef nestedCall = (MemberRef) inst.operand();
652:                        final int oldIndex = index;
653:                        index = inline(caller, nestedCall, index, callStack,
654:                                stackHeight, firstCall);
655:
656:                        if (index == oldIndex) {
657:                            stackHeight.handle(newInst);
658:                            Inline.db("  " + index + "." + stackHeight.height()
659:                                    + "> " + newInst);
660:                        }
661:
662:                        final int newHeight = stackHeight.height();
663:                        Assert.isTrue((newHeight == 0)
664:                                || (newHeight == expectedHeight),
665:                                "Inlining did not get the stack heights right: "
666:                                        + "Expected " + expectedHeight
667:                                        + ", got " + newHeight);
668:
669:                    } else {
670:                        // Add the instruction
671:                        newInst = new Instruction(opcode, operand);
672:                        code.add(++index, newInst);
673:                        stackHeight.handle(newInst);
674:                        Inline.db("  " + index + "." + stackHeight.height()
675:                                + "> " + newInst);
676:                    }
677:
678:                    // We want to do this after we've made any recursive calls to
679:                    // inline.
680:                    if (inst.isInvoke()) {
681:                        firstCall = false;
682:                    }
683:
684:                }
685:
686:                if (addEndLabel) {
687:                    // Done inlining. Add end label.
688:                    code.add(++index, endLabel);
689:                    stackHeight.handle(endLabel);
690:                    Inline
691:                            .db("  "
692:                                    + index
693:                                    + "."
694:                                    + stackHeight.height()
695:                                    + "> "
696:                                    + endLabel
697:                                    + (endLabel.startsBlock() ? " (starts block)"
698:                                            : ""));
699:                }
700:
701:                caller.setDirty(true);
702:                callStack.pop();
703:                return (index);
704:
705:            }
706:        }
707:
708:        /**
709:         * Utility class for mapping local variables and labels. Note that when mapping
710:         * local variables we have to be careful. We can't assume that a variable will
711:         * retain its "wideness" throughout the method. I learned this one the hard way.
712:         * So, we have to keep a constant difference between the mapped variables.
713:         */
714:        class Mapper {
715:            private Map varsMap; // Maps local variables
716:
717:            private Map labelsMap; // Maps labels
718:
719:            private MethodEditor method; // Method into which things are mapped
720:
721:            private int offset; // Start numbering new locals here
722:
723:            private static void db(final String s) {
724:                if (Inline.DEBUG) {
725:                    System.out.println(s);
726:                }
727:            }
728:
729:            /**
730:             * Constructor.
731:             */
732:            public Mapper(final MethodEditor method) {
733:                this .method = method;
734:                varsMap = new HashMap();
735:                labelsMap = new HashMap();
736:                offset = method.maxLocals() + 1;
737:            }
738:
739:            public Label map(final Label label) {
740:                Label newLabel = (Label) labelsMap.get(label);
741:                if (newLabel == null) {
742:                    newLabel = this .method.newLabel();
743:                    newLabel.setStartsBlock(label.startsBlock());
744:                    labelsMap.put(label, newLabel);
745:                    Mapper
746:                            .db("      "
747:                                    + label
748:                                    + " -> "
749:                                    + newLabel
750:                                    + (newLabel.startsBlock() ? " (starts block)"
751:                                            : ""));
752:                }
753:                return (newLabel);
754:            }
755:
756:            public LocalVariable map(final LocalVariable var, final Type type) {
757:                LocalVariable newVar = (LocalVariable) varsMap.get(var);
758:                if (newVar == null) {
759:                    newVar = this .method.localAt(var.index() + offset);
760:                    // newVar = this.method.newLocal(type);
761:                    varsMap.put(var, newVar);
762:                    Mapper.db("      " + var + " (" + var.index() + ") -> "
763:                            + newVar + "(" + var.index() + "+" + offset + ")"
764:                            + (type.isWide() ? " (" + type + ")" : ""));
765:                }
766:                return (newVar);
767:            }
768:
769:            public LocalVariable map(final LocalVariable var,
770:                    final boolean isWide) {
771:                LocalVariable newVar = (LocalVariable) varsMap.get(var);
772:                if (newVar == null) {
773:                    newVar = this .method.localAt(var.index() + offset);
774:                    // newVar = this.method.newLocal(isWide);
775:                    varsMap.put(var, newVar);
776:                    Mapper.db("      " + var + " (" + var.index() + ") -> "
777:                            + newVar + "(" + var.index() + "+" + offset + ")"
778:                            + (isWide ? " (wide)" : ""));
779:                }
780:                return (newVar);
781:            }
782:
783:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.