Source Code Cross Referenced for CodeAttr.java in  » Scripting » Kawa » gnu » bytecode » 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 » Scripting » Kawa » gnu.bytecode 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // Copyright (c) 1997, 1998, 1999, 2001, 2003, 2004  Per M.A. Bothner.
0002:        // This is free software;  for terms and warranty disclaimer see ./COPYING.
0003:
0004:        package gnu.bytecode;
0005:
0006:        import java.io.*;
0007:
0008:        /**
0009:         * Represents the contents of a standard "Code" attribute.
0010:         * <p>
0011:         * Most of the actual methods that generate bytecode operation
0012:         * are in this class (typically with names starting with <code>emit</code>),
0013:         * though there are also some in <code>Method</code>.
0014:         * <p>
0015:         * Note that a <code>CodeAttr</code> is an <code>Attribute</code>
0016:         * of a <code>Method</code>, and can in turn contain other
0017:         * <code>Attribute</code>s, such as a <code>LineNumbersAttr</code>.
0018:         *
0019:         * @author      Per Bothner
0020:         */
0021:
0022:        public class CodeAttr extends Attribute implements  AttrContainer {
0023:            Attribute attributes;
0024:
0025:            public final Attribute getAttributes() {
0026:                return attributes;
0027:            }
0028:
0029:            public final void setAttributes(Attribute attributes) {
0030:                this .attributes = attributes;
0031:            }
0032:
0033:            LineNumbersAttr lines;
0034:            public LocalVarsAttr locals;
0035:
0036:            SourceDebugExtAttr sourceDbgExt;
0037:
0038:            // In hindsight, maintaining stack_types is more hassle than it is worth.
0039:            // Instead, better to just keep track of SP, which should catch most
0040:            // stack errors, while being more general and less hassle.  FIXME.
0041:            Type[] stack_types;
0042:
0043:            int SP; // Current stack size (in "words")
0044:            private int max_stack;
0045:            private int max_locals;
0046:            /** Current active length of code array.
0047:             * Note that processFixups may expand/contract the code array.  */
0048:            int PC;
0049:            byte[] code;
0050:
0051:            /* The exception handler table, as a vector of quadruples
0052:               (start_pc, end_pc, handler_pc, catch_type).
0053:               Only the first exception_table_length quadruples are defined. */
0054:            short[] exception_table;
0055:
0056:            /* The number of (defined) exception handlers (i.e. quadruples)
0057:               in exception_table. */
0058:            int exception_table_length;
0059:
0060:            /** Not a fixup - a no-op. */
0061:            static final int FIXUP_NONE = 0;
0062:            /** The definition of a label. */
0063:            static final int FIXUP_DEFINE = 1;
0064:            /** The offset points to a tableswitch/lookupswitch - handle padding. */
0065:            static final int FIXUP_SWITCH = 2;
0066:            /** The offset contains a label relative to the previous FIXUP_SWITCH. */
0067:            static final int FIXUP_CASE = 3;
0068:            /** The offset points to a goto instruction.
0069:             * This case up to FIXUP_TRANSFER2 must be contiguous
0070:             * - see the jump-to-jump optimization in processFixups. */
0071:            static final int FIXUP_GOTO = 4;
0072:            /** The offset points to a jsr instruction. */
0073:            static final int FIXUP_JSR = 5;
0074:            /** The offset points to a conditional transfer (if_xxx) instruction. */
0075:            static final int FIXUP_TRANSFER = 6;
0076:            /** A FIXUP_GOTO_, FIXUP_JSR, or FIXUP_TRANSFER that uses a 2-byte offset. */
0077:            static final int FIXUP_TRANSFER2 = 7;
0078:            /** The offsets points to 3 bytes that should be deleted. */
0079:            static final int FIXUP_DELETE3 = 8;
0080:            /** The following instructions are moved to later in the code stream.
0081:             * Instead the instructions starting at the fixup label are patched here.
0082:             * (If the fixup label is null, we're done.)
0083:             * This allows re-arranging code to avoid unneeded gotos.
0084:             * The following instruction is the target of a later FIXUP_MOVE,
0085:             * and we'll insert then when we get to it. */
0086:            static final int FIXUP_MOVE = 9;
0087:            /** The following instructions are moved to the end of the code stream.
0088:             * Same as FIXUP_MOVE, but there is no explicit later FIXUP_MOVE that
0089:             * refers to the following instructions.  Created by beginFragment.
0090:             * The fixup_offset points to the end of the fragment.
0091:             * (The first processFixups patches these to FIXUP_MOVE.) */
0092:            static final int FIXUP_MOVE_TO_END = 10;
0093:            /** FIXUP_TRY with the following FIXUP_CATCH marks an exception handler.
0094:             * The label is the start of the try clause;
0095:             * the current offset marks the exception handler. */
0096:            static final int FIXUP_TRY = 11;
0097:            /** Second half of a FIXUP_TRY/FIXUP_CATCH pair.
0098:             * The label is the ed of the try clause;
0099:             * the current offset is the exception type as a constant pool index. */
0100:            static final int FIXUP_CATCH = 12;
0101:            /** With following FIXUP_LINE_NUMBER associates an offset with a line number.
0102:             * The fixup_offset is the code location; the fixup_label is null. */
0103:            static final int FIXUP_LINE_PC = 13;
0104:            /** With preceding FIXUP_LINE_PC associates an offset with a line number.
0105:             * The fixup_offset is the line number; the fixup_label is null. */
0106:            static final int FIXUP_LINE_NUMBER = 14;
0107:            int[] fixup_offsets;
0108:            Label[] fixup_labels;
0109:            int fixup_count;
0110:
0111:            /** This causes a later processFixup to rearrange the code.
0112:             * The code at target comes here, instead of the following instructions.
0113:             * Fuctionally equivalent to: <code>goto target; here:</code>,
0114:             * but implemented by code re-arranging.  Therefore there should be
0115:             * at some later point a <code>goto here; target:</code>.
0116:             */
0117:            public final void fixupChain(Label here, Label target) {
0118:                fixupAdd(CodeAttr.FIXUP_MOVE, 0, target);
0119:                here.define(this );
0120:            }
0121:
0122:            /** Add a fixup at this location.
0123:             * @param kind one of the FIXUP_xxx codes.
0124:             * @param label varies - typically the target of jump. */
0125:            public final void fixupAdd(int kind, Label label) {
0126:                fixupAdd(kind, PC, label);
0127:            }
0128:
0129:            final void fixupAdd(int kind, int offset, Label label) {
0130:                int count = fixup_count;
0131:                if (count == 0) {
0132:                    fixup_offsets = new int[30];
0133:                    fixup_labels = new Label[30];
0134:                } else if (fixup_count == fixup_offsets.length) {
0135:                    int new_length = 2 * count;
0136:                    Label[] new_labels = new Label[new_length];
0137:                    System.arraycopy(fixup_labels, 0, new_labels, 0, count);
0138:                    fixup_labels = new_labels;
0139:                    int[] new_offsets = new int[new_length];
0140:                    System.arraycopy(fixup_offsets, 0, new_offsets, 0, count);
0141:                    fixup_offsets = new_offsets;
0142:                }
0143:                fixup_offsets[count] = (offset << 4) | kind;
0144:                fixup_labels[count] = label;
0145:                fixup_count = count + 1;
0146:            }
0147:
0148:            private final int fixupOffset(int index) {
0149:                return fixup_offsets[index] >> 4;
0150:            }
0151:
0152:            private final int fixupKind(int index) {
0153:                return fixup_offsets[index] & 15;
0154:            }
0155:
0156:            /** If true we get a line number entry for each instruction.
0157:             * Normally false, but can be a convenient hack to allow instruction-level
0158:             * stepping/debugging and stacktraces.  In this case {@code LINE==PC}. */
0159:            public static boolean instructionLineMode = false;
0160:
0161:            /** The stack of currently active conditionals. */
0162:            IfState if_stack;
0163:
0164:            /** The stack of currently active try statements. */
0165:            TryState try_stack;
0166:
0167:            public final Method getMethod() {
0168:                return (Method) getContainer();
0169:            }
0170:
0171:            public final int getPC() {
0172:                return PC;
0173:            }
0174:
0175:            public final int getSP() {
0176:                return SP;
0177:            }
0178:
0179:            public final ConstantPool getConstants() {
0180:                return getMethod().classfile.constants;
0181:            }
0182:
0183:            /* True if we cannot fall through to bytes[PC] -
0184:               the previous instruction was an uncondition control transfer.  */
0185:            private boolean unreachable_here;
0186:
0187:            /** True if control could reach here. */
0188:            public final boolean reachableHere() {
0189:                return !unreachable_here;
0190:            }
0191:
0192:            public final void setReachable(boolean val) {
0193:                unreachable_here = !val;
0194:            }
0195:
0196:            public final void setUnreachable() {
0197:                unreachable_here = true;
0198:            }
0199:
0200:            /** Get the maximum number of words on the operand stack in this method. */
0201:            public int getMaxStack() {
0202:                return max_stack;
0203:            }
0204:
0205:            /** Get the maximum number of local variable words in this method. */
0206:            public int getMaxLocals() {
0207:                return max_locals;
0208:            }
0209:
0210:            /** Set the maximum number of words on the operand stack in this method. */
0211:            public void setMaxStack(int n) {
0212:                max_stack = n;
0213:            }
0214:
0215:            /** Set the maximum number of local variable words in this method. */
0216:            public void setMaxLocals(int n) {
0217:                max_locals = n;
0218:            }
0219:
0220:            /** Get the code (instruction bytes) of this method.
0221:             * Does not make a copy. */
0222:            public byte[] getCode() {
0223:                return code;
0224:            }
0225:
0226:            /** Set the code (instruction bytes) of this method.
0227:             * @param code the code bytes (which are not copied).
0228:             * Implicitly calls setCodeLength(code.length). */
0229:            public void setCode(byte[] code) {
0230:                this .code = code;
0231:                this .PC = code.length;
0232:            }
0233:
0234:            /** Set the length the the code (instruction bytes) of this method.
0235:             * That is the number of current used bytes in getCode().
0236:             * (Any remaing bytes provide for future growth.) */
0237:            public void setCodeLength(int len) {
0238:                PC = len;
0239:            }
0240:
0241:            /** Set the current lengthof the code (instruction bytes) of this method. */
0242:            public int getCodeLength() {
0243:                return PC;
0244:            }
0245:
0246:            public CodeAttr(Method meth) {
0247:                super ("Code");
0248:                addToFrontOf(meth);
0249:                meth.code = this ;
0250:            }
0251:
0252:            public final void reserve(int bytes) {
0253:                if (code == null)
0254:                    code = new byte[100 + bytes];
0255:                else if (PC + bytes > code.length) {
0256:                    byte[] new_code = new byte[2 * code.length + bytes];
0257:                    System.arraycopy(code, 0, new_code, 0, PC);
0258:                    code = new_code;
0259:                }
0260:            }
0261:
0262:            /** Get opcode that implements NOT (x OPCODE y). */
0263:            byte invert_opcode(byte opcode) {
0264:                if ((opcode >= 153 && opcode <= 166)
0265:                        || (opcode >= 198 && opcode <= 199))
0266:                    return (byte) (opcode ^ 1);
0267:                throw new Error("unknown opcode to invert_opcode");
0268:            }
0269:
0270:            /**
0271:             * Write an 8-bit byte to the current code-stream.
0272:             * @param i the byte to write
0273:             */
0274:            public final void put1(int i) {
0275:                code[PC++] = (byte) i;
0276:                unreachable_here = false;
0277:            }
0278:
0279:            /**
0280:             * Write a 16-bit short to the current code-stream
0281:             * @param i the value to write
0282:             */
0283:            public final void put2(int i) {
0284:                code[PC++] = (byte) (i >> 8);
0285:                code[PC++] = (byte) (i);
0286:                unreachable_here = false;
0287:            }
0288:
0289:            /**
0290:             * Write a 32-bit int to the current code-stream
0291:             * @param i the value to write
0292:             */
0293:            public final void put4(int i) {
0294:                code[PC++] = (byte) (i >> 24);
0295:                code[PC++] = (byte) (i >> 16);
0296:                code[PC++] = (byte) (i >> 8);
0297:
0298:                code[PC++] = (byte) (i);
0299:                unreachable_here = false;
0300:            }
0301:
0302:            public final void putIndex2(CpoolEntry cnst) {
0303:                put2(cnst.index);
0304:            }
0305:
0306:            public final void putLineNumber(String filename, int linenumber) {
0307:                getMethod().classfile.setSourceFile(filename);
0308:                putLineNumber(linenumber);
0309:            }
0310:
0311:            public final void putLineNumber(int linenumber) {
0312:                if (sourceDbgExt != null)
0313:                    linenumber = sourceDbgExt.fixLine(linenumber);
0314:                fixupAdd(FIXUP_LINE_PC, null);
0315:                fixupAdd(FIXUP_LINE_NUMBER, linenumber, null);
0316:            }
0317:
0318:            public final void pushType(Type type) {
0319:                if (type.size == 0)
0320:                    throw new Error("pushing void type onto stack");
0321:                if (stack_types == null)
0322:                    stack_types = new Type[20];
0323:                else if (SP + 1 >= stack_types.length) {
0324:                    Type[] new_array = new Type[2 * stack_types.length];
0325:                    System.arraycopy(stack_types, 0, new_array, 0, SP);
0326:                    stack_types = new_array;
0327:                }
0328:                if (type.size == 8)
0329:                    stack_types[SP++] = Type.void_type;
0330:                stack_types[SP++] = type;
0331:                if (SP > max_stack)
0332:                    max_stack = SP;
0333:            }
0334:
0335:            public final Type popType() {
0336:                if (SP <= 0)
0337:                    throw new Error("popType called with empty stack "
0338:                            + getMethod());
0339:                Type type = stack_types[--SP];
0340:                if (type.size == 8)
0341:                    if (!popType().isVoid())
0342:                        throw new Error("missing void type on stack");
0343:                return type;
0344:            }
0345:
0346:            public final Type topType() {
0347:                return stack_types[SP - 1];
0348:            }
0349:
0350:            /** Compile code to pop values off the stack (and ignore them).
0351:             * @param nvalues the number of values (not words) to pop
0352:             */
0353:            public void emitPop(int nvalues) {
0354:                for (; nvalues > 0; --nvalues) {
0355:                    reserve(1);
0356:                    Type type = popType();
0357:                    if (type.size > 4)
0358:                        put1(88); // pop2
0359:                    else if (nvalues > 1) { // optimization:  can we pop 2 4-byte words using a pop2
0360:                        Type type2 = popType();
0361:                        if (type2.size > 4) {
0362:                            put1(87); // pop
0363:                            reserve(1);
0364:                        }
0365:                        put1(88); // pop2
0366:                        --nvalues;
0367:                    } else
0368:                        put1(87); // pop
0369:                }
0370:            }
0371:
0372:            /** Get a new Label for the current location.
0373:             * Unlike Label.define, Does not change reachableHere().
0374:             */
0375:            public Label getLabel() {
0376:                boolean unreachable = unreachable_here;
0377:                Label label = new Label();
0378:                label.define(this );
0379:                unreachable_here = unreachable;
0380:                return label;
0381:            }
0382:
0383:            public void emitSwap() {
0384:                reserve(1);
0385:                Type type1 = popType();
0386:                Type type2 = popType();
0387:
0388:                if (type1.size > 4 || type2.size > 4) {
0389:                    // There is no swap instruction in the JVM for this case.
0390:                    // Fall back to a more convoluted way.
0391:                    pushType(type2);
0392:                    pushType(type1);
0393:                    emitDupX();
0394:                    emitPop(1);
0395:                } else {
0396:                    pushType(type1);
0397:                    put1(95); // swap
0398:                    pushType(type2);
0399:                }
0400:            }
0401:
0402:            /** Emit code to duplicate the top element of the stack. */
0403:            public void emitDup() {
0404:                reserve(1);
0405:
0406:                Type type = topType();
0407:                put1(type.size <= 4 ? 89 : 92); // dup or dup2
0408:                pushType(type);
0409:            }
0410:
0411:            /** Emit code to duplicate the top element of the stack
0412:                and place the copy before the previous element. */
0413:            public void emitDupX() {
0414:                reserve(1);
0415:
0416:                Type type = popType();
0417:                Type skipedType = popType();
0418:
0419:                if (skipedType.size <= 4)
0420:                    put1(type.size <= 4 ? 90 : 93); // dup_x1 or dup2_x1
0421:                else
0422:                    put1(type.size <= 4 ? 91 : 94); // dup_x2 or dup2_x2
0423:
0424:                pushType(type);
0425:                pushType(skipedType);
0426:                pushType(type);
0427:            }
0428:
0429:            /** Compile code to duplicate with offset.
0430:             * @param size the size of the stack item to duplicate (1 or 2)
0431:             * @param offset where to insert the result (must be 0, 1, or 2)
0432:             * The new words get inserted at stack[SP-size-offset]
0433:             */
0434:            public void emitDup(int size, int offset) {
0435:                if (size == 0)
0436:                    return;
0437:                reserve(1);
0438:                // copied1 and (optionally copied2) are the types of the duplicated words
0439:                Type copied1 = popType();
0440:                Type copied2 = null;
0441:                if (size == 1) {
0442:                    if (copied1.size > 4)
0443:                        throw new Error("using dup for 2-word type");
0444:                } else if (size != 2)
0445:                    throw new Error("invalid size to emitDup");
0446:                else if (copied1.size <= 4) {
0447:                    copied2 = popType();
0448:                    if (copied2.size > 4)
0449:                        throw new Error("dup will cause invalid types on stack");
0450:                }
0451:
0452:                int kind;
0453:                // These are the types of the words (in any) that are "skipped":
0454:                Type skipped1 = null;
0455:                Type skipped2 = null;
0456:                if (offset == 0) {
0457:                    kind = size == 1 ? 89 : 92; // dup or dup2
0458:                } else if (offset == 1) {
0459:                    kind = size == 1 ? 90 : 93; // dup_x1 or dup2_x1
0460:                    skipped1 = popType();
0461:                    if (skipped1.size > 4)
0462:                        throw new Error("dup will cause invalid types on stack");
0463:                } else if (offset == 2) {
0464:                    kind = size == 1 ? 91 : 94; // dup_x2 or dup2_x2
0465:                    skipped1 = popType();
0466:                    if (skipped1.size <= 4) {
0467:                        skipped2 = popType();
0468:                        if (skipped2.size > 4)
0469:                            throw new Error(
0470:                                    "dup will cause invalid types on stack");
0471:                    }
0472:                } else
0473:                    throw new Error("emitDup:  invalid offset");
0474:
0475:                put1(kind);
0476:                if (copied2 != null)
0477:                    pushType(copied2);
0478:                pushType(copied1);
0479:                if (skipped2 != null)
0480:                    pushType(skipped2);
0481:                if (skipped1 != null)
0482:                    pushType(skipped1);
0483:                if (copied2 != null)
0484:                    pushType(copied2);
0485:                pushType(copied1);
0486:            }
0487:
0488:            /**
0489:             * Compile code to duplicate the top 1 or 2 words.
0490:             * @param size number of words to duplicate
0491:             */
0492:            public void emitDup(int size) {
0493:                emitDup(size, 0);
0494:            }
0495:
0496:            public void emitDup(Type type) {
0497:                emitDup(type.size > 4 ? 2 : 1, 0);
0498:            }
0499:
0500:            public void enterScope(Scope scope) {
0501:                scope.setStartPC(this );
0502:                locals.enterScope(scope);
0503:            }
0504:
0505:            public Scope pushScope() {
0506:                Scope scope = new Scope();
0507:                if (locals == null)
0508:                    locals = new LocalVarsAttr(getMethod());
0509:                enterScope(scope);
0510:                if (locals.parameter_scope == null)
0511:                    locals.parameter_scope = scope;
0512:                return scope;
0513:            }
0514:
0515:            public Scope getCurrentScope() {
0516:                return locals.current_scope;
0517:            }
0518:
0519:            public Scope popScope() {
0520:                Scope scope = locals.current_scope;
0521:                locals.current_scope = scope.parent;
0522:                scope.freeLocals(this );
0523:                scope.end = getLabel();
0524:                return scope;
0525:            }
0526:
0527:            /** Get the index'th parameter. */
0528:            public Variable getArg(int index) {
0529:                return locals.parameter_scope.getVariable(index);
0530:            }
0531:
0532:            /**
0533:             * Search by name for a Variable
0534:             * @param name name to search for
0535:             * @return the Variable, or null if not found (in any scope of this Method).
0536:             */
0537:            public Variable lookup(String name) {
0538:                Scope scope = locals.current_scope;
0539:                for (; scope != null; scope = scope.parent) {
0540:                    Variable var = scope.lookup(name);
0541:                    if (var != null)
0542:                        return var;
0543:                }
0544:                return null;
0545:            }
0546:
0547:            /** Add a new local variable (in the current scope).
0548:             * @param type type of the new Variable.
0549:             * @return the new Variable. */
0550:            public Variable addLocal(Type type) {
0551:                return locals.current_scope.addVariable(this , type, null);
0552:            }
0553:
0554:            /** Add a new local variable (in the current scope).
0555:             * @param type type of the new Variable.
0556:             * @param name name of the new Variable.
0557:             * @return the new Variable. */
0558:            public Variable addLocal(Type type, String name) {
0559:                return locals.current_scope.addVariable(this , type, name);
0560:            }
0561:
0562:            /** Call addLocal for parameters (as implied by method type). */
0563:            public void addParamLocals() {
0564:                Method method = getMethod();
0565:                if ((method.access_flags & Access.STATIC) == 0)
0566:                    addLocal(method.classfile).setParameter(true);
0567:                int arg_count = method.arg_types.length;
0568:                for (int i = 0; i < arg_count; i++)
0569:                    addLocal(method.arg_types[i]).setParameter(true);
0570:            }
0571:
0572:            public final void emitPushConstant(int val, Type type) {
0573:                switch (type.getSignature().charAt(0)) {
0574:                case 'B':
0575:                case 'C':
0576:                case 'I':
0577:                case 'Z':
0578:                case 'S':
0579:                    emitPushInt(val);
0580:                    break;
0581:                case 'J':
0582:                    emitPushLong((long) val);
0583:                    break;
0584:                case 'F':
0585:                    emitPushFloat((float) val);
0586:                    break;
0587:                case 'D':
0588:                    emitPushDouble((double) val);
0589:                    break;
0590:                default:
0591:                    throw new Error("bad type to emitPushConstant");
0592:                }
0593:            }
0594:
0595:            /* Low-level method to pust a ConstantPool entry.
0596:             * Does not do the appropriatre <code>pushType</code>. */
0597:            public final void emitPushConstant(CpoolEntry cnst) {
0598:                reserve(3);
0599:                int index = cnst.index;
0600:                if (cnst instanceof  CpoolValue2) {
0601:                    put1(20); // ldc2_w
0602:                    put2(index);
0603:                } else if (index < 256) {
0604:                    put1(18); // ldc
0605:                    put1(index);
0606:                } else {
0607:                    put1(19); // ldc_w
0608:                    put2(index);
0609:                }
0610:            }
0611:
0612:            public final void emitPushInt(int i) {
0613:                reserve(3);
0614:                if (i >= -1 && i <= 5)
0615:                    put1(i + 3); // iconst_m1 .. iconst_5
0616:                else if (i >= -128 && i < 128) {
0617:                    put1(16); // bipush
0618:                    put1(i);
0619:                } else if (i >= -32768 && i < 32768) {
0620:                    put1(17); // sipush
0621:                    put2(i);
0622:                } else {
0623:                    emitPushConstant(getConstants().addInt(i));
0624:                }
0625:                pushType(Type.int_type);
0626:            }
0627:
0628:            public void emitPushLong(long i) {
0629:                if (i == 0 || i == 1) {
0630:                    reserve(1);
0631:                    put1(9 + (int) i); // lconst_0 .. lconst_1
0632:                } else if ((long) (int) i == i) {
0633:                    emitPushInt((int) i);
0634:                    reserve(1);
0635:                    popType();
0636:                    put1(133); // i2l
0637:                } else {
0638:                    emitPushConstant(getConstants().addLong(i));
0639:                }
0640:                pushType(Type.long_type);
0641:            }
0642:
0643:            public void emitPushFloat(float x) {
0644:                int xi = (int) x;
0645:                if ((float) xi == x && xi >= -128 && xi < 128) {
0646:                    if (xi >= 0 && xi <= 2) {
0647:                        reserve(1);
0648:                        put1(11 + xi); // fconst_0 .. fconst_2
0649:                        if (xi == 0 && Float.floatToIntBits(x) != 0) // x == -0.0
0650:                        {
0651:                            reserve(1);
0652:                            put1(118); // fneg
0653:                        }
0654:                    } else {
0655:                        // Saves space in the constant pool
0656:                        // Probably faster, at least on modern CPUs.
0657:                        emitPushInt(xi);
0658:                        reserve(1);
0659:                        popType();
0660:                        put1(134); // i2f
0661:                    }
0662:                } else {
0663:                    emitPushConstant(getConstants().addFloat(x));
0664:                }
0665:                pushType(Type.float_type);
0666:            }
0667:
0668:            public void emitPushDouble(double x) {
0669:                int xi = (int) x;
0670:                if ((double) xi == x && xi >= -128 && xi < 128) {
0671:                    if (xi == 0 || xi == 1) {
0672:                        reserve(1);
0673:                        put1(14 + xi); // dconst_0 or dconst_1
0674:                        if (xi == 0 && Double.doubleToLongBits(x) != 0L) // x == -0.0
0675:                        {
0676:                            reserve(1);
0677:                            put1(119); // dneg
0678:                        }
0679:                    } else {
0680:                        // Saves space in the constant pool
0681:                        // Probably faster, at least on modern CPUs.
0682:                        emitPushInt(xi);
0683:                        reserve(1);
0684:                        popType();
0685:                        put1(135); // i2d
0686:                    }
0687:                } else {
0688:                    emitPushConstant(getConstants().addDouble(x));
0689:                }
0690:                pushType(Type.double_type);
0691:            }
0692:
0693:            /** Calculate how many CONSTANT_String constants we need for a string.
0694:             * Each CONSTANT_String can be at most 0xFFFF bytes (as a UTF8 string).
0695:             * Returns a String, where each char, coerced to an int, is the length
0696:             * of a substring of the input that is at most 0xFFFF bytes.
0697:             */
0698:            public static final String calculateSplit(String str) {
0699:                int strLength = str.length();
0700:                StringBuffer sbuf = new StringBuffer(20);
0701:                // Where the current segments starts, as an index in 'str':
0702:                int segmentStart = 0;
0703:                int byteLength = 0; // Length in bytes of current segment so far.
0704:                for (int i = 0; i < strLength; i++) {
0705:                    char ch = str.charAt(i);
0706:                    int bytes = ch >= 0x0800 ? 3 : ch >= 0x0080 || ch == 0 ? 2
0707:                            : 1;
0708:                    if (byteLength + bytes > 0xFFFF) {
0709:                        sbuf.append((char) (i - segmentStart));
0710:                        segmentStart = i;
0711:                        byteLength = 0;
0712:                    }
0713:                    byteLength += bytes;
0714:                }
0715:                sbuf.append((char) (strLength - segmentStart));
0716:                return sbuf.toString();
0717:            }
0718:
0719:            /** Emit code to push the value of a constant String.
0720:             * Uses CONSTANT_String and CONSTANT_Utf8 constant pool entries as needed.
0721:             * Can handle Strings whose UTF8 length is greates than 0xFFFF bytes
0722:             * (the limit of a CONSTANT_Utf8) by generating String concatenation.
0723:             */
0724:            public final void emitPushString(String str) {
0725:                if (str == null)
0726:                    emitPushNull();
0727:                else {
0728:                    int length = str.length();
0729:                    String segments = calculateSplit(str);
0730:                    int numSegments = segments.length();
0731:                    if (numSegments <= 1)
0732:                        emitPushConstant(getConstants().addString(str));
0733:                    else {
0734:                        if (numSegments == 2) {
0735:                            int firstSegment = (int) segments.charAt(0);
0736:                            emitPushString(str.substring(0, firstSegment));
0737:                            emitPushString(str.substring(firstSegment));
0738:                            Method concatMethod = Type.string_type
0739:                                    .getDeclaredMethod("concat", 1);
0740:                            emitInvokeVirtual(concatMethod);
0741:                        } else {
0742:                            ClassType sbufType = ClassType
0743:                                    .make("java.lang.StringBuffer");
0744:                            emitNew(sbufType);
0745:                            emitDup(sbufType);
0746:                            emitPushInt(length);
0747:                            Type[] args1 = { Type.int_type };
0748:                            emitInvokeSpecial(sbufType.getDeclaredMethod(
0749:                                    "<init>", args1));
0750:                            Type[] args2 = { Type.string_type };
0751:                            Method appendMethod = sbufType.getDeclaredMethod(
0752:                                    "append", args2);
0753:                            int segStart = 0;
0754:                            for (int seg = 0; seg < numSegments; seg++) {
0755:                                emitDup(sbufType);
0756:                                int segEnd = segStart
0757:                                        + (int) segments.charAt(seg);
0758:                                emitPushString(str.substring(segStart, segEnd));
0759:                                emitInvokeVirtual(appendMethod);
0760:                                segStart = segEnd;
0761:                            }
0762:                            emitInvokeVirtual(Type.toString_method);
0763:                        }
0764:                        if (str == str.intern())
0765:                            emitInvokeVirtual(Type.string_type
0766:                                    .getDeclaredMethod("intern", 0));
0767:                        return;
0768:                    }
0769:                    pushType(Type.string_type);
0770:                }
0771:            }
0772:
0773:            /** Push a class constant pool entry.
0774:             * This is only supported by JDK 1.5 and later. */
0775:            public final void emitPushClass(String name) {
0776:                emitPushConstant(getConstants().addClass(name));
0777:                pushType(Type.java_lang_Class_type);
0778:            }
0779:
0780:            public void emitPushNull() {
0781:                reserve(1);
0782:                put1(1); // aconst_null
0783:                pushType(Type.pointer_type);
0784:            }
0785:
0786:            public final void emitPushThis() {
0787:                reserve(1);
0788:                put1(42); // aload_0
0789:                pushType(getMethod().getDeclaringClass());
0790:            }
0791:
0792:            /** Emit code to push a constant primitive array.
0793:             * @param value The array value that we want the emitted code to re-create.
0794:             * @param arrayType The ArrayType that matches value.
0795:             */
0796:            public final void emitPushPrimArray(Object value,
0797:                    ArrayType arrayType) {
0798:                Type elementType = arrayType.getComponentType();
0799:                int len = java.lang.reflect.Array.getLength(value);
0800:                emitPushInt(len);
0801:                emitNewArray(elementType);
0802:                char sig = elementType.getSignature().charAt(0);
0803:                for (int i = 0; i < len; i++) {
0804:                    long ival = 0;
0805:                    float fval = 0;
0806:                    double dval = 0;
0807:                    switch (sig) {
0808:                    case 'J':
0809:                        ival = ((long[]) value)[i];
0810:                        if (ival == 0)
0811:                            continue;
0812:                        break;
0813:                    case 'I':
0814:                        ival = ((int[]) value)[i];
0815:                        if (ival == 0)
0816:                            continue;
0817:                        break;
0818:                    case 'S':
0819:                        ival = ((short[]) value)[i];
0820:                        if (ival == 0)
0821:                            continue;
0822:                        break;
0823:                    case 'C':
0824:                        ival = ((char[]) value)[i];
0825:                        if (ival == 0)
0826:                            continue;
0827:                        break;
0828:                    case 'B':
0829:                        ival = ((byte[]) value)[i];
0830:                        if (ival == 0)
0831:                            continue;
0832:                        break;
0833:                    case 'Z':
0834:                        ival = ((boolean[]) value)[i] ? 1 : 0;
0835:                        if (ival == 0)
0836:                            continue;
0837:                        break;
0838:                    case 'F':
0839:                        fval = ((float[]) value)[i];
0840:                        if (fval == 0.0)
0841:                            continue;
0842:                        break;
0843:                    case 'D':
0844:                        dval = ((double[]) value)[i];
0845:                        if (dval == 0.0)
0846:                            continue;
0847:                        break;
0848:                    }
0849:                    emitDup(arrayType);
0850:                    emitPushInt(i);
0851:                    switch (sig) {
0852:                    case 'Z':
0853:                    case 'C':
0854:                    case 'B':
0855:                    case 'S':
0856:                    case 'I':
0857:                        emitPushInt((int) ival);
0858:                        break;
0859:                    case 'J':
0860:                        emitPushLong(ival);
0861:                        break;
0862:                    case 'F':
0863:                        emitPushFloat(fval);
0864:                        break;
0865:                    case 'D':
0866:                        emitPushDouble(dval);
0867:                        break;
0868:                    }
0869:                    emitArrayStore(elementType);
0870:                }
0871:            }
0872:
0873:            void emitNewArray(int type_code) {
0874:                reserve(2);
0875:                put1(188); // newarray
0876:                put1(type_code);
0877:            }
0878:
0879:            public final void emitArrayLength() {
0880:                if (!(popType() instanceof  ArrayType))
0881:                    throw new Error("non-array type in emitArrayLength");
0882:
0883:                reserve(1);
0884:                put1(190); // arraylength
0885:                pushType(Type.int_type);
0886:            }
0887:
0888:            /* Returns an integer in the range 0 (for 'int') through 4 (for object
0889:               reference) to 7 (for 'short') which matches the pattern of how JVM
0890:               opcodes typically depend on the operand type. */
0891:
0892:            private int adjustTypedOp(char sig) {
0893:                switch (sig) {
0894:                case 'I':
0895:                    return 0; // int
0896:                case 'J':
0897:                    return 1; // long
0898:                case 'F':
0899:                    return 2; // float
0900:                case 'D':
0901:                    return 3; // double
0902:                default:
0903:                    return 4; // object
0904:                case 'B':
0905:                case 'Z':
0906:                    return 5; // byte or boolean
0907:                case 'C':
0908:                    return 6; // char
0909:                case 'S':
0910:                    return 7; // short
0911:                }
0912:            }
0913:
0914:            private int adjustTypedOp(Type type) {
0915:                return adjustTypedOp(type.getSignature().charAt(0));
0916:            }
0917:
0918:            private void emitTypedOp(int op, Type type) {
0919:                reserve(1);
0920:                put1(op + adjustTypedOp(type));
0921:            }
0922:
0923:            private void emitTypedOp(int op, char sig) {
0924:                reserve(1);
0925:                put1(op + adjustTypedOp(sig));
0926:            }
0927:
0928:            /** Store into an element of an array.
0929:             * Must already have pushed the array reference, the index,
0930:             * and the new value (in that order).
0931:             * Stack:  ..., array, index, value => ...
0932:             */
0933:            public void emitArrayStore(Type element_type) {
0934:                popType(); // Pop new value
0935:                popType(); // Pop index
0936:                popType(); // Pop array reference
0937:                emitTypedOp(79, element_type);
0938:            }
0939:
0940:            /** Load an element from an array.
0941:             * Must already have pushed the array and the index (in that order):
0942:             * Stack:  ..., array, index => ..., value */
0943:            public void emitArrayLoad(Type element_type) {
0944:                popType(); // Pop index
0945:                popType(); // Pop array reference
0946:                emitTypedOp(46, element_type);
0947:                pushType(element_type);
0948:            }
0949:
0950:            /**
0951:             * Invoke new on a class type.
0952:             * Does not call the constructor!
0953:             * @param type the desired new object type
0954:             */
0955:            public void emitNew(ClassType type) {
0956:                reserve(3);
0957:                put1(187); // new
0958:                putIndex2(getConstants().addClass(type));
0959:                pushType(type);
0960:            }
0961:
0962:            /** Compile code to allocate a new array.
0963:             * The size should have been already pushed on the stack.
0964:             * @param element_type type of the array elements
0965:             */
0966:            public void emitNewArray(Type element_type, int dims) {
0967:                if (popType().promote() != Type.int_type)
0968:                    throw new Error("non-int dim. spec. in emitNewArray");
0969:
0970:                if (element_type instanceof  PrimType) {
0971:                    int code;
0972:                    switch (element_type.getSignature().charAt(0)) {
0973:                    case 'B':
0974:                        code = 8;
0975:                        break;
0976:                    case 'S':
0977:                        code = 9;
0978:                        break;
0979:                    case 'I':
0980:                        code = 10;
0981:                        break;
0982:                    case 'J':
0983:                        code = 11;
0984:                        break;
0985:                    case 'F':
0986:                        code = 6;
0987:                        break;
0988:                    case 'D':
0989:                        code = 7;
0990:                        break;
0991:                    case 'Z':
0992:                        code = 4;
0993:                        break;
0994:                    case 'C':
0995:                        code = 5;
0996:                        break;
0997:                    default:
0998:                        throw new Error("bad PrimType in emitNewArray");
0999:                    }
1000:                    emitNewArray(code);
1001:                } else if (element_type instanceof  ObjectType) {
1002:                    reserve(3);
1003:                    put1(189); // anewarray
1004:                    putIndex2(getConstants()
1005:                            .addClass((ObjectType) element_type));
1006:                } else if (element_type instanceof  ArrayType) {
1007:                    reserve(4);
1008:                    put1(197); // multianewarray
1009:                    putIndex2(getConstants().addClass(
1010:                            new ArrayType(element_type)));
1011:                    if (dims < 1 || dims > 255)
1012:                        throw new Error("dims out of range in emitNewArray");
1013:                    put1(dims);
1014:                    while (--dims > 0)
1015:                        // first dim already popped
1016:                        if (popType().promote() != Type.int_type)
1017:                            throw new Error(
1018:                                    "non-int dim. spec. in emitNewArray");
1019:                } else
1020:                    throw new Error("unimplemented type in emitNewArray");
1021:
1022:                pushType(new ArrayType(element_type));
1023:            }
1024:
1025:            public void emitNewArray(Type element_type) {
1026:                emitNewArray(element_type, 1);
1027:            }
1028:
1029:            // We may want to deprecate this, because it depends on popType.
1030:            private void emitBinop(int base_code) {
1031:                Type type2 = popType().promote();
1032:                Type type1_raw = popType();
1033:                Type type1 = type1_raw.promote();
1034:                if (type1 != type2 || !(type1 instanceof  PrimType))
1035:                    throw new Error(
1036:                            "non-matching or bad types in binary operation");
1037:                emitTypedOp(base_code, type1);
1038:                pushType(type1_raw);
1039:            }
1040:
1041:            private void emitBinop(int base_code, char sig) {
1042:                popType();
1043:                popType();
1044:                emitTypedOp(base_code, sig);
1045:                pushType(Type.signatureToPrimitive(sig));
1046:            }
1047:
1048:            private void emitBinop(int base_code, Type type) {
1049:                popType();
1050:                popType();
1051:                emitTypedOp(base_code, type);
1052:                pushType(type);
1053:            }
1054:
1055:            // public final void emitIntAdd () { put1(96); popType();}
1056:            // public final void emitLongAdd () { put1(97); popType();}
1057:            // public final void emitFloatAdd () { put1(98); popType();}
1058:            // public final void emitDoubleAdd () { put1(99); popType();}
1059:
1060:            public final void emitAdd(char sig) {
1061:                emitBinop(96, sig);
1062:            }
1063:
1064:            public final void emitAdd(PrimType type) {
1065:                emitBinop(96, type);
1066:            }
1067:
1068:            /** @deprecated */
1069:            public final void emitAdd() {
1070:                emitBinop(96);
1071:            }
1072:
1073:            public final void emitSub(char sig) {
1074:                emitBinop(100, sig);
1075:            }
1076:
1077:            public final void emitSub(PrimType type) {
1078:                emitBinop(100, type);
1079:            }
1080:
1081:            /** @deprecated */
1082:            public final void emitSub() {
1083:                emitBinop(100);
1084:            }
1085:
1086:            public final void emitMul() {
1087:                emitBinop(104);
1088:            }
1089:
1090:            public final void emitDiv() {
1091:                emitBinop(108);
1092:            }
1093:
1094:            public final void emitRem() {
1095:                emitBinop(112);
1096:            }
1097:
1098:            public final void emitAnd() {
1099:                emitBinop(126);
1100:            }
1101:
1102:            public final void emitIOr() {
1103:                emitBinop(128);
1104:            }
1105:
1106:            public final void emitXOr() {
1107:                emitBinop(130);
1108:            }
1109:
1110:            public final void emitShl() {
1111:                emitShift(120);
1112:            }
1113:
1114:            public final void emitShr() {
1115:                emitShift(122);
1116:            }
1117:
1118:            public final void emitUshr() {
1119:                emitShift(124);
1120:            }
1121:
1122:            private void emitShift(int base_code) {
1123:                Type type2 = popType().promote();
1124:                Type type1_raw = popType();
1125:                Type type1 = type1_raw.promote();
1126:
1127:                if (type1 != Type.int_type && type1 != Type.long_type)
1128:                    throw new Error(
1129:                            "the value shifted must be an int or a long");
1130:
1131:                if (type2 != Type.int_type)
1132:                    throw new Error("the amount of shift must be an int");
1133:
1134:                emitTypedOp(base_code, type1);
1135:                pushType(type1_raw);
1136:            }
1137:
1138:            public final void emitNot(Type type) {
1139:                emitPushConstant(1, type);
1140:                emitAdd();
1141:                emitPushConstant(1, type);
1142:                emitAnd();
1143:            }
1144:
1145:            public void emitPrimop(int opcode, int arg_count, Type retType) {
1146:                reserve(1);
1147:                while (--arg_count >= 0)
1148:                    popType();
1149:                put1(opcode);
1150:                pushType(retType);
1151:            }
1152:
1153:            void emitMaybeWide(int opcode, int index) {
1154:                if (index >= 256) {
1155:                    put1(196); // wide
1156:                    put1(opcode);
1157:                    put2(index);
1158:                } else {
1159:                    put1(opcode);
1160:                    put1(index);
1161:                }
1162:            }
1163:
1164:            /**
1165:             * Compile code to push the contents of a local variable onto the statck.
1166:             * @param var The variable whose contents we want to push.
1167:             */
1168:            public final void emitLoad(Variable var) {
1169:                if (var.dead())
1170:                    throw new Error("attempting to push dead variable");
1171:                int offset = var.offset;
1172:                if (offset < 0 || !var.isSimple())
1173:                    throw new Error(
1174:                            "attempting to load from unassigned variable "
1175:                                    + var + " simple:" + var.isSimple()
1176:                                    + ", offset: " + offset);
1177:                Type type = var.getType().promote();
1178:                reserve(4);
1179:                int kind = adjustTypedOp(type);
1180:                if (offset <= 3)
1181:                    put1(26 + 4 * kind + offset); // [ilfda]load_[0123]
1182:                else
1183:                    emitMaybeWide(21 + kind, offset); // [ilfda]load
1184:                pushType(var.getType());
1185:            }
1186:
1187:            public void emitStore(Variable var) {
1188:                if (var.dead())
1189:                    throw new Error("attempting to push dead variable");
1190:                int offset = var.offset;
1191:                if (offset < 0 || !var.isSimple())
1192:                    throw new Error("attempting to store in unassigned " + var
1193:                            + " simple:" + var.isSimple() + ", offset: "
1194:                            + offset);
1195:                Type type = var.getType().promote();
1196:                reserve(4);
1197:                popType();
1198:                int kind = adjustTypedOp(type);
1199:                if (offset <= 3)
1200:                    put1(59 + 4 * kind + offset); // [ilfda]store_[0123]
1201:                else
1202:                    emitMaybeWide(54 + kind, offset); // [ilfda]store
1203:            }
1204:
1205:            public void emitInc(Variable var, short inc) {
1206:                if (var.dead())
1207:                    throw new Error("attempting to increment dead variable");
1208:                int offset = var.offset;
1209:                if (offset < 0 || !var.isSimple())
1210:                    throw new Error(
1211:                            "attempting to increment unassigned variable"
1212:                                    + var.getName() + " simple:"
1213:                                    + var.isSimple() + ", offset: " + offset);
1214:                Type type = var.getType().promote();
1215:                reserve(6);
1216:                if (type != Type.int_type)
1217:                    throw new Error("attempting to increment non-int variable");
1218:
1219:                boolean wide = offset > 255 || inc > 255 || inc < -256;
1220:
1221:                if (wide) {
1222:                    put1(196); // wide
1223:                    put1(132); // iinc
1224:                    put2(offset);
1225:                    put2(inc);
1226:                } else {
1227:                    put1(132); // iinc
1228:                    put1(offset);
1229:                    put1(inc);
1230:                }
1231:            }
1232:
1233:            private final void emitFieldop(Field field, int opcode) {
1234:                reserve(3);
1235:                put1(opcode);
1236:                putIndex2(getConstants().addFieldRef(field));
1237:            }
1238:
1239:            /** Compile code to get a static field value.
1240:             * Stack:  ... => ..., value */
1241:
1242:            public final void emitGetStatic(Field field) {
1243:                pushType(field.type);
1244:                emitFieldop(field, 178); // getstatic
1245:            }
1246:
1247:            /** Compile code to get a non-static field value.
1248:             * Stack:  ..., objectref => ..., value */
1249:
1250:            public final void emitGetField(Field field) {
1251:                popType();
1252:                pushType(field.type);
1253:                emitFieldop(field, 180); // getfield
1254:            }
1255:
1256:            /** Compile code to put a static field value.
1257:             * Stack:  ..., value => ... */
1258:
1259:            public final void emitPutStatic(Field field) {
1260:                popType();
1261:                emitFieldop(field, 179); // putstatic
1262:            }
1263:
1264:            /** Compile code to put a non-static field value.
1265:             * Stack:  ..., objectref, value => ... */
1266:
1267:            public final void emitPutField(Field field) {
1268:                popType();
1269:                popType();
1270:                emitFieldop(field, 181); // putfield
1271:            }
1272:
1273:            /** Comptes the number of stack words taken by a list of types. */
1274:            private int words(Type[] types) {
1275:                int res = 0;
1276:                for (int i = types.length; --i >= 0;)
1277:                    if (types[i].size > 4)
1278:                        res += 2;
1279:                    else
1280:                        res++;
1281:                return res;
1282:            }
1283:
1284:            public void emitInvokeMethod(Method method, int opcode) {
1285:                reserve(opcode == 185 ? 5 : 3);
1286:                int arg_count = method.arg_types.length;
1287:                boolean is_invokestatic = opcode == 184;
1288:                if (is_invokestatic != ((method.access_flags & Access.STATIC) != 0))
1289:                    throw new Error(
1290:                            "emitInvokeXxx static flag mis-match method.flags="
1291:                                    + method.access_flags);
1292:                if (!is_invokestatic)
1293:                    arg_count++;
1294:                put1(opcode); // invokevirtual, invokespecial, or invokestatic
1295:                putIndex2(getConstants().addMethodRef(method));
1296:                if (opcode == 185) // invokeinterface
1297:                {
1298:                    put1(words(method.arg_types) + 1); // 1 word for 'this'
1299:                    put1(0);
1300:                }
1301:                while (--arg_count >= 0)
1302:                    popType();
1303:                if (method.return_type.size != 0)
1304:                    pushType(method.return_type);
1305:            }
1306:
1307:            public void emitInvoke(Method method) {
1308:                int opcode;
1309:                if ((method.access_flags & Access.STATIC) != 0)
1310:                    opcode = 184; // invokestatic
1311:                else if (method.classfile.isInterface())
1312:                    opcode = 185; // invokeinterface
1313:                else if ("<init>".equals(method.getName()))
1314:                    opcode = 183; // invokespecial
1315:                else
1316:                    opcode = 182; // invokevirtual
1317:                emitInvokeMethod(method, opcode);
1318:            }
1319:
1320:            /** Compile a virtual method call.
1321:             * The stack contains the 'this' object, followed by the arguments in order.
1322:             * @param method the method to invoke virtually
1323:             */
1324:            public void emitInvokeVirtual(Method method) {
1325:                emitInvokeMethod(method, 182); // invokevirtual
1326:            }
1327:
1328:            public void emitInvokeSpecial(Method method) {
1329:                emitInvokeMethod(method, 183); // invokespecial
1330:            }
1331:
1332:            /** Compile a static method call.
1333:             * The stack contains the the arguments in order.
1334:             * @param method the static method to invoke
1335:             */
1336:            public void emitInvokeStatic(Method method) {
1337:                emitInvokeMethod(method, 184); // invokestatic
1338:            }
1339:
1340:            public void emitInvokeInterface(Method method) {
1341:                emitInvokeMethod(method, 185); // invokeinterface
1342:            }
1343:
1344:            final void emitTransfer(Label label, int opcode) {
1345:                fixupAdd(FIXUP_TRANSFER, label);
1346:                put1(opcode);
1347:                PC += 2;
1348:            }
1349:
1350:            /** Compile an unconditional branch (goto).
1351:             * @param label target of the branch (must be in this method).
1352:             */
1353:            public final void emitGoto(Label label) {
1354:                fixupAdd(FIXUP_GOTO, label);
1355:                reserve(3);
1356:                put1(167);
1357:                PC += 2;
1358:                setUnreachable();
1359:            }
1360:
1361:            public final void emitJsr(Label label) {
1362:                fixupAdd(FIXUP_JSR, label);
1363:                reserve(3);
1364:                put1(168);
1365:                PC += 2;
1366:            }
1367:
1368:            public final void emitGotoIfCompare1(Label label, int opcode) {
1369:                popType();
1370:                reserve(3);
1371:                emitTransfer(label, opcode);
1372:            }
1373:
1374:            public final void emitGotoIfIntEqZero(Label label) {
1375:                emitGotoIfCompare1(label, 153);
1376:            }
1377:
1378:            public final void emitGotoIfIntNeZero(Label label) {
1379:                emitGotoIfCompare1(label, 154);
1380:            }
1381:
1382:            public final void emitGotoIfIntLtZero(Label label) {
1383:                emitGotoIfCompare1(label, 155);
1384:            }
1385:
1386:            public final void emitGotoIfIntGeZero(Label label) {
1387:                emitGotoIfCompare1(label, 156);
1388:            }
1389:
1390:            public final void emitGotoIfIntGtZero(Label label) {
1391:                emitGotoIfCompare1(label, 157);
1392:            }
1393:
1394:            public final void emitGotoIfIntLeZero(Label label) {
1395:                emitGotoIfCompare1(label, 158);
1396:            }
1397:
1398:            public final void emitGotoIfCompare2(Label label, int logop) {
1399:                if (logop < 153 || logop > 158)
1400:                    throw new Error(
1401:                            "emitGotoIfCompare2: logop must be one of ifeq...ifle");
1402:
1403:                Type type2 = popType().promote();
1404:                Type type1 = popType().promote();
1405:                reserve(4);
1406:                char sig1 = type1.getSignature().charAt(0);
1407:                char sig2 = type2.getSignature().charAt(0);
1408:
1409:                boolean cmpg = (logop == 155 || logop == 158); // iflt,ifle
1410:
1411:                if (sig1 == 'I' && sig2 == 'I')
1412:                    logop += 6; // iflt -> if_icmplt etc.
1413:                else if (sig1 == 'J' && sig2 == 'J')
1414:                    put1(148); // lcmp
1415:                else if (sig1 == 'F' && sig2 == 'F')
1416:                    put1(cmpg ? 149 : 150); // fcmpl/fcmpg
1417:                else if (sig1 == 'D' && sig2 == 'D')
1418:                    put1(cmpg ? 151 : 152); // dcmpl/dcmpg
1419:                else if ((sig1 == 'L' || sig1 == '[')
1420:                        && (sig2 == 'L' || sig2 == '[') && logop <= 154)
1421:                    logop += 12; // ifeq->if_acmpeq, ifne->if_acmpne
1422:                else
1423:                    throw new Error("invalid types to emitGotoIfCompare2");
1424:
1425:                emitTransfer(label, logop);
1426:            }
1427:
1428:            // binary comparisons
1429:            /** @deprecated */
1430:            public final void emitGotoIfEq(Label label, boolean invert) {
1431:                emitGotoIfCompare2(label, invert ? 154 : 153);
1432:            }
1433:
1434:            /** Compile a conditional transfer if 2 top stack elements are equal. */
1435:            public final void emitGotoIfEq(Label label) {
1436:                emitGotoIfCompare2(label, 153);
1437:            }
1438:
1439:            /** Compile conditional transfer if 2 top stack elements are not equal. */
1440:            public final void emitGotoIfNE(Label label) {
1441:                emitGotoIfCompare2(label, 154);
1442:            }
1443:
1444:            public final void emitGotoIfLt(Label label) {
1445:                emitGotoIfCompare2(label, 155);
1446:            }
1447:
1448:            public final void emitGotoIfGe(Label label) {
1449:                emitGotoIfCompare2(label, 156);
1450:            }
1451:
1452:            public final void emitGotoIfGt(Label label) {
1453:                emitGotoIfCompare2(label, 157);
1454:            }
1455:
1456:            public final void emitGotoIfLe(Label label) {
1457:                emitGotoIfCompare2(label, 158);
1458:            }
1459:
1460:            /** Compile start of a conditional:
1461:             *   <tt>if (!(<var>x</var> opcode 0)) ...</tt>.
1462:             * The value of <var>x</var> must already have been pushed. */
1463:            public final void emitIfCompare1(int opcode) {
1464:                IfState new_if = new IfState(this );
1465:                if (popType().promote() != Type.int_type)
1466:                    throw new Error("non-int type to emitIfCompare1");
1467:                reserve(3);
1468:                emitTransfer(new_if.end_label, opcode);
1469:                new_if.start_stack_size = SP;
1470:            }
1471:
1472:            /** Compile start of conditional:  <tt>if (x != 0) ...</tt>.
1473:             * Also use this if you have pushed a boolean value:  if (b) ... */
1474:            public final void emitIfIntNotZero() {
1475:                emitIfCompare1(153); // ifeq
1476:            }
1477:
1478:            /** Compile start of conditional:  <tt>if (x == 0) ...</tt>.
1479:             * Also use this if you have pushed a boolean value:  if (!b) ... */
1480:            public final void emitIfIntEqZero() {
1481:                emitIfCompare1(154); // ifne
1482:            }
1483:
1484:            /** Compile start of conditional:  <tt>if (x <= 0)</tt>. */
1485:            public final void emitIfIntLEqZero() {
1486:                emitIfCompare1(157); // ifgt
1487:            }
1488:
1489:            /** Compile start of a conditional:  <tt>if (!(x opcode null)) ...</tt>.
1490:             * The value of <tt>x</tt> must already have been pushed and must be of
1491:             * reference type. */
1492:            public final void emitIfRefCompare1(int opcode) {
1493:                IfState new_if = new IfState(this );
1494:                if (!(popType() instanceof  ObjectType))
1495:                    throw new Error("non-ref type to emitIfRefCompare1");
1496:                reserve(3);
1497:                emitTransfer(new_if.end_label, opcode);
1498:                new_if.start_stack_size = SP;
1499:            }
1500:
1501:            /** Compile start of conditional:  if (x != null) */
1502:            public final void emitIfNotNull() {
1503:                emitIfRefCompare1(198); // ifnull
1504:            }
1505:
1506:            /** Compile start of conditional:  if (x == null) */
1507:            public final void emitIfNull() {
1508:                emitIfRefCompare1(199); // ifnonnull
1509:            }
1510:
1511:            /** Compile start of a conditional:  if (!(x OPCODE y)) ...
1512:             * The value of x and y must already have been pushed. */
1513:            public final void emitIfIntCompare(int opcode) {
1514:                IfState new_if = new IfState(this );
1515:                popType();
1516:                popType();
1517:                reserve(3);
1518:                emitTransfer(new_if.end_label, opcode);
1519:                new_if.start_stack_size = SP;
1520:            }
1521:
1522:            /* Compile start of a conditional:  if (x < y) ... */
1523:            public final void emitIfIntLt() {
1524:                emitIfIntCompare(162); // if_icmpge
1525:            }
1526:
1527:            /** Compile start of a conditional:  if (x != y) ...
1528:             * The values of x and y must already have been pushed. */
1529:            public final void emitIfNEq() {
1530:                IfState new_if = new IfState(this );
1531:                emitGotoIfEq(new_if.end_label);
1532:                new_if.start_stack_size = SP;
1533:            }
1534:
1535:            /** Compile start of a conditional:  if (x == y) ...
1536:             * The values of x and y must already have been pushed. */
1537:            public final void emitIfEq() {
1538:                IfState new_if = new IfState(this );
1539:                emitGotoIfNE(new_if.end_label);
1540:                new_if.start_stack_size = SP;
1541:            }
1542:
1543:            /** Compile start of a conditional:  if (x < y) ...
1544:             * The values of x and y must already have been pushed. */
1545:            public final void emitIfLt() {
1546:                IfState new_if = new IfState(this );
1547:                emitGotoIfGe(new_if.end_label);
1548:                new_if.start_stack_size = SP;
1549:            }
1550:
1551:            /** Compile start of a conditional:  if (x >= y) ...
1552:             * The values of x and y must already have been pushed. */
1553:            public final void emitIfGe() {
1554:                IfState new_if = new IfState(this );
1555:                emitGotoIfLt(new_if.end_label);
1556:                new_if.start_stack_size = SP;
1557:            }
1558:
1559:            /** Compile start of a conditional:  if (x > y) ...
1560:             * The values of x and y must already have been pushed. */
1561:            public final void emitIfGt() {
1562:                IfState new_if = new IfState(this );
1563:                emitGotoIfLe(new_if.end_label);
1564:                new_if.start_stack_size = SP;
1565:            }
1566:
1567:            /** Compile start of a conditional:  if (x <= y) ...
1568:             * The values of x and y must already have been pushed. */
1569:            public final void emitIfLe() {
1570:                IfState new_if = new IfState(this );
1571:                emitGotoIfGt(new_if.end_label);
1572:                new_if.start_stack_size = SP;
1573:            }
1574:
1575:            /** Emit a 'ret' instruction.
1576:             * @param var the variable containing the return address */
1577:            public void emitRet(Variable var) {
1578:                int offset = var.offset;
1579:                if (offset < 256) {
1580:                    reserve(2);
1581:                    put1(169); // ret
1582:                    put1(offset);
1583:                } else {
1584:                    reserve(4);
1585:                    put1(196); // wide
1586:                    put1(169); // ret
1587:                    put2(offset);
1588:                }
1589:            }
1590:
1591:            public final void emitThen() {
1592:                if_stack.start_stack_size = SP;
1593:            }
1594:
1595:            public final void emitIfThen() {
1596:                new IfState(this , null);
1597:            }
1598:
1599:            /** Compile start of else clause. */
1600:            public final void emitElse() {
1601:                Label else_label = if_stack.end_label;
1602:                Label end_label = new Label(this );
1603:                if_stack.end_label = end_label;
1604:                if (reachableHere()) {
1605:                    int growth = SP - if_stack.start_stack_size;
1606:                    if_stack.stack_growth = growth;
1607:                    if (growth > 0) {
1608:                        if_stack.then_stacked_types = new Type[growth];
1609:                        System.arraycopy(stack_types,
1610:                                if_stack.start_stack_size,
1611:                                if_stack.then_stacked_types, 0, growth);
1612:                    } else
1613:                        if_stack.then_stacked_types = new Type[0]; // ???
1614:                    emitGoto(end_label);
1615:                }
1616:                while (SP > if_stack.start_stack_size)
1617:                    popType();
1618:                SP = if_stack.start_stack_size;
1619:                if (else_label != null)
1620:                    else_label.define(this );
1621:                if_stack.doing_else = true;
1622:            }
1623:
1624:            /** Compile end of conditional. */
1625:            public final void emitFi() {
1626:                boolean make_unreachable = false;
1627:                if (!if_stack.doing_else) { // There was no 'else' clause.
1628:                    if (reachableHere() && SP != if_stack.start_stack_size)
1629:                        throw new Error(
1630:                                "at PC "
1631:                                        + PC
1632:                                        + " then clause grows stack with no else clause");
1633:                } else if (if_stack.then_stacked_types != null) {
1634:                    int then_clause_stack_size = if_stack.start_stack_size
1635:                            + if_stack.stack_growth;
1636:                    if (!reachableHere()) {
1637:                        if (if_stack.stack_growth > 0)
1638:                            System.arraycopy(if_stack.then_stacked_types, 0,
1639:                                    stack_types, if_stack.start_stack_size,
1640:                                    if_stack.stack_growth);
1641:                        SP = then_clause_stack_size;
1642:                    } else if (SP != then_clause_stack_size)
1643:                        throw new Error("at PC " + PC
1644:                                + ": SP at end of 'then' was "
1645:                                + then_clause_stack_size
1646:                                + " while SP at end of 'else' was " + SP);
1647:                } else if (unreachable_here)
1648:                    make_unreachable = true;
1649:
1650:                if (if_stack.end_label != null)
1651:                    if_stack.end_label.define(this );
1652:                if (make_unreachable)
1653:                    setUnreachable();
1654:                // Pop the if_stack.
1655:                if_stack = if_stack.previous;
1656:            }
1657:
1658:            public final void emitConvert(Type from, Type to) {
1659:                String to_sig = to.getSignature();
1660:                String from_sig = from.getSignature();
1661:                int op = -1;
1662:                if (to_sig.length() == 1 || from_sig.length() == 1) {
1663:                    char to_sig0 = to_sig.charAt(0);
1664:                    char from_sig0 = from_sig.charAt(0);
1665:                    if (from_sig0 == to_sig0)
1666:                        return;
1667:                    if (from.size < 4)
1668:                        from_sig0 = 'I';
1669:                    if (to.size < 4) {
1670:                        emitConvert(from, Type.int_type);
1671:                        from_sig0 = 'I';
1672:                    }
1673:                    if (from_sig0 == to_sig0)
1674:                        return;
1675:                    switch (from_sig0) {
1676:                    case 'I':
1677:                        switch (to_sig0) {
1678:                        case 'B':
1679:                            op = 145;
1680:                            break; // i2b
1681:                        case 'C':
1682:                            op = 146;
1683:                            break; // i2c
1684:                        case 'S':
1685:                            op = 147;
1686:                            break; // i2s
1687:                        case 'J':
1688:                            op = 133;
1689:                            break; // i2l
1690:                        case 'F':
1691:                            op = 134;
1692:                            break; // i2f
1693:                        case 'D':
1694:                            op = 135;
1695:                            break; // i2d
1696:                        }
1697:                        break;
1698:                    case 'J':
1699:                        switch (to_sig0) {
1700:                        case 'I':
1701:                            op = 136;
1702:                            break; // l2i
1703:                        case 'F':
1704:                            op = 137;
1705:                            break; // l2f
1706:                        case 'D':
1707:                            op = 138;
1708:                            break; // l2d
1709:                        }
1710:                        break;
1711:                    case 'F':
1712:                        switch (to_sig0) {
1713:                        case 'I':
1714:                            op = 139;
1715:                            break; // f2i
1716:                        case 'J':
1717:                            op = 140;
1718:                            break; // f2l
1719:                        case 'D':
1720:                            op = 141;
1721:                            break; // f2d
1722:                        }
1723:                        break;
1724:                    case 'D':
1725:                        switch (to_sig0) {
1726:                        case 'I':
1727:                            op = 142;
1728:                            break; // d2i
1729:                        case 'J':
1730:                            op = 143;
1731:                            break; // d2l
1732:                        case 'F':
1733:                            op = 144;
1734:                            break; // d2f
1735:                        }
1736:                        break;
1737:                    }
1738:                }
1739:                if (op < 0)
1740:                    throw new Error("unsupported CodeAttr.emitConvert");
1741:                reserve(1);
1742:                popType();
1743:                put1(op);
1744:                pushType(to);
1745:            }
1746:
1747:            private void emitCheckcast(Type type, int opcode) {
1748:                reserve(3);
1749:                popType();
1750:                put1(opcode);
1751:                if (type instanceof  ArrayType) {
1752:                    ArrayType atype = (ArrayType) type;
1753:                    CpoolUtf8 name = getConstants().addUtf8(atype.signature);
1754:                    putIndex2(getConstants().addClass(name));
1755:                } else if (type instanceof  ClassType) {
1756:                    putIndex2(getConstants().addClass((ClassType) type));
1757:                } else
1758:                    throw new Error("unimplemented type " + type
1759:                            + " in emitCheckcast/emitInstanceof");
1760:            }
1761:
1762:            public static boolean castNeeded(Type top, Type required) {
1763:                for (;;) {
1764:                    if (required instanceof  ClassType
1765:                            && top instanceof  ClassType
1766:                            && ((ClassType) top)
1767:                                    .isSubclass((ClassType) required))
1768:                        return false;
1769:                    else if (required instanceof  ArrayType
1770:                            && top instanceof  ArrayType) {
1771:                        required = ((ArrayType) required).getComponentType();
1772:                        top = ((ArrayType) top).getComponentType();
1773:                        continue;
1774:                    }
1775:                    return true;
1776:                }
1777:            }
1778:
1779:            public void emitCheckcast(Type type) {
1780:                if (castNeeded(topType(), type)) {
1781:                    emitCheckcast(type, 192);
1782:                    pushType(type);
1783:                }
1784:            }
1785:
1786:            public void emitInstanceof(Type type) {
1787:                emitCheckcast(type, 193);
1788:                pushType(Type.boolean_type);
1789:            }
1790:
1791:            public final void emitThrow() {
1792:                popType();
1793:                reserve(1);
1794:                put1(191); // athrow
1795:                setUnreachable();
1796:            }
1797:
1798:            public final void emitMonitorEnter() {
1799:                popType();
1800:                reserve(1);
1801:                put1(194); // monitorenter
1802:            }
1803:
1804:            public final void emitMonitorExit() {
1805:                popType();
1806:                reserve(1);
1807:                put1(195); // monitorexit
1808:            }
1809:
1810:            /** Call pending finalizer functions.
1811:             * @param limit Only call finalizers more recent than this.
1812:             */
1813:            public void doPendingFinalizers(TryState limit) {
1814:                TryState stack = try_stack;
1815:
1816:                /* If a value is returned, it must be saved to a local variable,
1817:                   to prevent a verification error because of inconsistent stack sizes.
1818:                 */
1819:                boolean saveResult = !getMethod().getReturnType().isVoid();
1820:                Variable result = null;
1821:
1822:                while (stack != limit) {
1823:                    if (stack.finally_subr != null // there is a finally block
1824:                            && stack.finally_ret_addr == null) // 'return' is not inside it
1825:                    {
1826:                        if (saveResult && result == null) {
1827:                            result = addLocal(topType());
1828:                            emitStore(result);
1829:                        }
1830:                        emitJsr(stack.finally_subr);
1831:                    }
1832:
1833:                    stack = stack.previous;
1834:                }
1835:
1836:                if (result != null)
1837:                    emitLoad(result);
1838:                // We'd like to do freeLocal on the result Variable, but then we risk
1839:                // it being re-used in a finalizer, which would trash its value.  We
1840:                // don't have any convenient way to to do that (the pending Scope
1841:                // mechanism is over-kill), we for now we just leak the Variable.
1842:            }
1843:
1844:            /**
1845:             * Compile a method return.
1846:             * If inside a 'catch' clause, first call 'finally' clauses.
1847:             * The return value (unless the return type is void) must be on the stack,
1848:             * and have the correct type.
1849:             */
1850:            public final void emitReturn() {
1851:                doPendingFinalizers(null);
1852:                if (getMethod().getReturnType().size == 0) {
1853:                    reserve(1);
1854:                    put1(177); // return
1855:                } else
1856:                    emitTypedOp(172, popType().promote());
1857:                setUnreachable();
1858:            }
1859:
1860:            /** Add an exception handler. */
1861:            public void addHandler(int start_pc, int end_pc, int handler_pc,
1862:                    int catch_type) {
1863:                int index = 4 * exception_table_length;
1864:                if (exception_table == null) {
1865:                    exception_table = new short[20];
1866:                } else if (exception_table.length <= index) {
1867:                    short[] new_table = new short[2 * exception_table.length];
1868:                    System.arraycopy(exception_table, 0, new_table, 0, index);
1869:                    exception_table = new_table;
1870:                }
1871:                exception_table[index++] = (short) start_pc;
1872:                exception_table[index++] = (short) end_pc;
1873:                exception_table[index++] = (short) handler_pc;
1874:                exception_table[index++] = (short) catch_type;
1875:                exception_table_length++;
1876:            }
1877:
1878:            /** Add an exception handler. */
1879:            public void addHandler(Label start_try, Label end_try,
1880:                    ClassType catch_type) {
1881:                ConstantPool constants = getConstants();
1882:                int catch_type_index;
1883:                if (catch_type == null)
1884:                    catch_type_index = 0;
1885:                else
1886:                    catch_type_index = constants.addClass(catch_type).index;
1887:                fixupAdd(FIXUP_TRY, start_try);
1888:                fixupAdd(FIXUP_CATCH, catch_type_index, end_try);
1889:            }
1890:
1891:            /** Beginning of code that has a cleanup handler.
1892:             * This is similar to a try-finally, but the cleanup is only
1893:             * done in the case of an exception.  Alternatively, the try clause
1894:             * has to manually do the cleanup with code duplication.
1895:             * Equivalent to: <code>try <var>body</var> catch (Throwable ex) { <var>cleanup</var>; throw ex; }</code>
1896:             * Call <code>emitWithCleanupStart</code> before the <code><var>body</var></code>.
1897:             */
1898:            public void emitWithCleanupStart() {
1899:                int savedSP = SP;
1900:                SP = 0;
1901:                emitTryStart(false, null);
1902:                SP = savedSP;
1903:            }
1904:
1905:            /** Called after a <code><var>body</var></code> that has a <code><var>cleanup</var></code> clause.
1906:             * Followed by the <code><var>cleanup</var></code> code.
1907:             */
1908:            public void emitWithCleanupCatch(Variable catchVar) {
1909:                emitTryEnd();
1910:                Type[] savedTypes;
1911:                if (SP > 0) {
1912:                    savedTypes = new Type[SP];
1913:                    System.arraycopy(stack_types, 0, savedTypes, 0, SP);
1914:                    SP = 0;
1915:                } else
1916:                    savedTypes = null;
1917:                try_stack.savedTypes = savedTypes;
1918:
1919:                try_stack.saved_result = catchVar;
1920:                int save_SP = SP;
1921:                emitCatchStart(catchVar);
1922:            }
1923:
1924:            /** Called after generating a <code><var>cleanup</var></code> handler. */
1925:
1926:            public void emitWithCleanupDone() {
1927:                Variable catchVar = try_stack.saved_result;
1928:                try_stack.saved_result = null;
1929:                if (catchVar != null)
1930:                    emitLoad(catchVar);
1931:                emitThrow();
1932:                emitCatchEnd();
1933:                Type[] savedTypes = try_stack.savedTypes;
1934:                emitTryCatchEnd();
1935:                if (savedTypes != null) {
1936:                    SP = savedTypes.length;
1937:                    if (SP >= stack_types.length)
1938:                        stack_types = savedTypes;
1939:                    else
1940:                        System.arraycopy(savedTypes, 0, stack_types, 0, SP);
1941:                } else
1942:                    SP = 0;
1943:            }
1944:
1945:            public void emitTryStart(boolean has_finally, Type result_type) {
1946:                if (result_type != null && result_type.isVoid())
1947:                    result_type = null;
1948:                Variable[] savedStack = null;
1949:                if (result_type != null || SP > 0)
1950:                    pushScope();
1951:                if (SP > 0) {
1952:                    savedStack = new Variable[SP];
1953:                    int i = 0;
1954:                    while (SP > 0) {
1955:                        Variable var = addLocal(topType());
1956:                        emitStore(var);
1957:                        savedStack[i++] = var;
1958:                    }
1959:                }
1960:                TryState try_state = new TryState(this );
1961:                try_state.savedStack = savedStack;
1962:                if (result_type != null)
1963:                    try_state.saved_result = addLocal(result_type);
1964:                if (has_finally)
1965:                    try_state.finally_subr = new Label();
1966:            }
1967:
1968:            public void emitTryEnd() {
1969:                if (try_stack.end_label == null) {
1970:                    if (try_stack.saved_result != null && reachableHere())
1971:                        emitStore(try_stack.saved_result);
1972:                    try_stack.end_label = new Label();
1973:                    if (reachableHere()) {
1974:                        if (try_stack.finally_subr != null)
1975:                            emitJsr(try_stack.finally_subr);
1976:                        emitGoto(try_stack.end_label);
1977:                    }
1978:                    try_stack.end_try = getLabel();
1979:                }
1980:            }
1981:
1982:            public void emitCatchStart(Variable var) {
1983:                emitTryEnd();
1984:                SP = 0;
1985:                if (try_stack.try_type != null)
1986:                    emitCatchEnd();
1987:                ClassType type = var == null ? null : (ClassType) var.getType();
1988:                try_stack.try_type = type;
1989:                addHandler(try_stack.start_try, try_stack.end_try, type);
1990:                if (var != null) {
1991:                    pushType(type);
1992:                    emitStore(var);
1993:                } else
1994:                    pushType(Type.throwable_type);
1995:            }
1996:
1997:            public void emitCatchEnd() {
1998:                if (reachableHere()) {
1999:                    if (try_stack.saved_result != null)
2000:                        emitStore(try_stack.saved_result);
2001:                    if (try_stack.finally_subr != null)
2002:                        emitJsr(try_stack.finally_subr);
2003:                    emitGoto(try_stack.end_label);
2004:                }
2005:                try_stack.try_type = null;
2006:            }
2007:
2008:            public void emitFinallyStart() {
2009:                emitTryEnd();
2010:                if (try_stack.try_type != null)
2011:                    emitCatchEnd();
2012:                SP = 0;
2013:                try_stack.end_try = getLabel();
2014:
2015:                pushScope();
2016:                Type except_type = Type.pointer_type;
2017:                Variable except = addLocal(except_type);
2018:                emitCatchStart(null);
2019:                emitStore(except);
2020:                emitJsr(try_stack.finally_subr);
2021:                emitLoad(except);
2022:                emitThrow();
2023:
2024:                try_stack.finally_subr.define(this );
2025:                Type ret_addr_type = Type.pointer_type;
2026:                try_stack.finally_ret_addr = addLocal(ret_addr_type);
2027:                pushType(ret_addr_type);
2028:                emitStore(try_stack.finally_ret_addr);
2029:            }
2030:
2031:            public void emitFinallyEnd() {
2032:                emitRet(try_stack.finally_ret_addr);
2033:                setUnreachable();
2034:                popScope();
2035:                try_stack.finally_subr = null;
2036:            }
2037:
2038:            public void emitTryCatchEnd() {
2039:                if (try_stack.finally_subr != null)
2040:                    emitFinallyEnd();
2041:                try_stack.end_label.define(this );
2042:                Variable[] vars = try_stack.savedStack;
2043:                if (vars != null) {
2044:                    for (int i = vars.length; --i >= 0;) {
2045:                        Variable v = vars[i];
2046:                        if (v != null) {
2047:                            emitLoad(v);
2048:                        }
2049:                    }
2050:                }
2051:                if (try_stack.saved_result != null)
2052:                    emitLoad(try_stack.saved_result);
2053:                if (try_stack.saved_result != null || vars != null)
2054:                    popScope();
2055:                try_stack = try_stack.previous;
2056:            }
2057:
2058:            public final TryState getCurrentTry() {
2059:                return try_stack;
2060:            }
2061:
2062:            public final boolean isInTry() {
2063:                // This also return true if we're in  a catch clause, but that is
2064:                // good enough for now.
2065:                return try_stack != null;
2066:            }
2067:
2068:            /** Compile a tail-call to position 0 of the current procedure.
2069:             * @param pop_args if true, copy argument registers (except this) from stack.
2070:             * @param scope Scope whose start we jump back to. */
2071:            public void emitTailCall(boolean pop_args, Scope scope) {
2072:                if (pop_args) {
2073:                    Method meth = getMethod();
2074:                    int arg_slots = ((meth.access_flags & Access.STATIC) != 0) ? 0
2075:                            : 1;
2076:                    for (int i = meth.arg_types.length; --i >= 0;)
2077:                        arg_slots += meth.arg_types[i].size > 4 ? 2 : 1;
2078:                    for (int i = meth.arg_types.length; --i >= 0;) {
2079:                        arg_slots -= meth.arg_types[i].size > 4 ? 2 : 1;
2080:                        emitStore(locals.used[arg_slots]);
2081:                    }
2082:                }
2083:                emitGoto(scope.start);
2084:            }
2085:
2086:            public void processFixups() {
2087:                if (fixup_count == 0)
2088:                    return;
2089:
2090:                // For each label, set it to its maximum limit, assuming all
2091:                // fixups causes the code the be expanded.  We need a prepass
2092:                // for this, since FIXUP_MOVEs can cause code to be reordered.
2093:                // Also, convert each FIXUP_MOVE_TO_END to FIXUP_MOVE.
2094:
2095:                int delta = 0;
2096:                int instruction_tail = fixup_count;
2097:                fixupAdd(CodeAttr.FIXUP_MOVE, 0, null);
2098:
2099:                loop1: for (int i = 0;;) {
2100:                    int offset = fixup_offsets[i];
2101:                    int kind = offset & 15;
2102:                    offset >>= 4;
2103:                    Label label = fixup_labels[i];
2104:                    switch (kind) {
2105:                    case FIXUP_TRY:
2106:                    case FIXUP_LINE_PC:
2107:                        i++;
2108:                    case FIXUP_NONE:
2109:                    case FIXUP_CASE:
2110:                    case FIXUP_DELETE3:
2111:                        break;
2112:                    case FIXUP_DEFINE:
2113:                        label.position += delta;
2114:                        break;
2115:                    case FIXUP_SWITCH:
2116:                        delta += 3; // May need to add up to 3 padding bytes.
2117:                        break;
2118:                    case FIXUP_GOTO:
2119:                        // The first test fails in this case:  GOTO L2; L1: L2:  FIXME
2120:                        if (label.first_fixup == i + 1
2121:                                && fixupOffset(i + 1) == offset + 3) {
2122:                            // Optimize: GOTO L; L:
2123:                            fixup_offsets[i] = (offset << 4) | FIXUP_DELETE3;
2124:                            fixup_labels[i] = null;
2125:                            delta -= 3;
2126:                            break;
2127:                        }
2128:                        // ... else fall through ...
2129:                    case FIXUP_JSR:
2130:                        if (PC >= 0x8000)
2131:                            delta += 2; // May need to convert goto->goto_w, jsr->jsr_w.
2132:                        break;
2133:                    case FIXUP_TRANSFER:
2134:                        if (PC >= 0x8000)
2135:                            delta += 5; // May need to add a goto_w.
2136:                        break;
2137:                    case FIXUP_MOVE_TO_END:
2138:                        fixup_labels[instruction_tail] = fixup_labels[i + 1];
2139:                        instruction_tail = offset;
2140:                        // ... fall through ...
2141:                    case FIXUP_MOVE:
2142:                        int cur_pc = ((i + 1) >= fixup_count ? PC
2143:                                : fixupOffset(fixup_labels[i + 1].first_fixup));
2144:                        fixup_offsets[i] = (cur_pc << 4) | FIXUP_MOVE;
2145:                        if (label == null)
2146:                            break loop1;
2147:                        else {
2148:                            i = label.first_fixup;
2149:                            int next_pc = fixupOffset(i);
2150:                            delta = (cur_pc + delta) - next_pc;
2151:                            continue;
2152:                        }
2153:                    default:
2154:                        throw new Error("unexpected fixup");
2155:                    }
2156:                    i++;
2157:                }
2158:                // Next a loop to fix the position of each label, and calculate
2159:                // the exact number of code bytes.
2160:
2161:                // Number of bytes to be inserted or (if negative) removed, so far.
2162:                int new_size = PC;
2163:                // Current delta between final PC and offset in generate code array.
2164:                delta = 0;
2165:                loop2: for (int i = 0; i < fixup_count;) {
2166:                    int offset = fixup_offsets[i];
2167:                    int kind = offset & 15;
2168:                    Label label = fixup_labels[i];
2169:                    if (label != null && label.position < 0)
2170:                        throw new Error("undefined label " + label);
2171:                    while (label != null
2172:                            && kind >= FIXUP_GOTO
2173:                            && kind <= FIXUP_TRANSFER2
2174:                            && label.first_fixup + 1 < fixup_count
2175:                            && (fixup_offsets[label.first_fixup + 1] == ((fixup_offsets[label.first_fixup] & 15) | FIXUP_GOTO))) {
2176:                        // Optimize  JUMP L; ... L:  GOTO X
2177:                        // (where the JUMP is any GOTO or other transfer)
2178:                        // by changing the JUMP L to JUMP X.
2179:                        label = fixup_labels[label.first_fixup + 1];
2180:                        fixup_labels[i] = label;
2181:                    }
2182:                    offset = offset >> 4;
2183:                    switch (kind) {
2184:                    case FIXUP_TRY:
2185:                    case FIXUP_LINE_PC:
2186:                        i++;
2187:                    case FIXUP_NONE:
2188:                    case FIXUP_CASE:
2189:                        break;
2190:                    case FIXUP_DELETE3:
2191:                        delta -= 3;
2192:                        new_size -= 3;
2193:                        break;
2194:                    case FIXUP_DEFINE:
2195:                        label.position = offset + delta;
2196:                        break;
2197:                    case FIXUP_SWITCH:
2198:                        int padding = 3 - (offset + delta) & 3;
2199:                        delta += padding;
2200:                        new_size += padding;
2201:                        break;
2202:                    case FIXUP_GOTO:
2203:                    case FIXUP_JSR:
2204:                    case FIXUP_TRANSFER:
2205:                        int rel = label.position - (offset + delta);
2206:                        if ((short) rel == rel) {
2207:                            fixup_offsets[i] = (offset << 4) | FIXUP_TRANSFER2;
2208:                        } else {
2209:                            delta += kind == FIXUP_TRANSFER ? 5 : 2; // need goto_w
2210:                            new_size += kind == FIXUP_TRANSFER ? 5 : 2; // need goto_w
2211:                        }
2212:                        break;
2213:                    case FIXUP_MOVE:
2214:                        if (label == null)
2215:                            break loop2;
2216:                        else {
2217:                            i = label.first_fixup;
2218:                            int next_pc = fixupOffset(i);
2219:                            delta = (offset + delta) - next_pc;
2220:                            continue;
2221:                        }
2222:                    default:
2223:                        throw new Error("unexpected fixup");
2224:                    }
2225:                    i++;
2226:                }
2227:
2228:                byte[] new_code = new byte[new_size];
2229:                int new_pc = 0;
2230:                int next_fixup_index = 0;
2231:                int next_fixup_offset = fixupOffset(0);
2232:                loop3: for (int old_pc = 0;;) {
2233:                    if (old_pc < next_fixup_offset) {
2234:                        new_code[new_pc++] = code[old_pc++];
2235:                    } else {
2236:                        int kind = fixup_offsets[next_fixup_index] & 15;
2237:                        Label label = fixup_labels[next_fixup_index];
2238:                        switch (kind) {
2239:                        case FIXUP_NONE:
2240:                        case FIXUP_DEFINE:
2241:                            break;
2242:                        case FIXUP_DELETE3:
2243:                            old_pc += 3;
2244:                            break;
2245:                        case FIXUP_TRANSFER2:
2246:                            delta = label.position - new_pc;
2247:                            new_code[new_pc++] = code[old_pc];
2248:                            new_code[new_pc++] = (byte) (delta >> 8);
2249:                            new_code[new_pc++] = (byte) (delta & 0xFF);
2250:                            old_pc += 3;
2251:                            break;
2252:                        case FIXUP_GOTO:
2253:                        case FIXUP_JSR:
2254:                        case FIXUP_TRANSFER:
2255:                            delta = label.position - new_pc;
2256:                            byte opcode = code[old_pc];
2257:                            if (kind == FIXUP_TRANSFER) {
2258:                                // convert: IF_xxx L to IF_NOT_xxx Lt; GOTO L; Lt:
2259:                                opcode = invert_opcode(opcode);
2260:                                new_code[new_pc++] = opcode;
2261:                                new_code[new_pc++] = 0;
2262:                                new_code[new_pc++] = 8; // 8 byte offset to Lt.
2263:                                opcode = (byte) 200; // goto_w
2264:                            } else {
2265:                                // Change goto to goto_w; jsr to jsr_w:
2266:                                opcode = (byte) (opcode + (200 - 167));
2267:                            }
2268:                            new_code[new_pc++] = opcode;
2269:                            new_code[new_pc++] = (byte) (delta >> 24);
2270:                            new_code[new_pc++] = (byte) (delta >> 16);
2271:                            new_code[new_pc++] = (byte) (delta >> 8);
2272:                            new_code[new_pc++] = (byte) (delta & 0xFF);
2273:                            old_pc += 3;
2274:                            break;
2275:                        case FIXUP_SWITCH:
2276:                            int padding = 3 - new_pc & 3;
2277:                            int switch_start = new_pc;
2278:                            new_code[new_pc++] = code[old_pc++];
2279:                            while (--padding >= 0)
2280:                                new_code[new_pc++] = 0;
2281:                            while (next_fixup_index < fixup_count
2282:                                    && fixupKind(next_fixup_index + 1) == FIXUP_CASE) {
2283:                                next_fixup_index++;
2284:                                int offset = fixupOffset(next_fixup_index);
2285:                                while (old_pc < offset)
2286:                                    new_code[new_pc++] = code[old_pc++];
2287:                                delta = (fixup_labels[next_fixup_index].position - switch_start);
2288:                                new_code[new_pc++] = (byte) (delta >> 24);
2289:                                new_code[new_pc++] = (byte) (delta >> 16);
2290:                                new_code[new_pc++] = (byte) (delta >> 8);
2291:                                new_code[new_pc++] = (byte) (delta & 0xFF);
2292:                                old_pc += 4;
2293:                            }
2294:                            break;
2295:                        case FIXUP_TRY:
2296:                            addHandler(
2297:                                    fixup_labels[next_fixup_index].position,
2298:                                    fixup_labels[next_fixup_index + 1].position,
2299:                                    new_pc, fixupOffset(next_fixup_index + 1));
2300:                            next_fixup_index++;
2301:                            break;
2302:                        case FIXUP_LINE_PC:
2303:                            if (lines == null)
2304:                                lines = new LineNumbersAttr(this );
2305:                            next_fixup_index++;
2306:                            lines.put(fixupOffset(next_fixup_index), new_pc);
2307:                            break;
2308:                        case FIXUP_MOVE:
2309:                            if (label == null)
2310:                                break loop3;
2311:                            else {
2312:                                next_fixup_index = label.first_fixup;
2313:                                old_pc = fixupOffset(next_fixup_index);
2314:                                next_fixup_offset = old_pc;
2315:                                if (label.position != new_pc)
2316:                                    throw new Error("bad pc");
2317:                                continue;
2318:                            }
2319:                        default:
2320:                            throw new Error("unexpected fixup");
2321:                        }
2322:                        next_fixup_index++;
2323:                        next_fixup_offset = fixupOffset(next_fixup_index);
2324:                    }
2325:                }
2326:                if (new_size != new_pc)
2327:                    throw new Error("PC confusion new_pc:" + new_pc
2328:                            + " new_size:" + new_size);
2329:                PC = new_size;
2330:                code = new_code;
2331:                fixup_count = 0;
2332:                fixup_labels = null;
2333:                fixup_offsets = null;
2334:            }
2335:
2336:            public void assignConstants(ClassType cl) {
2337:                if (locals != null && locals.container == null
2338:                        && !locals.isEmpty())
2339:                    locals.addToFrontOf(this );
2340:                processFixups();
2341:                if (instructionLineMode) {
2342:                    // A kludge to low-level debugging:
2343:                    // Define a "line number" for each instrction.
2344:                    if (lines == null)
2345:                        lines = new LineNumbersAttr(this );
2346:                    lines.linenumber_count = 0;
2347:                    int codeLen = getCodeLength();
2348:                    for (int i = 0; i < codeLen; i++)
2349:                        lines.put(i, i);
2350:                }
2351:                super .assignConstants(cl);
2352:                Attribute.assignConstants(this , cl);
2353:            }
2354:
2355:            public final int getLength() {
2356:                return 12 + getCodeLength() + 8 * exception_table_length
2357:                        + Attribute.getLengthAll(this );
2358:            }
2359:
2360:            public void write(DataOutputStream dstr) throws java.io.IOException {
2361:                dstr.writeShort(max_stack);
2362:                dstr.writeShort(max_locals);
2363:                dstr.writeInt(PC);
2364:                dstr.write(code, 0, PC);
2365:
2366:                dstr.writeShort(exception_table_length);
2367:                int count = exception_table_length;
2368:                for (int i = 0; --count >= 0; i += 4) {
2369:                    dstr.writeShort(exception_table[i]);
2370:                    dstr.writeShort(exception_table[i + 1]);
2371:                    dstr.writeShort(exception_table[i + 2]);
2372:                    dstr.writeShort(exception_table[i + 3]);
2373:                }
2374:
2375:                Attribute.writeAll(this , dstr);
2376:            }
2377:
2378:            public void print(ClassTypeWriter dst) {
2379:                dst.print("Attribute \"");
2380:                dst.print(getName());
2381:                dst.print("\", length:");
2382:                dst.print(getLength());
2383:                dst.print(", max_stack:");
2384:                dst.print(max_stack);
2385:                dst.print(", max_locals:");
2386:                dst.print(max_locals);
2387:                dst.print(", code_length:");
2388:                int length = getCodeLength();
2389:                dst.println(length);
2390:                disAssemble(dst, 0, length);
2391:                if (exception_table_length > 0) {
2392:                    dst.print("Exceptions (count: ");
2393:                    dst.print(exception_table_length);
2394:                    dst.println("):");
2395:                    int count = exception_table_length;
2396:                    for (int i = 0; --count >= 0; i += 4) {
2397:                        dst.print("  start: ");
2398:                        dst.print(exception_table[i] & 0xffff);
2399:                        dst.print(", end: ");
2400:                        dst.print(exception_table[i + 1] & 0xffff);
2401:                        dst.print(", handler: ");
2402:                        dst.print(exception_table[i + 2] & 0xffff);
2403:                        dst.print(", type: ");
2404:                        int catch_type_index = exception_table[i + 3] & 0xffff;
2405:                        if (catch_type_index == 0)
2406:                            dst.print("0 /* finally */");
2407:                        else {
2408:                            dst.printOptionalIndex(catch_type_index);
2409:                            dst.printConstantTersely(catch_type_index,
2410:                                    ConstantPool.CLASS);
2411:                        }
2412:                        dst.println();
2413:                    }
2414:                }
2415:                dst.printAttributes(this );
2416:            }
2417:
2418:            /* DEBUGGING:
2419:            public void disAssembleWithFixups (ClassTypeWriter dst)
2420:            {
2421:              if (fixup_count == 0)
2422:                {
2423:            disAssemble(dst, 0, PC);
2424:            return;
2425:                }
2426:              int prev_pc = 0;
2427:              for (int i = 0;  i < fixup_count; )
2428:                {
2429:            int offset = fixup_offsets[i];
2430:            int kind = offset & 15;
2431:            Label label = fixup_labels[i];
2432:            offset = offset >> 4;
2433:            int pc = offset;
2434:            if (kind == FIXUP_MOVE || kind == FIXUP_MOVE_TO_END)
2435:              pc = (i+1 >= fixup_count) ? PC : fixup_offsets[i+1] >> 4;
2436:            disAssemble(dst, prev_pc, offset);
2437:            prev_pc = pc;
2438:            dst.print("fixup#");  dst.print(i);
2439:            dst.print(" @");  dst.print(offset);
2440:            switch (kind)
2441:              {
2442:              case FIXUP_NONE:
2443:                dst.println(" NONE");
2444:                break;
2445:              case FIXUP_DEFINE:
2446:                dst.print(" DEFINE ");
2447:                dst.println(label);
2448:                break;
2449:              case FIXUP_SWITCH:
2450:                dst.println(" SWITCH");
2451:                break;
2452:              case FIXUP_CASE:
2453:                dst.println(" CASE");
2454:                break;
2455:              case FIXUP_GOTO:
2456:                dst.print(" GOTO ");
2457:                dst.println(label);
2458:                break;
2459:              case FIXUP_TRANSFER:
2460:                dst.print(" TRANSFER ");
2461:                dst.println(label);
2462:                break;
2463:              case FIXUP_TRANSFER2:
2464:                dst.print(" TRANSFER2 ");
2465:                dst.println(label);
2466:                break;
2467:              case FIXUP_DELETE3:
2468:                dst.println(" DELETE3");
2469:                break;
2470:              case FIXUP_MOVE:
2471:                dst.print(" MOVE ");
2472:                dst.println(label);
2473:                break;
2474:              case FIXUP_MOVE_TO_END:
2475:                dst.print(" MOVE_TO_END ");
2476:                dst.println(label);
2477:                break;
2478:              case FIXUP_TRY:
2479:                dst.print(" TRY start: ");
2480:                dst.println(label);
2481:                i++;
2482:                dst.print(" - end: ");
2483:                dst.print(fixup_labels[i]);
2484:                dst.print(" type: ");
2485:                dst.println(fixup_offsets[i] >> 4);
2486:                break;
2487:              case FIXUP_LINE_PC:
2488:                dst.print(" LINE ");
2489:                i++;
2490:                dst.println(fixup_offsets[i] >> 4);
2491:                break;
2492:              default:
2493:                dst.println(" kind:"+fixupKind(i)+" offset:"+fixupOffset(i)+" "+fixup_labels[i]);
2494:              }
2495:            i++;
2496:                }
2497:            }
2498:             */
2499:
2500:            public void disAssemble(ClassTypeWriter dst, int start, int limit) {
2501:                boolean wide = false;
2502:                for (int i = start; i < limit;) {
2503:                    int oldpc = i++;
2504:                    int op = code[oldpc] & 0xff;
2505:                    String str = Integer.toString(oldpc);
2506:                    int printConstant = 0;
2507:                    int j = str.length();
2508:                    while (++j <= 3)
2509:                        dst.print(' ');
2510:                    dst.print(str);
2511:                    dst.print(": ");
2512:                    // We do a rough binary partition of the opcodes.
2513:                    if (op < 120) {
2514:                        if (op < 87) {
2515:                            if (op < 3)
2516:                                print("nop;aconst_null;iconst_m1;", op, dst);
2517:                            else if (op < 9) {
2518:                                dst.print("iconst_");
2519:                                dst.print(op - 3);
2520:                            } else if (op < 16) // op >= 9 [lconst_0] && op <= 15 [dconst_1]
2521:                            {
2522:                                char typ;
2523:                                if (op < 11) {
2524:                                    typ = 'l';
2525:                                    op -= 9;
2526:                                } else if (op < 14) {
2527:                                    typ = 'f';
2528:                                    op -= 11;
2529:                                } else {
2530:                                    typ = 'd';
2531:                                    op -= 14;
2532:                                }
2533:                                dst.print(typ);
2534:                                dst.print("const_");
2535:                                dst.print(op);
2536:                            } else if (op < 21) {
2537:                                if (op < 18) // op >= 16 [bipush] && op <= 17 [sipush]
2538:                                {
2539:                                    print("bipush ;sipush ;", op - 16, dst);
2540:                                    int constant;
2541:                                    if (op == 16)
2542:                                        constant = code[i++];
2543:                                    else {
2544:                                        constant = (short) readUnsignedShort(i);
2545:                                        i += 2;
2546:                                    }
2547:                                    dst.print(constant);
2548:                                } else // op >= 18 [ldc] && op <= 20 [ldc2_w]
2549:                                {
2550:                                    printConstant = op == 18 ? 1 : 2;
2551:                                    print("ldc;ldc_w;ldc2_w;", op - 18, dst);
2552:                                }
2553:                            } else // op >= 21 && op < 87
2554:                            {
2555:                                String load_or_store;
2556:                                if (op < 54) {
2557:                                    load_or_store = "load";
2558:                                } else {
2559:                                    load_or_store = "store";
2560:                                    op -= (54 - 21);
2561:                                }
2562:                                int index; // -2 if array op;  -1 if index follows
2563:                                if (op < 26) {
2564:                                    index = -1;
2565:                                    op -= 21;
2566:                                } else if (op < 46) {
2567:                                    op -= 26;
2568:                                    index = op % 4;
2569:                                    op >>= 2;
2570:                                } else {
2571:                                    index = -2;
2572:                                    op -= 46;
2573:                                }
2574:                                dst.print("ilfdabcs".charAt(op));
2575:                                if (index == -2)
2576:                                    dst.write('a');
2577:                                dst.print(load_or_store);
2578:                                if (index >= 0) {
2579:                                    dst.write('_');
2580:                                    dst.print(index);
2581:                                } else if (index == -1) {
2582:                                    if (wide) {
2583:                                        index = readUnsignedShort(i);
2584:                                        i += 2;
2585:                                    } else {
2586:                                        index = code[i] & 0xff;
2587:                                        i++;
2588:                                    }
2589:                                    wide = false;
2590:                                    dst.print(' ');
2591:                                    dst.print(index);
2592:                                }
2593:                            }
2594:                        } else // op >= 87 && op < 120
2595:                        {
2596:                            if (op < 96)
2597:                                print(
2598:                                        "pop;pop2;dup;dup_x1;dup_x2;dup2;dup2_x1;dup2_x2;swap;",
2599:                                        op - 87, dst);
2600:                            else // op >= 96 [iadd] && op <= 119 [dneg]
2601:                            {
2602:                                dst.print("ilfda".charAt((op - 96) % 4));
2603:                                print("add;sub;mul;div;rem;neg;",
2604:                                        (op - 96) >> 2, dst);
2605:                            }
2606:                        }
2607:                    } else // op >= 120
2608:                    {
2609:                        if (op < 170) {
2610:                            if (op < 132) // op >= 120 [ishl] && op <= 131 [lxor]
2611:                            {
2612:                                dst.print((op & 1) == 0 ? 'i' : 'l');
2613:                                print("shl;shr;ushr;and;or;xor;",
2614:                                        (op - 120) >> 1, dst);
2615:                            } else if (op == 132) // iinc
2616:                            {
2617:                                int var_index;
2618:                                int constant;
2619:                                dst.print("iinc");
2620:                                if (!wide) {
2621:                                    var_index = 0xff & code[i++];
2622:                                    constant = code[i++];
2623:                                } else {
2624:                                    var_index = readUnsignedShort(i);
2625:                                    i += 2;
2626:                                    constant = (short) readUnsignedShort(i);
2627:                                    i += 2;
2628:                                    wide = false;
2629:                                }
2630:                                dst.print(' ');
2631:                                dst.print(var_index);
2632:                                dst.print(' ');
2633:                                dst.print(constant);
2634:                            } else if (op < 148) // op >= 133 [i2l] && op <= 147 [i2s]
2635:                            {
2636:                                dst.print("ilfdi".charAt((op - 133) / 3));
2637:                                dst.print('2');
2638:                                dst.print("lfdifdildilfbcs".charAt(op - 133));
2639:                            } else if (op < 153) // op >= 148 [lcmp] && op <= 152 [dcmpg]
2640:                                print("lcmp;fcmpl;fcmpg;dcmpl;dcmpg;",
2641:                                        op - 148, dst);
2642:                            else if (op < 169) {
2643:                                if (op < 159) {
2644:                                    dst.print("if");
2645:                                    print("eq;ne;lt;ge;gt;le;", op - 153, dst);
2646:                                } else if (op < 167) {
2647:                                    if (op < 165) {
2648:                                        dst.print("if_icmp");
2649:                                    } else {
2650:                                        dst.print("if_acmp");
2651:                                        op -= 165 - 159;
2652:                                    }
2653:                                    print("eq;ne;lt;ge;gt;le;", op - 159, dst);
2654:                                } else
2655:                                    print("goto;jsr;", op - 167, dst);
2656:                                int delta = (short) readUnsignedShort(i);
2657:                                i += 2;
2658:                                dst.print(' ');
2659:                                dst.print(oldpc + delta);
2660:                            } else {
2661:                                int index;
2662:                                dst.print("ret ");
2663:                                if (wide) {
2664:                                    index = readUnsignedShort(i);
2665:                                    index += 2;
2666:                                } else {
2667:                                    index = code[i] & 0xff;
2668:                                    i++;
2669:                                }
2670:                                wide = false;
2671:                                dst.print(index);
2672:                            }
2673:                        } else {
2674:                            if (op < 172) //  [tableswitch] or [lookupswitch]
2675:                            {
2676:                                if (fixup_count == 0)
2677:                                    i = (i + 3) & ~3; // skip 0-3 byte padding.
2678:                                int code_offset = readInt(i);
2679:                                i += 4;
2680:                                if (op == 170) {
2681:                                    dst.print("tableswitch");
2682:                                    int low = readInt(i);
2683:                                    i += 4;
2684:                                    int high = readInt(i);
2685:                                    i += 4;
2686:                                    dst.print(" low: ");
2687:                                    dst.print(low);
2688:                                    dst.print(" high: ");
2689:                                    dst.print(high);
2690:                                    dst.print(" default: ");
2691:                                    dst.print(oldpc + code_offset);
2692:                                    for (; low <= high; low++) {
2693:                                        code_offset = readInt(i);
2694:                                        i += 4;
2695:                                        dst.println();
2696:                                        dst.print("  ");
2697:                                        dst.print(low);
2698:                                        dst.print(": ");
2699:                                        dst.print(oldpc + code_offset);
2700:                                    }
2701:                                } else {
2702:                                    dst.print("lookupswitch");
2703:                                    int npairs = readInt(i);
2704:                                    i += 4;
2705:                                    dst.print(" npairs: ");
2706:                                    dst.print(npairs);
2707:                                    dst.print(" default: ");
2708:                                    dst.print(oldpc + code_offset);
2709:                                    while (--npairs >= 0) {
2710:                                        int match = readInt(i);
2711:                                        i += 4;
2712:                                        code_offset = readInt(i);
2713:                                        i += 4;
2714:                                        dst.println();
2715:                                        dst.print("  ");
2716:                                        dst.print(match);
2717:                                        dst.print(": ");
2718:                                        dst.print(oldpc + code_offset);
2719:                                    }
2720:                                }
2721:                            } else if (op < 178) // op >= 172 [ireturn] && op <= 177 [return]
2722:                            {
2723:                                if (op < 177)
2724:                                    dst.print("ilfda".charAt(op - 172));
2725:                                dst.print("return");
2726:                            } else if (op < 182) // op >= 178 [getstatic] && op <= 181 [putfield]
2727:                            {
2728:                                print("getstatic;putstatic;getfield;putfield;",
2729:                                        op - 178, dst);
2730:                                printConstant = 2;
2731:                            } else if (op < 185) // op >= 182 && op <= 185 [invoke*]
2732:                            {
2733:                                dst.print("invoke");
2734:                                print("virtual;special;static;", op - 182, dst);
2735:                                printConstant = 2;
2736:                            } else if (op == 185) // invokeinterface
2737:                            {
2738:                                dst.print("invokeinterface (");
2739:                                int index = readUnsignedShort(i);
2740:                                i += 2;
2741:                                int args = 0xff & code[i];
2742:                                i += 2;
2743:                                dst.print(args + " args)");
2744:                                dst.printConstantOperand(index);
2745:                            } else if (op < 196) {
2746:                                print(
2747:                                        "186;new;newarray;anewarray;arraylength;athrow;checkcast;instanceof;monitorenter;monitorexit;",
2748:                                        op - 186, dst);
2749:                                if (op == 187 || op == 189 || op == 192
2750:                                        || op == 193)
2751:                                    printConstant = 2;
2752:                                else if (op == 188) // newarray
2753:                                {
2754:                                    int type = code[i++];
2755:                                    dst.print(' ');
2756:                                    if (type >= 4 && type <= 11)
2757:                                        print(
2758:                                                "boolean;char;float;double;byte;short;int;long;",
2759:                                                type - 4, dst);
2760:                                    else
2761:                                        dst.print(type);
2762:                                }
2763:
2764:                            } else if (op == 196) // wide
2765:                            {
2766:                                dst.print("wide");
2767:                                wide = true;
2768:                            } else if (op == 197) {
2769:                                dst.print("multianewarray");
2770:                                int index = readUnsignedShort(i);
2771:                                i += 2;
2772:                                dst.printConstantOperand(index);
2773:                                int dims = 0xff & code[i++];
2774:                                dst.print(' ');
2775:                                dst.print(dims);
2776:                            } else if (op < 200) {
2777:                                print("ifnull;ifnonnull;", op - 198, dst);
2778:                                int delta = (short) readUnsignedShort(i);
2779:                                i += 2;
2780:                                dst.print(' ');
2781:                                dst.print(oldpc + delta);
2782:                            } else if (op < 202) {
2783:                                print("goto_w;jsr_w;", op - 200, dst);
2784:                                int delta = readInt(i);
2785:                                i += 4;
2786:                                dst.print(' ');
2787:                                dst.print(oldpc + delta);
2788:                            } else
2789:                                dst.print(op);
2790:                        }
2791:                    }
2792:                    if (printConstant > 0) {
2793:                        int index;
2794:                        if (printConstant == 1)
2795:                            index = 0xff & code[i++];
2796:                        else {
2797:                            index = readUnsignedShort(i);
2798:                            i += 2;
2799:                        }
2800:                        dst.printConstantOperand(index);
2801:                    }
2802:                    dst.println();
2803:                }
2804:            }
2805:
2806:            private int readUnsignedShort(int offset) {
2807:                return ((0xff & code[offset]) << 8) | (0xff & code[offset + 1]);
2808:            }
2809:
2810:            private int readInt(int offset) {
2811:                return (readUnsignedShort(offset) << 16)
2812:                        | readUnsignedShort(offset + 2);
2813:            }
2814:
2815:            /*
2816:            public saveStack (ClassType into)
2817:            {
2818:              Field[] flds = new Field[SP];
2819:              while (SP > 0)
2820:                {
2821:            Field fld = ?;
2822:            emitStore(fld);
2823:            flds[SP...]
2824:                }
2825:            }
2826:             */
2827:
2828:            /* Print the i'th ';'-delimited substring of str on dst. */
2829:            private void print(String str, int i, PrintWriter dst) {
2830:                int last = 0;
2831:                int pos = -1;
2832:                for (; i >= 0; i--) {
2833:                    last = ++pos;
2834:                    pos = str.indexOf(';', last);
2835:                }
2836:                dst.write(str, last, pos - last);
2837:            }
2838:
2839:            /** Return an object encapsulating the type state of the JVM stack. */
2840:            public Type[] saveStackTypeState(boolean clear) {
2841:                if (SP == 0)
2842:                    return null;
2843:                Type[] typeState = new Type[SP];
2844:                System.arraycopy(stack_types, 0, typeState, 0, SP);
2845:                if (clear)
2846:                    SP = 0;
2847:                return typeState;
2848:            }
2849:
2850:            /** Restore a type state as saved by saveStackTypeState. */
2851:            public void restoreStackTypeState(Type[] save) {
2852:                if (save == null)
2853:                    SP = 0;
2854:                else {
2855:                    SP = save.length;
2856:                    System.arraycopy(save, 0, stack_types, 0, SP);
2857:                }
2858:            }
2859:
2860:            public int beginFragment(Label start, Label after) {
2861:                int i = fixup_count;
2862:                fixupAdd(FIXUP_MOVE_TO_END, after);
2863:                start.define(this );
2864:                return i;
2865:            }
2866:
2867:            /** End a fragment.
2868:             * @param cookie the return value from the previous beginFragment.
2869:             */
2870:            public void endFragment(int cookie) {
2871:                fixup_offsets[cookie] = (fixup_count << 4) | FIXUP_MOVE_TO_END;
2872:                Label after = fixup_labels[cookie];
2873:                fixupAdd(FIXUP_MOVE, 0, null);
2874:                after.define(this);
2875:            }
2876:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.