Source Code Cross Referenced for MethodAnalyzer.java in  » Development » jode » jode » decompiler » 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 » Development » jode » jode.decompiler 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* MethodAnalyzer Copyright (C) 1998-2002 Jochen Hoenicke.
0002:         *
0003:         * This program is free software; you can redistribute it and/or modify
0004:         * it under the terms of the GNU Lesser General Public License as published by
0005:         * the Free Software Foundation; either version 2, or (at your option)
0006:         * any later version.
0007:         *
0008:         * This program is distributed in the hope that it will be useful,
0009:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0010:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0011:         * GNU General Public License for more details.
0012:         *
0013:         * You should have received a copy of the GNU Lesser General Public License
0014:         * along with this program; see the file COPYING.LESSER.  If not, write to
0015:         * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
0016:         *
0017:         * $Id: MethodAnalyzer.java.in,v 4.8.2.4 2002/05/28 17:34:03 hoenicke Exp $
0018:         */
0019:
0020:        package jode.decompiler;
0021:
0022:        import jode.AssertError;
0023:        import jode.GlobalOptions;
0024:        import jode.bytecode.BytecodeInfo;
0025:        import jode.bytecode.ClassInfo;
0026:        import jode.bytecode.MethodInfo;
0027:        import jode.bytecode.Handler;
0028:        import jode.bytecode.Instruction;
0029:        import jode.bytecode.LocalVariableInfo;
0030:        import jode.jvm.SyntheticAnalyzer;
0031:        import jode.decompiler.Options;
0032:        import jode.type.*;
0033:        import jode.expr.Expression;
0034:        import jode.expr.ConstOperator;
0035:        import jode.expr.CheckNullOperator;
0036:        import jode.expr.ThisOperator;
0037:        import jode.expr.LocalLoadOperator;
0038:        import jode.expr.OuterLocalOperator;
0039:        import jode.expr.InvokeOperator;
0040:        import jode.flow.StructuredBlock;
0041:        import jode.flow.FlowBlock;
0042:        import jode.flow.TransformExceptionHandlers;
0043:        import jode.flow.Jump;
0044:        import jode.jvm.CodeVerifier;
0045:        import jode.jvm.VerifyException;
0046:        import jode.util.SimpleMap;
0047:
0048:        import java.lang.reflect.Modifier;
0049:        import java.util.BitSet;
0050:        import java.util.Stack;
0051:        import java.util.Vector;
0052:        import java.util.Enumeration;
0053:        import java.io.DataInputStream;
0054:        import java.io.ByteArrayInputStream;
0055:        import java.io.IOException;
0056:
0057:        import java.util.Map;
0058:        import java.util.Collection;
0059:        import java.util.ArrayList;
0060:        import java.util.Iterator;
0061:        import java.util.Set;
0062:
0063:        /**
0064:         * A method analyzer is the main class for analyzation of methods.
0065:         * There is exactly one MethodAnalyzer object for each method (even
0066:         * for abstract methods), that should be decompiled.
0067:         *
0068:         * Method analyzation is done in three passes:
0069:         * <dl>
0070:         * <dt><code>analyze()</code></dt>
0071:         * <dd>the main analyzation, decompiles the code of the method</dd>
0072:         * <dt><code>analyzeInners()</code></dt>
0073:         * <dd>This will analyze method scopes classes by calling their
0074:         * <code>analyze()</code> and <code>analyzeInners()</code>
0075:         * methods.</dd>
0076:         * <dt><code>makeDeclaration()</code></dt>
0077:         * <dd>This will determine when to declare variables. For constructors
0078:         * it will do special transformations like field initialization.</dd>
0079:         */
0080:        public class MethodAnalyzer implements  Scope, ClassDeclarer {
0081:            /**
0082:             * The minimal visible complexity.
0083:             */
0084:            private static double STEP_COMPLEXITY = 0.01;
0085:            /**
0086:             * The value of the strictfp modifier.
0087:             * JDK1.1 doesn't define it.
0088:             */
0089:            private static int STRICTFP = 0x800;
0090:            /**
0091:             * The import handler where we should register our types.
0092:             */
0093:            ImportHandler imports;
0094:            /**
0095:             * The class analyzer of the class that contains this method.
0096:             */
0097:            ClassAnalyzer classAnalyzer;
0098:            /**
0099:             * The method info structure for this method.
0100:             */
0101:            MethodInfo minfo;
0102:            /**
0103:             * This is the bytecode info structure, or null if this method has 
0104:             * no code (abstract or native).
0105:             */
0106:            BytecodeInfo code;
0107:
0108:            /**
0109:             * The method name.
0110:             */
0111:            String methodName;
0112:            /**
0113:             * The type of this method (parameter types + return type).
0114:             */
0115:            MethodType methodType;
0116:            /**
0117:             * True, iff this method is a constructor, i.e. methodName == <(cl)?init>
0118:             */
0119:            boolean isConstructor;
0120:
0121:            /**
0122:             * The exceptions this method may throw.
0123:             */
0124:            Type[] exceptions;
0125:
0126:            /**
0127:             * If the method is synthetic (access$, class$, etc.), this is the
0128:             * synthetic analyzer describing the function of this method, otherwise
0129:             * this is null.
0130:             */
0131:            SyntheticAnalyzer synth;
0132:
0133:            /**
0134:             * This is the first flow block of the method code.  If this
0135:             * method has no code, this is null.  This is initialized at the
0136:             * end of the <code>analyze()</code> phase.  
0137:             */
0138:            FlowBlock methodHeader;
0139:            /**
0140:             * A list of all locals contained in this method.
0141:             */
0142:            Vector allLocals = new Vector();
0143:
0144:            /**
0145:             * This array contains the locals in the parameter list, including
0146:             * the implicit <i>this</i> parameter for nonstatic methods.  
0147:             */
0148:            LocalInfo[] param;
0149:            /**
0150:             * The local variable table containing info about names and types of
0151:             * locals.
0152:             */
0153:            LocalVariableTable lvt;
0154:
0155:            /**
0156:             * If this method is the special constructor, that is generated
0157:             * by jikes (constructor$xx), this points to the real constructor.
0158:             * If this is the real constructor and calls a constructor$xx, it
0159:             * points to this. Otherwise this is null.
0160:             */
0161:            MethodAnalyzer jikesConstructor;
0162:            /**
0163:             * True, iff this method is the special constructor, and its first
0164:             * parameter is a reference to the outer class.
0165:             */
0166:            boolean hasJikesOuterValue;
0167:            /**
0168:             * True, iff this method is an anonymous constructor, that is
0169:             * omitted even if it has parameters.
0170:             */
0171:            boolean isAnonymousConstructor;
0172:            /**
0173:             * True, if this method is the special block$ method generated by jikes
0174:             * to initialize field members.
0175:             */
0176:            boolean isJikesBlockInitializer;
0177:
0178:            /**
0179:             * This list contains the InvokeOperator objects in the code of
0180:             * this method, that create method scoped classes.  */
0181:            Vector anonConstructors = new Vector();
0182:
0183:            /**
0184:             * This list contains the class analyzers of all method scoped
0185:             * classes that should be declared in this method or in a class
0186:             * that is declared in this method.
0187:             */
0188:            Vector innerAnalyzers;
0189:            /**
0190:             * This list contains the class analyzers of all method scoped
0191:             * classes that are used in this method.
0192:             */
0193:            Collection usedAnalyzers;
0194:
0195:            /**
0196:             * This is the default constructor.
0197:             * @param cla the ClassAnalyzer of the class that contains this method.
0198:             * @param minfo the method info structure for this method.
0199:             * @param imports the import handler that should be informed about types.
0200:             */
0201:            public MethodAnalyzer(ClassAnalyzer cla, MethodInfo minfo,
0202:                    ImportHandler imports) {
0203:                this .classAnalyzer = cla;
0204:                this .imports = imports;
0205:                this .minfo = minfo;
0206:                this .methodName = minfo.getName();
0207:                this .methodType = Type.tMethod(minfo.getType());
0208:                this .isConstructor = methodName.equals("<init>")
0209:                        || methodName.equals("<clinit>");
0210:
0211:                if (minfo.getBytecode() != null) {
0212:                    code = minfo.getBytecode();
0213:                }
0214:                String[] excattr = minfo.getExceptions();
0215:                if (excattr == null) {
0216:                    exceptions = new Type[0];
0217:                } else {
0218:                    int excCount = excattr.length;
0219:                    this .exceptions = new Type[excCount];
0220:                    for (int i = 0; i < excCount; i++)
0221:                        exceptions[i] = Type.tClass(excattr[i]);
0222:                }
0223:                if (minfo.isSynthetic() || methodName.indexOf('$') != -1)
0224:                    synth = new SyntheticAnalyzer(minfo, true);
0225:            }
0226:
0227:            /**
0228:             * Returns the name of this method.
0229:             */
0230:            public String getName() {
0231:                return methodName;
0232:            }
0233:
0234:            /**
0235:             * Returns the type of this method.
0236:             * @return the type of this method.
0237:             */
0238:            public MethodType getType() {
0239:                return methodType;
0240:            }
0241:
0242:            /**
0243:             * Returns the first flow block of the code.
0244:             * @return the first flow block of the code.
0245:             */
0246:            public FlowBlock getMethodHeader() {
0247:                return methodHeader;
0248:            }
0249:
0250:            /**
0251:             * Returns the bytecode info for this method.
0252:             * @return the bytecode info for this method, or null if it is
0253:             * abstract or native.
0254:             */
0255:            public final BytecodeInfo getBytecodeInfo() {
0256:                return code;
0257:            }
0258:
0259:            /**
0260:             * Returns the import handler. The import handler should be informed
0261:             * about all types we (or an expression in this method) use, so that
0262:             * the corresponding class can be imported.
0263:             * @return the import handler.
0264:             */
0265:            public final ImportHandler getImportHandler() {
0266:                return imports;
0267:            }
0268:
0269:            /**
0270:             * Registers a type at the import handler.  This should be called
0271:             * if an expression needs to print the type name to the code.  The
0272:             * corresponding class will be imported in that case (if used
0273:             * often enough).
0274:             * @param type the type that should be registered.
0275:             */
0276:            public final void useType(Type type) {
0277:                imports.useType(type);
0278:            }
0279:
0280:            /**
0281:             * Inserts a structured block to the beginning of the method.
0282:             * This is called by transform constructors, to move the super
0283:             * call from the real constructor to the constructor$xx method
0284:             * (the jikes constructor).
0285:             * @param insertBlock the structured block that should be inserted.
0286:             */
0287:            public void insertStructuredBlock(StructuredBlock insertBlock) {
0288:                if (methodHeader != null) {
0289:                    insertBlock.setJump(new Jump(FlowBlock.NEXT_BY_ADDR));
0290:                    FlowBlock insertFlowBlock = new FlowBlock(this , 0);
0291:                    insertFlowBlock.appendBlock(insertBlock, 0);
0292:                    insertFlowBlock.setNextByAddr(methodHeader);
0293:                    insertFlowBlock.doT2(methodHeader);
0294:                    methodHeader = insertFlowBlock;
0295:                } else {
0296:                    throw new IllegalStateException();
0297:                }
0298:            }
0299:
0300:            /**
0301:             * Checks if this method is a constructor, i.e. getName() returns
0302:             * "<init>" or "<clinit>".
0303:             * @return true, iff this method is a real constructor.  
0304:             */
0305:            public final boolean isConstructor() {
0306:                return isConstructor;
0307:            }
0308:
0309:            /**
0310:             * Checks if this method is static.
0311:             * @return true, iff this method is static.
0312:             */
0313:            public final boolean isStatic() {
0314:                return minfo.isStatic();
0315:            }
0316:
0317:            /**
0318:             * Checks if this method is synthetic, i.e. a synthetic attribute is
0319:             * present.
0320:             * @return true, iff this method is synthetic.
0321:             */
0322:            public final boolean isSynthetic() {
0323:                return minfo.isSynthetic();
0324:            }
0325:
0326:            /**
0327:             * Checks if this method is strictfp
0328:             * @return true, iff this method is synthetic.
0329:             */
0330:            public final boolean isStrictFP() {
0331:                return (minfo.getModifiers() & STRICTFP) != 0;
0332:            }
0333:
0334:            /**
0335:             * Tells if this method is the constructor$xx method generated by jikes.
0336:             * @param value true, iff this method is the jikes constructor.
0337:             */
0338:            public final void setJikesConstructor(MethodAnalyzer realConstr) {
0339:                jikesConstructor = realConstr;
0340:            }
0341:
0342:            /**
0343:             * Tells if this method is the block$xx method generated by jikes.
0344:             * @param value true, iff this method is the jikes block initializer.
0345:             */
0346:            public final void setJikesBlockInitializer(boolean value) {
0347:                isJikesBlockInitializer = value;
0348:            }
0349:
0350:            /**
0351:             * Tells if this (constructor$xx) method has as first (implicit)
0352:             * parameter the instance of the outer class.  
0353:             * @param value true, this method has the implicit parameter.
0354:             */
0355:            public final void setHasOuterValue(boolean value) {
0356:                hasJikesOuterValue = value;
0357:            }
0358:
0359:            /**
0360:             * Tells if this constructor can be omited, since it is implicit.
0361:             * @param value true, this method is the implicit constructor.
0362:             */
0363:            public final void setAnonymousConstructor(boolean value) {
0364:                isAnonymousConstructor = value;
0365:            }
0366:
0367:            /**
0368:             * Checks if this constructor can be omited, since it is implicit.
0369:             * @return true, this method is the implicit constructor.
0370:             */
0371:            public final boolean isAnonymousConstructor() {
0372:                return isAnonymousConstructor;
0373:            }
0374:
0375:            /**
0376:             * Get the synthetic analyzer for this method.
0377:             * @return the synthetic analyzer, or null if this method isn't
0378:             * synthetic.
0379:             */
0380:            public final SyntheticAnalyzer getSynthetic() {
0381:                return synth;
0382:            }
0383:
0384:            /**
0385:             * Get the return type of this method.
0386:             */
0387:            public Type getReturnType() {
0388:                return methodType.getReturnType();
0389:            }
0390:
0391:            /**
0392:             * Get the class analyzer for the class containing this method.
0393:             */
0394:            public ClassAnalyzer getClassAnalyzer() {
0395:                return classAnalyzer;
0396:            }
0397:
0398:            /**
0399:             * Get the class info for the class containing this method.
0400:             */
0401:            public ClassInfo getClazz() {
0402:                return classAnalyzer.clazz;
0403:            }
0404:
0405:            /**
0406:             * Get the local info for a parameter.  This call is valid after
0407:             * the analyze pass.
0408:             * @param nr the index of the parameter (start by zero and
0409:             * count the implicit this param for nonstatic method).
0410:             * @return the local info for the specified parameter.
0411:             * @see #getLocalInfo
0412:             */
0413:            public final LocalInfo getParamInfo(int nr) {
0414:                return param[nr];
0415:            }
0416:
0417:            /**
0418:             * Return the number of parameters for this method. This call is
0419:             * valid after the analyze pass.
0420:             */
0421:            public final int getParamCount() {
0422:                return param.length;
0423:            }
0424:
0425:            /**
0426:             * Create a local info for a local variable located at an
0427:             * instruction with the given address.
0428:             * @param addr the address of the instruction using this local.
0429:             *             the address of the next instruction for stores.
0430:             * @param slot the slot, the local variable uses.
0431:             * @return a new local info representing that local.
0432:             */
0433:            public LocalInfo getLocalInfo(int addr, int slot) {
0434:                LocalInfo li = new LocalInfo(this , slot);
0435:                if (lvt != null) {
0436:                    LocalVarEntry entry = lvt.getLocal(slot, addr);
0437:                    if (entry != null)
0438:                        li.addHint(entry.getName(), entry.getType());
0439:                }
0440:                allLocals.addElement(li);
0441:                return li;
0442:            }
0443:
0444:            /**
0445:             * Gets the complexity of this class.  Must be called after it has
0446:             * been initialized.  This is used for a nice progress bar.
0447:             */
0448:            public double getComplexity() {
0449:                if (code == null)
0450:                    return 0.0;
0451:                else
0452:                    return code.getInstructions().size();
0453:            }
0454:
0455:            /**
0456:             * Analyzes the code of this method.  This creates the
0457:             * flow blocks (including methodHeader) and analyzes them.  
0458:             */
0459:            private void analyzeCode(ProgressListener pl, double done,
0460:                    double scale) {
0461:                int instrsPerStep = Integer.MAX_VALUE;
0462:                if (GlobalOptions.verboseLevel > 0)
0463:                    GlobalOptions.err.print(methodName + ": ");
0464:
0465:                if (pl != null) {
0466:                    instrsPerStep = (int) ((code.getInstructions().size() * STEP_COMPLEXITY) / (scale * 0.9));
0467:                }
0468:
0469:                /* The adjacent analyzation relies on this */
0470:                DeadCodeAnalysis.removeDeadCode(code);
0471:                Handler[] handlers = code.getExceptionHandlers();
0472:                int returnCount;
0473:                TransformExceptionHandlers excHandlers;
0474:                {
0475:                    /* First create a FlowBlock for every block that has a 
0476:                     * predecessor other than the previous instruction.
0477:                     */
0478:                    for (Iterator i = code.getInstructions().iterator(); i
0479:                            .hasNext();) {
0480:                        Instruction instr = (Instruction) i.next();
0481:                        if (instr.getPrevByAddr() == null
0482:                                || instr.getPrevByAddr().doesAlwaysJump()
0483:                                || instr.getPreds() != null)
0484:                            instr.setTmpInfo(new FlowBlock(this , instr
0485:                                    .getAddr()));
0486:                    }
0487:
0488:                    for (int i = 0; i < handlers.length; i++) {
0489:                        Instruction instr = handlers[i].start;
0490:                        if (instr.getTmpInfo() == null)
0491:                            instr.setTmpInfo(new FlowBlock(this , instr
0492:                                    .getAddr()));
0493:                        /* end doesn't have a predecessor, but we must prevent
0494:                         * it from being merged with the previous instructions.
0495:                         */
0496:                        instr = handlers[i].end.getNextByAddr();
0497:                        if (instr.getTmpInfo() == null)
0498:                            instr.setTmpInfo(new FlowBlock(this , instr
0499:                                    .getAddr()));
0500:                        instr = handlers[i].catcher;
0501:                        if (instr.getTmpInfo() == null)
0502:                            instr.setTmpInfo(new FlowBlock(this , instr
0503:                                    .getAddr()));
0504:                    }
0505:
0506:                    /* While we read the opcodes into FlowBlocks 
0507:                     * we try to combine sequential blocks, as soon as we
0508:                     * find two sequential instructions in a row, where the
0509:                     * second has no predecessors.
0510:                     */
0511:                    int mark = 1000;
0512:                    int count = 0;
0513:                    FlowBlock lastBlock = null;
0514:                    boolean lastSequential = false;
0515:                    for (Iterator i = code.getInstructions().iterator(); i
0516:                            .hasNext();) {
0517:                        Instruction instr = (Instruction) i.next();
0518:
0519:                        jode.flow.StructuredBlock block = Opcodes.readOpcode(
0520:                                instr, this );
0521:
0522:                        if (GlobalOptions.verboseLevel > 0
0523:                                && instr.getAddr() > mark) {
0524:                            GlobalOptions.err.print('.');
0525:                            mark += 1000;
0526:                        }
0527:                        if (++count >= instrsPerStep) {
0528:                            done += count * scale
0529:                                    / code.getInstructions().size();
0530:                            pl.updateProgress(done, methodName);
0531:                            count = 0;
0532:                        }
0533:
0534:                        if (lastSequential && instr.getTmpInfo() == null
0535:                        /* Only merge with previous block, if this is sequential, 
0536:                         * too.  
0537:                         * Why?  appendBlock only handles sequential blocks.
0538:                         */
0539:                        && !instr.doesAlwaysJump() && instr.getSuccs() == null) {
0540:
0541:                            lastBlock.appendBlock(block, instr.getLength());
0542:                        } else {
0543:
0544:                            if (instr.getTmpInfo() == null)
0545:                                instr.setTmpInfo(new FlowBlock(this , instr
0546:                                        .getAddr()));
0547:                            FlowBlock flowBlock = (FlowBlock) instr
0548:                                    .getTmpInfo();
0549:                            flowBlock.appendBlock(block, instr.getLength());
0550:
0551:                            if (lastBlock != null)
0552:                                lastBlock.setNextByAddr(flowBlock);
0553:
0554:                            instr.setTmpInfo(lastBlock = flowBlock);
0555:                            lastSequential = !instr.doesAlwaysJump()
0556:                                    && instr.getSuccs() == null;
0557:                        }
0558:                    }
0559:
0560:                    methodHeader = (FlowBlock) ((Instruction) code
0561:                            .getInstructions().get(0)).getTmpInfo();
0562:                    excHandlers = new TransformExceptionHandlers();
0563:                    for (int i = 0; i < handlers.length; i++) {
0564:                        Type type = null;
0565:                        FlowBlock start = (FlowBlock) handlers[i].start
0566:                                .getTmpInfo();
0567:                        int endAddr = handlers[i].end.getNextByAddr().getAddr();
0568:                        FlowBlock handler = (FlowBlock) handlers[i].catcher
0569:                                .getTmpInfo();
0570:                        if (handlers[i].type != null)
0571:                            type = Type.tClass(handlers[i].type);
0572:
0573:                        excHandlers.addHandler(start, endAddr, handler, type);
0574:                    }
0575:                }
0576:                for (Iterator i = code.getInstructions().iterator(); i
0577:                        .hasNext();) {
0578:                    Instruction instr = (Instruction) i.next();
0579:                    instr.setTmpInfo(null);
0580:                }
0581:
0582:                if (GlobalOptions.verboseLevel > 0)
0583:                    GlobalOptions.err.print('-');
0584:
0585:                excHandlers.analyze();
0586:                methodHeader.analyze();
0587:
0588:                if ((Options.options & Options.OPTION_PUSH) == 0
0589:                        && methodHeader.mapStackToLocal())
0590:                    methodHeader.removePush();
0591:                if ((Options.options & Options.OPTION_ONETIME) != 0)
0592:                    methodHeader.removeOnetimeLocals();
0593:
0594:                methodHeader.mergeParams(param);
0595:
0596:                if (GlobalOptions.verboseLevel > 0)
0597:                    GlobalOptions.err.println("");
0598:                if (pl != null) {
0599:                    done += 0.1 * scale;
0600:                    pl.updateProgress(done, methodName);
0601:                }
0602:            }
0603:
0604:            /**
0605:             * This is the first pass of the analyzation.  It will analyze the
0606:             * code of this method, but not the method scoped classes.  
0607:             */
0608:            public void analyze(ProgressListener pl, double done, double scale)
0609:                    throws ClassFormatError {
0610:                if (pl != null)
0611:                    pl.updateProgress(done, methodName);
0612:                if (code != null) {
0613:                    if ((Options.options & Options.OPTION_VERIFY) != 0) {
0614:                        CodeVerifier verifier = new CodeVerifier(getClazz(),
0615:                                minfo, code);
0616:                        try {
0617:                            verifier.verify();
0618:                        } catch (VerifyException ex) {
0619:                            ex.printStackTrace(GlobalOptions.err);
0620:                            throw new jode.AssertError("Verification error");
0621:                        }
0622:                    }
0623:
0624:                    if ((Options.options & Options.OPTION_LVT) != 0) {
0625:                        LocalVariableInfo[] localvars = code
0626:                                .getLocalVariableTable();
0627:                        if (localvars != null)
0628:                            lvt = new LocalVariableTable(code.getMaxLocals(),
0629:                                    localvars);
0630:                    }
0631:                }
0632:
0633:                Type[] paramTypes = getType().getParameterTypes();
0634:                int paramCount = (isStatic() ? 0 : 1) + paramTypes.length;
0635:                param = new LocalInfo[paramCount];
0636:
0637:                int offset = 0;
0638:                int slot = 0;
0639:                if (!isStatic()) {
0640:                    ClassInfo classInfo = classAnalyzer.getClazz();
0641:                    LocalInfo this Local = getLocalInfo(0, slot++);
0642:                    this Local.setExpression(new ThisOperator(classInfo, true));
0643:                    param[offset++] = this Local;
0644:                }
0645:
0646:                for (int i = 0; i < paramTypes.length; i++) {
0647:                    param[offset] = getLocalInfo(0, slot);
0648:                    param[offset].setType(paramTypes[i]);
0649:                    slot += paramTypes[i].stackSize();
0650:                    offset++;
0651:                }
0652:
0653:                for (int i = 0; i < exceptions.length; i++)
0654:                    imports.useType(exceptions[i]);
0655:
0656:                if (!isConstructor)
0657:                    imports.useType(methodType.getReturnType());
0658:
0659:                if (code != null)
0660:                    analyzeCode(pl, done, scale);
0661:            }
0662:
0663:            /**
0664:             * This is the second pass of the analyzation.  It will analyze
0665:             * the method scoped classes.  
0666:             */
0667:            public void analyzeInnerClasses() throws ClassFormatError {
0668:                int serialnr = 0;
0669:                Enumeration elts = anonConstructors.elements();
0670:                while (elts.hasMoreElements()) {
0671:                    InvokeOperator cop = (InvokeOperator) elts.nextElement();
0672:                    analyzeInvokeOperator(cop);
0673:                }
0674:            }
0675:
0676:            /**
0677:             * This is the third and last pass of the analyzation.  It will analyze
0678:             * the types and names of the local variables and where to declare them.
0679:             * It will also determine where to declare method scoped local variables.
0680:             */
0681:            public void makeDeclaration(Set done) {
0682:	if (innerAnalyzers != null) {
0683:	    for (Enumeration enum = innerAnalyzers.elements();
0684:		 enum.hasMoreElements(); ) {
0685:		ClassAnalyzer classAna = (ClassAnalyzer) enum.nextElement();
0686:		if (classAna.getParent() == this ) {
0687:		    OuterValues innerOV = classAna.getOuterValues();
0688:		    for (int i=0; i < innerOV.getCount(); i++) {
0689:			Expression value = innerOV.getValue(i);
0690:			if (value instanceof  OuterLocalOperator) {
0691:			    LocalInfo li = ((OuterLocalOperator) 
0692:					    value).getLocalInfo();
0693:			    if (li.getMethodAnalyzer() == this )
0694:				li.markFinal();
0695:			}
0696:		    }
0697:		}
0698:	    }
0699:	}
0700:
0701:        for (Enumeration enum = allLocals.elements();
0702:	     enum.hasMoreElements(); ) {
0703:            LocalInfo li = (LocalInfo)enum.nextElement();
0704:            if (!li.isShadow())
0705:                imports.useType(li.getType());
0706:        }
0707:	for (int i=0; i < param.length; i++) {
0708:	    param[i].guessName();
0709:	    Iterator doneIter = done.iterator();
0710:	    while (doneIter.hasNext()) {
0711:		Declarable previous = (Declarable) doneIter.next();
0712:		if (param[i].getName().equals(previous.getName())) {
0713:		    /* A name conflict happened. */
0714:		    param[i].makeNameUnique();
0715:		    break;
0716:		}
0717:	    }
0718:	    done.add(param[i]);
0719:	}
0720:	
0721:	if (code != null) {
0722:	    methodHeader.makeDeclaration(done);
0723:	    methodHeader.simplify();
0724:	}
0725:	for (int i=0; i < param.length; i++) {
0726:	    done.remove(param[i]);
0727:	    // remove the parameters, since we leave the scope
0728:	}
0729:    }
0730:
0731:            /**
0732:             * Tells if this method is synthetic or implicit or something else, so
0733:             * that it doesn't have to be written to the source code.
0734:             * @return true, iff it shouldn't be written to the source code.
0735:             */
0736:            public boolean skipWriting() {
0737:                if (synth != null) {
0738:                    // We don't need this class anymore (hopefully?)
0739:                    if (synth.getKind() == synth.GETCLASS)
0740:                        return true;
0741:                    if (synth.getKind() >= synth.ACCESSGETFIELD
0742:                            && synth.getKind() <= synth.ACCESSDUPPUTSTATIC
0743:                            && (Options.options & Options.OPTION_INNER) != 0
0744:                            && (Options.options & Options.OPTION_ANON) != 0)
0745:                        return true;
0746:                }
0747:
0748:                if (jikesConstructor == this ) {
0749:                    // This is the first empty part of a jikes constructor
0750:                    return true;
0751:                }
0752:
0753:                boolean declareAsConstructor = isConstructor;
0754:                int skipParams = 0;
0755:                if (isConstructor() && !isStatic()
0756:                        && classAnalyzer.outerValues != null)
0757:                    skipParams = classAnalyzer.outerValues.getCount();
0758:
0759:                if (jikesConstructor != null) {
0760:                    // This is the real part of a jikes constructor
0761:                    declareAsConstructor = true;
0762:                    skipParams = hasJikesOuterValue
0763:                            && classAnalyzer.outerValues.getCount() > 0 ? 1 : 0;
0764:                }
0765:
0766:                if (isJikesBlockInitializer)
0767:                    return true;
0768:
0769:                /* The default constructor must be empty 
0770:                 * and mustn't throw exceptions */
0771:                if (getMethodHeader() == null
0772:                        || !(getMethodHeader().getBlock() instanceof  jode.flow.EmptyBlock)
0773:                        || !getMethodHeader().hasNoJumps()
0774:                        || exceptions.length > 0)
0775:                    return false;
0776:
0777:                if (declareAsConstructor
0778:                        /* The access rights of default constructor should
0779:                         * be public, iff the class is public, otherwise package.
0780:                         * But this rule doesn't necessarily apply for anonymous
0781:                         * classes...
0782:                         */
0783:                        && ((minfo.getModifiers() & (Modifier.PROTECTED
0784:                                | Modifier.PUBLIC | Modifier.PRIVATE
0785:                                | Modifier.SYNCHRONIZED | Modifier.STATIC
0786:                                | Modifier.ABSTRACT | Modifier.NATIVE)) == (getClassAnalyzer()
0787:                                .getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) || classAnalyzer
0788:                                .getName() == null)
0789:                        && classAnalyzer.constructors.length == 1) {
0790:
0791:                    // If the constructor doesn't take parameters (except outerValues)
0792:                    // or if it is the anonymous constructor it can be removed.
0793:                    if (methodType.getParameterTypes().length == skipParams
0794:                            || isAnonymousConstructor)
0795:                        return true;
0796:                }
0797:
0798:                if (isConstructor() && isStatic())
0799:                    return true;
0800:
0801:                return false;
0802:            }
0803:
0804:            /**
0805:             * Dumps the source code for this method to the specified writer.
0806:             * @param writer the tabbed print writer the code should be written to.
0807:             * @exception IOException, if writer throws an exception.
0808:             */
0809:            public void dumpSource(TabbedPrintWriter writer) throws IOException {
0810:                boolean declareAsConstructor = isConstructor;
0811:                int skipParams = 0;
0812:                int modifiedModifiers = minfo.getModifiers();
0813:
0814:                if (isConstructor() && !isStatic()
0815:                        && (Options.options & Options.OPTION_CONTRAFO) != 0
0816:                        && classAnalyzer.outerValues != null)
0817:                    skipParams = classAnalyzer.outerValues.getCount();
0818:
0819:                if (jikesConstructor != null) {
0820:                    // This is the real part of a jikes constructor
0821:                    declareAsConstructor = true;
0822:                    skipParams = hasJikesOuterValue
0823:                            && classAnalyzer.outerValues.getCount() > 0 ? 1 : 0;
0824:                    // get the modifiers of the real constructor
0825:                    modifiedModifiers = jikesConstructor.minfo.getModifiers();
0826:                }
0827:
0828:                if (minfo.isDeprecated()) {
0829:                    writer.println("/**");
0830:                    writer.println(" * @deprecated");
0831:                    writer.println(" */");
0832:                }
0833:
0834:                writer.pushScope(this );
0835:
0836:                /*
0837:                 * JLS-1.0, section 9.4:
0838:                 *
0839:                 * For compatibility with older versions of Java, it is
0840:                 * permitted but discouraged, as a matter of style, to
0841:                 * redundantly specify the abstract modifier for methods
0842:                 * declared in interfaces.
0843:                 *
0844:                 * Every method declaration in the body of an interface is
0845:                 * implicitly public. It is permitted, but strongly
0846:                 * discouraged as a matter of style, to redundantly specify
0847:                 * the public modifier for interface methods.  We don't
0848:                 * follow this second rule and mark this method explicitly
0849:                 * as public.
0850:                 */
0851:                if (classAnalyzer.getClazz().isInterface())
0852:                    modifiedModifiers &= ~Modifier.ABSTRACT;
0853:
0854:                /* Don't ask me why, but jikes declares the static constructor
0855:                 * as final.  Another compiler or obfuscator seems to declare
0856:                 * it as public.  I remove every fancy modifier, now.
0857:                 */
0858:                if (isConstructor() && isStatic())
0859:                    modifiedModifiers &= ~(Modifier.FINAL | Modifier.PUBLIC
0860:                            | Modifier.PROTECTED | Modifier.PRIVATE);
0861:                modifiedModifiers &= ~STRICTFP;
0862:
0863:                writer.startOp(writer.NO_PAREN, 1);
0864:                String delim = "";
0865:                if (minfo.isSynthetic()) {
0866:                    writer.print("/*synthetic*/");
0867:                    delim = " ";
0868:                }
0869:
0870:                String modif = Modifier.toString(modifiedModifiers);
0871:                if (modif.length() > 0) {
0872:                    writer.print(delim + modif);
0873:                    delim = " ";
0874:                }
0875:                if (isStrictFP()) {
0876:                    /* The STRICTFP modifier is set.
0877:                     * We handle it, since java.lang.reflect.Modifier is too dumb.
0878:                     */
0879:
0880:                    /* If STRICTFP is already set for class don't set it for method.
0881:                     * And don't set STRICTFP for native methods or constructors.
0882:                     */
0883:                    if (!classAnalyzer.isStrictFP() && !isConstructor()
0884:                            && (modifiedModifiers & Modifier.NATIVE) == 0) {
0885:                        writer.print(delim + "strictfp");
0886:                        delim = " ";
0887:                    }
0888:                }
0889:
0890:                if (isConstructor
0891:                        && (isStatic() || (classAnalyzer.getName() == null && skipParams == methodType
0892:                                .getParameterTypes().length))) {
0893:                    /* static block or unnamed constructor */
0894:                } else {
0895:                    writer.print(delim);
0896:                    if (declareAsConstructor)
0897:                        writer.print(classAnalyzer.getName());
0898:                    else {
0899:                        writer.printType(getReturnType());
0900:                        writer.print(" " + methodName);
0901:                    }
0902:                    writer.breakOp();
0903:                    if ((Options.outputStyle & Options.GNU_SPACING) != 0)
0904:                        writer.print(" ");
0905:                    writer.print("(");
0906:                    writer.startOp(writer.EXPL_PAREN, 0);
0907:                    int offset = skipParams + (isStatic() ? 0 : 1);
0908:                    for (int i = offset; i < param.length; i++) {
0909:                        if (i > offset) {
0910:                            writer.print(", ");
0911:                            writer.breakOp();
0912:                        }
0913:                        param[i].dumpDeclaration(writer);
0914:                    }
0915:                    writer.endOp();
0916:                    writer.print(")");
0917:                }
0918:                if (exceptions.length > 0) {
0919:                    writer.breakOp();
0920:                    writer.print(" throws ");
0921:                    writer.startOp(writer.EXPL_PAREN, 2);
0922:                    for (int i = 0; i < exceptions.length; i++) {
0923:                        if (i > 0) {
0924:                            writer.print(",");
0925:                            writer.breakOp();
0926:                            writer.print(" ");
0927:                        }
0928:                        writer.printType(exceptions[i]);
0929:                    }
0930:                    writer.endOp();
0931:                }
0932:                writer.endOp();
0933:                if (code != null) {
0934:                    writer.openBraceNoIndent();
0935:                    writer.tab();
0936:                    methodHeader.dumpSource(writer);
0937:                    writer.untab();
0938:                    writer.closeBraceNoIndent();
0939:                } else
0940:                    writer.println(";");
0941:                writer.popScope();
0942:            }
0943:
0944:            /**
0945:             * Checks if the variable set contains a local with the given name.
0946:             * @return the local info the has the given name, or null if it doesn't
0947:             * exists.
0948:             */
0949:            public LocalInfo findLocal(String name) {
0950:        Enumeration enum = allLocals.elements();
0951:        while (enum.hasMoreElements()) {
0952:            LocalInfo li = (LocalInfo) enum.nextElement();
0953:            if (li.getName().equals(name))
0954:                return li;
0955:        }
0956:        return null;
0957:    }
0958:
0959:            /**
0960:             * Checks if a method scoped class with the given name exists in this
0961:             * method (not in a parent method).
0962:             * @return the class analyzer with the given name, or null if it
0963:             * doesn' exists.  
0964:             */
0965:            public ClassAnalyzer findAnonClass(String name) {
0966:	if (innerAnalyzers != null) {
0967:	    Enumeration enum = innerAnalyzers.elements();
0968:	    while (enum.hasMoreElements()) {
0969:		ClassAnalyzer classAna = (ClassAnalyzer) enum.nextElement();
0970:		if (classAna.getParent() == this 
0971:		    && classAna.getName() != null
0972:		    && classAna.getName().equals(name)) {
0973:		    return classAna;
0974:		}
0975:	    }
0976:	}
0977:        return null;
0978:    }
0979:
0980:            /**
0981:             * Checks if the specified object lies in this scope.
0982:             * @param obj the object.
0983:             * @param scopeType the type of this object.
0984:             */
0985:            public boolean isScopeOf(Object obj, int scopeType) {
0986:                if (scopeType == METHODSCOPE && obj instanceof  ClassInfo) {
0987:                    ClassAnalyzer ana = getClassAnalyzer((ClassInfo) obj);
0988:                    if (ana != null)
0989:                        return ana.getParent() == this ;
0990:                }
0991:                return false;
0992:            }
0993:
0994:            /**
0995:             * Checks if the specified name conflicts with an object in this scope.
0996:             * @param name the name to check.
0997:             * @param scopeType the usage type of this name, AMBIGUOUSNAME if it is
0998:             * ambiguous.
0999:             */
1000:            public boolean conflicts(String name, int usageType) {
1001:                if (usageType == AMBIGUOUSNAME || usageType == LOCALNAME)
1002:                    return findLocal(name) != null;
1003:                if (usageType == AMBIGUOUSNAME || usageType == CLASSNAME)
1004:                    return findAnonClass(name) != null;
1005:                return false;
1006:            }
1007:
1008:            /**
1009:             * Gets the parent scope, i.e. the class analyzer for the class containing
1010:             * this method.
1011:             * @XXX needed?
1012:             */
1013:            public ClassDeclarer getParent() {
1014:                return getClassAnalyzer();
1015:            }
1016:
1017:            /**
1018:             * Registers an anonymous constructor invokation.  This should be called
1019:             * in the analyze or analyzeInner pass by invoke subexpressions.
1020:             * @param cop the constructor invokation, that creates the method scoped
1021:             * class.
1022:             */
1023:            public void addAnonymousConstructor(InvokeOperator cop) {
1024:                anonConstructors.addElement(cop);
1025:            }
1026:
1027:            public void analyzeInvokeOperator(InvokeOperator cop) {
1028:                ClassInfo clazz = (ClassInfo) cop.getClassInfo();
1029:                ClassAnalyzer anonAnalyzer = getParent()
1030:                        .getClassAnalyzer(clazz);
1031:
1032:                if (anonAnalyzer == null) {
1033:                    /* Create a new outerValues array corresponding to the
1034:                     * first constructor invocation.
1035:                     */
1036:                    Expression[] outerValueArray;
1037:                    Expression[] subExprs = cop.getSubExpressions();
1038:                    outerValueArray = new Expression[subExprs.length - 1];
1039:
1040:                    for (int j = 0; j < outerValueArray.length; j++) {
1041:                        Expression expr = subExprs[j + 1].simplify();
1042:                        if (expr instanceof  CheckNullOperator)
1043:                            expr = ((CheckNullOperator) expr)
1044:                                    .getSubExpressions()[0];
1045:                        if (expr instanceof  ThisOperator) {
1046:                            outerValueArray[j] = new ThisOperator(
1047:                                    ((ThisOperator) expr).getClassInfo());
1048:                            continue;
1049:                        }
1050:                        LocalInfo li = null;
1051:                        if (expr instanceof  LocalLoadOperator) {
1052:                            li = ((LocalLoadOperator) expr).getLocalInfo();
1053:                            if (!li.isConstant())
1054:                                li = null;
1055:                        }
1056:                        if (expr instanceof  OuterLocalOperator)
1057:                            li = ((OuterLocalOperator) expr).getLocalInfo();
1058:
1059:                        if (li != null) {
1060:                            outerValueArray[j] = new OuterLocalOperator(li);
1061:                            continue;
1062:                        }
1063:
1064:                        Expression[] newOuter = new Expression[j];
1065:                        System.arraycopy(outerValueArray, 0, newOuter, 0, j);
1066:                        outerValueArray = newOuter;
1067:                        break;
1068:                    }
1069:                    anonAnalyzer = new ClassAnalyzer(this , clazz, imports,
1070:                            outerValueArray);
1071:                    addClassAnalyzer(anonAnalyzer);
1072:                    anonAnalyzer.initialize();
1073:                    anonAnalyzer.analyze(null, 0.0, 0.0);
1074:                    anonAnalyzer.analyzeInnerClasses(null, 0.0, 0.0);
1075:                } else {
1076:                    /*
1077:                     * Get the previously created outerValues and
1078:                     * its length.  
1079:                     */
1080:                    OuterValues outerValues = anonAnalyzer.getOuterValues();
1081:                    /*
1082:                     * Merge the other constructor invocation and
1083:                     * possibly shrink outerValues array.  
1084:                     */
1085:                    Expression[] subExprs = cop.getSubExpressions();
1086:                    for (int j = 0; j < outerValues.getCount(); j++) {
1087:                        if (j + 1 < subExprs.length) {
1088:                            Expression expr = subExprs[j + 1].simplify();
1089:                            if (expr instanceof  CheckNullOperator)
1090:                                expr = ((CheckNullOperator) expr)
1091:                                        .getSubExpressions()[0];
1092:
1093:                            if (outerValues.unifyOuterValues(j, expr))
1094:                                continue;
1095:
1096:                        }
1097:                        outerValues.setCount(j);
1098:                        break;
1099:                    }
1100:                }
1101:
1102:                if (usedAnalyzers == null)
1103:                    usedAnalyzers = new ArrayList();
1104:                usedAnalyzers.add(anonAnalyzer);
1105:            }
1106:
1107:            /**
1108:             * Get the class analyzer for the given class info.  This searches
1109:             * the method scoped/anonymous classes in this method and all
1110:             * outer methods and the outer classes for the class analyzer.
1111:             * @param cinfo the classinfo for which the analyzer is searched.
1112:             * @return the class analyzer, or null if there is not an outer
1113:             * class that equals cinfo, and not a method scope/inner class in
1114:             * an outer method.
1115:             */
1116:            public ClassAnalyzer getClassAnalyzer(ClassInfo cinfo) {
1117:	if (innerAnalyzers != null) {
1118:	    Enumeration enum = innerAnalyzers.elements();
1119:	    while (enum.hasMoreElements()) {
1120:		ClassAnalyzer classAna = (ClassAnalyzer) enum.nextElement();
1121:		if (classAna.getClazz().equals(cinfo)) {
1122:		    if (classAna.getParent() != this ) {
1123:			ClassDeclarer declarer = classAna.getParent();
1124:			while (declarer != this ) {
1125:			    if (declarer instanceof  MethodAnalyzer)
1126:				((MethodAnalyzer) declarer)
1127:				    .innerAnalyzers.removeElement(classAna);
1128:			    declarer = declarer.getParent();
1129:			}
1130:			classAna.setParent(this );
1131:		    }
1132:		    return classAna;
1133:		}
1134:	    }
1135:	}
1136:	return getParent().getClassAnalyzer(cinfo);
1137:    }
1138:
1139:            public void addClassAnalyzer(ClassAnalyzer clazzAna) {
1140:                if (innerAnalyzers == null)
1141:                    innerAnalyzers = new Vector();
1142:                innerAnalyzers.addElement(clazzAna);
1143:                getParent().addClassAnalyzer(clazzAna);
1144:            }
1145:
1146:            /**
1147:             * We add the named method scoped classes to the declarables.
1148:             */
1149:            public void fillDeclarables(Collection used) {
1150:	if (usedAnalyzers != null)
1151:	    used.addAll(usedAnalyzers);
1152:	if (innerAnalyzers != null) {
1153:	    Enumeration enum = innerAnalyzers.elements();
1154:	    while (enum.hasMoreElements()) {
1155:		ClassAnalyzer classAna = (ClassAnalyzer) enum.nextElement();
1156:		if (classAna.getParent() == this )
1157:		    classAna.fillDeclarables(used);
1158:	    }
1159:	}
1160:    }
1161:
1162:            public boolean isMoreOuterThan(ClassDeclarer declarer) {
1163:                ClassDeclarer ancestor = declarer;
1164:                while (ancestor != null) {
1165:                    if (ancestor == this )
1166:                        return true;
1167:                    ancestor = ancestor.getParent();
1168:                }
1169:                return false;
1170:            }
1171:
1172:            public String toString() {
1173:                return getClass().getName() + "[" + getClazz() + "."
1174:                        + getName() + "]";
1175:            }
1176:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.