Source Code Cross Referenced for CodeGen.java in  » Byte-Code » Javassist » javassist » compiler » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /*
0002:         * Javassist, a Java-bytecode translator toolkit.
0003:         * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
0004:         *
0005:         * The contents of this file are subject to the Mozilla Public License Version
0006:         * 1.1 (the "License"); you may not use this file except in compliance with
0007:         * the License.  Alternatively, the contents of this file may be used under
0008:         * the terms of the GNU Lesser General Public License Version 2.1 or later.
0009:         *
0010:         * Software distributed under the License is distributed on an "AS IS" basis,
0011:         * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0012:         * for the specific language governing rights and limitations under the
0013:         * License.
0014:         */
0015:
0016:        package javassist.compiler;
0017:
0018:        import java.util.ArrayList;
0019:        import java.util.Arrays;
0020:        import javassist.compiler.ast.*;
0021:        import javassist.bytecode.*;
0022:
0023:        /* The code generator is implemeted by three files:
0024:         * CodeGen.java, MemberCodeGen.java, and JvstCodeGen.
0025:         * I just wanted to split a big file into three smaller ones.
0026:         */
0027:
0028:        public abstract class CodeGen extends Visitor implements  Opcode,
0029:                TokenId {
0030:            static final String javaLangObject = "java.lang.Object";
0031:            static final String jvmJavaLangObject = "java/lang/Object";
0032:
0033:            static final String javaLangString = "java.lang.String";
0034:            static final String jvmJavaLangString = "java/lang/String";
0035:
0036:            protected Bytecode bytecode;
0037:            private int tempVar;
0038:            TypeChecker typeChecker;
0039:
0040:            /**
0041:             * true if the last visited node is a return statement.
0042:             */
0043:            protected boolean hasReturned;
0044:
0045:            /**
0046:             * Must be true if compilation is for a static method.
0047:             */
0048:            public boolean inStaticMethod;
0049:
0050:            protected ArrayList breakList, continueList;
0051:
0052:            /**
0053:             * doit() in ReturnHook is called from atReturn().
0054:             */
0055:            protected static abstract class ReturnHook {
0056:                ReturnHook next;
0057:
0058:                protected abstract void doit(Bytecode b, int opcode);
0059:
0060:                protected ReturnHook(CodeGen gen) {
0061:                    next = gen.returnHooks;
0062:                    gen.returnHooks = this ;
0063:                }
0064:
0065:                protected void remove(CodeGen gen) {
0066:                    gen.returnHooks = next;
0067:                }
0068:            }
0069:
0070:            protected ReturnHook returnHooks;
0071:
0072:            /* The following fields are used by atXXX() methods
0073:             * for returning the type of the compiled expression.
0074:             */
0075:            protected int exprType; // VOID, NULL, CLASS, BOOLEAN, INT, ...
0076:            protected int arrayDim;
0077:            protected String className; // JVM-internal representation
0078:
0079:            public CodeGen(Bytecode b) {
0080:                bytecode = b;
0081:                tempVar = -1;
0082:                typeChecker = null;
0083:                hasReturned = false;
0084:                inStaticMethod = false;
0085:                breakList = null;
0086:                continueList = null;
0087:                returnHooks = null;
0088:            }
0089:
0090:            public void setTypeChecker(TypeChecker checker) {
0091:                typeChecker = checker;
0092:            }
0093:
0094:            protected static void fatal() throws CompileError {
0095:                throw new CompileError("fatal");
0096:            }
0097:
0098:            public static boolean is2word(int type, int dim) {
0099:                return dim == 0 && (type == DOUBLE || type == LONG);
0100:            }
0101:
0102:            public int getMaxLocals() {
0103:                return bytecode.getMaxLocals();
0104:            }
0105:
0106:            public void setMaxLocals(int n) {
0107:                bytecode.setMaxLocals(n);
0108:            }
0109:
0110:            protected void incMaxLocals(int size) {
0111:                bytecode.incMaxLocals(size);
0112:            }
0113:
0114:            /**
0115:             * Returns a local variable that single or double words can be
0116:             * stored in.
0117:             */
0118:            protected int getTempVar() {
0119:                if (tempVar < 0) {
0120:                    tempVar = getMaxLocals();
0121:                    incMaxLocals(2);
0122:                }
0123:
0124:                return tempVar;
0125:            }
0126:
0127:            protected int getLocalVar(Declarator d) {
0128:                int v = d.getLocalVar();
0129:                if (v < 0) {
0130:                    v = getMaxLocals(); // delayed variable allocation.
0131:                    d.setLocalVar(v);
0132:                    incMaxLocals(1);
0133:                }
0134:
0135:                return v;
0136:            }
0137:
0138:            /**
0139:             * Returns the JVM-internal representation of this class name.
0140:             */
0141:            protected abstract String getThisName();
0142:
0143:            /**
0144:             * Returns the JVM-internal representation of this super class name.
0145:             */
0146:            protected abstract String getSuperName() throws CompileError;
0147:
0148:            /* Converts a class name into a JVM-internal representation.
0149:             *
0150:             * It may also expand a simple class name to java.lang.*.
0151:             * For example, this converts Object into java/lang/Object.
0152:             */
0153:            protected abstract String resolveClassName(ASTList name)
0154:                    throws CompileError;
0155:
0156:            /* Expands a simple class name to java.lang.*.
0157:             * For example, this converts Object into java/lang/Object.
0158:             */
0159:            protected abstract String resolveClassName(String jvmClassName)
0160:                    throws CompileError;
0161:
0162:            /**
0163:             * @param name      the JVM-internal representation.
0164:             *                  name is not exapnded to java.lang.*.
0165:             */
0166:            protected static String toJvmArrayName(String name, int dim) {
0167:                if (name == null)
0168:                    return null;
0169:
0170:                if (dim == 0)
0171:                    return name;
0172:                else {
0173:                    StringBuffer sbuf = new StringBuffer();
0174:                    int d = dim;
0175:                    while (d-- > 0)
0176:                        sbuf.append('[');
0177:
0178:                    sbuf.append('L');
0179:                    sbuf.append(name);
0180:                    sbuf.append(';');
0181:
0182:                    return sbuf.toString();
0183:                }
0184:            }
0185:
0186:            protected static String toJvmTypeName(int type, int dim) {
0187:                char c = 'I';
0188:                switch (type) {
0189:                case BOOLEAN:
0190:                    c = 'Z';
0191:                    break;
0192:                case BYTE:
0193:                    c = 'B';
0194:                    break;
0195:                case CHAR:
0196:                    c = 'C';
0197:                    break;
0198:                case SHORT:
0199:                    c = 'S';
0200:                    break;
0201:                case INT:
0202:                    c = 'I';
0203:                    break;
0204:                case LONG:
0205:                    c = 'J';
0206:                    break;
0207:                case FLOAT:
0208:                    c = 'F';
0209:                    break;
0210:                case DOUBLE:
0211:                    c = 'D';
0212:                    break;
0213:                case VOID:
0214:                    c = 'V';
0215:                    break;
0216:                }
0217:
0218:                StringBuffer sbuf = new StringBuffer();
0219:                while (dim-- > 0)
0220:                    sbuf.append('[');
0221:
0222:                sbuf.append(c);
0223:                return sbuf.toString();
0224:            }
0225:
0226:            public void compileExpr(ASTree expr) throws CompileError {
0227:                doTypeCheck(expr);
0228:                expr.accept(this );
0229:            }
0230:
0231:            public boolean compileBooleanExpr(boolean branchIf, ASTree expr)
0232:                    throws CompileError {
0233:                doTypeCheck(expr);
0234:                return booleanExpr(branchIf, expr);
0235:            }
0236:
0237:            public void doTypeCheck(ASTree expr) throws CompileError {
0238:                if (typeChecker != null)
0239:                    expr.accept(typeChecker);
0240:            }
0241:
0242:            public void atASTList(ASTList n) throws CompileError {
0243:                fatal();
0244:            }
0245:
0246:            public void atPair(Pair n) throws CompileError {
0247:                fatal();
0248:            }
0249:
0250:            public void atSymbol(Symbol n) throws CompileError {
0251:                fatal();
0252:            }
0253:
0254:            public void atFieldDecl(FieldDecl field) throws CompileError {
0255:                field.getInit().accept(this );
0256:            }
0257:
0258:            public void atMethodDecl(MethodDecl method) throws CompileError {
0259:                ASTList mods = method.getModifiers();
0260:                setMaxLocals(1);
0261:                while (mods != null) {
0262:                    Keyword k = (Keyword) mods.head();
0263:                    mods = mods.tail();
0264:                    if (k.get() == STATIC) {
0265:                        setMaxLocals(0);
0266:                        inStaticMethod = true;
0267:                    }
0268:                }
0269:
0270:                ASTList params = method.getParams();
0271:                while (params != null) {
0272:                    atDeclarator((Declarator) params.head());
0273:                    params = params.tail();
0274:                }
0275:
0276:                Stmnt s = method.getBody();
0277:                atMethodBody(s, method.isConstructor(), method.getReturn()
0278:                        .getType() == VOID);
0279:            }
0280:
0281:            /**
0282:             * @param isCons	true if super() must be called.
0283:             *			false if the method is a class initializer.
0284:             */
0285:            public void atMethodBody(Stmnt s, boolean isCons, boolean isVoid)
0286:                    throws CompileError {
0287:                if (s == null)
0288:                    return;
0289:
0290:                if (isCons && needsSuperCall(s))
0291:                    insertDefaultSuperCall();
0292:
0293:                hasReturned = false;
0294:                s.accept(this );
0295:                if (!hasReturned)
0296:                    if (isVoid) {
0297:                        bytecode.addOpcode(Opcode.RETURN);
0298:                        hasReturned = true;
0299:                    } else
0300:                        throw new CompileError("no return statement");
0301:            }
0302:
0303:            private boolean needsSuperCall(Stmnt body) throws CompileError {
0304:                if (body.getOperator() == BLOCK)
0305:                    body = (Stmnt) body.head();
0306:
0307:                if (body != null && body.getOperator() == EXPR) {
0308:                    ASTree expr = body.head();
0309:                    if (expr != null && expr instanceof  Expr
0310:                            && ((Expr) expr).getOperator() == CALL) {
0311:                        ASTree target = ((Expr) expr).head();
0312:                        if (target instanceof  Keyword) {
0313:                            int token = ((Keyword) target).get();
0314:                            return token != THIS && token != SUPER;
0315:                        }
0316:                    }
0317:                }
0318:
0319:                return true;
0320:            }
0321:
0322:            protected abstract void insertDefaultSuperCall()
0323:                    throws CompileError;
0324:
0325:            public void atStmnt(Stmnt st) throws CompileError {
0326:                if (st == null)
0327:                    return; // empty
0328:
0329:                int op = st.getOperator();
0330:                if (op == EXPR) {
0331:                    ASTree expr = st.getLeft();
0332:                    doTypeCheck(expr);
0333:                    if (expr instanceof  AssignExpr)
0334:                        atAssignExpr((AssignExpr) expr, false);
0335:                    else if (isPlusPlusExpr(expr)) {
0336:                        Expr e = (Expr) expr;
0337:                        atPlusPlus(e.getOperator(), e.oprand1(), e, false);
0338:                    } else {
0339:                        expr.accept(this );
0340:                        if (is2word(exprType, arrayDim))
0341:                            bytecode.addOpcode(POP2);
0342:                        else if (exprType != VOID)
0343:                            bytecode.addOpcode(POP);
0344:                    }
0345:                } else if (op == DECL || op == BLOCK) {
0346:                    ASTList list = st;
0347:                    while (list != null) {
0348:                        ASTree h = list.head();
0349:                        list = list.tail();
0350:                        if (h != null)
0351:                            h.accept(this );
0352:                    }
0353:                } else if (op == IF)
0354:                    atIfStmnt(st);
0355:                else if (op == WHILE || op == DO)
0356:                    atWhileStmnt(st, op == WHILE);
0357:                else if (op == FOR)
0358:                    atForStmnt(st);
0359:                else if (op == BREAK || op == CONTINUE)
0360:                    atBreakStmnt(st, op == BREAK);
0361:                else if (op == TokenId.RETURN)
0362:                    atReturnStmnt(st);
0363:                else if (op == THROW)
0364:                    atThrowStmnt(st);
0365:                else if (op == TRY)
0366:                    atTryStmnt(st);
0367:                else if (op == SWITCH)
0368:                    atSwitchStmnt(st);
0369:                else if (op == SYNCHRONIZED)
0370:                    atSyncStmnt(st);
0371:                else {
0372:                    // LABEL, SWITCH label stament might be null?.
0373:                    hasReturned = false;
0374:                    throw new CompileError(
0375:                            "sorry, not supported statement: TokenId " + op);
0376:                }
0377:            }
0378:
0379:            private void atIfStmnt(Stmnt st) throws CompileError {
0380:                ASTree expr = st.head();
0381:                Stmnt thenp = (Stmnt) st.tail().head();
0382:                Stmnt elsep = (Stmnt) st.tail().tail().head();
0383:                compileBooleanExpr(false, expr);
0384:                int pc = bytecode.currentPc();
0385:                int pc2 = 0;
0386:                bytecode.addIndex(0); // correct later
0387:
0388:                hasReturned = false;
0389:                if (thenp != null)
0390:                    thenp.accept(this );
0391:
0392:                boolean thenHasReturned = hasReturned;
0393:                hasReturned = false;
0394:
0395:                if (elsep != null && !thenHasReturned) {
0396:                    bytecode.addOpcode(Opcode.GOTO);
0397:                    pc2 = bytecode.currentPc();
0398:                    bytecode.addIndex(0);
0399:                }
0400:
0401:                bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
0402:
0403:                if (elsep != null) {
0404:                    elsep.accept(this );
0405:                    if (!thenHasReturned)
0406:                        bytecode
0407:                                .write16bit(pc2, bytecode.currentPc() - pc2 + 1);
0408:
0409:                    hasReturned = thenHasReturned && hasReturned;
0410:                }
0411:            }
0412:
0413:            private void atWhileStmnt(Stmnt st, boolean notDo)
0414:                    throws CompileError {
0415:                ArrayList prevBreakList = breakList;
0416:                ArrayList prevContList = continueList;
0417:                breakList = new ArrayList();
0418:                continueList = new ArrayList();
0419:
0420:                ASTree expr = st.head();
0421:                Stmnt body = (Stmnt) st.tail();
0422:
0423:                int pc = 0;
0424:                if (notDo) {
0425:                    bytecode.addOpcode(Opcode.GOTO);
0426:                    pc = bytecode.currentPc();
0427:                    bytecode.addIndex(0);
0428:                }
0429:
0430:                int pc2 = bytecode.currentPc();
0431:                if (body != null)
0432:                    body.accept(this );
0433:
0434:                int pc3 = bytecode.currentPc();
0435:                if (notDo)
0436:                    bytecode.write16bit(pc, pc3 - pc + 1);
0437:
0438:                boolean alwaysBranch = compileBooleanExpr(true, expr);
0439:                bytecode.addIndex(pc2 - bytecode.currentPc() + 1);
0440:
0441:                patchGoto(breakList, bytecode.currentPc());
0442:                patchGoto(continueList, pc3);
0443:                continueList = prevContList;
0444:                breakList = prevBreakList;
0445:                hasReturned = alwaysBranch;
0446:            }
0447:
0448:            protected void patchGoto(ArrayList list, int targetPc) {
0449:                int n = list.size();
0450:                for (int i = 0; i < n; ++i) {
0451:                    int pc = ((Integer) list.get(i)).intValue();
0452:                    bytecode.write16bit(pc, targetPc - pc + 1);
0453:                }
0454:            }
0455:
0456:            private void atForStmnt(Stmnt st) throws CompileError {
0457:                ArrayList prevBreakList = breakList;
0458:                ArrayList prevContList = continueList;
0459:                breakList = new ArrayList();
0460:                continueList = new ArrayList();
0461:
0462:                Stmnt init = (Stmnt) st.head();
0463:                ASTList p = st.tail();
0464:                ASTree expr = p.head();
0465:                p = p.tail();
0466:                Stmnt update = (Stmnt) p.head();
0467:                Stmnt body = (Stmnt) p.tail();
0468:
0469:                if (init != null)
0470:                    init.accept(this );
0471:
0472:                int pc = bytecode.currentPc();
0473:                int pc2 = 0;
0474:                if (expr != null) {
0475:                    compileBooleanExpr(false, expr);
0476:                    pc2 = bytecode.currentPc();
0477:                    bytecode.addIndex(0);
0478:                }
0479:
0480:                if (body != null)
0481:                    body.accept(this );
0482:
0483:                int pc3 = bytecode.currentPc();
0484:                if (update != null)
0485:                    update.accept(this );
0486:
0487:                bytecode.addOpcode(Opcode.GOTO);
0488:                bytecode.addIndex(pc - bytecode.currentPc() + 1);
0489:
0490:                int pc4 = bytecode.currentPc();
0491:                if (expr != null)
0492:                    bytecode.write16bit(pc2, pc4 - pc2 + 1);
0493:
0494:                patchGoto(breakList, pc4);
0495:                patchGoto(continueList, pc3);
0496:                continueList = prevContList;
0497:                breakList = prevBreakList;
0498:                hasReturned = false;
0499:            }
0500:
0501:            private void atSwitchStmnt(Stmnt st) throws CompileError {
0502:                compileExpr(st.head());
0503:
0504:                ArrayList prevBreakList = breakList;
0505:                breakList = new ArrayList();
0506:                int opcodePc = bytecode.currentPc();
0507:                bytecode.addOpcode(LOOKUPSWITCH);
0508:                int npads = 3 - (opcodePc & 3);
0509:                while (npads-- > 0)
0510:                    bytecode.add(0);
0511:
0512:                Stmnt body = (Stmnt) st.tail();
0513:                int npairs = 0;
0514:                for (ASTList list = body; list != null; list = list.tail())
0515:                    if (((Stmnt) list.head()).getOperator() == CASE)
0516:                        ++npairs;
0517:
0518:                // opcodePc2 is the position at which the default jump offset is.
0519:                int opcodePc2 = bytecode.currentPc();
0520:                bytecode.addGap(4);
0521:                bytecode.add32bit(npairs);
0522:                bytecode.addGap(npairs * 8);
0523:
0524:                long[] pairs = new long[npairs];
0525:                int ipairs = 0;
0526:                int defaultPc = -1;
0527:                for (ASTList list = body; list != null; list = list.tail()) {
0528:                    Stmnt label = (Stmnt) list.head();
0529:                    int op = label.getOperator();
0530:                    if (op == DEFAULT)
0531:                        defaultPc = bytecode.currentPc();
0532:                    else if (op != CASE)
0533:                        fatal();
0534:                    else {
0535:                        pairs[ipairs++] = ((long) computeLabel(label.head()) << 32)
0536:                                + ((long) (bytecode.currentPc() - opcodePc) & 0xffffffff);
0537:                    }
0538:
0539:                    hasReturned = false;
0540:                    ((Stmnt) label.tail()).accept(this );
0541:                }
0542:
0543:                Arrays.sort(pairs);
0544:                int pc = opcodePc2 + 8;
0545:                for (int i = 0; i < npairs; ++i) {
0546:                    bytecode.write32bit(pc, (int) (pairs[i] >>> 32));
0547:                    bytecode.write32bit(pc + 4, (int) pairs[i]);
0548:                    pc += 8;
0549:                }
0550:
0551:                if (defaultPc < 0 || breakList.size() > 0)
0552:                    hasReturned = false;
0553:
0554:                int endPc = bytecode.currentPc();
0555:                if (defaultPc < 0)
0556:                    defaultPc = endPc;
0557:
0558:                bytecode.write32bit(opcodePc2, defaultPc - opcodePc);
0559:
0560:                patchGoto(breakList, endPc);
0561:                breakList = prevBreakList;
0562:            }
0563:
0564:            private int computeLabel(ASTree expr) throws CompileError {
0565:                doTypeCheck(expr);
0566:                expr = TypeChecker.stripPlusExpr(expr);
0567:                if (expr instanceof  IntConst)
0568:                    return (int) ((IntConst) expr).get();
0569:                else
0570:                    throw new CompileError("bad case label");
0571:            }
0572:
0573:            private void atBreakStmnt(Stmnt st, boolean notCont)
0574:                    throws CompileError {
0575:                if (st.head() != null)
0576:                    throw new CompileError(
0577:                            "sorry, not support labeled break or continue");
0578:
0579:                bytecode.addOpcode(Opcode.GOTO);
0580:                Integer pc = new Integer(bytecode.currentPc());
0581:                bytecode.addIndex(0);
0582:                if (notCont)
0583:                    breakList.add(pc);
0584:                else
0585:                    continueList.add(pc);
0586:            }
0587:
0588:            protected void atReturnStmnt(Stmnt st) throws CompileError {
0589:                atReturnStmnt2(st.getLeft());
0590:            }
0591:
0592:            protected final void atReturnStmnt2(ASTree result)
0593:                    throws CompileError {
0594:                int op;
0595:                if (result == null)
0596:                    op = Opcode.RETURN;
0597:                else {
0598:                    compileExpr(result);
0599:                    if (arrayDim > 0)
0600:                        op = ARETURN;
0601:                    else {
0602:                        int type = exprType;
0603:                        if (type == DOUBLE)
0604:                            op = DRETURN;
0605:                        else if (type == FLOAT)
0606:                            op = FRETURN;
0607:                        else if (type == LONG)
0608:                            op = LRETURN;
0609:                        else if (isRefType(type))
0610:                            op = ARETURN;
0611:                        else
0612:                            op = IRETURN;
0613:                    }
0614:                }
0615:
0616:                for (ReturnHook har = returnHooks; har != null; har = har.next)
0617:                    har.doit(bytecode, op);
0618:
0619:                bytecode.addOpcode(op);
0620:                hasReturned = true;
0621:            }
0622:
0623:            private void atThrowStmnt(Stmnt st) throws CompileError {
0624:                ASTree e = st.getLeft();
0625:                compileExpr(e);
0626:                if (exprType != CLASS || arrayDim > 0)
0627:                    throw new CompileError("bad throw statement");
0628:
0629:                bytecode.addOpcode(ATHROW);
0630:                hasReturned = true;
0631:            }
0632:
0633:            /* overridden in MemberCodeGen
0634:             */
0635:            protected void atTryStmnt(Stmnt st) throws CompileError {
0636:                hasReturned = false;
0637:            }
0638:
0639:            private void atSyncStmnt(Stmnt st) throws CompileError {
0640:                int nbreaks = getListSize(breakList);
0641:                int ncontinues = getListSize(continueList);
0642:
0643:                compileExpr(st.head());
0644:                if (exprType != CLASS && arrayDim == 0)
0645:                    throw new CompileError(
0646:                            "bad type expr for synchronized block");
0647:
0648:                Bytecode bc = bytecode;
0649:                final int var = bc.getMaxLocals();
0650:                bc.incMaxLocals(1);
0651:                bc.addOpcode(DUP);
0652:                bc.addAstore(var);
0653:                bc.addOpcode(MONITORENTER);
0654:
0655:                ReturnHook rh = new ReturnHook(this ) {
0656:                    protected void doit(Bytecode b, int opcode) {
0657:                        b.addAload(var);
0658:                        b.addOpcode(MONITOREXIT);
0659:                    }
0660:                };
0661:
0662:                int pc = bc.currentPc();
0663:                Stmnt body = (Stmnt) st.tail();
0664:                if (body != null)
0665:                    body.accept(this );
0666:
0667:                int pc2 = bc.currentPc();
0668:                int pc3 = 0;
0669:                if (!hasReturned) {
0670:                    rh.doit(bc, 0); // the 2nd arg is ignored.
0671:                    bc.addOpcode(Opcode.GOTO);
0672:                    pc3 = bc.currentPc();
0673:                    bc.addIndex(0);
0674:                }
0675:
0676:                int pc4 = bc.currentPc();
0677:                rh.doit(bc, 0); // the 2nd arg is ignored.
0678:                bc.addOpcode(ATHROW);
0679:                bc.addExceptionHandler(pc, pc2, pc4, 0);
0680:                if (!hasReturned)
0681:                    bc.write16bit(pc3, bc.currentPc() - pc3 + 1);
0682:
0683:                rh.remove(this );
0684:
0685:                if (getListSize(breakList) != nbreaks
0686:                        || getListSize(continueList) != ncontinues)
0687:                    throw new CompileError(
0688:                            "sorry, cannot break/continue in synchronized block");
0689:            }
0690:
0691:            private static int getListSize(ArrayList list) {
0692:                return list == null ? 0 : list.size();
0693:            }
0694:
0695:            private static boolean isPlusPlusExpr(ASTree expr) {
0696:                if (expr instanceof  Expr) {
0697:                    int op = ((Expr) expr).getOperator();
0698:                    return op == PLUSPLUS || op == MINUSMINUS;
0699:                }
0700:
0701:                return false;
0702:            }
0703:
0704:            public void atDeclarator(Declarator d) throws CompileError {
0705:                d.setLocalVar(getMaxLocals());
0706:                d.setClassName(resolveClassName(d.getClassName()));
0707:
0708:                int size;
0709:                if (is2word(d.getType(), d.getArrayDim()))
0710:                    size = 2;
0711:                else
0712:                    size = 1;
0713:
0714:                incMaxLocals(size);
0715:
0716:                /*  NOTE: Array initializers has not been supported.
0717:                 */
0718:                ASTree init = d.getInitializer();
0719:                if (init != null) {
0720:                    doTypeCheck(init);
0721:                    atVariableAssign(null, '=', null, d, init, false);
0722:                }
0723:            }
0724:
0725:            public abstract void atNewExpr(NewExpr n) throws CompileError;
0726:
0727:            public abstract void atArrayInit(ArrayInit init)
0728:                    throws CompileError;
0729:
0730:            public void atAssignExpr(AssignExpr expr) throws CompileError {
0731:                atAssignExpr(expr, true);
0732:            }
0733:
0734:            protected void atAssignExpr(AssignExpr expr, boolean doDup)
0735:                    throws CompileError {
0736:                // =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, >>>=
0737:                int op = expr.getOperator();
0738:                ASTree left = expr.oprand1();
0739:                ASTree right = expr.oprand2();
0740:                if (left instanceof  Variable)
0741:                    atVariableAssign(expr, op, (Variable) left,
0742:                            ((Variable) left).getDeclarator(), right, doDup);
0743:                else {
0744:                    if (left instanceof  Expr) {
0745:                        Expr e = (Expr) left;
0746:                        if (e.getOperator() == ARRAY) {
0747:                            atArrayAssign(expr, op, (Expr) left, right, doDup);
0748:                            return;
0749:                        }
0750:                    }
0751:
0752:                    atFieldAssign(expr, op, left, right, doDup);
0753:                }
0754:            }
0755:
0756:            protected static void badAssign(Expr expr) throws CompileError {
0757:                String msg;
0758:                if (expr == null)
0759:                    msg = "incompatible type for assignment";
0760:                else
0761:                    msg = "incompatible type for " + expr.getName();
0762:
0763:                throw new CompileError(msg);
0764:            }
0765:
0766:            /* op is either =, %=, &=, *=, /=, +=, -=, ^=, |=, <<=, >>=, or >>>=.
0767:             *
0768:             * expr and var can be null.
0769:             */
0770:            private void atVariableAssign(Expr expr, int op, Variable var,
0771:                    Declarator d, ASTree right, boolean doDup)
0772:                    throws CompileError {
0773:                int varType = d.getType();
0774:                int varArray = d.getArrayDim();
0775:                String varClass = d.getClassName();
0776:                int varNo = getLocalVar(d);
0777:
0778:                if (op != '=')
0779:                    atVariable(var);
0780:
0781:                // expr is null if the caller is atDeclarator().
0782:                if (expr == null && right instanceof  ArrayInit)
0783:                    atArrayVariableAssign((ArrayInit) right, varType, varArray,
0784:                            varClass);
0785:                else
0786:                    atAssignCore(expr, op, right, varType, varArray, varClass);
0787:
0788:                if (doDup)
0789:                    if (is2word(varType, varArray))
0790:                        bytecode.addOpcode(DUP2);
0791:                    else
0792:                        bytecode.addOpcode(DUP);
0793:
0794:                if (varArray > 0)
0795:                    bytecode.addAstore(varNo);
0796:                else if (varType == DOUBLE)
0797:                    bytecode.addDstore(varNo);
0798:                else if (varType == FLOAT)
0799:                    bytecode.addFstore(varNo);
0800:                else if (varType == LONG)
0801:                    bytecode.addLstore(varNo);
0802:                else if (isRefType(varType))
0803:                    bytecode.addAstore(varNo);
0804:                else
0805:                    bytecode.addIstore(varNo);
0806:
0807:                exprType = varType;
0808:                arrayDim = varArray;
0809:                className = varClass;
0810:            }
0811:
0812:            protected abstract void atArrayVariableAssign(ArrayInit init,
0813:                    int varType, int varArray, String varClass)
0814:                    throws CompileError;
0815:
0816:            private void atArrayAssign(Expr expr, int op, Expr array,
0817:                    ASTree right, boolean doDup) throws CompileError {
0818:                arrayAccess(array.oprand1(), array.oprand2());
0819:
0820:                if (op != '=') {
0821:                    bytecode.addOpcode(DUP2);
0822:                    bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
0823:                }
0824:
0825:                int aType = exprType;
0826:                int aDim = arrayDim;
0827:                String cname = className;
0828:
0829:                atAssignCore(expr, op, right, aType, aDim, cname);
0830:
0831:                if (doDup)
0832:                    if (is2word(aType, aDim))
0833:                        bytecode.addOpcode(DUP2_X2);
0834:                    else
0835:                        bytecode.addOpcode(DUP_X2);
0836:
0837:                bytecode.addOpcode(getArrayWriteOp(aType, aDim));
0838:                exprType = aType;
0839:                arrayDim = aDim;
0840:                className = cname;
0841:            }
0842:
0843:            protected abstract void atFieldAssign(Expr expr, int op,
0844:                    ASTree left, ASTree right, boolean doDup)
0845:                    throws CompileError;
0846:
0847:            protected void atAssignCore(Expr expr, int op, ASTree right,
0848:                    int type, int dim, String cname) throws CompileError {
0849:                if (op == PLUS_E && dim == 0 && type == CLASS)
0850:                    atStringPlusEq(expr, type, dim, cname, right);
0851:                else {
0852:                    right.accept(this );
0853:                    if (invalidDim(exprType, arrayDim, className, type, dim,
0854:                            cname, false)
0855:                            || (op != '=' && dim > 0))
0856:                        badAssign(expr);
0857:
0858:                    if (op != '=') {
0859:                        int token = assignOps[op - MOD_E];
0860:                        int k = lookupBinOp(token);
0861:                        if (k < 0)
0862:                            fatal();
0863:
0864:                        atArithBinExpr(expr, token, k, type);
0865:                    }
0866:                }
0867:
0868:                if (op != '=' || (dim == 0 && !isRefType(type)))
0869:                    atNumCastExpr(exprType, type);
0870:
0871:                // type check should be done here.
0872:            }
0873:
0874:            private void atStringPlusEq(Expr expr, int type, int dim,
0875:                    String cname, ASTree right) throws CompileError {
0876:                if (!jvmJavaLangString.equals(cname))
0877:                    badAssign(expr);
0878:
0879:                convToString(type, dim); // the value might be null.
0880:                right.accept(this );
0881:                convToString(exprType, arrayDim);
0882:                bytecode.addInvokevirtual(javaLangString, "concat",
0883:                        "(Ljava/lang/String;)Ljava/lang/String;");
0884:                exprType = CLASS;
0885:                arrayDim = 0;
0886:                className = jvmJavaLangString;
0887:            }
0888:
0889:            private boolean invalidDim(int srcType, int srcDim,
0890:                    String srcClass, int destType, int destDim,
0891:                    String destClass, boolean isCast) {
0892:                if (srcDim != destDim)
0893:                    if (srcType == NULL)
0894:                        return false;
0895:                    else if (destDim == 0 && destType == CLASS
0896:                            && jvmJavaLangObject.equals(destClass))
0897:                        return false;
0898:                    else if (isCast && srcDim == 0 && srcType == CLASS
0899:                            && jvmJavaLangObject.equals(srcClass))
0900:                        return false;
0901:                    else
0902:                        return true;
0903:
0904:                return false;
0905:            }
0906:
0907:            public void atCondExpr(CondExpr expr) throws CompileError {
0908:                booleanExpr(false, expr.condExpr());
0909:                int pc = bytecode.currentPc();
0910:                bytecode.addIndex(0); // correct later
0911:                expr.thenExpr().accept(this );
0912:                int dim1 = arrayDim;
0913:                bytecode.addOpcode(Opcode.GOTO);
0914:                int pc2 = bytecode.currentPc();
0915:                bytecode.addIndex(0);
0916:                bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
0917:                expr.elseExpr().accept(this );
0918:                if (dim1 != arrayDim)
0919:                    throw new CompileError("type mismatch in ?:");
0920:
0921:                bytecode.write16bit(pc2, bytecode.currentPc() - pc2 + 1);
0922:            }
0923:
0924:            static final int[] binOp = { '+', DADD, FADD, LADD, IADD, '-',
0925:                    DSUB, FSUB, LSUB, ISUB, '*', DMUL, FMUL, LMUL, IMUL, '/',
0926:                    DDIV, FDIV, LDIV, IDIV, '%', DREM, FREM, LREM, IREM, '|',
0927:                    NOP, NOP, LOR, IOR, '^', NOP, NOP, LXOR, IXOR, '&', NOP,
0928:                    NOP, LAND, IAND, LSHIFT, NOP, NOP, LSHL, ISHL, RSHIFT, NOP,
0929:                    NOP, LSHR, ISHR, ARSHIFT, NOP, NOP, LUSHR, IUSHR };
0930:
0931:            static int lookupBinOp(int token) {
0932:                int[] code = binOp;
0933:                int s = code.length;
0934:                for (int k = 0; k < s; k = k + 5)
0935:                    if (code[k] == token)
0936:                        return k;
0937:
0938:                return -1;
0939:            }
0940:
0941:            public void atBinExpr(BinExpr expr) throws CompileError {
0942:                int token = expr.getOperator();
0943:
0944:                /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
0945:                 */
0946:                int k = lookupBinOp(token);
0947:                if (k >= 0) {
0948:                    expr.oprand1().accept(this );
0949:                    ASTree right = expr.oprand2();
0950:                    if (right == null)
0951:                        return; // see TypeChecker.atBinExpr().
0952:
0953:                    int type1 = exprType;
0954:                    int dim1 = arrayDim;
0955:                    String cname1 = className;
0956:                    right.accept(this );
0957:                    if (dim1 != arrayDim)
0958:                        throw new CompileError("incompatible array types");
0959:
0960:                    if (token == '+' && dim1 == 0
0961:                            && (type1 == CLASS || exprType == CLASS))
0962:                        atStringConcatExpr(expr, type1, dim1, cname1);
0963:                    else
0964:                        atArithBinExpr(expr, token, k, type1);
0965:                } else {
0966:                    /* equation: &&, ||, ==, !=, <=, >=, <, >
0967:                     */
0968:                    booleanExpr(true, expr);
0969:                    bytecode.addIndex(7);
0970:                    bytecode.addIconst(0); // false
0971:                    bytecode.addOpcode(Opcode.GOTO);
0972:                    bytecode.addIndex(4);
0973:                    bytecode.addIconst(1); // true
0974:                }
0975:            }
0976:
0977:            /* arrayDim values of the two oprands must be equal.
0978:             * If an oprand type is not a numeric type, this method
0979:             * throws an exception.
0980:             */
0981:            private void atArithBinExpr(Expr expr, int token, int index,
0982:                    int type1) throws CompileError {
0983:                if (arrayDim != 0)
0984:                    badTypes(expr);
0985:
0986:                int type2 = exprType;
0987:                if (token == LSHIFT || token == RSHIFT || token == ARSHIFT)
0988:                    if (type2 == INT || type2 == SHORT || type2 == CHAR
0989:                            || type2 == BYTE)
0990:                        exprType = type1;
0991:                    else
0992:                        badTypes(expr);
0993:                else
0994:                    convertOprandTypes(type1, type2, expr);
0995:
0996:                int p = typePrecedence(exprType);
0997:                if (p >= 0) {
0998:                    int op = binOp[index + p + 1];
0999:                    if (op != NOP) {
1000:                        if (p == P_INT && exprType != BOOLEAN)
1001:                            exprType = INT; // type1 may be BYTE, ...
1002:
1003:                        bytecode.addOpcode(op);
1004:                        return;
1005:                    }
1006:                }
1007:
1008:                badTypes(expr);
1009:            }
1010:
1011:            private void atStringConcatExpr(Expr expr, int type1, int dim1,
1012:                    String cname1) throws CompileError {
1013:                int type2 = exprType;
1014:                int dim2 = arrayDim;
1015:                boolean type2Is2 = is2word(type2, dim2);
1016:                boolean type2IsString = (type2 == CLASS && jvmJavaLangString
1017:                        .equals(className));
1018:
1019:                if (type2Is2)
1020:                    convToString(type2, dim2);
1021:
1022:                if (is2word(type1, dim1)) {
1023:                    bytecode.addOpcode(DUP_X2);
1024:                    bytecode.addOpcode(POP);
1025:                } else
1026:                    bytecode.addOpcode(SWAP);
1027:
1028:                // even if type1 is String, the left operand might be null.
1029:                convToString(type1, dim1);
1030:                bytecode.addOpcode(SWAP);
1031:
1032:                if (!type2Is2 && !type2IsString)
1033:                    convToString(type2, dim2);
1034:
1035:                bytecode.addInvokevirtual(javaLangString, "concat",
1036:                        "(Ljava/lang/String;)Ljava/lang/String;");
1037:                exprType = CLASS;
1038:                arrayDim = 0;
1039:                className = jvmJavaLangString;
1040:            }
1041:
1042:            private void convToString(int type, int dim) throws CompileError {
1043:                final String method = "valueOf";
1044:
1045:                if (isRefType(type) || dim > 0)
1046:                    bytecode.addInvokestatic(javaLangString, method,
1047:                            "(Ljava/lang/Object;)Ljava/lang/String;");
1048:                else if (type == DOUBLE)
1049:                    bytecode.addInvokestatic(javaLangString, method,
1050:                            "(D)Ljava/lang/String;");
1051:                else if (type == FLOAT)
1052:                    bytecode.addInvokestatic(javaLangString, method,
1053:                            "(F)Ljava/lang/String;");
1054:                else if (type == LONG)
1055:                    bytecode.addInvokestatic(javaLangString, method,
1056:                            "(J)Ljava/lang/String;");
1057:                else if (type == BOOLEAN)
1058:                    bytecode.addInvokestatic(javaLangString, method,
1059:                            "(Z)Ljava/lang/String;");
1060:                else if (type == CHAR)
1061:                    bytecode.addInvokestatic(javaLangString, method,
1062:                            "(C)Ljava/lang/String;");
1063:                else if (type == VOID)
1064:                    throw new CompileError("void type expression");
1065:                else
1066:                    /* INT, BYTE, SHORT */
1067:                    bytecode.addInvokestatic(javaLangString, method,
1068:                            "(I)Ljava/lang/String;");
1069:            }
1070:
1071:            /* Produces the opcode to branch if the condition is true.
1072:             * The oprand is not produced.
1073:             *
1074:             * @return	true if the compiled code is GOTO (always branch).
1075:             */
1076:            private boolean booleanExpr(boolean branchIf, ASTree expr)
1077:                    throws CompileError {
1078:                boolean isAndAnd;
1079:                int op = getCompOperator(expr);
1080:                if (op == EQ) { // ==, !=, ...
1081:                    BinExpr bexpr = (BinExpr) expr;
1082:                    int type1 = compileOprands(bexpr);
1083:                    // here, arrayDim might represent the array dim. of the left oprand
1084:                    // if the right oprand is NULL.
1085:                    compareExpr(branchIf, bexpr.getOperator(), type1, bexpr);
1086:                } else if (op == '!')
1087:                    booleanExpr(!branchIf, ((Expr) expr).oprand1());
1088:                else if ((isAndAnd = (op == ANDAND)) || op == OROR) {
1089:                    BinExpr bexpr = (BinExpr) expr;
1090:                    booleanExpr(!isAndAnd, bexpr.oprand1());
1091:                    int pc = bytecode.currentPc();
1092:                    bytecode.addIndex(0); // correct later
1093:
1094:                    booleanExpr(isAndAnd, bexpr.oprand2());
1095:                    bytecode.write16bit(pc, bytecode.currentPc() - pc + 3);
1096:                    if (branchIf != isAndAnd) {
1097:                        bytecode.addIndex(6); // skip GOTO instruction
1098:                        bytecode.addOpcode(Opcode.GOTO);
1099:                    }
1100:                } else if (isAlwaysBranch(expr, branchIf)) {
1101:                    bytecode.addOpcode(Opcode.GOTO);
1102:                    return true; // always branch
1103:                } else { // others
1104:                    expr.accept(this );
1105:                    if (exprType != BOOLEAN || arrayDim != 0)
1106:                        throw new CompileError("boolean expr is required");
1107:
1108:                    bytecode.addOpcode(branchIf ? IFNE : IFEQ);
1109:                }
1110:
1111:                exprType = BOOLEAN;
1112:                arrayDim = 0;
1113:                return false;
1114:            }
1115:
1116:            private static boolean isAlwaysBranch(ASTree expr, boolean branchIf) {
1117:                if (expr instanceof  Keyword) {
1118:                    int t = ((Keyword) expr).get();
1119:                    return branchIf ? t == TRUE : t == FALSE;
1120:                }
1121:
1122:                return false;
1123:            }
1124:
1125:            static int getCompOperator(ASTree expr) throws CompileError {
1126:                if (expr instanceof  Expr) {
1127:                    Expr bexpr = (Expr) expr;
1128:                    int token = bexpr.getOperator();
1129:                    if (token == '!')
1130:                        return '!';
1131:                    else if ((bexpr instanceof  BinExpr) && token != OROR
1132:                            && token != ANDAND && token != '&' && token != '|')
1133:                        return EQ; // ==, !=, ...
1134:                    else
1135:                        return token;
1136:                }
1137:
1138:                return ' '; // others
1139:            }
1140:
1141:            private int compileOprands(BinExpr expr) throws CompileError {
1142:                expr.oprand1().accept(this );
1143:                int type1 = exprType;
1144:                int dim1 = arrayDim;
1145:                expr.oprand2().accept(this );
1146:                if (dim1 != arrayDim)
1147:                    if (type1 != NULL && exprType != NULL)
1148:                        throw new CompileError("incompatible array types");
1149:                    else if (exprType == NULL)
1150:                        arrayDim = dim1;
1151:
1152:                if (type1 == NULL)
1153:                    return exprType;
1154:                else
1155:                    return type1;
1156:            }
1157:
1158:            private static final int ifOp[] = { EQ, IF_ICMPEQ, IF_ICMPNE, NEQ,
1159:                    IF_ICMPNE, IF_ICMPEQ, LE, IF_ICMPLE, IF_ICMPGT, GE,
1160:                    IF_ICMPGE, IF_ICMPLT, '<', IF_ICMPLT, IF_ICMPGE, '>',
1161:                    IF_ICMPGT, IF_ICMPLE };
1162:
1163:            private static final int ifOp2[] = { EQ, IFEQ, IFNE, NEQ, IFNE,
1164:                    IFEQ, LE, IFLE, IFGT, GE, IFGE, IFLT, '<', IFLT, IFGE, '>',
1165:                    IFGT, IFLE };
1166:
1167:            /* Produces the opcode to branch if the condition is true.
1168:             * The oprands are not produced.
1169:             *
1170:             * Parameter expr - compare expression ==, !=, <=, >=, <, >
1171:             */
1172:            private void compareExpr(boolean branchIf, int token, int type1,
1173:                    BinExpr expr) throws CompileError {
1174:                if (arrayDim == 0)
1175:                    convertOprandTypes(type1, exprType, expr);
1176:
1177:                int p = typePrecedence(exprType);
1178:                if (p == P_OTHER || arrayDim > 0)
1179:                    if (token == EQ)
1180:                        bytecode.addOpcode(branchIf ? IF_ACMPEQ : IF_ACMPNE);
1181:                    else if (token == NEQ)
1182:                        bytecode.addOpcode(branchIf ? IF_ACMPNE : IF_ACMPEQ);
1183:                    else
1184:                        badTypes(expr);
1185:                else if (p == P_INT) {
1186:                    int op[] = ifOp;
1187:                    for (int i = 0; i < op.length; i += 3)
1188:                        if (op[i] == token) {
1189:                            bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
1190:                            return;
1191:                        }
1192:
1193:                    badTypes(expr);
1194:                } else {
1195:                    if (p == P_DOUBLE)
1196:                        if (token == '<' || token == LE)
1197:                            bytecode.addOpcode(DCMPG);
1198:                        else
1199:                            bytecode.addOpcode(DCMPL);
1200:                    else if (p == P_FLOAT)
1201:                        if (token == '<' || token == LE)
1202:                            bytecode.addOpcode(FCMPG);
1203:                        else
1204:                            bytecode.addOpcode(FCMPL);
1205:                    else if (p == P_LONG)
1206:                        bytecode.addOpcode(LCMP); // 1: >, 0: =, -1: <
1207:                    else
1208:                        fatal();
1209:
1210:                    int[] op = ifOp2;
1211:                    for (int i = 0; i < op.length; i += 3)
1212:                        if (op[i] == token) {
1213:                            bytecode.addOpcode(op[i + (branchIf ? 1 : 2)]);
1214:                            return;
1215:                        }
1216:
1217:                    badTypes(expr);
1218:                }
1219:            }
1220:
1221:            protected static void badTypes(Expr expr) throws CompileError {
1222:                throw new CompileError("invalid types for " + expr.getName());
1223:            }
1224:
1225:            private static final int P_DOUBLE = 0;
1226:            private static final int P_FLOAT = 1;
1227:            private static final int P_LONG = 2;
1228:            private static final int P_INT = 3;
1229:            private static final int P_OTHER = -1;
1230:
1231:            protected static boolean isRefType(int type) {
1232:                return type == CLASS || type == NULL;
1233:            }
1234:
1235:            private static int typePrecedence(int type) {
1236:                if (type == DOUBLE)
1237:                    return P_DOUBLE;
1238:                else if (type == FLOAT)
1239:                    return P_FLOAT;
1240:                else if (type == LONG)
1241:                    return P_LONG;
1242:                else if (isRefType(type))
1243:                    return P_OTHER;
1244:                else if (type == VOID)
1245:                    return P_OTHER; // this is wrong, but ...
1246:                else
1247:                    return P_INT; // BOOLEAN, BYTE, CHAR, SHORT, INT
1248:            }
1249:
1250:            // used in TypeChecker.
1251:            static boolean isP_INT(int type) {
1252:                return typePrecedence(type) == P_INT;
1253:            }
1254:
1255:            // used in TypeChecker.
1256:            static boolean rightIsStrong(int type1, int type2) {
1257:                int type1_p = typePrecedence(type1);
1258:                int type2_p = typePrecedence(type2);
1259:                return type1_p >= 0 && type2_p >= 0 && type1_p > type2_p;
1260:            }
1261:
1262:            private static final int[] castOp = {
1263:            /*            D    F    L    I */
1264:            /* double */NOP, D2F, D2L, D2I,
1265:            /* float  */F2D, NOP, F2L, F2I,
1266:            /* long   */L2D, L2F, NOP, L2I,
1267:            /* other  */I2D, I2F, I2L, NOP };
1268:
1269:            /* do implicit type conversion.
1270:             * arrayDim values of the two oprands must be zero.
1271:             */
1272:            private void convertOprandTypes(int type1, int type2, Expr expr)
1273:                    throws CompileError {
1274:                boolean rightStrong;
1275:                int type1_p = typePrecedence(type1);
1276:                int type2_p = typePrecedence(type2);
1277:
1278:                if (type2_p < 0 && type1_p < 0) // not primitive types
1279:                    return;
1280:
1281:                if (type2_p < 0 || type1_p < 0) // either is not a primitive type
1282:                    badTypes(expr);
1283:
1284:                int op, result_type;
1285:                if (type1_p <= type2_p) {
1286:                    rightStrong = false;
1287:                    exprType = type1;
1288:                    op = castOp[type2_p * 4 + type1_p];
1289:                    result_type = type1_p;
1290:                } else {
1291:                    rightStrong = true;
1292:                    op = castOp[type1_p * 4 + type2_p];
1293:                    result_type = type2_p;
1294:                }
1295:
1296:                if (rightStrong) {
1297:                    if (result_type == P_DOUBLE || result_type == P_LONG) {
1298:                        if (type1_p == P_DOUBLE || type1_p == P_LONG)
1299:                            bytecode.addOpcode(DUP2_X2);
1300:                        else
1301:                            bytecode.addOpcode(DUP2_X1);
1302:
1303:                        bytecode.addOpcode(POP2);
1304:                        bytecode.addOpcode(op);
1305:                        bytecode.addOpcode(DUP2_X2);
1306:                        bytecode.addOpcode(POP2);
1307:                    } else if (result_type == P_FLOAT) {
1308:                        if (type1_p == P_LONG) {
1309:                            bytecode.addOpcode(DUP_X2);
1310:                            bytecode.addOpcode(POP);
1311:                        } else
1312:                            bytecode.addOpcode(SWAP);
1313:
1314:                        bytecode.addOpcode(op);
1315:                        bytecode.addOpcode(SWAP);
1316:                    } else
1317:                        fatal();
1318:                } else if (op != NOP)
1319:                    bytecode.addOpcode(op);
1320:            }
1321:
1322:            public void atCastExpr(CastExpr expr) throws CompileError {
1323:                String cname = resolveClassName(expr.getClassName());
1324:                String toClass = checkCastExpr(expr, cname);
1325:                int srcType = exprType;
1326:                exprType = expr.getType();
1327:                arrayDim = expr.getArrayDim();
1328:                className = cname;
1329:                if (toClass == null)
1330:                    atNumCastExpr(srcType, exprType); // built-in type
1331:                else
1332:                    bytecode.addCheckcast(toClass);
1333:            }
1334:
1335:            public void atInstanceOfExpr(InstanceOfExpr expr)
1336:                    throws CompileError {
1337:                String cname = resolveClassName(expr.getClassName());
1338:                String toClass = checkCastExpr(expr, cname);
1339:                bytecode.addInstanceof(toClass);
1340:                exprType = BOOLEAN;
1341:                arrayDim = 0;
1342:            }
1343:
1344:            private String checkCastExpr(CastExpr expr, String name)
1345:                    throws CompileError {
1346:                final String msg = "invalid cast";
1347:                ASTree oprand = expr.getOprand();
1348:                int dim = expr.getArrayDim();
1349:                int type = expr.getType();
1350:                oprand.accept(this );
1351:                int srcType = exprType;
1352:                if (invalidDim(srcType, arrayDim, className, type, dim, name,
1353:                        true)
1354:                        || srcType == VOID || type == VOID)
1355:                    throw new CompileError(msg);
1356:
1357:                if (type == CLASS) {
1358:                    if (!isRefType(srcType))
1359:                        throw new CompileError(msg);
1360:
1361:                    return toJvmArrayName(name, dim);
1362:                } else if (dim > 0)
1363:                    return toJvmTypeName(type, dim);
1364:                else
1365:                    return null; // built-in type
1366:            }
1367:
1368:            void atNumCastExpr(int srcType, int destType) throws CompileError {
1369:                if (srcType == destType)
1370:                    return;
1371:
1372:                int op, op2;
1373:                int stype = typePrecedence(srcType);
1374:                int dtype = typePrecedence(destType);
1375:                if (0 <= stype && stype < 3)
1376:                    op = castOp[stype * 4 + dtype];
1377:                else
1378:                    op = NOP;
1379:
1380:                if (destType == DOUBLE)
1381:                    op2 = I2D;
1382:                else if (destType == FLOAT)
1383:                    op2 = I2F;
1384:                else if (destType == LONG)
1385:                    op2 = I2L;
1386:                else if (destType == SHORT)
1387:                    op2 = I2S;
1388:                else if (destType == CHAR)
1389:                    op2 = I2C;
1390:                else if (destType == BYTE)
1391:                    op2 = I2B;
1392:                else
1393:                    op2 = NOP;
1394:
1395:                if (op != NOP)
1396:                    bytecode.addOpcode(op);
1397:
1398:                if (op == NOP || op == L2I || op == F2I || op == D2I)
1399:                    if (op2 != NOP)
1400:                        bytecode.addOpcode(op2);
1401:            }
1402:
1403:            public void atExpr(Expr expr) throws CompileError {
1404:                // array access, member access,
1405:                // (unary) +, (unary) -, ++, --, !, ~
1406:
1407:                int token = expr.getOperator();
1408:                ASTree oprand = expr.oprand1();
1409:                if (token == '.') {
1410:                    String member = ((Symbol) expr.oprand2()).get();
1411:                    if (member.equals("class"))
1412:                        atClassObject(expr); // .class
1413:                    else
1414:                        atFieldRead(expr);
1415:                } else if (token == MEMBER) { // field read
1416:                    /* MEMBER ('#') is an extension by Javassist.
1417:                     * The compiler internally uses # for compiling .class
1418:                     * expressions such as "int.class".
1419:                     */
1420:                    atFieldRead(expr);
1421:                } else if (token == ARRAY)
1422:                    atArrayRead(oprand, expr.oprand2());
1423:                else if (token == PLUSPLUS || token == MINUSMINUS)
1424:                    atPlusPlus(token, oprand, expr, true);
1425:                else if (token == '!') {
1426:                    booleanExpr(false, expr);
1427:                    bytecode.addIndex(7);
1428:                    bytecode.addIconst(1);
1429:                    bytecode.addOpcode(Opcode.GOTO);
1430:                    bytecode.addIndex(4);
1431:                    bytecode.addIconst(0);
1432:                } else if (token == CALL) // method call
1433:                    fatal();
1434:                else {
1435:                    expr.oprand1().accept(this );
1436:                    int type = typePrecedence(exprType);
1437:                    if (arrayDim > 0)
1438:                        badType(expr);
1439:
1440:                    if (token == '-') {
1441:                        if (type == P_DOUBLE)
1442:                            bytecode.addOpcode(DNEG);
1443:                        else if (type == P_FLOAT)
1444:                            bytecode.addOpcode(FNEG);
1445:                        else if (type == P_LONG)
1446:                            bytecode.addOpcode(LNEG);
1447:                        else if (type == P_INT) {
1448:                            bytecode.addOpcode(INEG);
1449:                            exprType = INT; // type may be BYTE, ...
1450:                        } else
1451:                            badType(expr);
1452:                    } else if (token == '~') {
1453:                        if (type == P_INT) {
1454:                            bytecode.addIconst(-1);
1455:                            bytecode.addOpcode(IXOR);
1456:                            exprType = INT; // type may be BYTE. ...
1457:                        } else if (type == P_LONG) {
1458:                            bytecode.addLconst(-1);
1459:                            bytecode.addOpcode(LXOR);
1460:                        } else
1461:                            badType(expr);
1462:
1463:                    } else if (token == '+') {
1464:                        if (type == P_OTHER)
1465:                            badType(expr);
1466:
1467:                        // do nothing. ignore.
1468:                    } else
1469:                        fatal();
1470:                }
1471:            }
1472:
1473:            protected static void badType(Expr expr) throws CompileError {
1474:                throw new CompileError("invalid type for " + expr.getName());
1475:            }
1476:
1477:            public abstract void atCallExpr(CallExpr expr) throws CompileError;
1478:
1479:            protected abstract void atFieldRead(ASTree expr)
1480:                    throws CompileError;
1481:
1482:            public void atClassObject(Expr expr) throws CompileError {
1483:                ASTree op1 = expr.oprand1();
1484:                if (!(op1 instanceof  Symbol))
1485:                    throw new CompileError(
1486:                            "fatal error: badly parsed .class expr");
1487:
1488:                String cname = ((Symbol) op1).get();
1489:                if (cname.startsWith("[")) {
1490:                    int i = cname.indexOf("[L");
1491:                    if (i >= 0) {
1492:                        String name = cname
1493:                                .substring(i + 2, cname.length() - 1);
1494:                        String name2 = resolveClassName(name);
1495:                        if (!name.equals(name2)) {
1496:                            /* For example, to obtain String[].class,
1497:                             * "[Ljava.lang.String;" (not "[Ljava/lang/String"!)
1498:                             * must be passed to Class.forName().
1499:                             */
1500:                            name2 = MemberResolver.jvmToJavaName(name2);
1501:                            StringBuffer sbuf = new StringBuffer();
1502:                            while (i-- >= 0)
1503:                                sbuf.append('[');
1504:
1505:                            sbuf.append('L').append(name2).append(';');
1506:                            cname = sbuf.toString();
1507:                        }
1508:                    }
1509:                } else {
1510:                    cname = resolveClassName(MemberResolver
1511:                            .javaToJvmName(cname));
1512:                    cname = MemberResolver.jvmToJavaName(cname);
1513:                }
1514:
1515:                int start = bytecode.currentPc();
1516:                bytecode.addLdc(cname);
1517:                bytecode.addInvokestatic("java.lang.Class", "forName",
1518:                        "(Ljava/lang/String;)Ljava/lang/Class;");
1519:                int end = bytecode.currentPc();
1520:                bytecode.addOpcode(Opcode.GOTO);
1521:                int pc = bytecode.currentPc();
1522:                bytecode.addIndex(0); // correct later
1523:
1524:                bytecode.addExceptionHandler(start, end, bytecode.currentPc(),
1525:                        "java.lang.ClassNotFoundException");
1526:
1527:                /* -- the following code is for inlining a call to DotClass.fail().
1528:
1529:                int var = getMaxLocals();
1530:                incMaxLocals(1);
1531:                bytecode.growStack(1);
1532:                bytecode.addAstore(var);
1533:
1534:                bytecode.addNew("java.lang.NoClassDefFoundError");
1535:                bytecode.addOpcode(DUP);
1536:                bytecode.addAload(var);
1537:                bytecode.addInvokevirtual("java.lang.ClassNotFoundException",
1538:                                          "getMessage", "()Ljava/lang/String;");
1539:                bytecode.addInvokespecial("java.lang.NoClassDefFoundError", "<init>",
1540:                                          "(Ljava/lang/String;)V");
1541:                 */
1542:
1543:                bytecode.growStack(1);
1544:                bytecode.addInvokestatic("javassist.runtime.DotClass", "fail",
1545:                        "(Ljava/lang/ClassNotFoundException;)"
1546:                                + "Ljava/lang/NoClassDefFoundError;");
1547:                bytecode.addOpcode(ATHROW);
1548:                bytecode.write16bit(pc, bytecode.currentPc() - pc + 1);
1549:
1550:                exprType = CLASS;
1551:                arrayDim = 0;
1552:                className = "java/lang/Class";
1553:            }
1554:
1555:            public void atArrayRead(ASTree array, ASTree index)
1556:                    throws CompileError {
1557:                arrayAccess(array, index);
1558:                bytecode.addOpcode(getArrayReadOp(exprType, arrayDim));
1559:            }
1560:
1561:            protected void arrayAccess(ASTree array, ASTree index)
1562:                    throws CompileError {
1563:                array.accept(this );
1564:                int type = exprType;
1565:                int dim = arrayDim;
1566:                if (dim == 0)
1567:                    throw new CompileError("bad array access");
1568:
1569:                String cname = className;
1570:
1571:                index.accept(this );
1572:                if (typePrecedence(exprType) != P_INT || arrayDim > 0)
1573:                    throw new CompileError("bad array index");
1574:
1575:                exprType = type;
1576:                arrayDim = dim - 1;
1577:                className = cname;
1578:            }
1579:
1580:            protected static int getArrayReadOp(int type, int dim) {
1581:                if (dim > 0)
1582:                    return AALOAD;
1583:
1584:                switch (type) {
1585:                case DOUBLE:
1586:                    return DALOAD;
1587:                case FLOAT:
1588:                    return FALOAD;
1589:                case LONG:
1590:                    return LALOAD;
1591:                case INT:
1592:                    return IALOAD;
1593:                case SHORT:
1594:                    return SALOAD;
1595:                case CHAR:
1596:                    return CALOAD;
1597:                case BYTE:
1598:                case BOOLEAN:
1599:                    return BALOAD;
1600:                default:
1601:                    return AALOAD;
1602:                }
1603:            }
1604:
1605:            protected static int getArrayWriteOp(int type, int dim) {
1606:                if (dim > 0)
1607:                    return AASTORE;
1608:
1609:                switch (type) {
1610:                case DOUBLE:
1611:                    return DASTORE;
1612:                case FLOAT:
1613:                    return FASTORE;
1614:                case LONG:
1615:                    return LASTORE;
1616:                case INT:
1617:                    return IASTORE;
1618:                case SHORT:
1619:                    return SASTORE;
1620:                case CHAR:
1621:                    return CASTORE;
1622:                case BYTE:
1623:                case BOOLEAN:
1624:                    return BASTORE;
1625:                default:
1626:                    return AASTORE;
1627:                }
1628:            }
1629:
1630:            private void atPlusPlus(int token, ASTree oprand, Expr expr,
1631:                    boolean doDup) throws CompileError {
1632:                boolean isPost = oprand == null; // ++i or i++?
1633:                if (isPost)
1634:                    oprand = expr.oprand2();
1635:
1636:                if (oprand instanceof  Variable) {
1637:                    Declarator d = ((Variable) oprand).getDeclarator();
1638:                    int t = exprType = d.getType();
1639:                    arrayDim = d.getArrayDim();
1640:                    int var = getLocalVar(d);
1641:                    if (arrayDim > 0)
1642:                        badType(expr);
1643:
1644:                    if (t == DOUBLE) {
1645:                        bytecode.addDload(var);
1646:                        if (doDup && isPost)
1647:                            bytecode.addOpcode(DUP2);
1648:
1649:                        bytecode.addDconst(1.0);
1650:                        bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
1651:                        if (doDup && !isPost)
1652:                            bytecode.addOpcode(DUP2);
1653:
1654:                        bytecode.addDstore(var);
1655:                    } else if (t == LONG) {
1656:                        bytecode.addLload(var);
1657:                        if (doDup && isPost)
1658:                            bytecode.addOpcode(DUP2);
1659:
1660:                        bytecode.addLconst((long) 1);
1661:                        bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
1662:                        if (doDup && !isPost)
1663:                            bytecode.addOpcode(DUP2);
1664:
1665:                        bytecode.addLstore(var);
1666:                    } else if (t == FLOAT) {
1667:                        bytecode.addFload(var);
1668:                        if (doDup && isPost)
1669:                            bytecode.addOpcode(DUP);
1670:
1671:                        bytecode.addFconst(1.0f);
1672:                        bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
1673:                        if (doDup && !isPost)
1674:                            bytecode.addOpcode(DUP);
1675:
1676:                        bytecode.addFstore(var);
1677:                    } else if (t == BYTE || t == CHAR || t == SHORT || t == INT) {
1678:                        if (doDup && isPost)
1679:                            bytecode.addIload(var);
1680:
1681:                        bytecode.addOpcode(IINC);
1682:                        bytecode.add(var);
1683:                        bytecode.add(token == PLUSPLUS ? 1 : -1);
1684:
1685:                        if (doDup && !isPost)
1686:                            bytecode.addIload(var);
1687:                    } else
1688:                        badType(expr);
1689:                } else {
1690:                    if (oprand instanceof  Expr) {
1691:                        Expr e = (Expr) oprand;
1692:                        if (e.getOperator() == ARRAY) {
1693:                            atArrayPlusPlus(token, isPost, e, doDup);
1694:                            return;
1695:                        }
1696:                    }
1697:
1698:                    atFieldPlusPlus(token, isPost, oprand, expr, doDup);
1699:                }
1700:            }
1701:
1702:            public void atArrayPlusPlus(int token, boolean isPost, Expr expr,
1703:                    boolean doDup) throws CompileError {
1704:                arrayAccess(expr.oprand1(), expr.oprand2());
1705:                int t = exprType;
1706:                int dim = arrayDim;
1707:                if (dim > 0)
1708:                    badType(expr);
1709:
1710:                bytecode.addOpcode(DUP2);
1711:                bytecode.addOpcode(getArrayReadOp(t, arrayDim));
1712:                int dup_code = is2word(t, dim) ? DUP2_X2 : DUP_X2;
1713:                atPlusPlusCore(dup_code, doDup, token, isPost, expr);
1714:                bytecode.addOpcode(getArrayWriteOp(t, dim));
1715:            }
1716:
1717:            protected void atPlusPlusCore(int dup_code, boolean doDup,
1718:                    int token, boolean isPost, Expr expr) throws CompileError {
1719:                int t = exprType;
1720:
1721:                if (doDup && isPost)
1722:                    bytecode.addOpcode(dup_code);
1723:
1724:                if (t == INT || t == BYTE || t == CHAR || t == SHORT) {
1725:                    bytecode.addIconst(1);
1726:                    bytecode.addOpcode(token == PLUSPLUS ? IADD : ISUB);
1727:                    exprType = INT;
1728:                } else if (t == LONG) {
1729:                    bytecode.addLconst((long) 1);
1730:                    bytecode.addOpcode(token == PLUSPLUS ? LADD : LSUB);
1731:                } else if (t == FLOAT) {
1732:                    bytecode.addFconst(1.0f);
1733:                    bytecode.addOpcode(token == PLUSPLUS ? FADD : FSUB);
1734:                } else if (t == DOUBLE) {
1735:                    bytecode.addDconst(1.0);
1736:                    bytecode.addOpcode(token == PLUSPLUS ? DADD : DSUB);
1737:                } else
1738:                    badType(expr);
1739:
1740:                if (doDup && !isPost)
1741:                    bytecode.addOpcode(dup_code);
1742:            }
1743:
1744:            protected abstract void atFieldPlusPlus(int token, boolean isPost,
1745:                    ASTree oprand, Expr expr, boolean doDup)
1746:                    throws CompileError;
1747:
1748:            public abstract void atMember(Member n) throws CompileError;
1749:
1750:            public void atVariable(Variable v) throws CompileError {
1751:                Declarator d = v.getDeclarator();
1752:                exprType = d.getType();
1753:                arrayDim = d.getArrayDim();
1754:                className = d.getClassName();
1755:                int var = getLocalVar(d);
1756:
1757:                if (arrayDim > 0)
1758:                    bytecode.addAload(var);
1759:                else
1760:                    switch (exprType) {
1761:                    case CLASS:
1762:                        bytecode.addAload(var);
1763:                        break;
1764:                    case LONG:
1765:                        bytecode.addLload(var);
1766:                        break;
1767:                    case FLOAT:
1768:                        bytecode.addFload(var);
1769:                        break;
1770:                    case DOUBLE:
1771:                        bytecode.addDload(var);
1772:                        break;
1773:                    default: // BOOLEAN, BYTE, CHAR, SHORT, INT
1774:                        bytecode.addIload(var);
1775:                        break;
1776:                    }
1777:            }
1778:
1779:            public void atKeyword(Keyword k) throws CompileError {
1780:                arrayDim = 0;
1781:                int token = k.get();
1782:                switch (token) {
1783:                case TRUE:
1784:                    bytecode.addIconst(1);
1785:                    exprType = BOOLEAN;
1786:                    break;
1787:                case FALSE:
1788:                    bytecode.addIconst(0);
1789:                    exprType = BOOLEAN;
1790:                    break;
1791:                case NULL:
1792:                    bytecode.addOpcode(ACONST_NULL);
1793:                    exprType = NULL;
1794:                    break;
1795:                case THIS:
1796:                case SUPER:
1797:                    if (inStaticMethod)
1798:                        throw new CompileError("not-available: "
1799:                                + (token == THIS ? "this" : "super"));
1800:
1801:                    bytecode.addAload(0);
1802:                    exprType = CLASS;
1803:                    if (token == THIS)
1804:                        className = getThisName();
1805:                    else
1806:                        className = getSuperName();
1807:                    break;
1808:                default:
1809:                    fatal();
1810:                }
1811:            }
1812:
1813:            public void atStringL(StringL s) throws CompileError {
1814:                exprType = CLASS;
1815:                arrayDim = 0;
1816:                className = jvmJavaLangString;
1817:                bytecode.addLdc(s.get());
1818:            }
1819:
1820:            public void atIntConst(IntConst i) throws CompileError {
1821:                arrayDim = 0;
1822:                long value = i.get();
1823:                int type = i.getType();
1824:                if (type == IntConstant || type == CharConstant) {
1825:                    exprType = (type == IntConstant ? INT : CHAR);
1826:                    bytecode.addIconst((int) value);
1827:                } else {
1828:                    exprType = LONG;
1829:                    bytecode.addLconst(value);
1830:                }
1831:            }
1832:
1833:            public void atDoubleConst(DoubleConst d) throws CompileError {
1834:                arrayDim = 0;
1835:                if (d.getType() == DoubleConstant) {
1836:                    exprType = DOUBLE;
1837:                    bytecode.addDconst(d.get());
1838:                } else {
1839:                    exprType = FLOAT;
1840:                    bytecode.addFconst((float) d.get());
1841:                }
1842:            }
1843:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.