Source Code Cross Referenced for InstructionList.java in  » Byte-Code » Cojen » org » cojen » classfile » 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 » Byte Code » Cojen » org.cojen.classfile 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *  Copyright 2004 Brian S O'Neill
0003:         *
0004:         *  Licensed under the Apache License, Version 2.0 (the "License");
0005:         *  you may not use this file except in compliance with the License.
0006:         *  You may obtain a copy of the License at
0007:         *
0008:         *      http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         *  Unless required by applicable law or agreed to in writing, software
0011:         *  distributed under the License is distributed on an "AS IS" BASIS,
0012:         *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         *  See the License for the specific language governing permissions and
0014:         *  limitations under the License.
0015:         */
0016:
0017:        package org.cojen.classfile;
0018:
0019:        import java.util.AbstractCollection;
0020:        import java.util.ArrayList;
0021:        import java.util.Collection;
0022:        import java.util.HashMap;
0023:        import java.util.HashSet;
0024:        import java.util.Iterator;
0025:        import java.util.List;
0026:        import java.util.Map;
0027:        import java.util.NoSuchElementException;
0028:        import java.util.Set;
0029:
0030:        /**
0031:         * The InstructionList class is used by the CodeBuilder to perform lower-level
0032:         * bookkeeping operations and flow analysis.
0033:         * 
0034:         * @author Brian S O'Neill
0035:         * @see CodeBuilder
0036:         */
0037:        class InstructionList implements  CodeBuffer {
0038:            private static final boolean DEBUG = false;
0039:
0040:            Instruction mFirst;
0041:            Instruction mLast;
0042:
0043:            boolean mResolved = false;
0044:
0045:            private List mExceptionHandlers = new ArrayList(4);
0046:            private List mLocalVariables = new ArrayList();
0047:            private int mNextFixedVariableNumber;
0048:
0049:            private int mMaxStack;
0050:            private int mMaxLocals;
0051:
0052:            private byte[] mByteCodes;
0053:            private int mBufferLength;
0054:
0055:            protected InstructionList() {
0056:                super ();
0057:            }
0058:
0059:            /**
0060:             * Returns an immutable collection of all the instructions in this
0061:             * InstructionList.
0062:             */
0063:            public Collection getInstructions() {
0064:                return new AbstractCollection() {
0065:                    public Iterator iterator() {
0066:                        return new Iterator() {
0067:                            private Instruction mNext = mFirst;
0068:
0069:                            public boolean hasNext() {
0070:                                return mNext != null;
0071:                            }
0072:
0073:                            public Object next() {
0074:                                if (mNext == null) {
0075:                                    throw new NoSuchElementException();
0076:                                }
0077:
0078:                                Instruction current = mNext;
0079:                                mNext = mNext.mNext;
0080:                                return current;
0081:                            }
0082:
0083:                            public void remove() {
0084:                                throw new UnsupportedOperationException();
0085:                            }
0086:                        };
0087:                    }
0088:
0089:                    public int size() {
0090:                        int count = 0;
0091:                        for (Instruction i = mFirst; i != null; i = i.mNext) {
0092:                            count++;
0093:                        }
0094:                        return count;
0095:                    }
0096:                };
0097:            }
0098:
0099:            public int getMaxStackDepth() {
0100:                resolve();
0101:                return mMaxStack;
0102:            }
0103:
0104:            public int getMaxLocals() {
0105:                resolve();
0106:                return mMaxLocals;
0107:            }
0108:
0109:            public byte[] getByteCodes() {
0110:                resolve();
0111:                return mByteCodes;
0112:            }
0113:
0114:            public ExceptionHandler[] getExceptionHandlers() {
0115:                resolve();
0116:
0117:                ExceptionHandler[] handlers = new ExceptionHandler[mExceptionHandlers
0118:                        .size()];
0119:                return (ExceptionHandler[]) mExceptionHandlers
0120:                        .toArray(handlers);
0121:            }
0122:
0123:            public void addExceptionHandler(ExceptionHandler handler) {
0124:                mExceptionHandlers.add(handler);
0125:            }
0126:
0127:            public LocalVariable createLocalVariable(String name, TypeDesc type) {
0128:                LocalVariable var = new LocalVariableImpl(mLocalVariables
0129:                        .size(), name, type, -1);
0130:                mLocalVariables.add(var);
0131:                return var;
0132:            }
0133:
0134:            /**
0135:             * All parameters must be defined before adding instructions.
0136:             */
0137:            public LocalVariable createLocalParameter(String name, TypeDesc type) {
0138:                LocalVariable var = new LocalVariableImpl(mLocalVariables
0139:                        .size(), name, type, mNextFixedVariableNumber);
0140:                mLocalVariables.add(var);
0141:                mNextFixedVariableNumber += type.isDoubleWord() ? 2 : 1;
0142:                return var;
0143:            }
0144:
0145:            private void resolve() {
0146:                if (mResolved) {
0147:                    return;
0148:                }
0149:
0150:                if (!DEBUG) {
0151:                    resolve0();
0152:                } else {
0153:                    try {
0154:                        resolve0();
0155:                    } finally {
0156:                        System.out.println("-- Instructions --");
0157:
0158:                        Iterator it = getInstructions().iterator();
0159:                        while (it.hasNext()) {
0160:                            System.out.println(it.next());
0161:                        }
0162:                    }
0163:                }
0164:            }
0165:
0166:            private void resolve0() {
0167:                mMaxStack = 0;
0168:                mMaxLocals = 0;
0169:
0170:                Instruction instr;
0171:
0172:                // Sweep through the instructions, preparing for flow analysis.
0173:                int instrCount = 0;
0174:                for (instr = mFirst; instr != null; instr = instr.mNext) {
0175:                    // Set address to instruction index.
0176:                    instr.reset(instrCount++);
0177:                }
0178:
0179:                // Make sure exception handlers are registered with all guarded
0180:                // instructions.
0181:                Iterator it = mExceptionHandlers.iterator();
0182:                while (it.hasNext()) {
0183:                    ExceptionHandler handler = (ExceptionHandler) it.next();
0184:                    instr = (Instruction) handler.getStartLocation();
0185:                    Instruction end = (Instruction) handler.getEndLocation();
0186:                    for (; instr != null && instr != end; instr = instr.mNext) {
0187:                        instr.addExceptionHandler(handler);
0188:                    }
0189:                }
0190:
0191:                // Perform variable liveness flow analysis for each local variable, in
0192:                // order to determine which register it should be assigned. Takes
0193:                // advantage of the fact that instruction addresses are not yet
0194:                // resolved to true addresses, but are instead indexes. This means the
0195:                // liveness analysis operates on smaller BitLists, which makes some
0196:                // operations (i.e. intersection) a bit faster.
0197:                {
0198:                    int size = mLocalVariables.size();
0199:                    BitList[] liveIn = new BitList[size];
0200:                    BitList[] liveOut = new BitList[size];
0201:                    for (int v = 0; v < size; v++) {
0202:                        liveIn[v] = new BitList(instrCount);
0203:                        liveOut[v] = new BitList(instrCount);
0204:                    }
0205:
0206:                    livenessAnalysis(liveIn, liveOut);
0207:
0208:                    // Register number -> list of variables that use that register.
0209:                    List registerUsers = new ArrayList();
0210:
0211:                    // First fill up list with variables that have a fixed number.
0212:                    for (int v = 0; v < size; v++) {
0213:                        LocalVariableImpl var = (LocalVariableImpl) mLocalVariables
0214:                                .get(v);
0215:                        if (var.isFixedNumber()) {
0216:                            addRegisterUser(registerUsers, var);
0217:                            // Ensure that max locals is large enough to hold parameters.
0218:                            int num = var.getNumber();
0219:                            if (var.isDoubleWord()) {
0220:                                num++;
0221:                            }
0222:                            if (num >= mMaxLocals) {
0223:                                mMaxLocals = num + 1;
0224:                            }
0225:                        }
0226:                    }
0227:
0228:                    // Merge bit lists together.
0229:                    BitList[] live = liveIn;
0230:                    for (int v = 0; v < size; v++) {
0231:                        live[v].or(liveOut[v]);
0232:                        if (live[v].isAllClear()) {
0233:                            // Variable isn't needed.
0234:                            live[v] = null;
0235:                        }
0236:                    }
0237:
0238:                    for (int v = 0; v < size; v++) {
0239:                        if (live[v] == null) {
0240:                            continue;
0241:                        }
0242:                        LocalVariableImpl var = (LocalVariableImpl) mLocalVariables
0243:                                .get(v);
0244:                        if (var.isFixedNumber()) {
0245:                            continue;
0246:                        }
0247:                        int r = 0;
0248:                        while (true) {
0249:                            r = findAvailableRegister(registerUsers, r, live, v);
0250:                            if (var.isDoubleWord()) {
0251:                                if (findAvailableRegister(registerUsers, ++r,
0252:                                        live, v) == r) {
0253:                                    // Found consecutive registers, required for double word.
0254:                                    r--;
0255:                                    break;
0256:                                }
0257:                            } else {
0258:                                break;
0259:                            }
0260:                        }
0261:                        var.setNumber(r);
0262:                        addRegisterUser(registerUsers, var);
0263:                    }
0264:
0265:                    mMaxLocals = Math.max(mMaxLocals, registerUsers.size());
0266:                } // end liveness analysis
0267:
0268:                // Perform stack flow analysis to determine the max stack size.
0269:                {
0270:                    // Start the flow analysis at the first instruction.
0271:                    Map subAdjustMap = new HashMap(11);
0272:                    stackResolve(0, mFirst, subAdjustMap);
0273:
0274:                    // Continue flow analysis into exception handler entry points.
0275:                    it = mExceptionHandlers.iterator();
0276:                    while (it.hasNext()) {
0277:                        ExceptionHandler handler = (ExceptionHandler) it.next();
0278:                        Instruction enter = (Instruction) handler
0279:                                .getCatchLocation();
0280:                        stackResolve(1, enter, subAdjustMap);
0281:                    }
0282:                }
0283:
0284:                // Okay, build up the byte code and set real instruction locations.
0285:                // Multiple passes may be required because instructions may adjust
0286:                // their size as locations are set. Changing size affects the
0287:                // locations of other instructions, so that is why additional passes
0288:                // are required.
0289:
0290:                boolean passAgain;
0291:                do {
0292:                    passAgain = false;
0293:
0294:                    mByteCodes = new byte[instrCount * 2]; // estimate
0295:                    mBufferLength = 0;
0296:
0297:                    for (instr = mFirst; instr != null; instr = instr.mNext) {
0298:                        if (!instr.isResolved()) {
0299:                            passAgain = true;
0300:                        }
0301:
0302:                        if (instr instanceof  Label) {
0303:                            if (instr.mLocation != mBufferLength) {
0304:                                if (instr.mLocation >= 0) {
0305:                                    // If the location of this label is not where it
0306:                                    // should be, (most likely because an instruction
0307:                                    // needed to expand in size) then do another pass.
0308:                                    passAgain = true;
0309:                                }
0310:                                instr.mLocation = mBufferLength;
0311:                            }
0312:                        } else {
0313:                            instr.mLocation = mBufferLength;
0314:
0315:                            byte[] bytes = instr.getBytes();
0316:                            if (bytes != null) {
0317:                                if (passAgain) {
0318:                                    // If there is going to be another pass, don't 
0319:                                    // bother collecting bytes into the array. Just 
0320:                                    // expand the the length variable.
0321:                                    mBufferLength += bytes.length;
0322:                                } else {
0323:                                    addBytes(bytes);
0324:                                }
0325:                            }
0326:                        }
0327:                    }
0328:                } while (passAgain); // do {} while ();
0329:
0330:                if (mBufferLength != mByteCodes.length) {
0331:                    byte[] newBytes = new byte[mBufferLength];
0332:                    System.arraycopy(mByteCodes, 0, newBytes, 0, mBufferLength);
0333:                    mByteCodes = newBytes;
0334:                }
0335:
0336:                // Set resolved at end because during resolution, this field gets
0337:                // set false again while changes are being made to the list
0338:                // of instructions.
0339:                mResolved = true;
0340:            }
0341:
0342:            private void addBytes(byte[] code) {
0343:                growBuffer(code.length);
0344:                System.arraycopy(code, 0, mByteCodes, mBufferLength,
0345:                        code.length);
0346:                mBufferLength += code.length;
0347:            }
0348:
0349:            private void growBuffer(int amount) {
0350:                if ((mBufferLength + amount) > mByteCodes.length) {
0351:                    int newCapacity = mByteCodes.length * 2;
0352:                    if ((mBufferLength + amount) > newCapacity) {
0353:                        newCapacity = mBufferLength + amount;
0354:                    }
0355:
0356:                    byte[] newBuffer = new byte[newCapacity];
0357:                    System
0358:                            .arraycopy(mByteCodes, 0, newBuffer, 0,
0359:                                    mBufferLength);
0360:                    mByteCodes = newBuffer;
0361:                }
0362:            }
0363:
0364:            private void livenessAnalysis(BitList[] liveIn, BitList[] liveOut) {
0365:                // Track stores to variables to see if the result is discarded.
0366:                List[] localStores = new List[liveIn.length];
0367:
0368:                int passCount = -1;
0369:                boolean passAgain;
0370:                do {
0371:                    passCount++;
0372:                    passAgain = false;
0373:
0374:                    for (Instruction instr = mLast; instr != null; instr = instr.mPrev) {
0375:                        int n = instr.getLocation();
0376:
0377:                        int useIndex = -1;
0378:                        int defIndex = -1;
0379:
0380:                        if (instr instanceof  LocalOperandInstruction) {
0381:                            LocalOperandInstruction loi = (LocalOperandInstruction) instr;
0382:                            LocalVariableImpl var = loi.getLocalVariable();
0383:                            int varIndex = var.getIndex();
0384:
0385:                            if (loi.isLoad()) {
0386:                                useIndex = varIndex;
0387:                            }
0388:
0389:                            if (loi.isStore()) {
0390:                                defIndex = varIndex;
0391:                                if (passCount == 0
0392:                                        && loi instanceof  StoreLocalInstruction) {
0393:                                    List stores = localStores[varIndex];
0394:                                    if (stores == null) {
0395:                                        stores = new ArrayList();
0396:                                        localStores[varIndex] = stores;
0397:                                    }
0398:                                    stores.add(instr);
0399:                                }
0400:                            }
0401:                        }
0402:
0403:                        for (int v = liveIn.length; --v >= 0;) {
0404:                            boolean setLiveIn, setLiveOut;
0405:
0406:                            if (useIndex == v
0407:                                    || (v != defIndex && liveOut[v].get(n))) {
0408:                                passAgain |= liveIn[v].set(n);
0409:                                setLiveIn = true;
0410:                            } else {
0411:                                setLiveIn = false;
0412:                            }
0413:
0414:                            setLiveOut = false;
0415:
0416:                            if (instr.isFlowThrough() && instr.mNext != null) {
0417:                                if (liveIn[v].get(instr.mNext.getLocation())) {
0418:                                    setLiveOut = true;
0419:                                    passAgain |= liveOut[v].set(n);
0420:                                }
0421:                            }
0422:
0423:                            Location[] targets = instr.getBranchTargets();
0424:                            if (targets != null) {
0425:                                for (int i = 0; i < targets.length; i++) {
0426:                                    Instruction targetInstr = (Instruction) targets[i];
0427:                                    if (liveIn[v]
0428:                                            .get(targetInstr.getLocation())) {
0429:                                        setLiveOut = true;
0430:                                        passAgain |= liveOut[v].set(n);
0431:                                    }
0432:                                }
0433:                            }
0434:
0435:                            Iterator handlers = instr.getExceptionHandlers();
0436:                            if (handlers != null) {
0437:                                while (handlers.hasNext()) {
0438:                                    ExceptionHandler handler = (ExceptionHandler) handlers
0439:                                            .next();
0440:                                    Instruction catchInstr = (Instruction) handler
0441:                                            .getCatchLocation();
0442:                                    if (liveIn[v].get(catchInstr.getLocation())) {
0443:                                        setLiveOut = true;
0444:                                        passAgain |= liveOut[v].set(n);
0445:                                    }
0446:                                }
0447:                            }
0448:
0449:                            if (!setLiveIn && setLiveOut && v != defIndex) {
0450:                                // Set liveIn entry now that liveOut has been
0451:                                // updated. This greatly reduces the number of full
0452:                                // passes required.
0453:                                passAgain |= liveIn[v].set(n);
0454:                            }
0455:                        }
0456:                    }
0457:                } while (passAgain); // do {} while ();
0458:
0459:                // See which local store instructions should discard their results.
0460:                for (int v = localStores.length; --v >= 0;) {
0461:                    List stores = localStores[v];
0462:                    if (stores != null) {
0463:                        for (int i = stores.size(); --i >= 0;) {
0464:                            StoreLocalInstruction instr = (StoreLocalInstruction) stores
0465:                                    .get(i);
0466:                            if (!liveOut[v].get(instr.getLocation())) {
0467:                                instr.discardResult();
0468:                            }
0469:                        }
0470:                    }
0471:                }
0472:            }
0473:
0474:            private void addRegisterUser(List registerUsers, LocalVariable var) {
0475:                int num = var.getNumber();
0476:                if (num < 0) {
0477:                    throw new IllegalStateException(
0478:                            "Local variable number not resolved");
0479:                }
0480:                getRegisterUsers(registerUsers, num).add(var);
0481:                if (var.isDoubleWord()) {
0482:                    getRegisterUsers(registerUsers, num + 1).add(var);
0483:                }
0484:            }
0485:
0486:            private List getRegisterUsers(List registerUsers, int num) {
0487:                while (registerUsers.size() <= num) {
0488:                    registerUsers.add(new ArrayList());
0489:                }
0490:                return (List) registerUsers.get(num);
0491:            }
0492:
0493:            /**
0494:             * @param registerUsers
0495:             * @param r index into registerUsers
0496:             * @return index into registerUsers which is available, which may be equal
0497:             * to r or equal to the size of registerUsers
0498:             */
0499:            private int findAvailableRegister(List registerUsers, int r,
0500:                    BitList[] live, int v) {
0501:                registerScan: for (; r < registerUsers.size(); r++) {
0502:                    List users = getRegisterUsers(registerUsers, r);
0503:                    for (int i = 0; i < users.size(); i++) {
0504:                        int v2 = ((LocalVariableImpl) users.get(i)).getIndex();
0505:                        if (live[v].intersects(live[v2])) {
0506:                            continue registerScan;
0507:                        }
0508:                    }
0509:                    break;
0510:                }
0511:                return r;
0512:            }
0513:
0514:            private int stackResolve(int stackDepth, Instruction instr,
0515:                    Map subAdjustMap) {
0516:                while (instr != null) {
0517:                    // Set the stack depth, marking this instruction as being visited.
0518:                    // If already visited, break out of this flow.
0519:                    if (instr.mStackDepth < 0) {
0520:                        instr.mStackDepth = stackDepth;
0521:                    } else {
0522:                        if (instr.mStackDepth != stackDepth) {
0523:                            throw new IllegalStateException(
0524:                                    "Stack depth different at previously visited "
0525:                                            + "instruction: "
0526:                                            + instr.mStackDepth + " != "
0527:                                            + stackDepth);
0528:                        }
0529:
0530:                        break;
0531:                    }
0532:
0533:                    // Determine the next instruction to flow down to.
0534:                    Instruction next = null;
0535:
0536:                    if (instr.isFlowThrough()) {
0537:                        if ((next = instr.mNext) == null) {
0538:                            throw new IllegalStateException(
0539:                                    "Execution flows through end of method");
0540:                        }
0541:                    }
0542:
0543:                    stackDepth += instr.getStackAdjustment();
0544:                    if (stackDepth > mMaxStack) {
0545:                        mMaxStack = stackDepth;
0546:                    } else if (stackDepth < 0) {
0547:                        throw new IllegalStateException(
0548:                                "Stack depth is negative: " + stackDepth);
0549:                    }
0550:
0551:                    Location[] targets = instr.getBranchTargets();
0552:
0553:                    if (targets != null) {
0554:                        for (int i = 0; i < targets.length; i++) {
0555:                            LabelInstruction targetInstr = (LabelInstruction) targets[i];
0556:
0557:                            if (i == 0 && next == null) {
0558:                                // Flow to the first target if instruction doesn't
0559:                                // flow to its next instruction.
0560:                                next = targetInstr;
0561:                                continue;
0562:                            }
0563:
0564:                            if (!instr.isSubroutineCall()) {
0565:                                stackResolve(stackDepth, targetInstr,
0566:                                        subAdjustMap);
0567:                            } else {
0568:                                Integer subAdjust = (Integer) subAdjustMap
0569:                                        .get(targetInstr);
0570:
0571:                                if (subAdjust == null) {
0572:                                    int newDepth = stackResolve(stackDepth,
0573:                                            targetInstr, subAdjustMap);
0574:                                    subAdjust = new Integer(newDepth
0575:                                            - stackDepth);
0576:                                    subAdjustMap.put(targetInstr, subAdjust);
0577:                                }
0578:
0579:                                stackDepth += subAdjust.intValue();
0580:                            }
0581:                        }
0582:                    }
0583:
0584:                    instr = next;
0585:                }
0586:
0587:                return stackDepth;
0588:            }
0589:
0590:            private class LocalVariableImpl implements  LocalVariable {
0591:                private final int mIndex;
0592:
0593:                private String mName;
0594:                private TypeDesc mType;
0595:
0596:                private int mNumber;
0597:                private boolean mFixed;
0598:
0599:                public LocalVariableImpl(int index, String name, TypeDesc type,
0600:                        int number) {
0601:                    mIndex = index;
0602:                    mName = name;
0603:                    mType = type;
0604:                    mNumber = number;
0605:                    if (number >= 0) {
0606:                        mFixed = true;
0607:                    }
0608:                }
0609:
0610:                int getIndex() {
0611:                    return mIndex;
0612:                }
0613:
0614:                /**
0615:                 * May return null if this LocalVariable is unnamed.
0616:                 */
0617:                public String getName() {
0618:                    return mName;
0619:                }
0620:
0621:                public void setName(String name) {
0622:                    mName = name;
0623:                }
0624:
0625:                public TypeDesc getType() {
0626:                    return mType;
0627:                }
0628:
0629:                public boolean isDoubleWord() {
0630:                    return mType.isDoubleWord();
0631:                }
0632:
0633:                public int getNumber() {
0634:                    return mNumber;
0635:                }
0636:
0637:                public Set getLocationRangeSet() {
0638:                    // TODO
0639:                    return null;
0640:                }
0641:
0642:                public void setNumber(int number) {
0643:                    mNumber = number;
0644:                }
0645:
0646:                public void setFixedNumber(int number) {
0647:                    mNumber = number;
0648:                    mFixed = true;
0649:                }
0650:
0651:                public boolean isFixedNumber() {
0652:                    return mFixed;
0653:                }
0654:
0655:                public String toString() {
0656:                    if (getName() != null) {
0657:                        return String.valueOf(getType()) + ' ' + getName();
0658:                    } else {
0659:                        return String.valueOf(getType());
0660:                    }
0661:                }
0662:            }
0663:
0664:            /////////////////////////////////////////////////////////////////////////
0665:            //
0666:            // Begin inner class definitions for instructions of the InstructionList.
0667:            //
0668:            /////////////////////////////////////////////////////////////////////////
0669:
0670:            /**
0671:             * An Instruction is an element in an InstructionList, and represents a 
0672:             * Java byte code instruction.
0673:             */
0674:            public abstract class Instruction implements  Location {
0675:                private int mStackAdjust;
0676:
0677:                Instruction mPrev;
0678:                Instruction mNext;
0679:
0680:                // Indicates what the stack depth is when this instruction is reached.
0681:                // Is -1 if not reached. Flow analysis sets this value.
0682:                int mStackDepth = -1;
0683:
0684:                // Indicates the address of this instruction is, or -1 if not known.
0685:                int mLocation = -1;
0686:
0687:                private Set mExceptionHandlers;
0688:
0689:                /**
0690:                 * Newly created instructions are automatically added to the
0691:                 * InstructionList.
0692:                 */
0693:                public Instruction(int stackAdjust) {
0694:                    mStackAdjust = stackAdjust;
0695:                    add();
0696:                }
0697:
0698:                /**
0699:                 * This constructor allows sub-classes to disable auto-adding to the
0700:                 * InstructionList.
0701:                 */
0702:                protected Instruction(int stackAdjust, boolean addInstruction) {
0703:                    mStackAdjust = stackAdjust;
0704:
0705:                    if (addInstruction) {
0706:                        add();
0707:                    }
0708:                }
0709:
0710:                /**
0711:                 * Add this instruction to the end of the InstructionList. If the
0712:                 * Instruction is already in the list, then it is moved to the end.
0713:                 */
0714:                protected void add() {
0715:                    InstructionList.this .mResolved = false;
0716:
0717:                    if (mPrev != null) {
0718:                        mPrev.mNext = mNext;
0719:                    }
0720:
0721:                    if (mNext != null) {
0722:                        mNext.mPrev = mPrev;
0723:                    }
0724:
0725:                    mNext = null;
0726:
0727:                    if (InstructionList.this .mFirst == null) {
0728:                        mPrev = null;
0729:                        InstructionList.this .mFirst = this ;
0730:                    } else {
0731:                        mPrev = InstructionList.this .mLast;
0732:                        InstructionList.this .mLast.mNext = this ;
0733:                    }
0734:
0735:                    InstructionList.this .mLast = this ;
0736:                }
0737:
0738:                /**
0739:                 * Insert an Instruction immediately following this one.
0740:                 */
0741:                public void insert(Instruction instr) {
0742:                    InstructionList.this .mResolved = false;
0743:
0744:                    instr.mPrev = this ;
0745:                    instr.mNext = mNext;
0746:
0747:                    mNext = instr;
0748:
0749:                    if (this  == InstructionList.this .mLast) {
0750:                        InstructionList.this .mLast = instr;
0751:                    }
0752:                }
0753:
0754:                /**
0755:                 * Removes this Instruction from its parent InstructionList.
0756:                 */
0757:                public void remove() {
0758:                    InstructionList.this .mResolved = false;
0759:
0760:                    if (mPrev != null) {
0761:                        mPrev.mNext = mNext;
0762:                    }
0763:
0764:                    if (mNext != null) {
0765:                        mNext.mPrev = mPrev;
0766:                    }
0767:
0768:                    if (this  == InstructionList.this .mFirst) {
0769:                        InstructionList.this .mFirst = mNext;
0770:                    }
0771:
0772:                    if (this  == InstructionList.this .mLast) {
0773:                        InstructionList.this .mLast = mPrev;
0774:                    }
0775:
0776:                    mPrev = null;
0777:                    mNext = null;
0778:                }
0779:
0780:                /**
0781:                 * Replace this Instruction with another one.
0782:                 */
0783:                public void replace(Instruction replacement) {
0784:                    if (replacement == null) {
0785:                        remove();
0786:                        return;
0787:                    }
0788:
0789:                    InstructionList.this .mResolved = false;
0790:
0791:                    replacement.mPrev = mPrev;
0792:                    replacement.mNext = mNext;
0793:
0794:                    if (mPrev != null) {
0795:                        mPrev.mNext = replacement;
0796:                    }
0797:
0798:                    if (mNext != null) {
0799:                        mNext.mPrev = replacement;
0800:                    }
0801:
0802:                    if (this  == InstructionList.this .mFirst) {
0803:                        InstructionList.this .mFirst = replacement;
0804:                    }
0805:
0806:                    if (this  == InstructionList.this .mLast) {
0807:                        InstructionList.this .mLast = replacement;
0808:                    }
0809:                }
0810:
0811:                /**
0812:                 * Returns a positive, negative or zero value indicating what affect
0813:                 * this generated instruction has on the runtime stack.
0814:                 */
0815:                public int getStackAdjustment() {
0816:                    return mStackAdjust;
0817:                }
0818:
0819:                /**
0820:                 * Returns the stack depth for when this instruction is reached. If the
0821:                 * value is negative, then this instruction is never reached.
0822:                 */
0823:                public int getStackDepth() {
0824:                    return mStackDepth;
0825:                }
0826:
0827:                /**
0828:                 * Returns the address of this instruction or -1 if not known.
0829:                 */
0830:                public int getLocation() {
0831:                    return mLocation;
0832:                }
0833:
0834:                /**
0835:                 * Returns all of the targets that this instruction may branch to. Not
0836:                 * all instructions support branching, and null is returned by default.
0837:                 */
0838:                public Location[] getBranchTargets() {
0839:                    return null;
0840:                }
0841:
0842:                /**
0843:                 * Returns an all the exception handlers that wraps this instruction,
0844:                 * or null if none.
0845:                 */
0846:                public Iterator getExceptionHandlers() {
0847:                    if (mExceptionHandlers == null) {
0848:                        return null;
0849:                    }
0850:                    return mExceptionHandlers.iterator();
0851:                }
0852:
0853:                /**
0854:                 * Adds an exception handler that wraps this instruction.
0855:                 */
0856:                public void addExceptionHandler(ExceptionHandler handler) {
0857:                    if (mExceptionHandlers == null) {
0858:                        mExceptionHandlers = new HashSet(4);
0859:                    }
0860:                    mExceptionHandlers.add(handler);
0861:                }
0862:
0863:                /**
0864:                 * Returns true if execution flow may continue after this instruction.
0865:                 * It may be a goto, a method return, an exception throw or a
0866:                 * subroutine return. Default implementation returns true.
0867:                 */
0868:                public boolean isFlowThrough() {
0869:                    return true;
0870:                }
0871:
0872:                public boolean isSubroutineCall() {
0873:                    return false;
0874:                }
0875:
0876:                /**
0877:                 * Returns null if this is a pseudo instruction and no bytes are
0878:                 * generated.
0879:                 */
0880:                public abstract byte[] getBytes();
0881:
0882:                /**
0883:                 * An instruction is resolved when it has all information needed to
0884:                 * generate correct byte code.
0885:                 */
0886:                public abstract boolean isResolved();
0887:
0888:                public int compareTo(Object obj) {
0889:                    if (this  == obj) {
0890:                        return 0;
0891:                    }
0892:                    Location other = (Location) obj;
0893:
0894:                    int loca = getLocation();
0895:                    int locb = other.getLocation();
0896:
0897:                    if (loca < locb) {
0898:                        return -1;
0899:                    } else if (loca > locb) {
0900:                        return 1;
0901:                    } else {
0902:                        return 0;
0903:                    }
0904:                }
0905:
0906:                /**
0907:                 * Returns a string containing the type of this instruction, the stack
0908:                 * adjustment and the list of byte codes. Unvisted instructions are
0909:                 * marked with an asterisk.
0910:                 */
0911:                public String toString() {
0912:                    String name = getClass().getName();
0913:                    int index = name.lastIndexOf('.');
0914:                    if (index >= 0) {
0915:                        name = name.substring(index + 1);
0916:                    }
0917:                    index = name.lastIndexOf('$');
0918:                    if (index >= 0) {
0919:                        name = name.substring(index + 1);
0920:                    }
0921:
0922:                    StringBuffer buf = new StringBuffer(name.length() + 20);
0923:
0924:                    int adjust = getStackAdjustment();
0925:                    int depth = getStackDepth();
0926:
0927:                    if (depth >= 0) {
0928:                        buf.append(' ');
0929:                    } else {
0930:                        buf.append('*');
0931:                    }
0932:
0933:                    buf.append('[');
0934:                    buf.append(mLocation);
0935:                    buf.append("] ");
0936:
0937:                    buf.append(name);
0938:                    buf.append(" (");
0939:
0940:                    if (depth >= 0) {
0941:                        buf.append(depth);
0942:                        buf.append(" + ");
0943:                        buf.append(adjust);
0944:                        buf.append(" = ");
0945:                        buf.append(depth + adjust);
0946:                    } else {
0947:                        buf.append(adjust);
0948:                    }
0949:
0950:                    buf.append(") ");
0951:
0952:                    try {
0953:                        byte[] bytes = getBytes();
0954:                        boolean wide = false;
0955:                        if (bytes != null) {
0956:                            for (int i = 0; i < bytes.length; i++) {
0957:                                if (i > 0) {
0958:                                    buf.append(',');
0959:                                }
0960:
0961:                                byte code = bytes[i];
0962:
0963:                                if (i == 0 || wide) {
0964:                                    buf.append(Opcode.getMnemonic(code));
0965:                                    wide = code == Opcode.WIDE;
0966:                                } else {
0967:                                    buf.append(code & 0xff);
0968:                                }
0969:                            }
0970:                        }
0971:                    } catch (Exception e) {
0972:                    }
0973:
0974:                    return buf.toString();
0975:                }
0976:
0977:                /**
0978:                 * Reset this instruction in preparation for flow analysis.
0979:                 */
0980:                void reset(int instrCount) {
0981:                    mStackDepth = -1;
0982:                    // Start with a fake location.
0983:                    mLocation = instrCount;
0984:                }
0985:            }
0986:
0987:            /**
0988:             * Defines a pseudo instruction for a label. No byte code is ever generated
0989:             * from a label. Labels are not automatically added to the list.
0990:             */
0991:            public class LabelInstruction extends Instruction implements  Label {
0992:                public LabelInstruction() {
0993:                    super (0, false);
0994:                }
0995:
0996:                /**
0997:                 * Set this label's branch location to be the current address
0998:                 * in this label's parent CodeBuilder or InstructionList.
0999:                 *
1000:                 * @return This Label.
1001:                 */
1002:                public Label setLocation() {
1003:                    add();
1004:                    return this ;
1005:                }
1006:
1007:                /**
1008:                 * @return -1 when not resolved yet
1009:                 */
1010:                public int getLocation() throws IllegalStateException {
1011:                    int loc;
1012:                    if ((loc = mLocation) < 0) {
1013:                        if (mPrev == null && mNext == null) {
1014:                            throw new IllegalStateException(
1015:                                    "Label location is not set");
1016:                        }
1017:                    }
1018:                    return loc;
1019:                }
1020:
1021:                /**
1022:                 * Always returns null.
1023:                 */
1024:                public byte[] getBytes() {
1025:                    return null;
1026:                }
1027:
1028:                public boolean isResolved() {
1029:                    return getLocation() >= 0;
1030:                }
1031:            }
1032:
1033:            /**
1034:             * Defines a code instruction and has storage for byte codes.
1035:             */
1036:            public class CodeInstruction extends Instruction {
1037:                protected byte[] mBytes;
1038:
1039:                private Set mExceptionHandlers;
1040:
1041:                public CodeInstruction(int stackAdjust) {
1042:                    super (stackAdjust);
1043:                }
1044:
1045:                protected CodeInstruction(int stackAdjust,
1046:                        boolean addInstruction) {
1047:                    super (stackAdjust, addInstruction);
1048:                }
1049:
1050:                public CodeInstruction(int stackAdjust, byte b) {
1051:                    super (stackAdjust);
1052:                    mBytes = new byte[] { b };
1053:                }
1054:
1055:                public CodeInstruction(int stackAdjust, byte[] bytes) {
1056:                    super (stackAdjust);
1057:                    mBytes = bytes;
1058:                }
1059:
1060:                public boolean isFlowThrough() {
1061:                    if (mBytes != null && mBytes.length > 0) {
1062:                        switch (mBytes[0]) {
1063:                        case Opcode.GOTO:
1064:                        case Opcode.GOTO_W:
1065:                        case Opcode.IRETURN:
1066:                        case Opcode.LRETURN:
1067:                        case Opcode.FRETURN:
1068:                        case Opcode.DRETURN:
1069:                        case Opcode.ARETURN:
1070:                        case Opcode.RETURN:
1071:                        case Opcode.ATHROW:
1072:                            return false;
1073:                        }
1074:                    }
1075:
1076:                    return true;
1077:                }
1078:
1079:                public byte[] getBytes() {
1080:                    return mBytes;
1081:                }
1082:
1083:                public boolean isResolved() {
1084:                    return true;
1085:                }
1086:            }
1087:
1088:            /**
1089:             * Defines a branch instruction, like a goto, jsr or any conditional 
1090:             * branch.
1091:             */
1092:            public class BranchInstruction extends CodeInstruction {
1093:                private Location mTarget;
1094:                private boolean mHasShortHop = false;
1095:                private boolean mIsSub = false;
1096:
1097:                public BranchInstruction(int stackAdjust, byte opcode,
1098:                        Location target) {
1099:                    this (stackAdjust, true, opcode, target);
1100:                }
1101:
1102:                private BranchInstruction(int stackAdjust,
1103:                        boolean addInstruction, byte opcode, Location target) {
1104:                    super (stackAdjust, addInstruction);
1105:
1106:                    mTarget = target;
1107:
1108:                    switch (opcode) {
1109:                    case Opcode.JSR_W:
1110:                        mIsSub = true;
1111:                        // Flow through to next case.
1112:                    case Opcode.GOTO_W:
1113:                        mBytes = new byte[5];
1114:                        mBytes[0] = opcode;
1115:                        break;
1116:                    case Opcode.JSR:
1117:                        mIsSub = true;
1118:                        // Flow through to next case.
1119:                    case Opcode.GOTO:
1120:                    case Opcode.IF_ACMPEQ:
1121:                    case Opcode.IF_ACMPNE:
1122:                    case Opcode.IF_ICMPEQ:
1123:                    case Opcode.IF_ICMPNE:
1124:                    case Opcode.IF_ICMPLT:
1125:                    case Opcode.IF_ICMPGE:
1126:                    case Opcode.IF_ICMPGT:
1127:                    case Opcode.IF_ICMPLE:
1128:                    case Opcode.IFEQ:
1129:                    case Opcode.IFNE:
1130:                    case Opcode.IFLT:
1131:                    case Opcode.IFGE:
1132:                    case Opcode.IFGT:
1133:                    case Opcode.IFLE:
1134:                    case Opcode.IFNONNULL:
1135:                    case Opcode.IFNULL:
1136:                        mBytes = new byte[3];
1137:                        mBytes[0] = opcode;
1138:                        break;
1139:                    default:
1140:                        throw new IllegalArgumentException(
1141:                                "Opcode not a branch instruction: "
1142:                                        + Opcode.getMnemonic(opcode));
1143:                    }
1144:                }
1145:
1146:                public Location[] getBranchTargets() {
1147:                    return new Location[] { mTarget };
1148:                }
1149:
1150:                public boolean isSubroutineCall() {
1151:                    return mIsSub;
1152:                }
1153:
1154:                public byte[] getBytes() {
1155:                    if (!isResolved() || mHasShortHop) {
1156:                        return mBytes;
1157:                    }
1158:
1159:                    int offset = mTarget.getLocation() - mLocation;
1160:                    byte opcode = mBytes[0];
1161:
1162:                    if (opcode == Opcode.GOTO_W || opcode == Opcode.JSR_W) {
1163:                        mBytes[1] = (byte) (offset >> 24);
1164:                        mBytes[2] = (byte) (offset >> 16);
1165:                        mBytes[3] = (byte) (offset >> 8);
1166:                        mBytes[4] = (byte) (offset >> 0);
1167:                    } else if (-32768 <= offset && offset <= 32767) {
1168:                        mBytes[1] = (byte) (offset >> 8);
1169:                        mBytes[2] = (byte) (offset >> 0);
1170:                    } else if (opcode == Opcode.GOTO || opcode == Opcode.JSR) {
1171:                        mBytes = new byte[5];
1172:                        if (opcode == Opcode.GOTO) {
1173:                            mBytes[0] = Opcode.GOTO_W;
1174:                        } else {
1175:                            mBytes[0] = Opcode.JSR_W;
1176:                        }
1177:                        mBytes[1] = (byte) (offset >> 24);
1178:                        mBytes[2] = (byte) (offset >> 16);
1179:                        mBytes[3] = (byte) (offset >> 8);
1180:                        mBytes[4] = (byte) (offset >> 0);
1181:                    } else {
1182:                        // The if branch requires a 32 bit offset.
1183:
1184:                        // Convert:
1185:                        //
1186:                        //           if <cond> goto target
1187:                        //           // reached if <cond> false
1188:                        // target:   // reached if <cond> true
1189:
1190:                        // to this:
1191:                        //
1192:                        //           if not <cond> goto shortHop
1193:                        //           goto_w target
1194:                        // shortHop: // reached if <cond> false
1195:                        // target:   // reached if <cond> true
1196:
1197:                        mHasShortHop = true;
1198:
1199:                        opcode = Opcode.reverseIfOpcode(opcode);
1200:
1201:                        mBytes[0] = opcode;
1202:                        mBytes[1] = (byte) 0;
1203:                        mBytes[2] = (byte) 8;
1204:
1205:                        // insert goto_w instruction after this one.
1206:                        insert(new BranchInstruction(0, false, Opcode.GOTO_W,
1207:                                mTarget));
1208:                    }
1209:
1210:                    return mBytes;
1211:                }
1212:
1213:                public boolean isResolved() {
1214:                    return mTarget.getLocation() >= 0;
1215:                }
1216:            }
1217:
1218:            /**
1219:             * Defines an instruction that has a single operand which references a
1220:             * constant in the constant pool.
1221:             */
1222:            public class ConstantOperandInstruction extends CodeInstruction {
1223:                private ConstantInfo mInfo;
1224:
1225:                public ConstantOperandInstruction(int stackAdjust,
1226:                        byte[] bytes, ConstantInfo info) {
1227:                    super (stackAdjust, bytes);
1228:                    mInfo = info;
1229:                }
1230:
1231:                public byte[] getBytes() {
1232:                    int index = mInfo.getIndex();
1233:
1234:                    if (index < 0) {
1235:                        throw new IllegalStateException(
1236:                                "Constant pool index not resolved");
1237:                    }
1238:
1239:                    mBytes[1] = (byte) (index >> 8);
1240:                    mBytes[2] = (byte) index;
1241:
1242:                    return mBytes;
1243:                }
1244:
1245:                public boolean isResolved() {
1246:                    return mInfo.getIndex() >= 0;
1247:                }
1248:            }
1249:
1250:            /**
1251:             * Defines an instruction that loads a constant onto the stack from the
1252:             * constant pool.
1253:             */
1254:            public class LoadConstantInstruction extends CodeInstruction {
1255:                private ConstantInfo mInfo;
1256:                private boolean mWideOnly;
1257:
1258:                public LoadConstantInstruction(int stackAdjust,
1259:                        ConstantInfo info) {
1260:                    this (stackAdjust, info, false);
1261:                }
1262:
1263:                public LoadConstantInstruction(int stackAdjust,
1264:                        ConstantInfo info, boolean wideOnly) {
1265:                    super (stackAdjust);
1266:                    mInfo = info;
1267:                    mWideOnly = wideOnly;
1268:                }
1269:
1270:                public boolean isFlowThrough() {
1271:                    return true;
1272:                }
1273:
1274:                public byte[] getBytes() {
1275:                    int index = mInfo.getIndex();
1276:
1277:                    if (index < 0) {
1278:                        throw new IllegalStateException(
1279:                                "Constant pool index not resolved");
1280:                    }
1281:
1282:                    if (mWideOnly) {
1283:                        byte[] bytes = new byte[3];
1284:                        bytes[0] = Opcode.LDC2_W;
1285:                        bytes[1] = (byte) (index >> 8);
1286:                        bytes[2] = (byte) index;
1287:                        return bytes;
1288:                    } else if (index <= 255) {
1289:                        byte[] bytes = new byte[2];
1290:                        bytes[0] = Opcode.LDC;
1291:                        bytes[1] = (byte) index;
1292:                        return bytes;
1293:                    } else {
1294:                        byte[] bytes = new byte[3];
1295:                        bytes[0] = Opcode.LDC_W;
1296:                        bytes[1] = (byte) (index >> 8);
1297:                        bytes[2] = (byte) index;
1298:                        return bytes;
1299:                    }
1300:                }
1301:
1302:                public boolean isResolved() {
1303:                    return mInfo.getIndex() >= 0;
1304:                }
1305:            }
1306:
1307:            /**
1308:             * Defines an instruction that contains an operand for referencing a
1309:             * LocalVariable.
1310:             */
1311:            public abstract class LocalOperandInstruction extends
1312:                    CodeInstruction {
1313:                protected LocalVariableImpl mLocal;
1314:
1315:                public LocalOperandInstruction(int stackAdjust,
1316:                        LocalVariable local) {
1317:                    super (stackAdjust);
1318:                    mLocal = (LocalVariableImpl) local;
1319:                }
1320:
1321:                public boolean isResolved() {
1322:                    return mLocal.getNumber() >= 0;
1323:                }
1324:
1325:                public LocalVariableImpl getLocalVariable() {
1326:                    return mLocal;
1327:                }
1328:
1329:                public int getVariableNumber() {
1330:                    int varNum = mLocal.getNumber();
1331:
1332:                    if (varNum < 0) {
1333:                        throw new IllegalStateException(
1334:                                "Local variable number not resolved");
1335:                    }
1336:
1337:                    return varNum;
1338:                }
1339:
1340:                public abstract boolean isLoad();
1341:
1342:                public abstract boolean isStore();
1343:            }
1344:
1345:            /**
1346:             * Defines an instruction that loads a local variable onto the stack.
1347:             */
1348:            public class LoadLocalInstruction extends LocalOperandInstruction {
1349:                public LoadLocalInstruction(int stackAdjust, LocalVariable local) {
1350:                    super (stackAdjust, local);
1351:                }
1352:
1353:                public boolean isFlowThrough() {
1354:                    return true;
1355:                }
1356:
1357:                public byte[] getBytes() {
1358:                    int varNum = getVariableNumber();
1359:                    byte opcode;
1360:                    boolean writeIndex = false;
1361:
1362:                    int typeCode = mLocal.getType().getTypeCode();
1363:
1364:                    switch (varNum) {
1365:                    case 0:
1366:                        switch (typeCode) {
1367:                        default:
1368:                            opcode = Opcode.ALOAD_0;
1369:                            break;
1370:                        case TypeDesc.LONG_CODE:
1371:                            opcode = Opcode.LLOAD_0;
1372:                            break;
1373:                        case TypeDesc.FLOAT_CODE:
1374:                            opcode = Opcode.FLOAD_0;
1375:                            break;
1376:                        case TypeDesc.DOUBLE_CODE:
1377:                            opcode = Opcode.DLOAD_0;
1378:                            break;
1379:                        case TypeDesc.INT_CODE:
1380:                        case TypeDesc.BOOLEAN_CODE:
1381:                        case TypeDesc.BYTE_CODE:
1382:                        case TypeDesc.CHAR_CODE:
1383:                        case TypeDesc.SHORT_CODE:
1384:                            opcode = Opcode.ILOAD_0;
1385:                            break;
1386:                        }
1387:                        break;
1388:                    case 1:
1389:                        switch (typeCode) {
1390:                        default:
1391:                            opcode = Opcode.ALOAD_1;
1392:                            break;
1393:                        case TypeDesc.LONG_CODE:
1394:                            opcode = Opcode.LLOAD_1;
1395:                            break;
1396:                        case TypeDesc.FLOAT_CODE:
1397:                            opcode = Opcode.FLOAD_1;
1398:                            break;
1399:                        case TypeDesc.DOUBLE_CODE:
1400:                            opcode = Opcode.DLOAD_1;
1401:                            break;
1402:                        case TypeDesc.INT_CODE:
1403:                        case TypeDesc.BOOLEAN_CODE:
1404:                        case TypeDesc.BYTE_CODE:
1405:                        case TypeDesc.CHAR_CODE:
1406:                        case TypeDesc.SHORT_CODE:
1407:                            opcode = Opcode.ILOAD_1;
1408:                            break;
1409:                        }
1410:                        break;
1411:                    case 2:
1412:                        switch (typeCode) {
1413:                        default:
1414:                            opcode = Opcode.ALOAD_2;
1415:                            break;
1416:                        case TypeDesc.LONG_CODE:
1417:                            opcode = Opcode.LLOAD_2;
1418:                            break;
1419:                        case TypeDesc.FLOAT_CODE:
1420:                            opcode = Opcode.FLOAD_2;
1421:                            break;
1422:                        case TypeDesc.DOUBLE_CODE:
1423:                            opcode = Opcode.DLOAD_2;
1424:                            break;
1425:                        case TypeDesc.INT_CODE:
1426:                        case TypeDesc.BOOLEAN_CODE:
1427:                        case TypeDesc.BYTE_CODE:
1428:                        case TypeDesc.CHAR_CODE:
1429:                        case TypeDesc.SHORT_CODE:
1430:                            opcode = Opcode.ILOAD_2;
1431:                            break;
1432:                        }
1433:                        break;
1434:                    case 3:
1435:                        switch (typeCode) {
1436:                        default:
1437:                            opcode = Opcode.ALOAD_3;
1438:                            break;
1439:                        case TypeDesc.LONG_CODE:
1440:                            opcode = Opcode.LLOAD_3;
1441:                            break;
1442:                        case TypeDesc.FLOAT_CODE:
1443:                            opcode = Opcode.FLOAD_3;
1444:                            break;
1445:                        case TypeDesc.DOUBLE_CODE:
1446:                            opcode = Opcode.DLOAD_3;
1447:                            break;
1448:                        case TypeDesc.INT_CODE:
1449:                        case TypeDesc.BOOLEAN_CODE:
1450:                        case TypeDesc.BYTE_CODE:
1451:                        case TypeDesc.CHAR_CODE:
1452:                        case TypeDesc.SHORT_CODE:
1453:                            opcode = Opcode.ILOAD_3;
1454:                            break;
1455:                        }
1456:                        break;
1457:                    default:
1458:                        writeIndex = true;
1459:
1460:                        switch (typeCode) {
1461:                        default:
1462:                            opcode = Opcode.ALOAD;
1463:                            break;
1464:                        case TypeDesc.LONG_CODE:
1465:                            opcode = Opcode.LLOAD;
1466:                            break;
1467:                        case TypeDesc.FLOAT_CODE:
1468:                            opcode = Opcode.FLOAD;
1469:                            break;
1470:                        case TypeDesc.DOUBLE_CODE:
1471:                            opcode = Opcode.DLOAD;
1472:                            break;
1473:                        case TypeDesc.INT_CODE:
1474:                        case TypeDesc.BOOLEAN_CODE:
1475:                        case TypeDesc.BYTE_CODE:
1476:                        case TypeDesc.CHAR_CODE:
1477:                        case TypeDesc.SHORT_CODE:
1478:                            opcode = Opcode.ILOAD;
1479:                            break;
1480:                        }
1481:                        break;
1482:                    }
1483:
1484:                    if (!writeIndex) {
1485:                        mBytes = new byte[] { opcode };
1486:                    } else {
1487:                        if (varNum <= 255) {
1488:                            mBytes = new byte[] { opcode, (byte) varNum };
1489:                        } else {
1490:                            mBytes = new byte[] { Opcode.WIDE, opcode,
1491:                                    (byte) (varNum >> 8), (byte) varNum };
1492:                        }
1493:                    }
1494:
1495:                    return mBytes;
1496:                }
1497:
1498:                public boolean isLoad() {
1499:                    return true;
1500:                }
1501:
1502:                public boolean isStore() {
1503:                    return false;
1504:                }
1505:            }
1506:
1507:            /**
1508:             * Defines an instruction that stores a value from the stack into a local 
1509:             * variable.
1510:             */
1511:            public class StoreLocalInstruction extends LocalOperandInstruction {
1512:                private boolean mDiscardResult;
1513:
1514:                public StoreLocalInstruction(int stackAdjust,
1515:                        LocalVariable local) {
1516:                    super (stackAdjust, local);
1517:                }
1518:
1519:                public boolean isFlowThrough() {
1520:                    return true;
1521:                }
1522:
1523:                public byte[] getBytes() {
1524:                    if (mDiscardResult) {
1525:                        // Liveness analysis discovered that the results of this store
1526:                        // are not needed so just pop if off the stack.
1527:                        return new byte[] { mLocal.isDoubleWord() ? Opcode.POP2
1528:                                : Opcode.POP };
1529:                    }
1530:
1531:                    int varNum = getVariableNumber();
1532:
1533:                    byte opcode;
1534:                    boolean writeIndex = false;
1535:
1536:                    int typeCode = mLocal.getType().getTypeCode();
1537:
1538:                    switch (varNum) {
1539:                    case 0:
1540:                        switch (typeCode) {
1541:                        default:
1542:                            opcode = Opcode.ASTORE_0;
1543:                            break;
1544:                        case TypeDesc.LONG_CODE:
1545:                            opcode = Opcode.LSTORE_0;
1546:                            break;
1547:                        case TypeDesc.FLOAT_CODE:
1548:                            opcode = Opcode.FSTORE_0;
1549:                            break;
1550:                        case TypeDesc.DOUBLE_CODE:
1551:                            opcode = Opcode.DSTORE_0;
1552:                            break;
1553:                        case TypeDesc.INT_CODE:
1554:                        case TypeDesc.BOOLEAN_CODE:
1555:                        case TypeDesc.BYTE_CODE:
1556:                        case TypeDesc.CHAR_CODE:
1557:                        case TypeDesc.SHORT_CODE:
1558:                            opcode = Opcode.ISTORE_0;
1559:                            break;
1560:                        }
1561:                        break;
1562:                    case 1:
1563:                        switch (typeCode) {
1564:                        default:
1565:                            opcode = Opcode.ASTORE_1;
1566:                            break;
1567:                        case TypeDesc.LONG_CODE:
1568:                            opcode = Opcode.LSTORE_1;
1569:                            break;
1570:                        case TypeDesc.FLOAT_CODE:
1571:                            opcode = Opcode.FSTORE_1;
1572:                            break;
1573:                        case TypeDesc.DOUBLE_CODE:
1574:                            opcode = Opcode.DSTORE_1;
1575:                            break;
1576:                        case TypeDesc.INT_CODE:
1577:                        case TypeDesc.BOOLEAN_CODE:
1578:                        case TypeDesc.BYTE_CODE:
1579:                        case TypeDesc.CHAR_CODE:
1580:                        case TypeDesc.SHORT_CODE:
1581:                            opcode = Opcode.ISTORE_1;
1582:                            break;
1583:                        }
1584:                        break;
1585:                    case 2:
1586:                        switch (typeCode) {
1587:                        default:
1588:                            opcode = Opcode.ASTORE_2;
1589:                            break;
1590:                        case TypeDesc.LONG_CODE:
1591:                            opcode = Opcode.LSTORE_2;
1592:                            break;
1593:                        case TypeDesc.FLOAT_CODE:
1594:                            opcode = Opcode.FSTORE_2;
1595:                            break;
1596:                        case TypeDesc.DOUBLE_CODE:
1597:                            opcode = Opcode.DSTORE_2;
1598:                            break;
1599:                        case TypeDesc.INT_CODE:
1600:                        case TypeDesc.BOOLEAN_CODE:
1601:                        case TypeDesc.BYTE_CODE:
1602:                        case TypeDesc.CHAR_CODE:
1603:                        case TypeDesc.SHORT_CODE:
1604:                            opcode = Opcode.ISTORE_2;
1605:                            break;
1606:                        }
1607:                        break;
1608:                    case 3:
1609:                        switch (typeCode) {
1610:                        default:
1611:                            opcode = Opcode.ASTORE_3;
1612:                            break;
1613:                        case TypeDesc.LONG_CODE:
1614:                            opcode = Opcode.LSTORE_3;
1615:                            break;
1616:                        case TypeDesc.FLOAT_CODE:
1617:                            opcode = Opcode.FSTORE_3;
1618:                            break;
1619:                        case TypeDesc.DOUBLE_CODE:
1620:                            opcode = Opcode.DSTORE_3;
1621:                            break;
1622:                        case TypeDesc.INT_CODE:
1623:                        case TypeDesc.BOOLEAN_CODE:
1624:                        case TypeDesc.BYTE_CODE:
1625:                        case TypeDesc.CHAR_CODE:
1626:                        case TypeDesc.SHORT_CODE:
1627:                            opcode = Opcode.ISTORE_3;
1628:                            break;
1629:                        }
1630:                        break;
1631:                    default:
1632:                        writeIndex = true;
1633:
1634:                        switch (typeCode) {
1635:                        default:
1636:                            opcode = Opcode.ASTORE;
1637:                            break;
1638:                        case TypeDesc.LONG_CODE:
1639:                            opcode = Opcode.LSTORE;
1640:                            break;
1641:                        case TypeDesc.FLOAT_CODE:
1642:                            opcode = Opcode.FSTORE;
1643:                            break;
1644:                        case TypeDesc.DOUBLE_CODE:
1645:                            opcode = Opcode.DSTORE;
1646:                            break;
1647:                        case TypeDesc.INT_CODE:
1648:                        case TypeDesc.BOOLEAN_CODE:
1649:                        case TypeDesc.BYTE_CODE:
1650:                        case TypeDesc.CHAR_CODE:
1651:                        case TypeDesc.SHORT_CODE:
1652:                            opcode = Opcode.ISTORE;
1653:                            break;
1654:                        }
1655:                        break;
1656:                    }
1657:
1658:                    if (!writeIndex) {
1659:                        mBytes = new byte[] { opcode };
1660:                    } else {
1661:                        if (varNum <= 255) {
1662:                            mBytes = new byte[] { opcode, (byte) varNum };
1663:                        } else {
1664:                            mBytes = new byte[] { Opcode.WIDE, opcode,
1665:                                    (byte) (varNum >> 8), (byte) varNum };
1666:                        }
1667:                    }
1668:
1669:                    return mBytes;
1670:                }
1671:
1672:                public boolean isResolved() {
1673:                    return true;
1674:                }
1675:
1676:                public boolean isLoad() {
1677:                    return false;
1678:                }
1679:
1680:                public boolean isStore() {
1681:                    return true;
1682:                }
1683:
1684:                public void discardResult() {
1685:                    mDiscardResult = true;
1686:                }
1687:            }
1688:
1689:            /**
1690:             * Defines a ret instruction for returning from a jsr call. 
1691:             */
1692:            public class RetInstruction extends LocalOperandInstruction {
1693:                // Note: This instruction does not provide any branch targets. The
1694:                // analysis for determining all possible return locations is
1695:                // complicated. Instead, the stack flow analysis assumes that all jsr
1696:                // calls are "well formed", and so it doesn't need to follow the ret
1697:                // back to a "comes from" label. Liveness analysis could take advantage
1698:                // of the branch targets, and reduce the set of variables used to
1699:                // manage jsr return addresses. Since jsr/ret is used infrequently,
1700:                // local variables used by ret are fixed and are not optimized.
1701:
1702:                public RetInstruction(LocalVariable local) {
1703:                    super (0, local);
1704:                    ((LocalVariableImpl) local)
1705:                            .setFixedNumber(mNextFixedVariableNumber++);
1706:                }
1707:
1708:                public boolean isFlowThrough() {
1709:                    return false;
1710:                }
1711:
1712:                public byte[] getBytes() {
1713:                    int varNum = getVariableNumber();
1714:
1715:                    if (varNum <= 255) {
1716:                        mBytes = new byte[] { Opcode.RET, (byte) varNum };
1717:                    } else {
1718:                        mBytes = new byte[] { Opcode.WIDE, Opcode.RET,
1719:                                (byte) (varNum >> 8), (byte) varNum };
1720:                    }
1721:
1722:                    return mBytes;
1723:                }
1724:
1725:                public boolean isLoad() {
1726:                    return true;
1727:                }
1728:
1729:                public boolean isStore() {
1730:                    return false;
1731:                }
1732:            }
1733:
1734:            /**
1735:             * Defines a specialized instruction that increments a local variable by
1736:             * a signed 16-bit amount.
1737:             */
1738:            public class ShortIncrementInstruction extends
1739:                    LocalOperandInstruction {
1740:                private short mAmount;
1741:
1742:                public ShortIncrementInstruction(LocalVariable local,
1743:                        short amount) {
1744:                    super (0, local);
1745:                    mAmount = amount;
1746:                }
1747:
1748:                public boolean isFlowThrough() {
1749:                    return true;
1750:                }
1751:
1752:                public byte[] getBytes() {
1753:                    int varNum = getVariableNumber();
1754:
1755:                    if ((-128 <= mAmount && mAmount <= 127) && varNum <= 255) {
1756:                        mBytes = new byte[] { Opcode.IINC, (byte) varNum,
1757:                                (byte) mAmount };
1758:                    } else {
1759:                        mBytes = new byte[] { Opcode.WIDE, Opcode.IINC,
1760:                                (byte) (varNum >> 8), (byte) varNum,
1761:                                (byte) (mAmount >> 8), (byte) mAmount };
1762:                    }
1763:
1764:                    return mBytes;
1765:                }
1766:
1767:                public boolean isLoad() {
1768:                    return true;
1769:                }
1770:
1771:                public boolean isStore() {
1772:                    return true;
1773:                }
1774:            }
1775:
1776:            /**
1777:             * Defines a switch instruction. The choice of which actual switch 
1778:             * implementation to use (table or lookup switch) is determined 
1779:             * automatically based on which generates to the smallest amount of bytes.
1780:             */
1781:            public class SwitchInstruction extends CodeInstruction {
1782:                private int[] mCases;
1783:                private Location[] mLocations;
1784:                private Location mDefaultLocation;
1785:
1786:                private byte mOpcode;
1787:
1788:                private int mSmallest;
1789:                private int mLargest;
1790:
1791:                public SwitchInstruction(int[] casesParam,
1792:                        Location[] locationsParam, Location defaultLocation) {
1793:                    // A SwitchInstruction always adjusts the stack by -1 because it 
1794:                    // pops the switch key off the stack.
1795:                    super (-1);
1796:
1797:                    if (casesParam.length != locationsParam.length) {
1798:                        throw new IllegalArgumentException(
1799:                                "Switch cases and locations sizes differ: "
1800:                                        + casesParam.length + ", "
1801:                                        + locationsParam.length);
1802:                    }
1803:
1804:                    mCases = new int[casesParam.length];
1805:                    System.arraycopy(casesParam, 0, mCases, 0,
1806:                            casesParam.length);
1807:
1808:                    mLocations = new Location[locationsParam.length];
1809:                    System.arraycopy(locationsParam, 0, mLocations, 0,
1810:                            locationsParam.length);
1811:
1812:                    mDefaultLocation = defaultLocation;
1813:
1814:                    // First sort the cases and locations.
1815:                    sort(0, mCases.length - 1);
1816:
1817:                    // Check for duplicate cases.
1818:                    int lastCase = 0;
1819:                    for (int i = 0; i < mCases.length; i++) {
1820:                        if (i > 0 && mCases[i] == lastCase) {
1821:                            throw new IllegalArgumentException(
1822:                                    "Duplicate switch cases: " + lastCase);
1823:                        }
1824:                        lastCase = mCases[i];
1825:                    }
1826:
1827:                    // Now determine which kind of switch to use.
1828:
1829:                    mSmallest = mCases[0];
1830:                    mLargest = mCases[mCases.length - 1];
1831:                    int tSize = 12 + 4 * (mLargest - mSmallest + 1);
1832:
1833:                    int lSize = 8 + 8 * mCases.length;
1834:
1835:                    if (tSize <= lSize) {
1836:                        mOpcode = Opcode.TABLESWITCH;
1837:                    } else {
1838:                        mOpcode = Opcode.LOOKUPSWITCH;
1839:                    }
1840:                }
1841:
1842:                public Location[] getBranchTargets() {
1843:                    Location[] targets = new Location[mLocations.length + 1];
1844:                    System.arraycopy(mLocations, 0, targets, 0,
1845:                            mLocations.length);
1846:                    targets[targets.length - 1] = mDefaultLocation;
1847:
1848:                    return targets;
1849:                }
1850:
1851:                public boolean isFlowThrough() {
1852:                    return false;
1853:                }
1854:
1855:                public byte[] getBytes() {
1856:                    int length = 1;
1857:                    int pad = 3 - (mLocation & 3);
1858:                    length += pad;
1859:
1860:                    if (mOpcode == Opcode.TABLESWITCH) {
1861:                        length += 12 + 4 * (mLargest - mSmallest + 1);
1862:                    } else {
1863:                        length += 8 + 8 * mCases.length;
1864:                    }
1865:
1866:                    mBytes = new byte[length];
1867:
1868:                    if (!isResolved()) {
1869:                        return mBytes;
1870:                    }
1871:
1872:                    mBytes[0] = mOpcode;
1873:                    int cursor = pad + 1;
1874:
1875:                    int defaultOffset = mDefaultLocation.getLocation()
1876:                            - mLocation;
1877:                    mBytes[cursor++] = (byte) (defaultOffset >> 24);
1878:                    mBytes[cursor++] = (byte) (defaultOffset >> 16);
1879:                    mBytes[cursor++] = (byte) (defaultOffset >> 8);
1880:                    mBytes[cursor++] = (byte) (defaultOffset >> 0);
1881:
1882:                    if (mOpcode == Opcode.TABLESWITCH) {
1883:                        mBytes[cursor++] = (byte) (mSmallest >> 24);
1884:                        mBytes[cursor++] = (byte) (mSmallest >> 16);
1885:                        mBytes[cursor++] = (byte) (mSmallest >> 8);
1886:                        mBytes[cursor++] = (byte) (mSmallest >> 0);
1887:
1888:                        mBytes[cursor++] = (byte) (mLargest >> 24);
1889:                        mBytes[cursor++] = (byte) (mLargest >> 16);
1890:                        mBytes[cursor++] = (byte) (mLargest >> 8);
1891:                        mBytes[cursor++] = (byte) (mLargest >> 0);
1892:
1893:                        int index = 0;
1894:                        for (int case_ = mSmallest; case_ <= mLargest; case_++) {
1895:                            if (case_ == mCases[index]) {
1896:                                int offset = mLocations[index].getLocation()
1897:                                        - mLocation;
1898:                                mBytes[cursor++] = (byte) (offset >> 24);
1899:                                mBytes[cursor++] = (byte) (offset >> 16);
1900:                                mBytes[cursor++] = (byte) (offset >> 8);
1901:                                mBytes[cursor++] = (byte) (offset >> 0);
1902:
1903:                                index++;
1904:                            } else {
1905:                                mBytes[cursor++] = (byte) (defaultOffset >> 24);
1906:                                mBytes[cursor++] = (byte) (defaultOffset >> 16);
1907:                                mBytes[cursor++] = (byte) (defaultOffset >> 8);
1908:                                mBytes[cursor++] = (byte) (defaultOffset >> 0);
1909:                            }
1910:                        }
1911:                    } else {
1912:                        mBytes[cursor++] = (byte) (mCases.length >> 24);
1913:                        mBytes[cursor++] = (byte) (mCases.length >> 16);
1914:                        mBytes[cursor++] = (byte) (mCases.length >> 8);
1915:                        mBytes[cursor++] = (byte) (mCases.length >> 0);
1916:
1917:                        for (int index = 0; index < mCases.length; index++) {
1918:                            int case_ = mCases[index];
1919:
1920:                            mBytes[cursor++] = (byte) (case_ >> 24);
1921:                            mBytes[cursor++] = (byte) (case_ >> 16);
1922:                            mBytes[cursor++] = (byte) (case_ >> 8);
1923:                            mBytes[cursor++] = (byte) (case_ >> 0);
1924:
1925:                            int offset = mLocations[index].getLocation()
1926:                                    - mLocation;
1927:                            mBytes[cursor++] = (byte) (offset >> 24);
1928:                            mBytes[cursor++] = (byte) (offset >> 16);
1929:                            mBytes[cursor++] = (byte) (offset >> 8);
1930:                            mBytes[cursor++] = (byte) (offset >> 0);
1931:                        }
1932:                    }
1933:
1934:                    return mBytes;
1935:                }
1936:
1937:                public boolean isResolved() {
1938:                    if (mDefaultLocation.getLocation() >= 0) {
1939:                        for (int i = 0; i < mLocations.length; i++) {
1940:                            if (mLocations[i].getLocation() < 0) {
1941:                                break;
1942:                            }
1943:                        }
1944:
1945:                        return true;
1946:                    }
1947:
1948:                    return false;
1949:                }
1950:
1951:                private void sort(int left, int right) {
1952:                    if (left >= right) {
1953:                        return;
1954:                    }
1955:
1956:                    swap(left, (left + right) / 2); // move middle element to 0
1957:
1958:                    int last = left;
1959:
1960:                    for (int i = left + 1; i <= right; i++) {
1961:                        if (mCases[i] < mCases[left]) {
1962:                            swap(++last, i);
1963:                        }
1964:                    }
1965:
1966:                    swap(left, last);
1967:                    sort(left, last - 1);
1968:                    sort(last + 1, right);
1969:                }
1970:
1971:                private void swap(int i, int j) {
1972:                    int tempInt = mCases[i];
1973:                    mCases[i] = mCases[j];
1974:                    mCases[j] = tempInt;
1975:
1976:                    Location tempLocation = mLocations[i];
1977:                    mLocations[i] = mLocations[j];
1978:                    mLocations[j] = tempLocation;
1979:                }
1980:            }
1981:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.