Source Code Cross Referenced for GenerateJavaScriptAST.java in  » Ajax » GWT » com » google » gwt » dev » jjs » impl » 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 » Ajax » GWT » com.google.gwt.dev.jjs.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2007 Google Inc.
0003:         * 
0004:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0005:         * use this file except in compliance with the License. You may obtain a copy of
0006:         * the License at
0007:         * 
0008:         * http://www.apache.org/licenses/LICENSE-2.0
0009:         * 
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0012:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0013:         * License for the specific language governing permissions and limitations under
0014:         * the License.
0015:         */
0016:        package com.google.gwt.dev.jjs.impl;
0017:
0018:        import com.google.gwt.dev.jjs.InternalCompilerException;
0019:        import com.google.gwt.dev.jjs.JsOutputOption;
0020:        import com.google.gwt.dev.jjs.ast.Context;
0021:        import com.google.gwt.dev.jjs.ast.HasEnclosingType;
0022:        import com.google.gwt.dev.jjs.ast.HasName;
0023:        import com.google.gwt.dev.jjs.ast.JAbsentArrayDimension;
0024:        import com.google.gwt.dev.jjs.ast.JAbstractMethodBody;
0025:        import com.google.gwt.dev.jjs.ast.JArrayRef;
0026:        import com.google.gwt.dev.jjs.ast.JArrayType;
0027:        import com.google.gwt.dev.jjs.ast.JAssertStatement;
0028:        import com.google.gwt.dev.jjs.ast.JBinaryOperation;
0029:        import com.google.gwt.dev.jjs.ast.JBinaryOperator;
0030:        import com.google.gwt.dev.jjs.ast.JBlock;
0031:        import com.google.gwt.dev.jjs.ast.JBreakStatement;
0032:        import com.google.gwt.dev.jjs.ast.JCaseStatement;
0033:        import com.google.gwt.dev.jjs.ast.JCastOperation;
0034:        import com.google.gwt.dev.jjs.ast.JClassLiteral;
0035:        import com.google.gwt.dev.jjs.ast.JClassType;
0036:        import com.google.gwt.dev.jjs.ast.JConditional;
0037:        import com.google.gwt.dev.jjs.ast.JContinueStatement;
0038:        import com.google.gwt.dev.jjs.ast.JDoStatement;
0039:        import com.google.gwt.dev.jjs.ast.JExpressionStatement;
0040:        import com.google.gwt.dev.jjs.ast.JField;
0041:        import com.google.gwt.dev.jjs.ast.JFieldRef;
0042:        import com.google.gwt.dev.jjs.ast.JForStatement;
0043:        import com.google.gwt.dev.jjs.ast.JIfStatement;
0044:        import com.google.gwt.dev.jjs.ast.JInstanceOf;
0045:        import com.google.gwt.dev.jjs.ast.JInterfaceType;
0046:        import com.google.gwt.dev.jjs.ast.JLabel;
0047:        import com.google.gwt.dev.jjs.ast.JLabeledStatement;
0048:        import com.google.gwt.dev.jjs.ast.JLocal;
0049:        import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement;
0050:        import com.google.gwt.dev.jjs.ast.JLocalRef;
0051:        import com.google.gwt.dev.jjs.ast.JMethod;
0052:        import com.google.gwt.dev.jjs.ast.JMethodBody;
0053:        import com.google.gwt.dev.jjs.ast.JMethodCall;
0054:        import com.google.gwt.dev.jjs.ast.JNewArray;
0055:        import com.google.gwt.dev.jjs.ast.JNewInstance;
0056:        import com.google.gwt.dev.jjs.ast.JParameter;
0057:        import com.google.gwt.dev.jjs.ast.JParameterRef;
0058:        import com.google.gwt.dev.jjs.ast.JPostfixOperation;
0059:        import com.google.gwt.dev.jjs.ast.JPrefixOperation;
0060:        import com.google.gwt.dev.jjs.ast.JProgram;
0061:        import com.google.gwt.dev.jjs.ast.JReferenceType;
0062:        import com.google.gwt.dev.jjs.ast.JReturnStatement;
0063:        import com.google.gwt.dev.jjs.ast.JStatement;
0064:        import com.google.gwt.dev.jjs.ast.JSwitchStatement;
0065:        import com.google.gwt.dev.jjs.ast.JThisRef;
0066:        import com.google.gwt.dev.jjs.ast.JThrowStatement;
0067:        import com.google.gwt.dev.jjs.ast.JTryStatement;
0068:        import com.google.gwt.dev.jjs.ast.JType;
0069:        import com.google.gwt.dev.jjs.ast.JTypeOracle;
0070:        import com.google.gwt.dev.jjs.ast.JUnaryOperator;
0071:        import com.google.gwt.dev.jjs.ast.JVisitor;
0072:        import com.google.gwt.dev.jjs.ast.JWhileStatement;
0073:        import com.google.gwt.dev.jjs.ast.js.JClassSeed;
0074:        import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
0075:        import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
0076:        import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
0077:        import com.google.gwt.dev.jjs.ast.js.JsonArray;
0078:        import com.google.gwt.dev.jjs.ast.js.JsonObject;
0079:        import com.google.gwt.dev.jjs.ast.js.JsonObject.JsonPropInit;
0080:        import com.google.gwt.dev.js.ast.JsArrayAccess;
0081:        import com.google.gwt.dev.js.ast.JsArrayLiteral;
0082:        import com.google.gwt.dev.js.ast.JsBinaryOperation;
0083:        import com.google.gwt.dev.js.ast.JsBinaryOperator;
0084:        import com.google.gwt.dev.js.ast.JsBlock;
0085:        import com.google.gwt.dev.js.ast.JsBreak;
0086:        import com.google.gwt.dev.js.ast.JsCase;
0087:        import com.google.gwt.dev.js.ast.JsCatch;
0088:        import com.google.gwt.dev.js.ast.JsConditional;
0089:        import com.google.gwt.dev.js.ast.JsContext;
0090:        import com.google.gwt.dev.js.ast.JsContinue;
0091:        import com.google.gwt.dev.js.ast.JsDefault;
0092:        import com.google.gwt.dev.js.ast.JsDoWhile;
0093:        import com.google.gwt.dev.js.ast.JsExprStmt;
0094:        import com.google.gwt.dev.js.ast.JsExpression;
0095:        import com.google.gwt.dev.js.ast.JsFor;
0096:        import com.google.gwt.dev.js.ast.JsFunction;
0097:        import com.google.gwt.dev.js.ast.JsIf;
0098:        import com.google.gwt.dev.js.ast.JsIntegralLiteral;
0099:        import com.google.gwt.dev.js.ast.JsInvocation;
0100:        import com.google.gwt.dev.js.ast.JsLabel;
0101:        import com.google.gwt.dev.js.ast.JsModVisitor;
0102:        import com.google.gwt.dev.js.ast.JsName;
0103:        import com.google.gwt.dev.js.ast.JsNameRef;
0104:        import com.google.gwt.dev.js.ast.JsNew;
0105:        import com.google.gwt.dev.js.ast.JsNode;
0106:        import com.google.gwt.dev.js.ast.JsObjectLiteral;
0107:        import com.google.gwt.dev.js.ast.JsParameter;
0108:        import com.google.gwt.dev.js.ast.JsPostfixOperation;
0109:        import com.google.gwt.dev.js.ast.JsPrefixOperation;
0110:        import com.google.gwt.dev.js.ast.JsProgram;
0111:        import com.google.gwt.dev.js.ast.JsPropertyInitializer;
0112:        import com.google.gwt.dev.js.ast.JsReturn;
0113:        import com.google.gwt.dev.js.ast.JsScope;
0114:        import com.google.gwt.dev.js.ast.JsStatement;
0115:        import com.google.gwt.dev.js.ast.JsSwitch;
0116:        import com.google.gwt.dev.js.ast.JsSwitchMember;
0117:        import com.google.gwt.dev.js.ast.JsThisRef;
0118:        import com.google.gwt.dev.js.ast.JsThrow;
0119:        import com.google.gwt.dev.js.ast.JsTry;
0120:        import com.google.gwt.dev.js.ast.JsUnaryOperation;
0121:        import com.google.gwt.dev.js.ast.JsUnaryOperator;
0122:        import com.google.gwt.dev.js.ast.JsVars;
0123:        import com.google.gwt.dev.js.ast.JsWhile;
0124:        import com.google.gwt.dev.js.ast.JsVars.JsVar;
0125:
0126:        import java.math.BigInteger;
0127:        import java.util.Arrays;
0128:        import java.util.Collections;
0129:        import java.util.HashMap;
0130:        import java.util.HashSet;
0131:        import java.util.IdentityHashMap;
0132:        import java.util.Iterator;
0133:        import java.util.List;
0134:        import java.util.Map;
0135:        import java.util.Set;
0136:        import java.util.Stack;
0137:        import java.util.TreeMap;
0138:
0139:        /**
0140:         * Creates a JavaScript AST from a <code>JProgram</code> node.
0141:         */
0142:        public class GenerateJavaScriptAST {
0143:
0144:            private class CreateNamesAndScopesVisitor extends JVisitor {
0145:
0146:                private final JField arrayLengthField = program
0147:                        .getIndexedField("Array.length");
0148:                private final Stack<JsScope> scopeStack = new Stack<JsScope>();
0149:
0150:                @Override
0151:                public void endVisit(JClassType x, Context ctx) {
0152:                    pop();
0153:                }
0154:
0155:                @Override
0156:                public void endVisit(JField x, Context ctx) {
0157:                    String name = x.getName();
0158:                    String mangleName = mangleName(x);
0159:                    if (x.isStatic()) {
0160:                        names.put(x, topScope.declareName(mangleName, name));
0161:                    } else {
0162:                        JsName jsName;
0163:                        if (x == arrayLengthField) {
0164:                            jsName = peek().declareName(name);
0165:                            jsName.setObfuscatable(false);
0166:                        } else if (belongsToSpecialObfuscatedType(x)) {
0167:                            jsName = peek().declareName(
0168:                                    mangleNameSpecialObfuscate(x));
0169:                            jsName.setObfuscatable(false);
0170:                        } else {
0171:                            jsName = peek().declareName(mangleName, name);
0172:                        }
0173:                        names.put(x, jsName);
0174:                    }
0175:                }
0176:
0177:                @Override
0178:                public void endVisit(JInterfaceType x, Context ctx) {
0179:                    pop();
0180:                }
0181:
0182:                @Override
0183:                public void endVisit(JLabel x, Context ctx) {
0184:                    if (names.get(x) != null) {
0185:                        return;
0186:                    }
0187:                    names.put(x, peek().declareName(x.getName()));
0188:                }
0189:
0190:                @Override
0191:                public void endVisit(JLocal x, Context ctx) {
0192:                    // locals can conflict, that's okay just reuse the same variable
0193:                    JsScope scope = peek();
0194:                    JsName jsName = scope.declareName(x.getName());
0195:                    names.put(x, jsName);
0196:                }
0197:
0198:                @Override
0199:                public void endVisit(JMethod x, Context ctx) {
0200:                    pop();
0201:                }
0202:
0203:                @Override
0204:                public void endVisit(JParameter x, Context ctx) {
0205:                    names.put(x, peek().declareName(x.getName()));
0206:                }
0207:
0208:                @Override
0209:                public void endVisit(JProgram x, Context ctx) {
0210:                    /*
0211:                     * put the null method and field into objectScope since they can be
0212:                     * referenced as instance on null-types (as determined by type flow)
0213:                     */
0214:                    JMethod nullMethod = x.getNullMethod();
0215:                    polymorphicNames.put(nullMethod, objectScope
0216:                            .declareName(nullMethod.getName()));
0217:                    JField nullField = x.getNullField();
0218:                    JsName nullFieldName = objectScope.declareName(nullField
0219:                            .getName());
0220:                    names.put(nullField, nullFieldName);
0221:
0222:                    /*
0223:                     * put nullMethod in the global scope, too; it's the replacer for clinits
0224:                     */
0225:                    nullMethodName = topScope.declareName(nullMethod.getName());
0226:                    names.put(nullMethod, nullMethodName);
0227:                }
0228:
0229:                @Override
0230:                public boolean visit(JClassType x, Context ctx) {
0231:                    // have I already been visited as a super type?
0232:                    JsScope myScope = classScopes.get(x);
0233:                    if (myScope != null) {
0234:                        push(myScope);
0235:                        return false;
0236:                    }
0237:
0238:                    // My seed function name
0239:                    names.put(x, topScope.declareName(getNameString(x), x
0240:                            .getShortName()));
0241:
0242:                    // My class scope
0243:                    if (x.extnds == null) {
0244:                        myScope = objectScope;
0245:                    } else {
0246:                        JsScope parentScope = classScopes.get(x.extnds);
0247:                        // Run my superclass first!
0248:                        if (parentScope == null) {
0249:                            accept(x.extnds);
0250:                        }
0251:                        parentScope = classScopes.get(x.extnds);
0252:                        assert (parentScope != null);
0253:                        /*
0254:                         * WEIRD: we wedge the global interface scope in between object and all
0255:                         * of its subclasses; this ensures that interface method names trump all
0256:                         * (except Object method names)
0257:                         */
0258:                        if (parentScope == objectScope) {
0259:                            parentScope = interfaceScope;
0260:                        }
0261:                        myScope = new JsScope(parentScope, "class "
0262:                                + x.getShortName());
0263:                    }
0264:                    classScopes.put(x, myScope);
0265:
0266:                    push(myScope);
0267:                    return true;
0268:                }
0269:
0270:                @Override
0271:                public boolean visit(JInterfaceType x, Context ctx) {
0272:                    // interfaces have no name at run time
0273:                    push(interfaceScope);
0274:                    return true;
0275:                }
0276:
0277:                @Override
0278:                public boolean visit(JMethod x, Context ctx) {
0279:                    // my polymorphic name
0280:                    String name = x.getName();
0281:                    if (!x.isStatic()) {
0282:                        if (polymorphicNames.get(x) == null) {
0283:                            String mangleName = mangleNameForPoly(x);
0284:                            JsName polyName;
0285:                            if (belongsToSpecialObfuscatedType(x)) {
0286:                                polyName = interfaceScope
0287:                                        .declareName(mangleNameSpecialObfuscate(x));
0288:                                polyName.setObfuscatable(false);
0289:                            } else {
0290:                                polyName = interfaceScope.declareName(
0291:                                        mangleName, name);
0292:                            }
0293:                            polymorphicNames.put(x, polyName);
0294:                        }
0295:                    }
0296:
0297:                    if (x.isAbstract()) {
0298:                        // just push a dummy scope that we can pop in endVisit
0299:                        push(null);
0300:                        return false;
0301:                    }
0302:
0303:                    // my global name
0304:                    JsName globalName;
0305:                    if (x.getEnclosingType() == null) {
0306:                        globalName = topScope.declareName(name);
0307:                    } else {
0308:                        String mangleName = mangleNameForGlobal(x);
0309:                        globalName = topScope.declareName(mangleName, name);
0310:                    }
0311:                    names.put(x, globalName);
0312:
0313:                    JsFunction jsFunction;
0314:                    if (x.isNative()) {
0315:                        // set the global name of the JSNI peer
0316:                        JsniMethodBody body = (JsniMethodBody) x.getBody();
0317:                        jsFunction = body.getFunc();
0318:                        jsFunction.setName(globalName);
0319:                    } else {
0320:                        // create a new peer JsFunction
0321:                        jsFunction = new JsFunction(topScope, globalName, true);
0322:                        methodBodyMap.put(x.getBody(), jsFunction);
0323:                    }
0324:                    push(jsFunction.getScope());
0325:                    return true;
0326:                }
0327:
0328:                @Override
0329:                public boolean visit(JTryStatement x, Context ctx) {
0330:                    accept(x.getTryBlock());
0331:
0332:                    List<JLocalRef> catchArgs = x.getCatchArgs();
0333:                    List<JBlock> catchBlocks = x.getCatchBlocks();
0334:                    for (int i = 0, c = catchArgs.size(); i < c; ++i) {
0335:                        JLocalRef arg = catchArgs.get(i);
0336:                        JBlock catchBlock = catchBlocks.get(i);
0337:                        JsCatch jsCatch = new JsCatch(peek(), arg.getTarget()
0338:                                .getName());
0339:                        JsParameter jsParam = jsCatch.getParameter();
0340:                        names.put(arg.getTarget(), jsParam.getName());
0341:                        catchMap.put(catchBlock, jsCatch);
0342:
0343:                        push(jsCatch.getScope());
0344:                        accept(catchBlock);
0345:                        pop();
0346:                    }
0347:
0348:                    // TODO: normalize this so it's never null?
0349:                    if (x.getFinallyBlock() != null) {
0350:                        accept(x.getFinallyBlock());
0351:                    }
0352:                    return false;
0353:                }
0354:
0355:                private JsScope peek() {
0356:                    return scopeStack.peek();
0357:                }
0358:
0359:                private void pop() {
0360:                    scopeStack.pop();
0361:                }
0362:
0363:                private void push(JsScope scope) {
0364:                    scopeStack.push(scope);
0365:                }
0366:            }
0367:
0368:            private class GenerateJavaScriptVisitor extends
0369:                    GenerateJavaScriptLiterals {
0370:
0371:                private final Set<JClassType> alreadyRan = new HashSet<JClassType>();
0372:
0373:                private JMethod currentMethod = null;
0374:
0375:                private final JsName globalTemp = topScope.declareName("_");
0376:
0377:                private final JsName prototype = objectScope
0378:                        .declareName("prototype");
0379:
0380:                private Map<JClassType, JsFunction> clinitMap = new HashMap<JClassType, JsFunction>();
0381:
0382:                {
0383:                    globalTemp.setObfuscatable(false);
0384:                    prototype.setObfuscatable(false);
0385:                }
0386:
0387:                public GenerateJavaScriptVisitor() {
0388:                    super (jsProgram);
0389:                }
0390:
0391:                @Override
0392:                public void endVisit(JAbsentArrayDimension x, Context ctx) {
0393:                    throw new InternalCompilerException("Should not get here.");
0394:                }
0395:
0396:                @Override
0397:                public void endVisit(JArrayRef x, Context ctx) {
0398:                    JsArrayAccess jsArrayAccess = new JsArrayAccess();
0399:                    jsArrayAccess.setIndexExpr((JsExpression) pop());
0400:                    jsArrayAccess.setArrayExpr((JsExpression) pop());
0401:                    push(jsArrayAccess);
0402:                }
0403:
0404:                @Override
0405:                public void endVisit(JAssertStatement x, Context ctx) {
0406:                    throw new InternalCompilerException("Should not get here.");
0407:                }
0408:
0409:                @Override
0410:                public void endVisit(JBinaryOperation x, Context ctx) {
0411:                    JsExpression rhs = (JsExpression) pop(); // rhs
0412:                    JsExpression lhs = (JsExpression) pop(); // lhs
0413:                    JsBinaryOperator myOp = JavaToJsOperatorMap.get(x.getOp());
0414:
0415:                    /*
0416:                     * Use === and !== on reference types, or else you can get wrong answers
0417:                     * when Object.toString() == 'some string'.
0418:                     */
0419:                    if (myOp == JsBinaryOperator.EQ
0420:                            && x.getLhs().getType() instanceof  JReferenceType
0421:                            && x.getRhs().getType() instanceof  JReferenceType) {
0422:                        myOp = JsBinaryOperator.REF_EQ;
0423:                    } else if (myOp == JsBinaryOperator.NEQ
0424:                            && x.getLhs().getType() instanceof  JReferenceType
0425:                            && x.getRhs().getType() instanceof  JReferenceType) {
0426:                        myOp = JsBinaryOperator.REF_NEQ;
0427:                    }
0428:
0429:                    push(new JsBinaryOperation(myOp, lhs, rhs));
0430:                }
0431:
0432:                @Override
0433:                public void endVisit(JBlock x, Context ctx) {
0434:                    JsBlock jsBlock = new JsBlock();
0435:                    List<JsStatement> stmts = jsBlock.getStatements();
0436:                    popList(stmts, x.statements.size()); // stmts
0437:                    Iterator<JsStatement> iterator = stmts.iterator();
0438:                    while (iterator.hasNext()) {
0439:                        JsStatement stmt = iterator.next();
0440:                        if (stmt == jsProgram.getEmptyStmt()) {
0441:                            iterator.remove();
0442:                        }
0443:                    }
0444:                    push(jsBlock);
0445:                }
0446:
0447:                @Override
0448:                public void endVisit(JBreakStatement x, Context ctx) {
0449:                    JsNameRef labelRef = null;
0450:                    if (x.getLabel() != null) {
0451:                        JsLabel label = (JsLabel) pop(); // label
0452:                        labelRef = label.getName().makeRef();
0453:                    }
0454:                    push(new JsBreak(labelRef));
0455:                }
0456:
0457:                @Override
0458:                public void endVisit(JCaseStatement x, Context ctx) {
0459:                    if (x.getExpr() == null) {
0460:                        push(new JsDefault());
0461:                    } else {
0462:                        JsCase jsCase = new JsCase();
0463:                        jsCase.setCaseExpr((JsExpression) pop()); // expr
0464:                        push(jsCase);
0465:                    }
0466:                }
0467:
0468:                @Override
0469:                public void endVisit(JCastOperation x, Context ctx) {
0470:                    throw new InternalCompilerException("Should not get here.");
0471:                }
0472:
0473:                @Override
0474:                public void endVisit(JClassLiteral x, Context ctx) {
0475:                    JsExpression classObjectAllocation = pop(); // classObjectAllocation
0476:
0477:                    // My seed function name
0478:                    String nameString = x.getRefType().getJavahSignatureName()
0479:                            + "_classlit";
0480:                    JsName classLit = topScope.declareName(nameString);
0481:                    classLits.put(x.getRefType(), classLit);
0482:                    classObjects.put(classLit, classObjectAllocation);
0483:                    push(classLit.makeRef());
0484:                }
0485:
0486:                @Override
0487:                public void endVisit(JClassSeed x, Context ctx) {
0488:                    push(names.get(x.getRefType()).makeRef());
0489:                }
0490:
0491:                @Override
0492:                public void endVisit(JClassType x, Context ctx) {
0493:                    if (alreadyRan.contains(x)) {
0494:                        return;
0495:                    }
0496:
0497:                    alreadyRan.add(x);
0498:
0499:                    List<JsFunction> jsFuncs = popList(x.methods.size()); // methods
0500:                    List<JsNode> jsFields = popList(x.fields.size()); // fields
0501:
0502:                    if (typeOracle.hasClinit(x)) {
0503:                        JsFunction super Clinit = clinitMap.get(x.extnds);
0504:                        JsFunction myClinit = jsFuncs.get(0);
0505:                        handleClinit(myClinit, super Clinit);
0506:                        clinitMap.put(x, myClinit);
0507:                    } else {
0508:                        jsFuncs.set(0, null);
0509:                    }
0510:
0511:                    List<JsStatement> globalStmts = jsProgram.getGlobalBlock()
0512:                            .getStatements();
0513:
0514:                    // declare all methods into the global scope
0515:                    for (int i = 0; i < jsFuncs.size(); ++i) {
0516:                        JsFunction func = jsFuncs.get(i);
0517:                        if (func != null) {
0518:                            globalStmts.add(func.makeStmt());
0519:                        }
0520:                    }
0521:
0522:                    if (typeOracle.isInstantiatedType(x)) {
0523:                        generateClassSetup(x, globalStmts);
0524:                    }
0525:
0526:                    // setup fields
0527:                    JsVars vars = new JsVars();
0528:                    for (int i = 0; i < jsFields.size(); ++i) {
0529:                        JsNode node = jsFields.get(i);
0530:                        if (node instanceof  JsVar) {
0531:                            vars.add((JsVar) node);
0532:                        } else {
0533:                            assert (node instanceof  JsStatement);
0534:                            JsStatement stmt = (JsStatement) jsFields.get(i);
0535:                            globalStmts.add(stmt);
0536:                        }
0537:                    }
0538:                    if (!vars.isEmpty()) {
0539:                        globalStmts.add(vars);
0540:                    }
0541:                }
0542:
0543:                @Override
0544:                public void endVisit(JConditional x, Context ctx) {
0545:                    JsExpression elseExpr = (JsExpression) pop(); // elseExpr
0546:                    JsExpression thenExpr = (JsExpression) pop(); // thenExpr
0547:                    JsExpression ifTest = (JsExpression) pop(); // ifTest
0548:                    push(new JsConditional(ifTest, thenExpr, elseExpr));
0549:                }
0550:
0551:                @Override
0552:                public void endVisit(JContinueStatement x, Context ctx) {
0553:                    JsNameRef labelRef = null;
0554:                    if (x.getLabel() != null) {
0555:                        JsLabel label = (JsLabel) pop(); // label
0556:                        labelRef = label.getName().makeRef();
0557:                    }
0558:                    push(new JsContinue(labelRef));
0559:                }
0560:
0561:                @Override
0562:                public void endVisit(JDoStatement x, Context ctx) {
0563:                    JsDoWhile stmt = new JsDoWhile();
0564:                    if (x.getBody() != null) {
0565:                        stmt.setBody((JsStatement) pop()); // body
0566:                    } else {
0567:                        stmt.setBody(jsProgram.getEmptyStmt());
0568:                    }
0569:                    stmt.setCondition((JsExpression) pop()); // testExpr
0570:                    push(stmt);
0571:                }
0572:
0573:                @Override
0574:                public void endVisit(JExpressionStatement x, Context ctx) {
0575:                    JsExpression expr = (JsExpression) pop(); // expr
0576:                    push(expr.makeStmt());
0577:                }
0578:
0579:                @Override
0580:                public void endVisit(JField x, Context ctx) {
0581:                    // if we need an initial value, create an assignment
0582:                    if (x.constInitializer != null) {
0583:                        // setup the constant value
0584:                        accept(x.constInitializer);
0585:                    } else if (x == program.getIndexedField("Cast.typeIdArray")) {
0586:                        // magic: setup the type id table
0587:                        push(generateTypeTable());
0588:                    } else if (!x.hasInitializer()) {
0589:                        // setup a default value
0590:                        accept(x.getType().getDefaultValue());
0591:                    } else {
0592:                        // the variable is setup during clinit, no need to initialize here
0593:                        push(null);
0594:                    }
0595:                    JsExpression rhs = (JsExpression) pop();
0596:                    JsName name = names.get(x);
0597:
0598:                    if (x.isStatic()) {
0599:                        // setup a var for the static
0600:                        JsVar var = new JsVar(name);
0601:                        var.setInitExpr(rhs);
0602:                        push(var);
0603:                    } else {
0604:                        // for non-statics, only setup an assignment if needed
0605:                        if (rhs != null) {
0606:                            JsNameRef fieldRef = name.makeRef();
0607:                            fieldRef.setQualifier(globalTemp.makeRef());
0608:                            JsExpression asg = createAssignment(fieldRef, rhs);
0609:                            push(new JsExprStmt(asg));
0610:                        } else {
0611:                            push(null);
0612:                        }
0613:                    }
0614:                }
0615:
0616:                @Override
0617:                public void endVisit(JFieldRef x, Context ctx) {
0618:                    JField field = x.getField();
0619:                    JsName jsFieldName = names.get(field);
0620:                    JsNameRef nameRef = jsFieldName.makeRef();
0621:                    JsExpression curExpr = nameRef;
0622:
0623:                    /*
0624:                     * Note: the comma expressions here would cause an illegal tree state if
0625:                     * the result expression ended up on the lhs of an assignment. A hack in
0626:                     * in endVisit(JBinaryOperation) rectifies the situation.
0627:                     */
0628:
0629:                    // See if we need a clinit
0630:                    JsInvocation jsInvocation = maybeCreateClinitCall(field);
0631:                    if (jsInvocation != null) {
0632:                        curExpr = createCommaExpression(jsInvocation, curExpr);
0633:                    }
0634:
0635:                    if (x.getInstance() != null) {
0636:                        JsExpression qualifier = (JsExpression) pop();
0637:                        if (field.isStatic()) {
0638:                            // unnecessary qualifier, create a comma expression
0639:                            curExpr = createCommaExpression(qualifier, curExpr);
0640:                        } else {
0641:                            // necessary qualifier, qualify the name ref
0642:                            nameRef.setQualifier(qualifier);
0643:                        }
0644:                    }
0645:
0646:                    push(curExpr);
0647:                }
0648:
0649:                @Override
0650:                public void endVisit(JForStatement x, Context ctx) {
0651:                    JsFor jsFor = new JsFor();
0652:
0653:                    // body
0654:                    if (x.getBody() != null) {
0655:                        jsFor.setBody((JsStatement) pop());
0656:                    } else {
0657:                        jsFor.setBody(jsProgram.getEmptyStmt());
0658:                    }
0659:
0660:                    // increments
0661:                    {
0662:                        JsExpression incrExpr = null;
0663:                        List<JsExprStmt> exprStmts = popList(x.getIncrements()
0664:                                .size());
0665:                        for (int i = 0; i < exprStmts.size(); ++i) {
0666:                            JsExprStmt exprStmt = exprStmts.get(i);
0667:                            incrExpr = createCommaExpression(incrExpr, exprStmt
0668:                                    .getExpression());
0669:                        }
0670:                        jsFor.setIncrExpr(incrExpr);
0671:                    }
0672:
0673:                    // condition
0674:                    if (x.getTestExpr() != null) {
0675:                        jsFor.setCondition((JsExpression) pop());
0676:                    }
0677:
0678:                    // initializers
0679:                    JsExpression initExpr = null;
0680:                    List<JsExprStmt> initStmts = popList(x.getInitializers()
0681:                            .size());
0682:                    for (int i = 0; i < initStmts.size(); ++i) {
0683:                        JsExprStmt initStmt = initStmts.get(i);
0684:                        if (initStmt != null) {
0685:                            initExpr = createCommaExpression(initExpr, initStmt
0686:                                    .getExpression());
0687:                        }
0688:                    }
0689:                    jsFor.setInitExpr(initExpr);
0690:
0691:                    push(jsFor);
0692:                }
0693:
0694:                @Override
0695:                public void endVisit(JIfStatement x, Context ctx) {
0696:                    JsIf stmt = new JsIf();
0697:
0698:                    if (x.getElseStmt() != null) {
0699:                        stmt.setElseStmt((JsStatement) pop()); // elseStmt
0700:                    }
0701:
0702:                    if (x.getThenStmt() != null) {
0703:                        stmt.setThenStmt((JsStatement) pop()); // thenStmt
0704:                    } else {
0705:                        stmt.setThenStmt(jsProgram.getEmptyStmt());
0706:                    }
0707:
0708:                    stmt.setIfExpr((JsExpression) pop()); // ifExpr
0709:                    push(stmt);
0710:                }
0711:
0712:                @Override
0713:                public void endVisit(JInstanceOf x, Context ctx) {
0714:                    throw new InternalCompilerException("Should not get here.");
0715:                }
0716:
0717:                @Override
0718:                public void endVisit(JInterfaceType x, Context ctx) {
0719:                    List<JsFunction> jsFuncs = popList(x.methods.size()); // methods
0720:                    List<JsVar> jsFields = popList(x.fields.size()); // fields
0721:                    List<JsStatement> globalStmts = jsProgram.getGlobalBlock()
0722:                            .getStatements();
0723:
0724:                    if (typeOracle.hasClinit(x)) {
0725:                        JsFunction clinitFunc = jsFuncs.get(0);
0726:                        handleClinit(clinitFunc, null);
0727:                        globalStmts.add(clinitFunc.makeStmt());
0728:                    }
0729:
0730:                    // setup fields
0731:                    JsVars vars = new JsVars();
0732:                    for (int i = 0; i < jsFields.size(); ++i) {
0733:                        vars.add(jsFields.get(i));
0734:                    }
0735:                    if (!vars.isEmpty()) {
0736:                        globalStmts.add(vars);
0737:                    }
0738:                }
0739:
0740:                @Override
0741:                public void endVisit(JLabel x, Context ctx) {
0742:                    push(new JsLabel(names.get(x)));
0743:                }
0744:
0745:                @Override
0746:                public void endVisit(JLabeledStatement x, Context ctx) {
0747:                    JsStatement body = (JsStatement) pop(); // body
0748:                    JsLabel label = (JsLabel) pop(); // label
0749:                    label.setStmt(body);
0750:                    push(label);
0751:                }
0752:
0753:                @Override
0754:                public void endVisit(JLocal x, Context ctx) {
0755:                    push(names.get(x).makeRef());
0756:                }
0757:
0758:                @Override
0759:                public void endVisit(JLocalDeclarationStatement x, Context ctx) {
0760:
0761:                    if (x.getInitializer() == null) {
0762:                        pop(); // localRef
0763:                        /*
0764:                         * local decls can only appear in blocks, so it's okay to push null
0765:                         * instead of an empty statement
0766:                         */
0767:                        push(null);
0768:                        return;
0769:                    }
0770:
0771:                    JsExpression initializer = (JsExpression) pop(); // initializer
0772:                    JsNameRef localRef = (JsNameRef) pop(); // localRef
0773:
0774:                    JsBinaryOperation binOp = new JsBinaryOperation(
0775:                            JsBinaryOperator.ASG, localRef, initializer);
0776:
0777:                    push(binOp.makeStmt());
0778:                }
0779:
0780:                @Override
0781:                public void endVisit(JLocalRef x, Context ctx) {
0782:                    push(names.get(x.getTarget()).makeRef());
0783:                }
0784:
0785:                @Override
0786:                public void endVisit(JMethod x, Context ctx) {
0787:                    if (x.isAbstract()) {
0788:                        push(null);
0789:                        return;
0790:                    }
0791:
0792:                    JsFunction jsFunc = (JsFunction) pop(); // body
0793:                    List<JsParameter> params = popList(x.params.size()); // params
0794:
0795:                    if (!x.isNative()) {
0796:                        // Setup params on the generated function. A native method already got
0797:                        // its jsParams set in BuildTypeMap.
0798:                        // TODO: Do we really need to do that in BuildTypeMap?
0799:                        List<JsParameter> jsParams = jsFunc.getParameters();
0800:                        for (int i = 0; i < params.size(); ++i) {
0801:                            JsParameter param = params.get(i);
0802:                            jsParams.add(param);
0803:                        }
0804:                    }
0805:
0806:                    JsInvocation jsInvocation = maybeCreateClinitCall(x);
0807:                    if (jsInvocation != null) {
0808:                        jsFunc.getBody().getStatements().add(0,
0809:                                jsInvocation.makeStmt());
0810:                    }
0811:
0812:                    push(jsFunc);
0813:                    currentMethod = null;
0814:                }
0815:
0816:                @Override
0817:                public void endVisit(JMethodBody x, Context ctx) {
0818:
0819:                    JsBlock body = (JsBlock) pop();
0820:                    List<JsNameRef> locals = popList(x.locals.size()); // locals
0821:
0822:                    JsFunction jsFunc = methodBodyMap.get(x);
0823:                    jsFunc.setBody(body); // body
0824:
0825:                    /*
0826:                     * Emit a statement to declare the method's complete set of local
0827:                     * variables. JavaScript doesn't have the same concept of lexical scoping
0828:                     * as Java, so it's okay to just predeclare all local vars at the top of
0829:                     * the function, which saves us having to use the "var" keyword over and
0830:                     * over.
0831:                     * 
0832:                     * Note: it's fine to use the same JS ident to represent two different
0833:                     * Java locals of the same name since they could never conflict with each
0834:                     * other in Java. We use the alreadySeen set to make sure we don't declare
0835:                     * the same-named local var twice.
0836:                     */
0837:                    JsVars vars = new JsVars();
0838:                    Set<String> alreadySeen = new HashSet<String>();
0839:                    for (int i = 0; i < locals.size(); ++i) {
0840:                        JsName name = names.get(x.locals.get(i));
0841:                        String ident = name.getIdent();
0842:                        if (!alreadySeen.contains(ident)) {
0843:                            alreadySeen.add(ident);
0844:                            vars.add(new JsVar(name));
0845:                        }
0846:                    }
0847:
0848:                    if (!vars.isEmpty()) {
0849:                        jsFunc.getBody().getStatements().add(0, vars);
0850:                    }
0851:
0852:                    push(jsFunc);
0853:                }
0854:
0855:                @Override
0856:                public void endVisit(JMethodCall x, Context ctx) {
0857:                    JMethod method = x.getTarget();
0858:                    JsInvocation jsInvocation = new JsInvocation();
0859:
0860:                    popList(jsInvocation.getArguments(), x.getArgs().size()); // args
0861:
0862:                    JsNameRef qualifier;
0863:                    JsExpression unnecessaryQualifier = null;
0864:                    if (method.isStatic()) {
0865:                        if (x.getInstance() != null) {
0866:                            unnecessaryQualifier = (JsExpression) pop(); // instance
0867:                        }
0868:                        qualifier = names.get(method).makeRef();
0869:                    } else {
0870:                        if (x.isStaticDispatchOnly()) {
0871:                            /*
0872:                             * Dispatch statically (odd case). This happens when a call that must
0873:                             * be static is targeting an instance method that could not be
0874:                             * transformed into a static. For example, making a super call into a
0875:                             * native method currently causes this, because we cannot currently
0876:                             * staticify native methods.
0877:                             * 
0878:                             * Have to use a "call" construct.
0879:                             */
0880:                            JsName callName = objectScope.declareName("call");
0881:                            callName.setObfuscatable(false);
0882:                            qualifier = callName.makeRef();
0883:                            qualifier.setQualifier(names.get(method).makeRef());
0884:                            jsInvocation.getArguments().add(0,
0885:                                    (JsExpression) pop()); // instance
0886:                        } else {
0887:                            // Dispatch polymorphically (normal case).
0888:                            qualifier = polymorphicNames.get(method).makeRef();
0889:                            qualifier.setQualifier((JsExpression) pop()); // instance
0890:                        }
0891:                    }
0892:                    jsInvocation.setQualifier(qualifier);
0893:                    push(createCommaExpression(unnecessaryQualifier,
0894:                            jsInvocation));
0895:                }
0896:
0897:                @Override
0898:                public void endVisit(JMultiExpression x, Context ctx) {
0899:                    List<JsExpression> exprs = popList(x.exprs.size());
0900:                    JsExpression cur = null;
0901:                    for (int i = 0; i < exprs.size(); ++i) {
0902:                        JsExpression next = exprs.get(i);
0903:                        cur = createCommaExpression(cur, next);
0904:                    }
0905:                    push(cur);
0906:                }
0907:
0908:                @Override
0909:                public void endVisit(JNewArray x, Context ctx) {
0910:                    throw new InternalCompilerException("Should not get here.");
0911:                }
0912:
0913:                @Override
0914:                public void endVisit(JNewInstance x, Context ctx) {
0915:                    JsNew newOp = new JsNew();
0916:                    JsNameRef nameRef = names.get(x.getType()).makeRef();
0917:                    newOp.setConstructorExpression(nameRef);
0918:                    push(newOp);
0919:                }
0920:
0921:                @Override
0922:                public void endVisit(JParameter x, Context ctx) {
0923:                    push(new JsParameter(names.get(x)));
0924:                }
0925:
0926:                @Override
0927:                public void endVisit(JParameterRef x, Context ctx) {
0928:                    push(names.get(x.getTarget()).makeRef());
0929:                }
0930:
0931:                @Override
0932:                public void endVisit(JPostfixOperation x, Context ctx) {
0933:                    JsUnaryOperation op = new JsPostfixOperation(
0934:                            JavaToJsOperatorMap.get(x.getOp()),
0935:                            ((JsExpression) pop())); // arg
0936:                    push(op);
0937:                }
0938:
0939:                @Override
0940:                public void endVisit(JPrefixOperation x, Context ctx) {
0941:                    JsUnaryOperation op = new JsPrefixOperation(
0942:                            JavaToJsOperatorMap.get(x.getOp()),
0943:                            ((JsExpression) pop())); // arg
0944:                    push(op);
0945:                }
0946:
0947:                @Override
0948:                public void endVisit(JProgram x, Context ctx) {
0949:                    List<JsStatement> globalStmts = jsProgram.getGlobalBlock()
0950:                            .getStatements();
0951:
0952:                    // types don't push
0953:
0954:                    // Generate entry methods
0955:                    List<JsFunction> entryFuncs = popList(x.entryMethods.size()); // entryMethods
0956:                    for (int i = 0; i < entryFuncs.size(); ++i) {
0957:                        JsFunction func = entryFuncs.get(i);
0958:                        if (func != null) {
0959:                            globalStmts.add(func.makeStmt());
0960:                        }
0961:                    }
0962:
0963:                    generateGwtOnLoad(entryFuncs, globalStmts);
0964:                    generateNullFunc(globalStmts);
0965:
0966:                    // Add a few things onto the beginning.
0967:
0968:                    // Reserve the "_" identifier.
0969:                    JsVars vars = new JsVars();
0970:                    vars.add(new JsVar(globalTemp));
0971:                    globalStmts.add(0, vars);
0972:
0973:                    // Generate class objects.
0974:                    vars = new JsVars();
0975:                    generateClassLiterals(vars);
0976:                    if (!vars.isEmpty()) {
0977:                        globalStmts.add(vars);
0978:                    }
0979:                }
0980:
0981:                @Override
0982:                public void endVisit(JReturnStatement x, Context ctx) {
0983:                    if (x.getExpr() != null) {
0984:                        push(new JsReturn((JsExpression) pop())); // expr
0985:                    } else {
0986:                        push(new JsReturn());
0987:                    }
0988:                }
0989:
0990:                @Override
0991:                public void endVisit(JsniMethodRef x, Context ctx) {
0992:                    JMethod method = x.getTarget();
0993:                    JsNameRef nameRef = names.get(method).makeRef();
0994:                    push(nameRef);
0995:                }
0996:
0997:                @Override
0998:                public void endVisit(JsonArray x, Context ctx) {
0999:                    JsArrayLiteral jsArrayLiteral = new JsArrayLiteral();
1000:                    popList(jsArrayLiteral.getExpressions(), x.exprs.size());
1001:                    push(jsArrayLiteral);
1002:                }
1003:
1004:                @Override
1005:                public void endVisit(JsonObject x, Context ctx) {
1006:                    JsObjectLiteral jsObjectLiteral = new JsObjectLiteral();
1007:                    popList(jsObjectLiteral.getPropertyInitializers(),
1008:                            x.propInits.size());
1009:                    push(jsObjectLiteral);
1010:                }
1011:
1012:                @Override
1013:                public void endVisit(JsonPropInit init, Context ctx) {
1014:                    JsExpression valueExpr = (JsExpression) pop();
1015:                    JsExpression labelExpr = (JsExpression) pop();
1016:                    push(new JsPropertyInitializer(labelExpr, valueExpr));
1017:                }
1018:
1019:                @Override
1020:                public void endVisit(JThisRef x, Context ctx) {
1021:                    push(new JsThisRef());
1022:                }
1023:
1024:                @Override
1025:                public void endVisit(JThrowStatement x, Context ctx) {
1026:                    push(new JsThrow((JsExpression) pop())); // expr
1027:                }
1028:
1029:                @Override
1030:                public void endVisit(JTryStatement x, Context ctx) {
1031:                    JsTry jsTry = new JsTry();
1032:
1033:                    if (x.getFinallyBlock() != null) {
1034:                        JsBlock finallyBlock = (JsBlock) pop(); // finallyBlock
1035:                        if (finallyBlock.getStatements().size() > 0) {
1036:                            jsTry.setFinallyBlock(finallyBlock);
1037:                        }
1038:                    }
1039:
1040:                    int size = x.getCatchArgs().size();
1041:                    assert (size < 2 && size == x.getCatchBlocks().size());
1042:                    if (size == 1) {
1043:                        JsBlock catchBlock = (JsBlock) pop(); // catchBlocks
1044:                        pop(); // catchArgs
1045:                        JsCatch jsCatch = catchMap.get(x.getCatchBlocks()
1046:                                .get(0));
1047:                        jsCatch.setBody(catchBlock);
1048:                        jsTry.getCatches().add(jsCatch);
1049:                    }
1050:
1051:                    jsTry.setTryBlock((JsBlock) pop()); // tryBlock
1052:
1053:                    push(jsTry);
1054:                }
1055:
1056:                @Override
1057:                public void endVisit(JWhileStatement x, Context ctx) {
1058:                    JsWhile stmt = new JsWhile();
1059:                    if (x.getBody() != null) {
1060:                        stmt.setBody((JsStatement) pop()); // body
1061:                    } else {
1062:                        stmt.setBody(jsProgram.getEmptyStmt());
1063:                    }
1064:                    stmt.setCondition((JsExpression) pop()); // testExpr
1065:                    push(stmt);
1066:                }
1067:
1068:                @Override
1069:                public boolean visit(JClassType x, Context ctx) {
1070:                    if (alreadyRan.contains(x)) {
1071:                        return false;
1072:                    }
1073:
1074:                    // force super type to generate code first, this is required for prototype
1075:                    // chaining to work properly
1076:                    if (x.extnds != null && !alreadyRan.contains(x)) {
1077:                        accept(x.extnds);
1078:                    }
1079:
1080:                    return true;
1081:                }
1082:
1083:                @Override
1084:                public boolean visit(JMethod x, Context ctx) {
1085:                    if (x.isAbstract()) {
1086:                        return false;
1087:                    }
1088:                    currentMethod = x;
1089:                    return true;
1090:                }
1091:
1092:                @Override
1093:                public boolean visit(JsniMethodBody x, Context ctx) {
1094:                    JsFunction jsFunc = x.getFunc();
1095:
1096:                    // replace all JSNI idents with a real JsName now that we know it
1097:                    new JsModVisitor() {
1098:
1099:                        @Override
1100:                        public void endVisit(JsNameRef x,
1101:                                JsContext<JsExpression> ctx) {
1102:                            String ident = x.getIdent();
1103:                            if (ident.charAt(0) == '@') {
1104:                                HasEnclosingType node = program.jsniMap
1105:                                        .get(ident);
1106:                                assert (node != null);
1107:                                if (node instanceof  JField) {
1108:                                    JField field = (JField) node;
1109:                                    JsName jsName = names.get(field);
1110:                                    assert (jsName != null);
1111:                                    x.resolve(jsName);
1112:
1113:                                    // See if we need to add a clinit call to a static field ref
1114:                                    JsInvocation clinitCall = maybeCreateClinitCall(field);
1115:                                    if (clinitCall != null) {
1116:                                        JsExpression commaExpr = createCommaExpression(
1117:                                                clinitCall, x);
1118:                                        ctx.replaceMe(commaExpr);
1119:                                    }
1120:                                } else {
1121:                                    JMethod method = (JMethod) node;
1122:                                    if (x.getQualifier() == null) {
1123:                                        JsName jsName = names.get(method);
1124:                                        assert (jsName != null);
1125:                                        x.resolve(jsName);
1126:                                    } else {
1127:                                        JsName jsName = polymorphicNames
1128:                                                .get(method);
1129:                                        if (jsName == null) {
1130:                                            // this can occur when JSNI references an instance method on a
1131:                                            // type that was never actually instantiated.
1132:                                            jsName = nullMethodName;
1133:                                        }
1134:                                        x.resolve(jsName);
1135:                                    }
1136:                                }
1137:                            }
1138:                        }
1139:                    }.accept(jsFunc);
1140:
1141:                    push(jsFunc);
1142:
1143:                    // Do NOT visit JsniMethodRefs/JsniFieldRefs.
1144:                    return false;
1145:                }
1146:
1147:                @Override
1148:                public boolean visit(JSwitchStatement x, Context ctx) {
1149:                    /*
1150:                     * What a pain.. JSwitchStatement and JsSwitch are modeled completely
1151:                     * differently. Here we try to resolve those differences.
1152:                     */
1153:                    JsSwitch jsSwitch = new JsSwitch();
1154:                    accept(x.getExpr());
1155:                    jsSwitch.setExpr((JsExpression) pop()); // expr
1156:
1157:                    List<JStatement> bodyStmts = x.getBody().statements;
1158:                    if (bodyStmts.size() > 0) {
1159:                        List<JsStatement> curStatements = null;
1160:                        for (int i = 0; i < bodyStmts.size(); ++i) {
1161:                            JStatement stmt = bodyStmts.get(i);
1162:                            accept(stmt);
1163:                            if (stmt instanceof  JCaseStatement) {
1164:                                // create a new switch member
1165:                                JsSwitchMember switchMember = (JsSwitchMember) pop(); // stmt
1166:                                jsSwitch.getCases().add(switchMember);
1167:                                curStatements = switchMember.getStmts();
1168:                            } else {
1169:                                // add to statements for current case
1170:                                assert (curStatements != null);
1171:                                JsStatement newStmt = (JsStatement) pop(); // stmt
1172:                                if (newStmt != null) {
1173:                                    // Empty JLocalDeclarationStatement produces a null
1174:                                    curStatements.add(newStmt);
1175:                                }
1176:                            }
1177:                        }
1178:                    }
1179:
1180:                    push(jsSwitch);
1181:                    return false;
1182:                }
1183:
1184:                private JsExpression createAssignment(JsExpression lhs,
1185:                        JsExpression rhs) {
1186:                    return new JsBinaryOperation(JsBinaryOperator.ASG, lhs, rhs);
1187:                }
1188:
1189:                private JsExpression createCommaExpression(JsExpression lhs,
1190:                        JsExpression rhs) {
1191:                    if (lhs == null) {
1192:                        return rhs;
1193:                    } else if (rhs == null) {
1194:                        return lhs;
1195:                    }
1196:                    return new JsBinaryOperation(JsBinaryOperator.COMMA, lhs,
1197:                            rhs);
1198:                }
1199:
1200:                private void generateClassLiterals(JsVars vars) {
1201:                    Set<JType> alreadyGenerated = new HashSet<JType>();
1202:                    for (Object element : classLits.keySet()) {
1203:                        JType type = (JType) element;
1204:                        generateClassLiteralsRecursive(alreadyGenerated, type,
1205:                                vars);
1206:                    }
1207:                }
1208:
1209:                private void generateClassLiteralsRecursive(
1210:                        Set<JType> alreadyGenerated, JType type, JsVars vars) {
1211:                    if (alreadyGenerated.contains(type)) {
1212:                        return;
1213:                    }
1214:                    alreadyGenerated.add(type);
1215:
1216:                    if (type instanceof  JClassType
1217:                            && !(type instanceof  JArrayType)) {
1218:                        /*
1219:                         * If this type is a regular class or an enum, then ensure that its
1220:                         * superclass's class literal is generated before its own.
1221:                         * 
1222:                         * NOTE: JInterfaceTypes can have their JReferenceType.extnds member set
1223:                         * to its first implemented interface. JArrayTypes always have Object as
1224:                         * their superclass so there is no need to explicitly set it here.
1225:                         */
1226:                        JClassType classType = (JClassType) type;
1227:                        if (classType.extnds != null) {
1228:                            generateClassLiteralsRecursive(alreadyGenerated,
1229:                                    classType.extnds, vars);
1230:                        }
1231:                    }
1232:
1233:                    JsName jsName = classLits.get(type);
1234:                    JsExpression classObjectAlloc = classObjects.get(jsName);
1235:                    JsVar var = new JsVar(jsName);
1236:                    var.setInitExpr(classObjectAlloc);
1237:                    vars.add(var);
1238:                }
1239:
1240:                private void generateClassSetup(JClassType x,
1241:                        List<JsStatement> globalStmts) {
1242:                    generateSeedFuncAndPrototype(x, globalStmts);
1243:                    generateVTables(x, globalStmts);
1244:
1245:                    if (x == program.getTypeJavaLangObject()) {
1246:                        // special: setup a "toString" alias for java.lang.Object.toString()
1247:                        generateToStringAlias(x, globalStmts);
1248:                    }
1249:
1250:                    generateTypeId(x, globalStmts);
1251:                }
1252:
1253:                private void generateGwtOnLoad(List<JsFunction> entryFuncs,
1254:                        List<JsStatement> globalStmts) {
1255:                    /**
1256:                     * <pre>
1257:                     * function gwtOnLoad(errFn, modName, modBase){
1258:                     *   $moduleName = modName;
1259:                     *   $moduleBase = modBase;
1260:                     *   if (errFn) {
1261:                     *     try {
1262:                     *       init();
1263:                     *     } catch(e) {
1264:                     *       errFn(modName);
1265:                     *     }
1266:                     *   } else {
1267:                     *     init();
1268:                     *   }
1269:                     * }
1270:                     * </pre>
1271:                     */
1272:                    JsFunction gwtOnLoad = new JsFunction(topScope);
1273:                    globalStmts.add(gwtOnLoad.makeStmt());
1274:                    JsName gwtOnLoadName = topScope.declareName("gwtOnLoad");
1275:                    gwtOnLoadName.setObfuscatable(false);
1276:                    gwtOnLoad.setName(gwtOnLoadName);
1277:                    JsBlock body = new JsBlock();
1278:                    gwtOnLoad.setBody(body);
1279:                    JsScope fnScope = gwtOnLoad.getScope();
1280:                    List<JsParameter> params = gwtOnLoad.getParameters();
1281:                    JsName errFn = fnScope.declareName("errFn");
1282:                    JsName modName = fnScope.declareName("modName");
1283:                    JsName modBase = fnScope.declareName("modBase");
1284:                    params.add(new JsParameter(errFn));
1285:                    params.add(new JsParameter(modName));
1286:                    params.add(new JsParameter(modBase));
1287:                    JsExpression asg = createAssignment(topScope
1288:                            .findExistingUnobfuscatableName("$moduleName")
1289:                            .makeRef(), modName.makeRef());
1290:                    body.getStatements().add(asg.makeStmt());
1291:                    asg = createAssignment(topScope
1292:                            .findExistingUnobfuscatableName("$moduleBase")
1293:                            .makeRef(), modBase.makeRef());
1294:                    body.getStatements().add(asg.makeStmt());
1295:                    JsIf jsIf = new JsIf();
1296:                    body.getStatements().add(jsIf);
1297:                    jsIf.setIfExpr(errFn.makeRef());
1298:                    JsTry jsTry = new JsTry();
1299:                    jsIf.setThenStmt(jsTry);
1300:                    JsBlock callBlock = new JsBlock();
1301:                    jsIf.setElseStmt(callBlock);
1302:                    jsTry.setTryBlock(callBlock);
1303:                    for (int i = 0; i < entryFuncs.size(); ++i) {
1304:                        JsFunction func = entryFuncs.get(i);
1305:                        if (func != null) {
1306:                            JsInvocation call = new JsInvocation();
1307:                            call.setQualifier(func.getName().makeRef());
1308:                            callBlock.getStatements().add(call.makeStmt());
1309:                        }
1310:                    }
1311:                    JsCatch jsCatch = new JsCatch(fnScope, "e");
1312:                    jsTry.getCatches().add(jsCatch);
1313:                    JsBlock catchBlock = new JsBlock();
1314:                    jsCatch.setBody(catchBlock);
1315:                    JsInvocation errCall = new JsInvocation();
1316:                    catchBlock.getStatements().add(errCall.makeStmt());
1317:                    errCall.setQualifier(errFn.makeRef());
1318:                    errCall.getArguments().add(modName.makeRef());
1319:                }
1320:
1321:                private void generateNullFunc(List<JsStatement> globalStatements) {
1322:                    // handle null method
1323:                    JsFunction nullFunc = new JsFunction(topScope,
1324:                            nullMethodName);
1325:                    nullFunc.setBody(new JsBlock());
1326:                    globalStatements.add(nullFunc.makeStmt());
1327:                }
1328:
1329:                private void generateSeedFuncAndPrototype(JClassType x,
1330:                        List<JsStatement> globalStmts) {
1331:                    if (x != program.getTypeJavaLangString()) {
1332:                        JsName seedFuncName = names.get(x);
1333:
1334:                        // seed function
1335:                        // function com_example_foo_Foo() { }
1336:                        JsFunction seedFunc = new JsFunction(topScope,
1337:                                seedFuncName);
1338:                        JsBlock body = new JsBlock();
1339:                        seedFunc.setBody(body);
1340:                        globalStmts.add(seedFunc.makeStmt());
1341:
1342:                        // setup prototype, assign to temp
1343:                        // _ = com_example_foo_Foo.prototype = new com_example_foo_FooSuper();
1344:                        JsNameRef lhs = prototype.makeRef();
1345:                        lhs.setQualifier(seedFuncName.makeRef());
1346:                        JsExpression rhs;
1347:                        if (x.extnds != null) {
1348:                            JsNew newExpr = new JsNew();
1349:                            newExpr.setConstructorExpression(names
1350:                                    .get(x.extnds).makeRef());
1351:                            rhs = newExpr;
1352:                        } else {
1353:                            rhs = new JsObjectLiteral();
1354:                        }
1355:                        JsExpression protoAsg = createAssignment(lhs, rhs);
1356:                        JsExpression tmpAsg = createAssignment(globalTemp
1357:                                .makeRef(), protoAsg);
1358:                        globalStmts.add(tmpAsg.makeStmt());
1359:                    } else {
1360:                        /*
1361:                         * MAGIC: java.lang.String is implemented as a JavaScript String
1362:                         * primitive with a modified prototype.
1363:                         */
1364:                        JsNameRef rhs = prototype.makeRef();
1365:                        rhs.setQualifier(jsProgram.getRootScope().declareName(
1366:                                "String").makeRef());
1367:                        JsExpression tmpAsg = createAssignment(globalTemp
1368:                                .makeRef(), rhs);
1369:                        globalStmts.add(tmpAsg.makeStmt());
1370:                    }
1371:                }
1372:
1373:                private void generateToStringAlias(JClassType x,
1374:                        List<JsStatement> globalStmts) {
1375:                    JMethod toStringMeth = program
1376:                            .getIndexedMethod("Object.toString");
1377:                    if (x.methods.contains(toStringMeth)) {
1378:                        // _.toString = function(){return this.java_lang_Object_toString();}
1379:
1380:                        // lhs
1381:                        JsName lhsName = objectScope.declareName("toString");
1382:                        lhsName.setObfuscatable(false);
1383:                        JsNameRef lhs = lhsName.makeRef();
1384:                        lhs.setQualifier(globalTemp.makeRef());
1385:
1386:                        // rhs
1387:                        JsInvocation call = new JsInvocation();
1388:                        JsNameRef toStringRef = new JsNameRef(polymorphicNames
1389:                                .get(toStringMeth));
1390:                        toStringRef.setQualifier(new JsThisRef());
1391:                        call.setQualifier(toStringRef);
1392:                        JsReturn jsReturn = new JsReturn(call);
1393:                        JsFunction rhs = new JsFunction(topScope);
1394:                        JsBlock body = new JsBlock();
1395:                        body.getStatements().add(jsReturn);
1396:                        rhs.setBody(body);
1397:
1398:                        // asg
1399:                        JsExpression asg = createAssignment(lhs, rhs);
1400:                        globalStmts.add(new JsExprStmt(asg));
1401:                    }
1402:                }
1403:
1404:                private void generateTypeId(JClassType x,
1405:                        List<JsStatement> globalStmts) {
1406:                    int typeId = program.getTypeId(x);
1407:                    if (typeId >= 0) {
1408:                        JField typeIdField = program
1409:                                .getIndexedField("Object.typeId");
1410:                        JsName typeIdName = names.get(typeIdField);
1411:                        if (typeIdName == null) {
1412:                            // Was pruned; this compilation must have no dynamic casts.
1413:                            return;
1414:                        }
1415:                        JsNameRef fieldRef = typeIdName.makeRef();
1416:                        fieldRef.setQualifier(globalTemp.makeRef());
1417:                        JsIntegralLiteral typeIdLit = jsProgram
1418:                                .getIntegralLiteral(BigInteger.valueOf(typeId));
1419:                        JsExpression asg = createAssignment(fieldRef, typeIdLit);
1420:                        globalStmts.add(new JsExprStmt(asg));
1421:                    }
1422:                }
1423:
1424:                private JsExpression generateTypeTable() {
1425:                    JsArrayLiteral arrayLit = new JsArrayLiteral();
1426:                    for (int i = 0; i < program.getJsonTypeTable().size(); ++i) {
1427:                        JsonObject jsonObject = program.getJsonTypeTable().get(
1428:                                i);
1429:                        accept(jsonObject);
1430:                        arrayLit.getExpressions().add((JsExpression) pop());
1431:                    }
1432:                    return arrayLit;
1433:                }
1434:
1435:                private void generateVTables(JClassType x,
1436:                        List<JsStatement> globalStmts) {
1437:                    for (int i = 0; i < x.methods.size(); ++i) {
1438:                        JMethod method = x.methods.get(i);
1439:                        if (!method.isStatic() && !method.isAbstract()) {
1440:                            JsNameRef lhs = polymorphicNames.get(method)
1441:                                    .makeRef();
1442:                            lhs.setQualifier(globalTemp.makeRef());
1443:                            JsNameRef rhs = names.get(method).makeRef();
1444:                            JsExpression asg = createAssignment(lhs, rhs);
1445:                            globalStmts.add(new JsExprStmt(asg));
1446:                        }
1447:                    }
1448:                }
1449:
1450:                private void handleClinit(JsFunction clinitFunc,
1451:                        JsFunction super Clinit) {
1452:                    clinitFunc.setExecuteOnce(true);
1453:                    clinitFunc.setImpliedExecute(super Clinit);
1454:                    List<JsStatement> statements = clinitFunc.getBody()
1455:                            .getStatements();
1456:                    // self-assign to the null method immediately (to prevent reentrancy)
1457:                    JsExpression asg = createAssignment(clinitFunc.getName()
1458:                            .makeRef(), nullMethodName.makeRef());
1459:                    statements.add(0, asg.makeStmt());
1460:                }
1461:
1462:                private JsInvocation maybeCreateClinitCall(JField x) {
1463:                    if (!x.isStatic()) {
1464:                        return null;
1465:                    }
1466:
1467:                    JReferenceType enclosingType = x.getEnclosingType();
1468:                    if (!typeOracle.checkClinit(currentMethod
1469:                            .getEnclosingType(), enclosingType)) {
1470:                        return null;
1471:                    }
1472:
1473:                    JMethod clinitMethod = enclosingType.methods.get(0);
1474:                    JsInvocation jsInvocation = new JsInvocation();
1475:                    jsInvocation
1476:                            .setQualifier(names.get(clinitMethod).makeRef());
1477:                    return jsInvocation;
1478:                }
1479:
1480:                private JsInvocation maybeCreateClinitCall(JMethod x) {
1481:                    if (!crossClassTargets.contains(x)) {
1482:                        return null;
1483:                    }
1484:                    if (!x.isStatic() || program.isStaticImpl(x)) {
1485:                        return null;
1486:                    }
1487:                    JReferenceType enclosingType = x.getEnclosingType();
1488:                    if (!typeOracle.hasClinit(enclosingType)) {
1489:                        return null;
1490:                    }
1491:                    // avoid recursion sickness
1492:                    if (x == enclosingType.methods.get(0)) {
1493:                        return null;
1494:                    }
1495:
1496:                    JMethod clinitMethod = enclosingType.methods.get(0);
1497:                    JsInvocation jsInvocation = new JsInvocation();
1498:                    jsInvocation
1499:                            .setQualifier(names.get(clinitMethod).makeRef());
1500:                    return jsInvocation;
1501:                }
1502:            }
1503:
1504:            private static class JavaToJsOperatorMap {
1505:                private static final Map<JBinaryOperator, JsBinaryOperator> bOpMap = new IdentityHashMap<JBinaryOperator, JsBinaryOperator>();
1506:                private static final Map<JUnaryOperator, JsUnaryOperator> uOpMap = new IdentityHashMap<JUnaryOperator, JsUnaryOperator>();
1507:
1508:                static {
1509:                    bOpMap.put(JBinaryOperator.MUL, JsBinaryOperator.MUL);
1510:                    bOpMap.put(JBinaryOperator.DIV, JsBinaryOperator.DIV);
1511:                    bOpMap.put(JBinaryOperator.MOD, JsBinaryOperator.MOD);
1512:                    bOpMap.put(JBinaryOperator.ADD, JsBinaryOperator.ADD);
1513:                    bOpMap.put(JBinaryOperator.SUB, JsBinaryOperator.SUB);
1514:                    bOpMap.put(JBinaryOperator.SHL, JsBinaryOperator.SHL);
1515:                    bOpMap.put(JBinaryOperator.SHR, JsBinaryOperator.SHR);
1516:                    bOpMap.put(JBinaryOperator.SHRU, JsBinaryOperator.SHRU);
1517:                    bOpMap.put(JBinaryOperator.LT, JsBinaryOperator.LT);
1518:                    bOpMap.put(JBinaryOperator.LTE, JsBinaryOperator.LTE);
1519:                    bOpMap.put(JBinaryOperator.GT, JsBinaryOperator.GT);
1520:                    bOpMap.put(JBinaryOperator.GTE, JsBinaryOperator.GTE);
1521:                    bOpMap.put(JBinaryOperator.EQ, JsBinaryOperator.EQ);
1522:                    bOpMap.put(JBinaryOperator.NEQ, JsBinaryOperator.NEQ);
1523:                    bOpMap.put(JBinaryOperator.BIT_AND,
1524:                            JsBinaryOperator.BIT_AND);
1525:                    bOpMap.put(JBinaryOperator.BIT_XOR,
1526:                            JsBinaryOperator.BIT_XOR);
1527:                    bOpMap.put(JBinaryOperator.BIT_OR, JsBinaryOperator.BIT_OR);
1528:                    bOpMap.put(JBinaryOperator.AND, JsBinaryOperator.AND);
1529:                    bOpMap.put(JBinaryOperator.OR, JsBinaryOperator.OR);
1530:                    bOpMap.put(JBinaryOperator.ASG, JsBinaryOperator.ASG);
1531:                    bOpMap.put(JBinaryOperator.ASG_ADD,
1532:                            JsBinaryOperator.ASG_ADD);
1533:                    bOpMap.put(JBinaryOperator.ASG_SUB,
1534:                            JsBinaryOperator.ASG_SUB);
1535:                    bOpMap.put(JBinaryOperator.ASG_MUL,
1536:                            JsBinaryOperator.ASG_MUL);
1537:                    bOpMap.put(JBinaryOperator.ASG_DIV,
1538:                            JsBinaryOperator.ASG_DIV);
1539:                    bOpMap.put(JBinaryOperator.ASG_MOD,
1540:                            JsBinaryOperator.ASG_MOD);
1541:                    bOpMap.put(JBinaryOperator.ASG_SHL,
1542:                            JsBinaryOperator.ASG_SHL);
1543:                    bOpMap.put(JBinaryOperator.ASG_SHR,
1544:                            JsBinaryOperator.ASG_SHR);
1545:                    bOpMap.put(JBinaryOperator.ASG_SHRU,
1546:                            JsBinaryOperator.ASG_SHRU);
1547:                    bOpMap.put(JBinaryOperator.ASG_BIT_AND,
1548:                            JsBinaryOperator.ASG_BIT_AND);
1549:                    bOpMap.put(JBinaryOperator.ASG_BIT_OR,
1550:                            JsBinaryOperator.ASG_BIT_OR);
1551:                    bOpMap.put(JBinaryOperator.ASG_BIT_XOR,
1552:                            JsBinaryOperator.ASG_BIT_XOR);
1553:
1554:                    uOpMap.put(JUnaryOperator.INC, JsUnaryOperator.INC);
1555:                    uOpMap.put(JUnaryOperator.DEC, JsUnaryOperator.DEC);
1556:                    uOpMap.put(JUnaryOperator.NEG, JsUnaryOperator.NEG);
1557:                    uOpMap.put(JUnaryOperator.NOT, JsUnaryOperator.NOT);
1558:                    uOpMap.put(JUnaryOperator.BIT_NOT, JsUnaryOperator.BIT_NOT);
1559:                }
1560:
1561:                public static JsBinaryOperator get(JBinaryOperator op) {
1562:                    return bOpMap.get(op);
1563:                }
1564:
1565:                public static JsUnaryOperator get(JUnaryOperator op) {
1566:                    return uOpMap.get(op);
1567:                }
1568:            }
1569:
1570:            private class RecordCrossClassCalls extends JVisitor {
1571:
1572:                private JMethod currentMethod;
1573:
1574:                @Override
1575:                public void endVisit(JMethod x, Context ctx) {
1576:                    currentMethod = null;
1577:                }
1578:
1579:                @Override
1580:                public void endVisit(JMethodCall x, Context ctx) {
1581:                    JReferenceType sourceType = currentMethod
1582:                            .getEnclosingType();
1583:                    JReferenceType targetType = x.getTarget()
1584:                            .getEnclosingType();
1585:                    if (typeOracle.checkClinit(sourceType, targetType)) {
1586:                        crossClassTargets.add(x.getTarget());
1587:                    }
1588:                }
1589:
1590:                @Override
1591:                public void endVisit(JsniMethodRef x, Context ctx) {
1592:                    endVisit((JMethodCall) x, ctx);
1593:                }
1594:
1595:                @Override
1596:                public boolean visit(JMethod x, Context ctx) {
1597:                    currentMethod = x;
1598:                    return true;
1599:                }
1600:            }
1601:
1602:            private class SortVisitor extends JVisitor {
1603:
1604:                private final HasNameSort hasNameSort = new HasNameSort();
1605:
1606:                @Override
1607:                public void endVisit(JClassType x, Context ctx) {
1608:                    Collections.sort(x.fields, hasNameSort);
1609:
1610:                    // Sort the methods manually to avoid sorting clinit out of place!
1611:                    List<JMethod> methods = x.methods;
1612:                    JMethod a[] = methods.toArray(new JMethod[methods.size()]);
1613:                    Arrays.sort(a, 1, a.length, hasNameSort);
1614:                    for (int i = 1; i < a.length; i++) {
1615:                        methods.set(i, a[i]);
1616:                    }
1617:                }
1618:
1619:                @Override
1620:                public void endVisit(JInterfaceType x, Context ctx) {
1621:                    Collections.sort(x.fields, hasNameSort);
1622:                    Collections.sort(x.methods, hasNameSort);
1623:                }
1624:
1625:                @Override
1626:                public void endVisit(JMethodBody x, Context ctx) {
1627:                    Collections.sort(x.locals, hasNameSort);
1628:                }
1629:
1630:                @Override
1631:                public void endVisit(JProgram x, Context ctx) {
1632:                    Collections.sort(x.entryMethods, hasNameSort);
1633:                    Collections.sort(x.getDeclaredTypes(), hasNameSort);
1634:                }
1635:            }
1636:
1637:            public static void exec(JProgram program, JsProgram jsProgram,
1638:                    JsOutputOption output) {
1639:                GenerateJavaScriptAST generateJavaScriptAST = new GenerateJavaScriptAST(
1640:                        program, jsProgram, output);
1641:                generateJavaScriptAST.execImpl();
1642:            }
1643:
1644:            private final Map<JBlock, JsCatch> catchMap = new IdentityHashMap<JBlock, JsCatch>();
1645:
1646:            /**
1647:             * Sorted to avoid nondeterministic iteration.
1648:             */
1649:            private final Map<JType, JsName> classLits = new TreeMap<JType, JsName>(
1650:                    new HasNameSort());
1651:
1652:            private final Map<JsName, JsExpression> classObjects = new IdentityHashMap<JsName, JsExpression>();
1653:            private final Map<JClassType, JsScope> classScopes = new IdentityHashMap<JClassType, JsScope>();
1654:
1655:            /**
1656:             * A list of methods that are called from another class (ie might need to
1657:             * clinit).
1658:             */
1659:            private Set<JMethod> crossClassTargets = new HashSet<JMethod>();
1660:
1661:            /**
1662:             * Contains JsNames for all interface methods. A special scope is needed so
1663:             * that independent classes will obfuscate their interface implementation
1664:             * methods the same way.
1665:             */
1666:            private final JsScope interfaceScope;
1667:
1668:            private final JsProgram jsProgram;
1669:            private final Map<JAbstractMethodBody, JsFunction> methodBodyMap = new IdentityHashMap<JAbstractMethodBody, JsFunction>();
1670:            private final Map<HasName, JsName> names = new IdentityHashMap<HasName, JsName>();
1671:            private JsName nullMethodName;
1672:
1673:            /**
1674:             * Contains JsNames for the Object instance methods, such as equals, hashCode,
1675:             * and toString. All other class scopes have this scope as an ultimate parent.
1676:             */
1677:            private final JsScope objectScope;
1678:            private final Map<JMethod, JsName> polymorphicNames = new IdentityHashMap<JMethod, JsName>();
1679:            private final JProgram program;
1680:
1681:            /**
1682:             * All of the fields and polymorphic methods in String.
1683:             * 
1684:             * Because we modify String's prototype, all fields and polymorphic methods on
1685:             * String's super types need special handling.
1686:             */
1687:            private final Map<String, String> specialObfuscatedIdents = new HashMap<String, String>();
1688:
1689:            /**
1690:             * All of the super types of String.
1691:             * 
1692:             * Because we modify String's prototype, all fields and polymorphic methods on
1693:             * String's super types need special handling.
1694:             */
1695:            private final Set<JReferenceType> specialObfuscatedTypes = new HashSet<JReferenceType>();
1696:
1697:            /**
1698:             * Contains JsNames for all globals, such as static fields and methods.
1699:             */
1700:            private final JsScope topScope;
1701:
1702:            private final JTypeOracle typeOracle;
1703:            private final JsOutputOption output;
1704:
1705:            private GenerateJavaScriptAST(JProgram program,
1706:                    JsProgram jsProgram, JsOutputOption output) {
1707:                this .program = program;
1708:                typeOracle = program.typeOracle;
1709:                this .jsProgram = jsProgram;
1710:                topScope = jsProgram.getScope();
1711:                objectScope = jsProgram.getObjectScope();
1712:                interfaceScope = new JsScope(objectScope, "Interfaces");
1713:                this .output = output;
1714:
1715:                /*
1716:                 * Because we modify String's prototype, all fields and polymorphic methods
1717:                 * on String's super types need special handling.
1718:                 */
1719:                specialObfuscatedTypes
1720:                        .add(program.getIndexedType("Comparable"));
1721:                specialObfuscatedTypes.add(program
1722:                        .getIndexedType("CharSequence"));
1723:                specialObfuscatedTypes.add(program.getTypeJavaLangObject());
1724:                specialObfuscatedTypes.add(program.getTypeJavaLangString());
1725:                specialObfuscatedTypes.add(program.getIndexedType("Array"));
1726:
1727:                // Object polymorphic
1728:                specialObfuscatedIdents.put("getClass", "gC");
1729:                specialObfuscatedIdents.put("hashCode", "hC");
1730:                specialObfuscatedIdents.put("equals", "eQ");
1731:                specialObfuscatedIdents.put("toString", "tS");
1732:                specialObfuscatedIdents.put("finalize", "fZ");
1733:
1734:                // Object fields
1735:                specialObfuscatedIdents.put("typeId", "tI");
1736:
1737:                // String polymorphic
1738:                specialObfuscatedIdents.put("charAt", "cA");
1739:                specialObfuscatedIdents.put("compareTo", "cT");
1740:                specialObfuscatedIdents.put("length", "lN");
1741:                specialObfuscatedIdents.put("subSequence", "sS");
1742:
1743:                // Array magic field
1744:                specialObfuscatedIdents.put("arrayClass", "aC");
1745:                specialObfuscatedIdents.put("queryId", "qI");
1746:            }
1747:
1748:            boolean belongsToSpecialObfuscatedType(JField x) {
1749:                return specialObfuscatedTypes.contains(x.getEnclosingType());
1750:            }
1751:
1752:            boolean belongsToSpecialObfuscatedType(JMethod x) {
1753:                if (specialObfuscatedTypes.contains(x.getEnclosingType())) {
1754:                    return true;
1755:                }
1756:                for (Object element : x.overrides) {
1757:                    JMethod override = (JMethod) element;
1758:                    if (specialObfuscatedTypes.contains(override
1759:                            .getEnclosingType())) {
1760:                        return true;
1761:                    }
1762:                }
1763:                return false;
1764:            }
1765:
1766:            String getNameString(HasName hasName) {
1767:                String s = hasName.getName().replaceAll("_", "_1").replace('.',
1768:                        '_');
1769:                return s;
1770:            }
1771:
1772:            String mangleName(JField x) {
1773:                String s = getNameString(x.getEnclosingType()) + '_'
1774:                        + getNameString(x);
1775:                return s;
1776:            }
1777:
1778:            String mangleNameForGlobal(JMethod x) {
1779:                String s = getNameString(x.getEnclosingType()) + '_'
1780:                        + getNameString(x) + "__";
1781:                for (int i = 0; i < x.getOriginalParamTypes().size(); ++i) {
1782:                    JType type = x.getOriginalParamTypes().get(i);
1783:                    s += type.getJavahSignatureName();
1784:                }
1785:                return s;
1786:            }
1787:
1788:            String mangleNameForPoly(JMethod x) {
1789:                if (x.overrides.isEmpty()) {
1790:                    return mangleNameForPolyImpl(x);
1791:                } else {
1792:                    for (JMethod override : x.overrides) {
1793:                        if (override.overrides.isEmpty()) {
1794:                            return mangleNameForPolyImpl(override);
1795:                        }
1796:                    }
1797:                }
1798:                throw new InternalCompilerException("Cycle in overrides???");
1799:            }
1800:
1801:            String mangleNameForPolyImpl(JMethod x) {
1802:                String s = getNameString(x) + "__";
1803:                for (int i = 0; i < x.getOriginalParamTypes().size(); ++i) {
1804:                    JType type = x.getOriginalParamTypes().get(i);
1805:                    s += type.getJavahSignatureName();
1806:                }
1807:                return s;
1808:            }
1809:
1810:            String mangleNameSpecialObfuscate(JField x) {
1811:                assert (specialObfuscatedIdents.containsKey(x.getName()));
1812:                switch (output) {
1813:                case OBFUSCATED:
1814:                    return specialObfuscatedIdents.get(x.getName());
1815:                case PRETTY:
1816:                    return x.getName() + "$";
1817:                case DETAILED:
1818:                    return mangleName(x) + "$";
1819:                }
1820:                throw new InternalCompilerException("Unknown output mode");
1821:            }
1822:
1823:            String mangleNameSpecialObfuscate(JMethod x) {
1824:                assert (specialObfuscatedIdents.containsKey(x.getName()));
1825:                switch (output) {
1826:                case OBFUSCATED:
1827:                    return specialObfuscatedIdents.get(x.getName());
1828:                case PRETTY:
1829:                    return x.getName() + "$";
1830:                case DETAILED:
1831:                    return mangleNameForPoly(x) + "$";
1832:                }
1833:                throw new InternalCompilerException("Unknown output mode");
1834:            }
1835:
1836:            private void execImpl() {
1837:                SortVisitor sorter = new SortVisitor();
1838:                sorter.accept(program);
1839:                RecordCrossClassCalls recorder = new RecordCrossClassCalls();
1840:                recorder.accept(program);
1841:                CreateNamesAndScopesVisitor creator = new CreateNamesAndScopesVisitor();
1842:                creator.accept(program);
1843:                GenerateJavaScriptVisitor generator = new GenerateJavaScriptVisitor();
1844:                generator.accept(program);
1845:            }
1846:
1847:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.